mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
feat: 添加对内核引导协议的抽象 (#913)
* 添加multiboot header * head.S传参增加bootloader类型 * feat: 添加引导加载协议的抽象,并为multiboot2实现这个抽象. * 把framebuffer的映射地址改为从early ioremap和mmio pool分配 * riscv64能运行
This commit is contained in:
parent
cf7f801e1d
commit
2b7818e80e
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -129,7 +129,6 @@
|
||||
"assert.h": "c",
|
||||
"sys_version.h": "c",
|
||||
"cmd.h": "c",
|
||||
"sleep.h": "c",
|
||||
"net.h": "c",
|
||||
"cmd_test.h": "c",
|
||||
"cmpxchg.h": "c",
|
||||
|
@ -1,12 +1,24 @@
|
||||
# 引导加载程序
|
||||
|
||||
## 原理
|
||||
## X86_64
|
||||
|
||||
  目前,DragonOS支持Legacy BIOS以及UEFI两种方式,进行启动引导。
|
||||
- [x] multiboot2
|
||||
|
||||
  在`head.S`的头部包含了Multiboot2引导头,里面标志了一些Multiboot2相关的特定信息,以及一些配置命令。
|
||||
## RISC-V 64
|
||||
|
||||
  在DragonOS的启动初期,会存储由GRUB2传来的magic number以及multiboot2_boot_info_addr。当系统进入`Start_Kernel`函数之后,将会把这两个信息保存到multiboot2驱动程序之中。信息的具体含义请参照Multiboot2 Specification进行理解,该部分难度不大,相信读者经过思考能理解其中的原理。
|
||||
DragonOS在RISC-V 64上,启动流程为:
|
||||
|
||||
opensbi --> uboot --> DragonStub --> kernel
|
||||
|
||||
这个启动流程,使得DragonOS内核与具体的硬件板卡解耦,能够以同一个二进制文件,在不同的硬件板卡上启动运行。
|
||||
|
||||
|
||||
## 内核启动回调
|
||||
|
||||
DragonOS对内核引导加载程序进行了抽象,体现为`BootCallbacks`这个trait。
|
||||
不同的引导加载程序,实现对应的callback,初始化内核bootParams或者是其他的一些数据结构。
|
||||
|
||||
内核启动时,自动根据引导加载程序的类型,注册回调。并且在适当的时候,会调用这些回调函数。
|
||||
|
||||
## 参考资料
|
||||
|
||||
|
@ -8,4 +8,3 @@
|
||||
:caption: 目录
|
||||
|
||||
bootloader
|
||||
multiboot2
|
||||
|
@ -1,46 +0,0 @@
|
||||
# Multiboot2支持模块
|
||||
|
||||
  Multiboot2支持模块提供对Multiboot2协议的支持。位于`kernel/driver/multiboot2`文件夹中。
|
||||
|
||||
  根据Multiboot2协议,操作系统能够从BootLoader处获得一些信息,比如基本的硬件信息以及ACPI表的起始地址等。
|
||||
|
||||
---
|
||||
|
||||
## 数据结构
|
||||
|
||||
  `kernel/driver/multiboot2/multiboot2.h`中按照Multiboot2协议的规定,定义了大部分的数据结构,具体细节可查看该文件: [DragonOS/multiboot2.h at master · fslongjin/DragonOS · GitHub](https://github.com/fslongjin/DragonOS/blob/master/kernel/driver/multiboot2/multiboot2.h)
|
||||
|
||||
---
|
||||
|
||||
## 迭代器
|
||||
|
||||
  由于Multiboot2的信息存储在自`multiboot2_boot_info_addr`开始的一段连续的内存空间之中,且不同类型的header的长度不同,因此设计了一迭代器`multiboot2_iter`。
|
||||
|
||||
### 函数原型
|
||||
|
||||
```c
|
||||
void multiboot2_iter(bool (*_fun)(const struct iter_data_t *, void *, unsigned int *),
|
||||
void *data, unsigned int *count)
|
||||
```
|
||||
|
||||
**_fun**
|
||||
|
||||
  指定的handler。当某个header的tag与该handler所处理的tag相同时,handler将处理该header,并返回true。
|
||||
|
||||
  其第一个参数为tag类型,第二个参数为返回的数据的指针,第三个值为计数(某些没有用到该值的地方,该值可以为空)
|
||||
|
||||
**data**
|
||||
|
||||
  传递给`_fun`的第二个参数,`_fun`函数将填充该指针所指向的内存区域,从而返回数据。
|
||||
|
||||
**count**
|
||||
|
||||
  当返回的**data**为一个列表时,通过该值来指示列表中有多少项。
|
||||
|
||||
---
|
||||
|
||||
## 迭代工作函数
|
||||
|
||||
  在模块中,按照我们需要获取不同类型的tag的需要,定义了一些迭代器工作函数。
|
||||
|
||||
|
@ -27,7 +27,7 @@ fatfs-secure = ["fatfs"]
|
||||
|
||||
# 运行时依赖项
|
||||
[dependencies]
|
||||
acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "fb69243dcf" }
|
||||
acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "282df2af7b" }
|
||||
asm_macros = { path = "crates/asm_macros" }
|
||||
atomic_enum = "=0.2.0"
|
||||
bit_field = "=0.10"
|
||||
@ -35,9 +35,9 @@ bitfield-struct = "=0.5.3"
|
||||
bitflags = "=1.3.2"
|
||||
bitmap = { path = "crates/bitmap" }
|
||||
driver_base_macros = { "path" = "crates/driver_base_macros" }
|
||||
# 一个no_std的hashmap、hashset
|
||||
elf = { version = "=0.7.2", default-features = false }
|
||||
fdt = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt", rev = "9862813020" }
|
||||
# 一个no_std的hashmap、hashset
|
||||
hashbrown = "=0.13.2"
|
||||
ida = { path = "src/libs/ida" }
|
||||
intertrait = { path = "crates/intertrait" }
|
||||
@ -63,6 +63,7 @@ lru = "0.12.3"
|
||||
# target为x86_64时,使用下面的依赖
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
mini-backtrace = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/mini-backtrace.git", rev = "e0b1d90940" }
|
||||
multiboot2 = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/multiboot2", rev = "05739aab40" }
|
||||
raw-cpuid = "11.0.1"
|
||||
x86 = "=0.52.0"
|
||||
x86_64 = "=0.14.10"
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::ptr::addr_of;
|
||||
|
||||
/// 向控制台打印字符串。
|
||||
///
|
||||
/// 该函数接受一个字节切片 `s` 作为输入,并迭代切片中的每个字节 `c`。
|
||||
@ -75,7 +77,7 @@ impl SbiDriver {
|
||||
|
||||
/// 获取probe得到的SBI扩展信息。
|
||||
pub fn extensions() -> &'static SBIExtensions {
|
||||
unsafe { &EXTENSIONS }
|
||||
unsafe { addr_of!(EXTENSIONS).as_ref().unwrap() }
|
||||
}
|
||||
|
||||
fn probe_extensions() -> SBIExtensions {
|
||||
|
15
kernel/src/arch/riscv64/init/boot.rs
Normal file
15
kernel/src/arch/riscv64/init/boot.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::dragonstub::early_dragonstub_init;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u64)]
|
||||
pub(super) enum BootProtocol {
|
||||
DragonStub = 1,
|
||||
}
|
||||
|
||||
pub(super) fn early_boot_init(protocol: BootProtocol) -> Result<(), SystemError> {
|
||||
match protocol {
|
||||
BootProtocol::DragonStub => early_dragonstub_init(),
|
||||
}
|
||||
}
|
41
kernel/src/arch/riscv64/init/dragonstub.rs
Normal file
41
kernel/src/arch/riscv64/init/dragonstub.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use alloc::string::String;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::video::fbdev::base::BootTimeScreenInfo,
|
||||
init::boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
|
||||
};
|
||||
|
||||
pub(super) fn early_dragonstub_init() -> Result<(), SystemError> {
|
||||
register_boot_callbacks(&DragonStubCallBack);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct DragonStubCallBack;
|
||||
|
||||
impl BootCallbacks for DragonStubCallBack {
|
||||
fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
|
||||
Ok(format!("DragonStub").into())
|
||||
}
|
||||
|
||||
fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
|
||||
Ok(BootloaderAcpiArg::NotProvided)
|
||||
}
|
||||
|
||||
fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
|
||||
// parsed in `early_init_scan_chosen()`
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn early_init_framebuffer_info(
|
||||
&self,
|
||||
_scinfo: &mut BootTimeScreenInfo,
|
||||
) -> Result<(), SystemError> {
|
||||
unimplemented!("dragonstub early_init_framebuffer_info")
|
||||
}
|
||||
|
||||
fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
|
||||
// parsed in `early_init_scan_memory()` and uefi driver
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -3,7 +3,11 @@ use log::{debug, info};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{driver::sbi::SbiDriver, mm::init::mm_early_init},
|
||||
arch::{
|
||||
driver::sbi::SbiDriver,
|
||||
init::boot::{early_boot_init, BootProtocol},
|
||||
mm::init::mm_early_init,
|
||||
},
|
||||
driver::{firmware::efi::init::efi_init, open_firmware::fdt::open_firmware_fdt_driver},
|
||||
init::{boot_params, init::start_kernel},
|
||||
mm::{memblock::mem_block_manager, PhysAddr, VirtAddr},
|
||||
@ -13,6 +17,9 @@ use crate::{
|
||||
|
||||
use super::{cpu::init_local_context, interrupt::entry::handle_exception};
|
||||
|
||||
mod boot;
|
||||
mod dragonstub;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArchBootParams {
|
||||
/// 启动时的fdt物理地址
|
||||
@ -119,6 +126,7 @@ pub fn early_setup_arch() -> Result<(), SystemError> {
|
||||
"DragonOS kernel is running on hart {}, fdt address:{:?}",
|
||||
hartid, fdt_paddr
|
||||
);
|
||||
early_boot_init(BootProtocol::DragonStub).expect("Failed to init boot protocol!");
|
||||
mm_early_init();
|
||||
|
||||
print_node(fdt.find_node("/").unwrap(), 0);
|
||||
|
@ -1,3 +1,13 @@
|
||||
pub fn rand() -> usize {
|
||||
unimplemented!("RiscV64 rand");
|
||||
static mut SEED: u64 = 0xdead_beef_cafe_babe;
|
||||
let mut buf = [0u8; size_of::<usize>()];
|
||||
for x in buf.iter_mut() {
|
||||
unsafe {
|
||||
// from musl
|
||||
SEED = SEED.wrapping_mul(0x5851_f42d_4c95_7f2d);
|
||||
*x = (SEED >> 33) as u8;
|
||||
}
|
||||
}
|
||||
let x: usize = unsafe { core::mem::transmute(buf) };
|
||||
return x;
|
||||
}
|
||||
|
@ -13,8 +13,7 @@
|
||||
// The magic field should contain this.
|
||||
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||
|
||||
// This should be in %eax.
|
||||
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
|
||||
|
||||
|
||||
// Alignment of multiboot modules.
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
@ -71,7 +70,15 @@
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||
|
||||
// This should be in %eax.
|
||||
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2badb002
|
||||
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
|
||||
|
||||
// 存储到boot_entry_type的值
|
||||
#define BOOT_ENTRY_TYPE_MULTIBOOT 1
|
||||
#define BOOT_ENTRY_TYPE_MULTIBOOT2 2
|
||||
#define BOOT_ENTRY_TYPE_LINUX_32 3
|
||||
#define BOOT_ENTRY_TYPE_LINUX_64 4
|
||||
|
||||
// 直接用 -m64 编译出来的是 64 位代码,
|
||||
// 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
|
||||
@ -85,25 +92,40 @@
|
||||
// 声明这一段代码以 32 位模式编译
|
||||
.code32
|
||||
|
||||
.section ".multiboot_header", "a"
|
||||
|
||||
MB_MAGIC = 0x1BADB002
|
||||
MB_FLAGS = 0
|
||||
MB_CHECKSUM = -(MB_MAGIC + MB_FLAGS)
|
||||
|
||||
.code32
|
||||
multiboot_header:
|
||||
.align 8
|
||||
.long MB_MAGIC
|
||||
.long MB_FLAGS
|
||||
.long MB_CHECKSUM
|
||||
|
||||
|
||||
// multiboot2 文件头
|
||||
// 计算头长度
|
||||
.SET HEADER_LENGTH, multiboot_header_end - multiboot_header
|
||||
.SET MB2_HEADER_LENGTH, multiboot2_header_end - multiboot2_header
|
||||
// 计算校验和
|
||||
.SET CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + HEADER_LENGTH)
|
||||
.SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
|
||||
// 8 字节对齐
|
||||
.section .multiboot_header
|
||||
.code32
|
||||
.section .multiboot2_header
|
||||
.align MULTIBOOT_HEADER_ALIGN
|
||||
// 声明所属段
|
||||
|
||||
multiboot_header:
|
||||
multiboot2_header:
|
||||
// 魔数
|
||||
.long MULTIBOOT2_HEADER_MAGIC
|
||||
// 架构
|
||||
.long MULTIBOOT_ARCHITECTURE_I386
|
||||
// 头长度
|
||||
.long HEADER_LENGTH
|
||||
.long MB2_HEADER_LENGTH
|
||||
// 校验和
|
||||
.long CHECKSUM
|
||||
.long MB2_CHECKSUM
|
||||
// 添加其它内容在此,详细信息见 Multiboot2 Specification version 2.0.pdf
|
||||
|
||||
// 设置帧缓冲区(同时在这里设置qemu的分辨率, 默认为: 1440*900, 还支持: 640*480, 等)
|
||||
@ -121,13 +143,13 @@ framebuffer_tag_end:
|
||||
// 结束标记
|
||||
.short 0
|
||||
.long 8
|
||||
multiboot_header_end:
|
||||
multiboot2_header_end:
|
||||
|
||||
.section .bootstrap
|
||||
|
||||
|
||||
.global _start
|
||||
.type _start, @function
|
||||
# 在 multiboot2.cpp 中定义
|
||||
|
||||
.extern _start64
|
||||
.extern boot_info_addr
|
||||
@ -136,12 +158,30 @@ ENTRY(_start)
|
||||
// 关中断
|
||||
cli
|
||||
|
||||
// multiboot2_info 结构体指针
|
||||
mov %ebx, mb2_info
|
||||
// multiboot2_info/ multiboot_info 结构体指针
|
||||
mov %ebx, mb_entry_info
|
||||
//mov %ebx, %e8
|
||||
// 魔数
|
||||
mov %eax, mb2_magic
|
||||
// multiboot魔数
|
||||
mov %eax, mb_entry_magic
|
||||
|
||||
mov $MULTIBOOT_BOOTLOADER_MAGIC, %ebx
|
||||
cmp %eax, %ebx
|
||||
je bl_magic_is_mb
|
||||
mov $MULTIBOOT2_BOOTLOADER_MAGIC, %ebx
|
||||
cmp %eax, %ebx
|
||||
je bl_magic_is_mb2
|
||||
jmp halt // unreachable
|
||||
|
||||
bl_magic_is_mb:
|
||||
mov $BOOT_ENTRY_TYPE_MULTIBOOT, %ebx
|
||||
mov %ebx, boot_entry_type
|
||||
jmp protected_mode_setup
|
||||
bl_magic_is_mb2:
|
||||
mov $BOOT_ENTRY_TYPE_MULTIBOOT2, %ebx
|
||||
mov %ebx, boot_entry_type
|
||||
jmp protected_mode_setup
|
||||
|
||||
protected_mode_setup:
|
||||
//mov %eax, %e9
|
||||
/ 从保护模式跳转到长模式
|
||||
// 1. 允许 PAE
|
||||
@ -225,9 +265,10 @@ switch_to_start64:
|
||||
|
||||
|
||||
.code64
|
||||
is_from_ap:
|
||||
|
||||
halt:
|
||||
cli
|
||||
hlt
|
||||
jmp halt
|
||||
|
||||
.global _start64
|
||||
.type _start64, @function
|
||||
@ -435,10 +476,11 @@ repeat_set_idt:
|
||||
|
||||
|
||||
// 传参
|
||||
movq mb2_info, %rdi
|
||||
movq mb2_magic, %rsi
|
||||
movq mb_entry_info, %rdi
|
||||
movq mb_entry_magic, %rsi
|
||||
movq %r13, %rdx // GDT size
|
||||
movq %r12, %r10 // IDT size
|
||||
movq boot_entry_type, %r8
|
||||
|
||||
lretq
|
||||
|
||||
@ -573,8 +615,10 @@ IDT_BASE64: .quad IDT_Table + 0xffff800000000000
|
||||
|
||||
|
||||
.section .bootstrap.data
|
||||
mb2_magic: .quad 0
|
||||
mb2_info: .quad 0
|
||||
mb_entry_magic: .quad 0
|
||||
mb_entry_info: .quad 0
|
||||
// 引导协议类型
|
||||
boot_entry_type: .quad 0
|
||||
|
||||
.code32
|
||||
// 临时页表 4KB/页
|
||||
|
55
kernel/src/arch/x86_64/init/boot.rs
Normal file
55
kernel/src/arch/x86_64/init/boot.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::multiboot2::early_multiboot2_init;
|
||||
|
||||
const BOOT_ENTRY_TYPE_MULTIBOOT: u64 = 1;
|
||||
const BOOT_ENTRY_TYPE_MULTIBOOT2: u64 = 2;
|
||||
const BOOT_ENTRY_TYPE_LINUX_32: u64 = 3;
|
||||
const BOOT_ENTRY_TYPE_LINUX_64: u64 = 4;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u64)]
|
||||
enum BootProtocol {
|
||||
Multiboot = 1,
|
||||
Multiboot2,
|
||||
Linux32,
|
||||
Linux64,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for BootProtocol {
|
||||
type Error = SystemError;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
BOOT_ENTRY_TYPE_MULTIBOOT => Ok(BootProtocol::Multiboot),
|
||||
BOOT_ENTRY_TYPE_MULTIBOOT2 => Ok(BootProtocol::Multiboot2),
|
||||
BOOT_ENTRY_TYPE_LINUX_32 => Ok(BootProtocol::Linux32),
|
||||
BOOT_ENTRY_TYPE_LINUX_64 => Ok(BootProtocol::Linux64),
|
||||
_ => Err(SystemError::EINVAL),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub(super) fn early_boot_init(
|
||||
boot_entry_type: u64,
|
||||
arg1: u64,
|
||||
arg2: u64,
|
||||
) -> Result<(), SystemError> {
|
||||
let boot_protocol = BootProtocol::try_from(boot_entry_type)?;
|
||||
match boot_protocol {
|
||||
BootProtocol::Multiboot => {
|
||||
// early_multiboot_init(arg1, arg2);
|
||||
unimplemented!();
|
||||
}
|
||||
BootProtocol::Multiboot2 => early_multiboot2_init(arg1 as u32, arg2),
|
||||
BootProtocol::Linux32 => {
|
||||
// linux32_init(arg1, arg2);
|
||||
unimplemented!();
|
||||
}
|
||||
BootProtocol::Linux64 => {
|
||||
// linux64_init(arg1, arg2);
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::{
|
||||
hint::spin_loop,
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
|
||||
use log::debug;
|
||||
use system_error::SystemError;
|
||||
@ -11,6 +14,8 @@ use crate::{
|
||||
mm::{MemoryManagementArch, PhysAddr},
|
||||
};
|
||||
|
||||
use self::boot::early_boot_init;
|
||||
|
||||
use super::{
|
||||
driver::{
|
||||
hpet::{hpet_init, hpet_instance},
|
||||
@ -19,6 +24,9 @@ use super::{
|
||||
MMArch,
|
||||
};
|
||||
|
||||
mod boot;
|
||||
mod multiboot2;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArchBootParams {}
|
||||
|
||||
@ -31,7 +39,6 @@ extern "C" {
|
||||
static mut IDT_Table: [usize; 0usize];
|
||||
fn head_stack_start();
|
||||
|
||||
fn multiboot2_init(mb2_info: u64, mb2_magic: u32) -> bool;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -41,6 +48,7 @@ unsafe extern "C" fn kernel_main(
|
||||
mb2_magic: u64,
|
||||
bsp_gdt_size: u64,
|
||||
bsp_idt_size: u64,
|
||||
boot_entry_type: u64,
|
||||
) -> ! {
|
||||
let mut gdtp = DescriptorTablePointer::<usize>::default();
|
||||
let gdt_vaddr =
|
||||
@ -59,7 +67,11 @@ unsafe extern "C" fn kernel_main(
|
||||
x86::dtables::lidt(&idtp);
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
multiboot2_init(mb2_info, (mb2_magic & 0xFFFF_FFFF) as u32);
|
||||
if early_boot_init(boot_entry_type, mb2_magic, mb2_info).is_err() {
|
||||
loop {
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
start_kernel();
|
||||
|
248
kernel/src/arch/x86_64/init/multiboot2.rs
Normal file
248
kernel/src/arch/x86_64/init/multiboot2.rs
Normal file
@ -0,0 +1,248 @@
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use acpi::rsdp::Rsdp;
|
||||
use alloc::string::{String, ToString};
|
||||
use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType, RsdpV1Tag};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::mm::x86_64_set_kernel_load_base_paddr,
|
||||
driver::{
|
||||
serial::serial8250::send_to_default_serial8250_port,
|
||||
video::fbdev::{
|
||||
base::{BootTimeScreenInfo, BootTimeVideoType},
|
||||
vesafb::vesafb_early_map,
|
||||
},
|
||||
},
|
||||
init::{
|
||||
boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
|
||||
boot_params,
|
||||
},
|
||||
libs::lazy_init::Lazy,
|
||||
mm::{memblock::mem_block_manager, PhysAddr},
|
||||
};
|
||||
|
||||
pub(super) const MULTIBOOT2_ENTRY_MAGIC: u32 = multiboot2::MAGIC;
|
||||
static MB2_INFO: Lazy<BootInformation> = Lazy::new();
|
||||
const MB2_RAW_INFO_MAX_SIZE: usize = 4096;
|
||||
|
||||
static mut MB2_RAW_INFO: [u8; MB2_RAW_INFO_MAX_SIZE] = [0u8; MB2_RAW_INFO_MAX_SIZE];
|
||||
|
||||
fn mb2_rsdp_v1_tag_to_rsdp_struct(tag: &RsdpV1Tag) -> Rsdp {
|
||||
Rsdp {
|
||||
signature: tag.signature,
|
||||
checksum: tag.checksum,
|
||||
oem_id: tag.oem_id,
|
||||
revision: tag.revision,
|
||||
rsdt_address: tag.rsdt_address,
|
||||
length: 0,
|
||||
xsdt_address: 0,
|
||||
ext_checksum: 0,
|
||||
reserved: [0u8; 3],
|
||||
}
|
||||
}
|
||||
|
||||
fn mb2_rsdp_v2_tag_to_rsdp_struct(tag: &multiboot2::RsdpV2Tag) -> Rsdp {
|
||||
Rsdp {
|
||||
signature: tag.signature,
|
||||
checksum: tag.checksum,
|
||||
oem_id: tag.oem_id,
|
||||
revision: tag.revision,
|
||||
rsdt_address: tag.rsdt_address,
|
||||
length: tag.length,
|
||||
xsdt_address: tag.xsdt_address,
|
||||
ext_checksum: tag.ext_checksum,
|
||||
reserved: tag._reserved,
|
||||
}
|
||||
}
|
||||
struct Mb2Callback;
|
||||
|
||||
impl BootCallbacks for Mb2Callback {
|
||||
fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
|
||||
let name = MB2_INFO
|
||||
.get()
|
||||
.boot_loader_name_tag()
|
||||
.expect("MB2: Bootloader name tag not found!")
|
||||
.name()
|
||||
.expect("Failed to parse bootloader name!")
|
||||
.to_string();
|
||||
Ok(Some(name))
|
||||
}
|
||||
|
||||
fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
|
||||
if let Some(v1_tag) = MB2_INFO.get().rsdp_v1_tag() {
|
||||
Ok(BootloaderAcpiArg::Rsdt(mb2_rsdp_v1_tag_to_rsdp_struct(
|
||||
v1_tag,
|
||||
)))
|
||||
} else if let Some(v2_tag) = MB2_INFO.get().rsdp_v2_tag() {
|
||||
Ok(BootloaderAcpiArg::Xsdt(mb2_rsdp_v2_tag_to_rsdp_struct(
|
||||
v2_tag,
|
||||
)))
|
||||
} else {
|
||||
Ok(BootloaderAcpiArg::NotProvided)
|
||||
}
|
||||
}
|
||||
|
||||
fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
|
||||
let cmdline = MB2_INFO
|
||||
.get()
|
||||
.command_line_tag()
|
||||
.expect("Mb2: Command line tag not found!")
|
||||
.cmdline()
|
||||
.expect("Mb2: Failed to parse command line!");
|
||||
boot_params()
|
||||
.write_irqsave()
|
||||
.boot_cmdline_append(cmdline.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn early_init_framebuffer_info(
|
||||
&self,
|
||||
scinfo: &mut BootTimeScreenInfo,
|
||||
) -> Result<(), SystemError> {
|
||||
let Some(Ok(fb_tag)) = MB2_INFO.get().framebuffer_tag() else {
|
||||
return Err(SystemError::ENODEV);
|
||||
};
|
||||
let width = fb_tag.width();
|
||||
let height = fb_tag.height();
|
||||
scinfo.is_vga = true;
|
||||
scinfo.lfb_base = PhysAddr::new(fb_tag.address() as usize);
|
||||
|
||||
let fb_type = fb_tag.buffer_type().unwrap();
|
||||
match fb_type {
|
||||
multiboot2::FramebufferType::Indexed { palette: _ } => todo!(),
|
||||
multiboot2::FramebufferType::RGB { red, green, blue } => {
|
||||
scinfo.lfb_width = width;
|
||||
scinfo.lfb_height = height;
|
||||
scinfo.video_type = BootTimeVideoType::Vlfb;
|
||||
scinfo.lfb_depth = fb_tag.bpp();
|
||||
scinfo.red_pos = red.position;
|
||||
scinfo.red_size = red.size;
|
||||
scinfo.green_pos = green.position;
|
||||
scinfo.green_size = green.size;
|
||||
scinfo.blue_pos = blue.position;
|
||||
scinfo.blue_size = blue.size;
|
||||
}
|
||||
multiboot2::FramebufferType::Text => {
|
||||
scinfo.origin_video_cols = width as u8;
|
||||
scinfo.origin_video_lines = height as u8;
|
||||
scinfo.video_type = BootTimeVideoType::Mda;
|
||||
scinfo.lfb_depth = 8;
|
||||
}
|
||||
};
|
||||
|
||||
scinfo.lfb_size = (width * height * ((fb_tag.bpp() as u32 + 7) / 8)) as usize;
|
||||
|
||||
scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
|
||||
let mb2_info = MB2_INFO.get();
|
||||
send_to_default_serial8250_port("init_memory_area_from_multiboot2\n\0".as_bytes());
|
||||
|
||||
let mem_regions_tag = mb2_info
|
||||
.memory_map_tag()
|
||||
.expect("MB2: Memory map tag not found!");
|
||||
let mut total_mem_size = 0usize;
|
||||
let mut usable_mem_size = 0usize;
|
||||
for region in mem_regions_tag.memory_areas() {
|
||||
let start = PhysAddr::new(region.start_address() as usize);
|
||||
let size = region.size() as usize;
|
||||
let area_typ = MemoryAreaType::from(region.typ());
|
||||
total_mem_size += size;
|
||||
|
||||
match area_typ {
|
||||
MemoryAreaType::Available => {
|
||||
usable_mem_size += size;
|
||||
mem_block_manager()
|
||||
.add_block(start, size)
|
||||
.unwrap_or_else(|e| {
|
||||
log::warn!(
|
||||
"Failed to add memory block: base={:?}, size={:#x}, error={:?}",
|
||||
start,
|
||||
size,
|
||||
e
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_ => {
|
||||
mem_block_manager()
|
||||
.reserve_block(start, size)
|
||||
.unwrap_or_else(|e| {
|
||||
log::warn!(
|
||||
"Failed to reserve memory block: base={:?}, size={:#x}, error={:?}",
|
||||
start,
|
||||
size,
|
||||
e
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
send_to_default_serial8250_port("init_memory_area_from_multiboot2 end\n\0".as_bytes());
|
||||
log::info!(
|
||||
"Total memory size: {:#x}, Usable memory size: {:#x}",
|
||||
total_mem_size,
|
||||
usable_mem_size
|
||||
);
|
||||
|
||||
// Add the boot module region since Grub does not specify it.
|
||||
let mb2_module_tag = mb2_info.module_tags();
|
||||
for module in mb2_module_tag {
|
||||
let start = PhysAddr::new(module.start_address() as usize);
|
||||
let size = module.module_size() as usize;
|
||||
mem_block_manager()
|
||||
.reserve_block(start, size)
|
||||
.unwrap_or_else(|e| {
|
||||
log::warn!(
|
||||
"Failed to reserve memory block for mb2 modules: base={:?}, size={:#x}, error={:?}",
|
||||
start,
|
||||
size,
|
||||
e
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// setup kernel load base
|
||||
self.setup_kernel_load_base();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mb2Callback {
|
||||
fn setup_kernel_load_base(&self) {
|
||||
let mb2_info = MB2_INFO.get();
|
||||
let kernel_start = mb2_info
|
||||
.load_base_addr_tag()
|
||||
.expect("MB2: Load base address tag not found!")
|
||||
.load_base_addr();
|
||||
let loadbase = PhysAddr::new(kernel_start as usize);
|
||||
x86_64_set_kernel_load_base_paddr(loadbase);
|
||||
}
|
||||
}
|
||||
pub(super) fn early_multiboot2_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError> {
|
||||
assert_eq!(boot_magic, MULTIBOOT2_ENTRY_MAGIC);
|
||||
let bi_ptr = boot_info as usize as *const BootInformationHeader;
|
||||
let bi_size = unsafe { (*bi_ptr).total_size() as usize };
|
||||
assert!(bi_size <= MB2_RAW_INFO_MAX_SIZE);
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(bi_ptr as *const u8, MB2_RAW_INFO.as_mut_ptr(), bi_size);
|
||||
}
|
||||
|
||||
let boot_info =
|
||||
unsafe { BootInformation::load(MB2_RAW_INFO.as_mut_ptr() as *const BootInformationHeader) }
|
||||
.inspect_err(|_| loop {
|
||||
spin_loop();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
MB2_INFO.init(boot_info);
|
||||
|
||||
register_boot_callbacks(&Mb2Callback);
|
||||
|
||||
return Ok(());
|
||||
}
|
@ -13,6 +13,7 @@ SECTIONS
|
||||
.boot.text :
|
||||
{
|
||||
KEEP(*(.multiboot_header))
|
||||
KEEP(*(.multiboot2_header))
|
||||
*(.bootstrap)
|
||||
*(.bootstrap.code64)
|
||||
*(.bootstrap.data)
|
||||
|
@ -6,15 +6,13 @@ pub mod pkru;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use hashbrown::HashSet;
|
||||
use log::{debug, info, warn};
|
||||
use log::{debug, info};
|
||||
use x86::time::rdtsc;
|
||||
use x86_64::registers::model_specific::EferFlags;
|
||||
|
||||
use crate::driver::serial::serial8250::send_to_default_serial8250_port;
|
||||
use crate::include::bindings::bindings::{
|
||||
multiboot2_get_load_base, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
||||
multiboot_tag_load_base_addr_t,
|
||||
};
|
||||
|
||||
use crate::init::boot::boot_callbacks;
|
||||
use crate::libs::align::page_align_up;
|
||||
use crate::libs::lib_ui::screen_manager::scm_disable_put_to_window;
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
@ -34,9 +32,7 @@ use crate::mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, VmFlags
|
||||
use system_error::SystemError;
|
||||
|
||||
use core::arch::asm;
|
||||
use core::ffi::c_void;
|
||||
use core::fmt::Debug;
|
||||
use core::mem::{self};
|
||||
|
||||
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
|
||||
|
||||
@ -63,6 +59,12 @@ pub struct X86_64MMBootstrapInfo {
|
||||
|
||||
pub(super) static mut BOOTSTRAP_MM_INFO: Option<X86_64MMBootstrapInfo> = None;
|
||||
|
||||
pub(super) fn x86_64_set_kernel_load_base_paddr(paddr: PhysAddr) {
|
||||
unsafe {
|
||||
BOOTSTRAP_MM_INFO.as_mut().unwrap().kernel_load_base_paddr = paddr.data();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief X86_64的内存管理架构结构体
|
||||
#[derive(Debug, Clone, Copy, Hash)]
|
||||
pub struct X86_64MMArch;
|
||||
@ -125,8 +127,8 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
const USER_STACK_START: VirtAddr = VirtAddr::new(0x6ffff0a00000);
|
||||
|
||||
const FIXMAP_START_VADDR: VirtAddr = VirtAddr::new(0xffffb00000000000);
|
||||
/// 设置FIXMAP区域大小为1M
|
||||
const FIXMAP_SIZE: usize = 256 * 4096;
|
||||
/// 设置FIXMAP区域大小为16M
|
||||
const FIXMAP_SIZE: usize = 256 * 4096 * 16;
|
||||
|
||||
const MMIO_BASE: VirtAddr = VirtAddr::new(0xffffa10000000000);
|
||||
const MMIO_SIZE: usize = 1 << PAGE_1G_SHIFT;
|
||||
@ -142,10 +144,9 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
}
|
||||
|
||||
Self::init_xd_rsvd();
|
||||
let load_base_paddr = Self::get_load_base_paddr();
|
||||
|
||||
let bootstrap_info = X86_64MMBootstrapInfo {
|
||||
kernel_load_base_paddr: load_base_paddr.data(),
|
||||
kernel_load_base_paddr: 0,
|
||||
kernel_code_start: _text as usize,
|
||||
kernel_code_end: _etext as usize,
|
||||
kernel_data_end: _edata as usize,
|
||||
@ -157,8 +158,10 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
BOOTSTRAP_MM_INFO = Some(bootstrap_info);
|
||||
}
|
||||
|
||||
// 初始化物理内存区域(从multiboot2中获取)
|
||||
Self::init_memory_area_from_multiboot2().expect("init memory area failed");
|
||||
// 初始化物理内存区域
|
||||
boot_callbacks()
|
||||
.early_init_memory_blocks()
|
||||
.expect("init memory area failed");
|
||||
|
||||
debug!("bootstrap info: {:?}", unsafe { BOOTSTRAP_MM_INFO });
|
||||
debug!("phys[0]=virt[0x{:x}]", unsafe {
|
||||
@ -168,7 +171,7 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
// 初始化内存管理器
|
||||
unsafe { allocator_init() };
|
||||
|
||||
send_to_default_serial8250_port("x86 64 init done\n\0".as_bytes());
|
||||
send_to_default_serial8250_port("x86 64 mm init done\n\0".as_bytes());
|
||||
}
|
||||
|
||||
/// @brief 刷新TLB中,关于指定虚拟地址的条目
|
||||
@ -416,73 +419,6 @@ const fn protection_map() -> [EntryFlags<MMArch>; 16] {
|
||||
}
|
||||
|
||||
impl X86_64MMArch {
|
||||
unsafe fn get_load_base_paddr() -> PhysAddr {
|
||||
let mut mb2_lb_info: [multiboot_tag_load_base_addr_t; 512] = mem::zeroed();
|
||||
send_to_default_serial8250_port("get_load_base_paddr begin\n\0".as_bytes());
|
||||
|
||||
let mut mb2_count: u32 = 0;
|
||||
multiboot2_iter(
|
||||
Some(multiboot2_get_load_base),
|
||||
&mut mb2_lb_info as *mut [multiboot_tag_load_base_addr_t; 512] as usize as *mut c_void,
|
||||
&mut mb2_count,
|
||||
);
|
||||
|
||||
if mb2_count == 0 {
|
||||
send_to_default_serial8250_port(
|
||||
"get_load_base_paddr mb2_count == 0, default to 1MB\n\0".as_bytes(),
|
||||
);
|
||||
return PhysAddr::new(0x100000);
|
||||
}
|
||||
|
||||
let phys = mb2_lb_info[0].load_base_addr as usize;
|
||||
|
||||
return PhysAddr::new(phys);
|
||||
}
|
||||
unsafe fn init_memory_area_from_multiboot2() -> Result<usize, SystemError> {
|
||||
// 这个数组用来存放内存区域的信息(从C获取)
|
||||
let mut mb2_mem_info: [multiboot_mmap_entry_t; 512] = mem::zeroed();
|
||||
send_to_default_serial8250_port("init_memory_area_from_multiboot2 begin\n\0".as_bytes());
|
||||
|
||||
let mut mb2_count: u32 = 0;
|
||||
multiboot2_iter(
|
||||
Some(multiboot2_get_memory),
|
||||
&mut mb2_mem_info as *mut [multiboot_mmap_entry_t; 512] as usize as *mut c_void,
|
||||
&mut mb2_count,
|
||||
);
|
||||
send_to_default_serial8250_port("init_memory_area_from_multiboot2 2\n\0".as_bytes());
|
||||
|
||||
let mb2_count = mb2_count as usize;
|
||||
let mut areas_count = 0usize;
|
||||
let mut total_mem_size = 0usize;
|
||||
for info_entry in mb2_mem_info.iter().take(mb2_count) {
|
||||
// Only use the memory area if its type is 1 (RAM)
|
||||
if info_entry.type_ == 1 {
|
||||
// Skip the memory area if its len is 0
|
||||
if info_entry.len == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
total_mem_size += info_entry.len as usize;
|
||||
|
||||
mem_block_manager()
|
||||
.add_block(
|
||||
PhysAddr::new(info_entry.addr as usize),
|
||||
info_entry.len as usize,
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
warn!(
|
||||
"Failed to add memory block: base={:#x}, size={:#x}, error={:?}",
|
||||
info_entry.addr, info_entry.len, e
|
||||
);
|
||||
});
|
||||
areas_count += 1;
|
||||
}
|
||||
}
|
||||
send_to_default_serial8250_port("init_memory_area_from_multiboot2 end\n\0".as_bytes());
|
||||
info!("Total memory size: {} MB, total areas from multiboot2: {mb2_count}, valid areas: {areas_count}", total_mem_size / 1024 / 1024);
|
||||
return Ok(areas_count);
|
||||
}
|
||||
|
||||
fn init_xd_rsvd() {
|
||||
// 读取ia32-EFER寄存器的值
|
||||
let efer: EferFlags = x86_64::registers::model_specific::Efer::read();
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::arch::TraitPciArch;
|
||||
use crate::arch::io::PortIOArch;
|
||||
use crate::arch::{CurrentPortIOArch, TraitPciArch};
|
||||
use crate::driver::acpi::acpi_manager;
|
||||
use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo};
|
||||
use crate::driver::pci::pci::{
|
||||
@ -6,7 +7,6 @@ use crate::driver::pci::pci::{
|
||||
PORT_PCI_CONFIG_DATA,
|
||||
};
|
||||
use crate::driver::pci::root::{pci_root_manager, PciRoot};
|
||||
use crate::include::bindings::bindings::{io_in32, io_in8, io_out32};
|
||||
use crate::init::initcall::INITCALL_SUBSYS;
|
||||
use crate::mm::PhysAddr;
|
||||
|
||||
@ -22,7 +22,7 @@ impl X86_64PciArch {
|
||||
/// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/early.c?fi=read_pci_config_byte#19
|
||||
fn read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u8 {
|
||||
unsafe {
|
||||
io_out32(
|
||||
CurrentPortIOArch::out32(
|
||||
PORT_PCI_CONFIG_ADDRESS,
|
||||
0x80000000
|
||||
| ((bus as u32) << 16)
|
||||
@ -31,7 +31,7 @@ impl X86_64PciArch {
|
||||
| offset as u32,
|
||||
);
|
||||
}
|
||||
let value = unsafe { io_in8(PORT_PCI_CONFIG_DATA + (offset & 3) as u16) };
|
||||
let value = unsafe { CurrentPortIOArch::in8(PORT_PCI_CONFIG_DATA + (offset & 3) as u16) };
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@ -45,8 +45,8 @@ impl TraitPciArch for X86_64PciArch {
|
||||
| (offset & 0xfc) as u32
|
||||
| (0x80000000);
|
||||
let ret = unsafe {
|
||||
io_out32(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
let temp = io_in32(PORT_PCI_CONFIG_DATA);
|
||||
CurrentPortIOArch::out32(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
let temp = CurrentPortIOArch::in32(PORT_PCI_CONFIG_DATA);
|
||||
temp
|
||||
};
|
||||
return ret;
|
||||
@ -59,9 +59,9 @@ impl TraitPciArch for X86_64PciArch {
|
||||
| (offset & 0xfc) as u32
|
||||
| (0x80000000);
|
||||
unsafe {
|
||||
io_out32(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
CurrentPortIOArch::out32(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
// 写入数据
|
||||
io_out32(PORT_PCI_CONFIG_DATA, data);
|
||||
CurrentPortIOArch::out32(PORT_PCI_CONFIG_DATA, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
kernel_driver_subdirs:=acpi multiboot2
|
||||
kernel_driver_subdirs:=
|
||||
|
||||
ECHO:
|
||||
@echo "$@"
|
||||
|
@ -1,10 +0,0 @@
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CFLAGS += -I .
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
@ -1,35 +0,0 @@
|
||||
#include "acpi.h"
|
||||
#include <common/kprint.h>
|
||||
#include <driver/multiboot2/multiboot2.h>
|
||||
|
||||
extern void rs_acpi_init(uint64_t rsdp_paddr1, uint64_t rsdp_paddr2);
|
||||
|
||||
static struct acpi_RSDP_t *rsdpv1;
|
||||
static struct acpi_RSDP_2_t *rsdpv2;
|
||||
|
||||
static struct multiboot_tag_old_acpi_t old_acpi;
|
||||
static struct multiboot_tag_new_acpi_t new_acpi;
|
||||
|
||||
/**
|
||||
* @brief 初始化acpi模块
|
||||
*
|
||||
*/
|
||||
void acpi_init()
|
||||
{
|
||||
kinfo("Initializing ACPI...");
|
||||
|
||||
// 获取物理地址
|
||||
int reserved;
|
||||
|
||||
multiboot2_iter(multiboot2_get_acpi_old_RSDP, &old_acpi, &reserved);
|
||||
rsdpv1 = &(old_acpi.rsdp);
|
||||
|
||||
multiboot2_iter(multiboot2_get_acpi_new_RSDP, &new_acpi, &reserved);
|
||||
rsdpv2 = &(new_acpi.rsdp);
|
||||
|
||||
// rsdpv1、rsdpv2,二者有一个能成功即可
|
||||
rs_acpi_init((uint64_t)rsdpv1, (uint64_t)rsdpv2);
|
||||
|
||||
kinfo("ACPI module initialized!");
|
||||
return;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* 解析acpi信息的模块
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <mm/mm.h>
|
||||
|
||||
struct acpi_RSDP_t
|
||||
{
|
||||
unsigned char Signature[8];
|
||||
unsigned char Checksum;
|
||||
unsigned char OEMID[6];
|
||||
|
||||
unsigned char Revision;
|
||||
|
||||
// 32bit physical address of the RSDT
|
||||
uint RsdtAddress;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_RSDP_2_t
|
||||
{
|
||||
struct acpi_RSDP_t rsdp1;
|
||||
|
||||
// fields below are only valid when the revision value is 2 or above
|
||||
// 表的长度(单位:字节)从offset=0开始算
|
||||
uint Length;
|
||||
// 64bit的XSDT的物理地址
|
||||
ul XsdtAddress;
|
||||
unsigned char ExtendedChecksum; // 整个表的checksum,包括了之前的checksum区域
|
||||
|
||||
unsigned char Reserved[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
// 初始化acpi模块
|
||||
void acpi_init();
|
@ -1,8 +0,0 @@
|
||||
use super::acpi_manager;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_acpi_init(rsdp_vaddr1: u64, rsdp_vaddr2: u64) {
|
||||
acpi_manager()
|
||||
.init(rsdp_vaddr1, rsdp_vaddr2)
|
||||
.expect("rs_acpi_init(): failed to init acpi");
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use core::{fmt::Debug, hint::spin_loop, ptr::NonNull};
|
||||
use core::{fmt::Debug, ptr::NonNull};
|
||||
|
||||
use acpi::{AcpiHandler, AcpiTables, PlatformInfo};
|
||||
use alloc::{string::ToString, sync::Arc};
|
||||
@ -7,6 +7,7 @@ use log::{error, info};
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::base::firmware::sys_firmware_kset,
|
||||
init::{boot::BootloaderAcpiArg, boot_params},
|
||||
libs::align::{page_align_down, page_align_up, AlignedBox},
|
||||
mm::{
|
||||
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||||
@ -20,7 +21,6 @@ use super::base::kset::KSet;
|
||||
extern crate acpi;
|
||||
|
||||
pub mod bus;
|
||||
mod c_adapter;
|
||||
pub mod glue;
|
||||
pub mod pmtmr;
|
||||
mod sysfs;
|
||||
@ -56,7 +56,7 @@ impl AcpiManager {
|
||||
/// ## 参考资料
|
||||
///
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1390
|
||||
pub fn init(&self, rsdp_vaddr1: u64, rsdp_vaddr2: u64) -> Result<(), SystemError> {
|
||||
fn init(&self) -> Result<(), SystemError> {
|
||||
info!("Initializing Acpi Manager...");
|
||||
|
||||
// 初始化`/sys/firmware/acpi`的kset
|
||||
@ -65,45 +65,45 @@ impl AcpiManager {
|
||||
unsafe {
|
||||
ACPI_KSET_INSTANCE = Some(kset.clone());
|
||||
}
|
||||
self.map_tables(rsdp_vaddr1, rsdp_vaddr2)?;
|
||||
let acpi_args = boot_params().read().acpi;
|
||||
if let BootloaderAcpiArg::NotProvided = acpi_args {
|
||||
error!("acpi_init(): ACPI not provided by bootloader");
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
|
||||
self.map_tables(acpi_args)?;
|
||||
self.bus_init()?;
|
||||
info!("Acpi Manager initialized.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn map_tables(&self, rsdp_vaddr1: u64, rsdp_vaddr2: u64) -> Result<(), SystemError> {
|
||||
let rsdp_paddr1 = Self::rsdp_paddr(rsdp_vaddr1);
|
||||
let res1 = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr1.data()) };
|
||||
let e1;
|
||||
match res1 {
|
||||
// 如果rsdpv1能够获取到acpi_table,则就用该表,不用rsdpv2了
|
||||
fn map_tables(&self, acpi_args: BootloaderAcpiArg) -> Result<(), SystemError> {
|
||||
let table_paddr: PhysAddr = match acpi_args {
|
||||
BootloaderAcpiArg::Rsdt(rsdpv1) => Self::rsdp_paddr(&rsdpv1),
|
||||
BootloaderAcpiArg::Xsdt(rsdpv2) => Self::rsdp_paddr(&rsdpv2),
|
||||
_ => {
|
||||
error!(
|
||||
"AcpiManager::map_tables(): unsupported acpi_args: {:?}",
|
||||
acpi_args
|
||||
);
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
};
|
||||
let res = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, table_paddr.data()) };
|
||||
match res {
|
||||
Ok(acpi_table) => {
|
||||
Self::set_acpi_table(acpi_table);
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
e1 = e;
|
||||
error!(
|
||||
"AcpiManager::map_tables(): failed to map tables, error: {:?}",
|
||||
e
|
||||
);
|
||||
Self::drop_rsdp_tmp_box();
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
}
|
||||
|
||||
let rsdp_paddr2 = Self::rsdp_paddr(rsdp_vaddr2);
|
||||
let res2 = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr2.data()) };
|
||||
match res2 {
|
||||
Ok(acpi_table) => {
|
||||
Self::set_acpi_table(acpi_table);
|
||||
}
|
||||
// 如果rsdpv1和rsdpv2都无法获取到acpi_table,说明有问题,打印报错信息后进入死循环
|
||||
Err(e2) => {
|
||||
error!("acpi_init(): failed to parse acpi tables, error: (rsdpv1: {:?}) or (rsdpv2: {:?})", e1, e2);
|
||||
Self::drop_rsdp_tmp_box();
|
||||
loop {
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 通过RSDP虚拟地址获取RSDP物理地址
|
||||
@ -115,13 +115,18 @@ impl AcpiManager {
|
||||
/// ## 返回值
|
||||
///
|
||||
/// RSDP物理地址
|
||||
fn rsdp_paddr(rsdp_vaddr: u64) -> PhysAddr {
|
||||
fn rsdp_paddr(rsdp_instance: &acpi::rsdp::Rsdp) -> PhysAddr {
|
||||
unsafe {
|
||||
RSDP_TMP_BOX = Some(AlignedBox::new_zeroed().expect("rs_acpi_init(): failed to alloc"))
|
||||
};
|
||||
|
||||
let size = core::mem::size_of::<acpi::rsdp::Rsdp>();
|
||||
let tmp_data =
|
||||
unsafe { core::slice::from_raw_parts(rsdp_vaddr as usize as *const u8, size) };
|
||||
let tmp_data = unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
rsdp_instance as *const acpi::rsdp::Rsdp as usize as *const u8,
|
||||
size,
|
||||
)
|
||||
};
|
||||
unsafe { RSDP_TMP_BOX.as_mut().unwrap()[0..size].copy_from_slice(tmp_data) };
|
||||
let rsdp_paddr = unsafe {
|
||||
MMArch::virt_2_phys(VirtAddr::new(
|
||||
@ -221,3 +226,17 @@ impl AcpiHandler for AcpiHandlerImpl {
|
||||
drop(mmio_guard);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn acpi_init() -> Result<(), SystemError> {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
acpi_manager().init()
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
{
|
||||
log::warn!("acpi_init(): unsupported arch");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CFLAGS += -I .
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
@ -1,165 +0,0 @@
|
||||
#include "multiboot2.h"
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <common/kprint.h>
|
||||
// uintptr_t multiboot2_boot_info_addr;
|
||||
// unsigned int multiboot2_magic;
|
||||
unsigned int multiboot2_boot_info_size;
|
||||
|
||||
#define MBI_RAW_MAX_SIZE 409600
|
||||
// 由于启动时传递的mb2 info所在的地址,在内存管理初始化之后会被覆盖,所以需要将其拷贝到一个固定的位置
|
||||
static uint8_t mbi_raw[MBI_RAW_MAX_SIZE] = {0};
|
||||
bool multiboot2_init(uint64_t mb2_info_paddr, uint32_t mb2_magic)
|
||||
{
|
||||
uint64_t vaddr = (uint64_t)phys_2_virt(mb2_info_paddr);
|
||||
if (mb2_magic != MULTIBOOT2_BOOTLOADER_MAGIC)
|
||||
return false;
|
||||
// vaddr+0 处保存了大小
|
||||
multiboot2_boot_info_size = *(uint32_t *)vaddr;
|
||||
if (multiboot2_boot_info_size > MBI_RAW_MAX_SIZE)
|
||||
return false;
|
||||
|
||||
memcpy((void *)mbi_raw, (void *)vaddr, multiboot2_boot_info_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void multiboot2_iter(bool (*_fun)(const struct iter_data_t *, void *, unsigned int *),
|
||||
void *data, unsigned int *count)
|
||||
{
|
||||
// kdebug("multiboot2_boot_info_addr=%#018lx", multiboot2_boot_info_addr);
|
||||
|
||||
// uintptr_t addr = multiboot2_boot_info_addr;
|
||||
|
||||
// for(int i=0;i<8192;i++)
|
||||
// {
|
||||
// mbi_raw[i] = ((uint8_t *)multiboot2_boot_info_addr)[i];
|
||||
// }
|
||||
uint8_t * addr = mbi_raw;
|
||||
// 接下来的第8字节开始,为 tag 信息
|
||||
struct iter_data_t *tag = (struct iter_data_t *)((void *)addr + 8);
|
||||
for (; tag->type != MULTIBOOT_TAG_TYPE_END;
|
||||
tag = (struct iter_data_t *)((uint8_t *)tag + ALIGN(tag->size, 8)))
|
||||
{
|
||||
|
||||
if (_fun(tag, data, count) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取 grub2 传递的物理内存信息,保存到 e820map_t 结构体中
|
||||
// 一般而言是这样的
|
||||
// 地址(长度) 类型
|
||||
// 0x00(0x9F000) 0x1
|
||||
// 0x9F000(0x1000) 0x2
|
||||
// 0xE8000(0x18000) 0x2
|
||||
// 0x100000(0x7EF0000) 0x1
|
||||
// 0x7FF0000(0x10000) 0x3
|
||||
// 0xFFFC0000(0x40000) 0x2
|
||||
/**
|
||||
* @brief 获取multiboot2协议提供的内存区域信息
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data 返回信息的结构体指针
|
||||
* @param count 返回数组的长度
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool multiboot2_get_memory(const struct iter_data_t *_iter_data, void *data, unsigned int *count)
|
||||
{
|
||||
if (_iter_data->type != MULTIBOOT_TAG_TYPE_MMAP)
|
||||
return false;
|
||||
|
||||
struct multiboot_mmap_entry_t *resource = (struct multiboot_mmap_entry_t *)data;
|
||||
struct multiboot_mmap_entry_t *mmap = ((struct multiboot_tag_mmap_t *)_iter_data)->entries;
|
||||
*count = 0;
|
||||
for (; (uint8_t *)mmap < (uint8_t *)_iter_data + _iter_data->size;
|
||||
mmap = (struct multiboot_mmap_entry_t *)((uint8_t *)mmap + ((struct multiboot_tag_mmap_t *)_iter_data)->entry_size))
|
||||
{
|
||||
*resource = *mmap;
|
||||
// 将指针进行增加
|
||||
resource = (struct multiboot_mmap_entry_t *)((uint8_t *)resource + ((struct multiboot_tag_mmap_t *)_iter_data)->entry_size);
|
||||
++(*count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取VBE信息
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data 返回信息的结构体指针
|
||||
*/
|
||||
bool multiboot2_get_VBE_info(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved)
|
||||
{
|
||||
|
||||
if (_iter_data->type != MULTIBOOT_TAG_TYPE_VBE)
|
||||
return false;
|
||||
*(struct multiboot_tag_vbe_t *)data = *(struct multiboot_tag_vbe_t *)_iter_data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief 获取加载基地址
|
||||
/// @param _iter_data
|
||||
/// @param data
|
||||
/// @param reserved
|
||||
/// @return
|
||||
bool multiboot2_get_load_base(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved)
|
||||
{
|
||||
|
||||
if (_iter_data->type != MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR)
|
||||
return false;
|
||||
*(struct multiboot_tag_load_base_addr_t *)data = *(struct multiboot_tag_load_base_addr_t *)_iter_data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取帧缓冲区信息
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data 返回信息的结构体指针
|
||||
*/
|
||||
bool multiboot2_get_Framebuffer_info(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved)
|
||||
{
|
||||
if (_iter_data->type != MULTIBOOT_TAG_TYPE_FRAMEBUFFER)
|
||||
return false;
|
||||
*(struct multiboot_tag_framebuffer_info_t *)data = *(struct multiboot_tag_framebuffer_info_t *)_iter_data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取acpi旧版RSDP
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data old RSDP的结构体指针
|
||||
* @param reserved
|
||||
* @return uint8_t* struct multiboot_tag_old_acpi_t
|
||||
*/
|
||||
bool multiboot2_get_acpi_old_RSDP(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved)
|
||||
{
|
||||
if (_iter_data->type != MULTIBOOT_TAG_TYPE_ACPI_OLD)
|
||||
return false;
|
||||
|
||||
*(struct multiboot_tag_old_acpi_t *)data = *(struct multiboot_tag_old_acpi_t *)_iter_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取acpi新版RSDP
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data old RSDP的结构体指针
|
||||
* @param reserved
|
||||
* @return uint8_t* struct multiboot_tag_old_acpi_t
|
||||
*/
|
||||
bool multiboot2_get_acpi_new_RSDP(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved)
|
||||
{
|
||||
if (_iter_data->type != MULTIBOOT_TAG_TYPE_ACPI_NEW)
|
||||
return false;
|
||||
*(struct multiboot_tag_new_acpi_t *)data = *(struct multiboot_tag_new_acpi_t *)_iter_data;
|
||||
return true;
|
||||
}
|
@ -1,473 +0,0 @@
|
||||
/**
|
||||
* @file multiboot2.h
|
||||
* @brief multiboot2 解析
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DragonOS/stdint.h>
|
||||
#include "stdbool.h"
|
||||
#include <common/boot_info.h>
|
||||
#include <driver/acpi/acpi.h>
|
||||
|
||||
/// @see Multiboot2 Specification version 2.0.pdf
|
||||
// 启动后,在 32 位内核进入点,机器状态如下:
|
||||
// 1. CS 指向基地址为 0x00000000,限长为4G – 1的代码段描述符。
|
||||
// 2. DS,SS,ES,FS 和 GS 指向基地址为0x00000000,限长为4G –
|
||||
// 1的数据段描述符。
|
||||
// 3. A20 地址线已经打开。
|
||||
// 4. 页机制被禁止。
|
||||
// 5. 中断被禁止。
|
||||
// 6. EAX = 0x2BADB002
|
||||
// 7. 系统信息和启动信息块的线性地址保存在 EBX中(相当于一个指针)。
|
||||
// 以下即为这个信息块的结构
|
||||
|
||||
/**
|
||||
* @brief MULTIBOOT2 接口抽象
|
||||
*/
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
static const unsigned int MULTIBOOT_SEARCH = 32768;
|
||||
static const unsigned int MULTIBOOT_HEADER_ALIGN = 8;
|
||||
|
||||
/* The magic field should contain this. */
|
||||
static const unsigned int MULTIBOOT2_HEADER_MAGIC = 0xe85250d6;
|
||||
|
||||
/* This should be in %eax. */
|
||||
static const unsigned int MULTIBOOT2_BOOTLOADER_MAGIC = 0x36d76289;
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
static const unsigned int MULTIBOOT_MOD_ALIGN = 0x00001000;
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
static const unsigned int MULTIBOOT_INFO_ALIGN = 0x00000008;
|
||||
|
||||
/* Flags set in the 'flags' member of the multiboot header. */
|
||||
|
||||
static const unsigned int MULTIBOOT_TAG_ALIGN = 8;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_END = 0;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_CMDLINE = 1;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME = 2;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_MODULE = 3;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_BASIC_MEMINFO = 4;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_BOOTDEV = 5;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_MMAP = 6;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_VBE = 7;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_FRAMEBUFFER = 8;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_ELF_SECTIONS = 9;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_APM = 10;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_EFI32 = 11;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_EFI64 = 12;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_SMBIOS = 13;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_ACPI_OLD = 14;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_ACPI_NEW = 15;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_NETWORK = 16;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_EFI_MMAP = 17;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_EFI_BS = 18;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_EFI32_IH = 19;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_EFI64_IH = 20;
|
||||
static const unsigned int MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR = 21;
|
||||
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_END = 0;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST =
|
||||
1;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_ADDRESS = 2;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS = 3;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS = 4;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_FRAMEBUFFER = 5;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_MODULE_ALIGN = 6;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_EFI_BS = 7;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 =
|
||||
8;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 =
|
||||
9;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_RELOCATABLE = 10;
|
||||
|
||||
static const unsigned int MULTIBOOT_ARCHITECTURE_I386 = 0;
|
||||
static const unsigned int MULTIBOOT_ARCHITECTURE_MIPS32 = 4;
|
||||
static const unsigned int MULTIBOOT_HEADER_TAG_OPTIONAL = 1;
|
||||
|
||||
static const unsigned int MULTIBOOT_LOAD_PREFERENCE_NONE = 0;
|
||||
static const unsigned int MULTIBOOT_LOAD_PREFERENCE_LOW = 1;
|
||||
static const unsigned int MULTIBOOT_LOAD_PREFERENCE_HIGH = 2;
|
||||
|
||||
static const unsigned int MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED =
|
||||
1;
|
||||
static const unsigned int MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED =
|
||||
2;
|
||||
|
||||
static const unsigned int MULTIBOOT_MEMORY_AVAILABLE = 1;
|
||||
static const unsigned int MULTIBOOT_MEMORY_RESERVED = 2;
|
||||
static const unsigned int MULTIBOOT_MEMORY_ACPI_RECLAIMABLE = 3;
|
||||
static const unsigned int MULTIBOOT_MEMORY_NVS = 4;
|
||||
static const unsigned int MULTIBOOT_MEMORY_BADRAM = 5;
|
||||
|
||||
struct multiboot_header_t
|
||||
{
|
||||
// Must be MULTIBOOT_MAGIC - see above.
|
||||
unsigned int magic;
|
||||
// ISA
|
||||
unsigned int architecture;
|
||||
// Total header length.
|
||||
unsigned int header_length;
|
||||
// The above fields plus this one must equal 0 mod 2^32.
|
||||
unsigned int checksum;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
};
|
||||
struct multiboot_header_tag_information_request_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
|
||||
unsigned int requests[0];
|
||||
};
|
||||
struct multiboot_header_tag_address_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
|
||||
unsigned int header_addr;
|
||||
unsigned int load_addr;
|
||||
unsigned int load_end_addr;
|
||||
unsigned int bss_end_addr;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_entry_address_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
|
||||
unsigned int entry_addr;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_console_flags_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
|
||||
unsigned int console_flags;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_framebuffer_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int depth;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_module_align_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_relocatable_t
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
unsigned int size;
|
||||
|
||||
unsigned int min_addr;
|
||||
unsigned int max_addr;
|
||||
unsigned int align;
|
||||
unsigned int preference;
|
||||
};
|
||||
|
||||
struct multiboot_color_t
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
|
||||
// multiboot2协议的内存区域信息
|
||||
struct multiboot_mmap_entry_t
|
||||
{
|
||||
uint64_t addr;
|
||||
uint64_t len;
|
||||
unsigned int type;
|
||||
unsigned int reserved;
|
||||
};
|
||||
|
||||
struct multiboot_tag_t
|
||||
{
|
||||
unsigned int type;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct multiboot_tag_string_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
char string[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_module_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int mod_start;
|
||||
unsigned int mod_end;
|
||||
char cmdline[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_basic_meminfo_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int mem_lower;
|
||||
unsigned int mem_upper;
|
||||
};
|
||||
|
||||
struct multiboot_tag_bootdev_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int biosdev;
|
||||
unsigned int slice;
|
||||
unsigned int part;
|
||||
};
|
||||
|
||||
struct multiboot_tag_mmap_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int entry_size;
|
||||
unsigned int entry_version;
|
||||
struct multiboot_mmap_entry_t entries[0];
|
||||
};
|
||||
|
||||
struct multiboot_vbe_info_block_t
|
||||
{
|
||||
uint8_t external_specification[512];
|
||||
};
|
||||
|
||||
struct multiboot_vbe_mode_info_block_t
|
||||
{
|
||||
uint8_t external_specification[256];
|
||||
};
|
||||
|
||||
// bootloader传递的VBE信息的结构体
|
||||
struct multiboot_tag_vbe_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint16_t vbe_mode;
|
||||
uint16_t vbe_interface_seg;
|
||||
uint16_t vbe_interface_off;
|
||||
uint16_t vbe_interface_len;
|
||||
|
||||
// The fields ‘vbe_control_info’ and ‘vbe_mode_info’ contain VBE control information returned by the VBE Function 00h and VBE mode information
|
||||
// returned by the VBE Function 01h, respectively.
|
||||
struct multiboot_vbe_info_block_t vbe_control_info;
|
||||
struct multiboot_vbe_mode_info_block_t vbe_mode_info;
|
||||
};
|
||||
|
||||
struct multiboot_tag_framebuffer_info_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint64_t framebuffer_addr;
|
||||
uint32_t framebuffer_pitch; // 帧缓存上界
|
||||
// width and height expressed in pixels except type=2
|
||||
// when type=2, they are expressed in characters
|
||||
uint32_t framebuffer_width;
|
||||
uint32_t framebuffer_height;
|
||||
// number of bits per pixel.
|
||||
uint8_t framebuffer_bpp;
|
||||
// 帧缓存的类型
|
||||
uint8_t framebuffer_type;
|
||||
uint8_t reserved;
|
||||
};
|
||||
|
||||
// indexed color
|
||||
struct multiboot_tag_framebuffer_info_type0_t
|
||||
{
|
||||
struct multiboot_tag_framebuffer_info_t header;
|
||||
uint32_t framebuffer_palette_num_colors;
|
||||
struct multiboot_color_t color_desc;
|
||||
};
|
||||
|
||||
// direct RGB color
|
||||
struct multiboot_tag_framebuffer_info_type1_t
|
||||
{
|
||||
struct multiboot_tag_framebuffer_info_t header;
|
||||
|
||||
uint8_t framebuffer_red_field_position;
|
||||
uint8_t framebuffer_red_mask_size;
|
||||
uint8_t framebuffer_green_field_position;
|
||||
uint8_t framebuffer_green_mask_size;
|
||||
uint8_t framebuffer_blue_field_position;
|
||||
uint8_t framebuffer_blue_mask_size;
|
||||
};
|
||||
|
||||
struct multiboot_tag_elf_sections_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int num;
|
||||
unsigned int entsize;
|
||||
// 段字符串表索引
|
||||
unsigned int shndx;
|
||||
char sections[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_apm_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint16_t version;
|
||||
uint16_t cseg;
|
||||
unsigned int offset;
|
||||
uint16_t cseg_16;
|
||||
uint16_t dseg;
|
||||
uint16_t flags;
|
||||
uint16_t cseg_len;
|
||||
uint16_t cseg_16_len;
|
||||
uint16_t dseg_len;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi32_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi64_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint64_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_smbios_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
uint8_t reserved[6];
|
||||
uint8_t tables[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_old_acpi_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
//uint8_t rsdp[0];
|
||||
struct acpi_RSDP_t rsdp;
|
||||
};
|
||||
|
||||
struct multiboot_tag_new_acpi_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
//uint8_t rsdp[0];
|
||||
struct acpi_RSDP_2_t rsdp;
|
||||
};
|
||||
|
||||
struct multiboot_tag_network_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint8_t dhcpack[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi_mmap_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int descr_size;
|
||||
unsigned int descr_vers;
|
||||
uint8_t efi_mmap[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi32_ih_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi64_ih_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
uint64_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_load_base_addr_t
|
||||
{
|
||||
struct multiboot_tag_t tag_t;
|
||||
unsigned int load_base_addr;
|
||||
};
|
||||
|
||||
// 迭代变量
|
||||
// 与 multiboot_tag_t 相同
|
||||
struct iter_data_t
|
||||
{
|
||||
unsigned int type;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化
|
||||
* @return true 成功
|
||||
* @return false 失败
|
||||
*/
|
||||
bool multiboot2_init(uint64_t mb2_info_paddr, uint32_t mb2_magic);
|
||||
|
||||
/**
|
||||
* @brief 迭代器
|
||||
* @param _fun 迭代操作
|
||||
* @param _data 数据
|
||||
*/
|
||||
void multiboot2_iter(bool (*_fun)(const struct iter_data_t *, void *, unsigned int *),
|
||||
void *_data, unsigned int *count);
|
||||
|
||||
/**
|
||||
* @brief 获取multiboot2协议提供的内存区域信息
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data 返回信息的结构体指针
|
||||
* @param count 返回数组的长度
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool multiboot2_get_memory(const struct iter_data_t *_iter_data, void *_data, unsigned int *count);
|
||||
|
||||
bool multiboot2_get_load_base(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved);
|
||||
|
||||
/**
|
||||
* @brief 获取VBE信息
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data 返回信息的结构体指针
|
||||
*/
|
||||
bool multiboot2_get_VBE_info(const struct iter_data_t *_iter_data, void *_data, unsigned int *reserved);
|
||||
|
||||
/**
|
||||
* @brief 获取帧缓冲区信息
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data 返回信息的结构体指针
|
||||
*/
|
||||
bool multiboot2_get_Framebuffer_info(const struct iter_data_t *_iter_data, void *_data, unsigned int *reserved);
|
||||
|
||||
/**
|
||||
* @brief 获取acpi旧版RSDP
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data old RSDP的结构体指针
|
||||
* @param reserved
|
||||
* @return uint8_t*
|
||||
*/
|
||||
bool multiboot2_get_acpi_old_RSDP(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved);
|
||||
|
||||
/**
|
||||
* @brief 获取acpi新版RSDP
|
||||
*
|
||||
* @param _iter_data 要被迭代的信息的结构体
|
||||
* @param _data old RSDP的结构体指针
|
||||
* @param reserved
|
||||
* @return uint8_t* struct multiboot_tag_old_acpi_t
|
||||
*/
|
||||
bool multiboot2_get_acpi_new_RSDP(const struct iter_data_t *_iter_data, void *data, unsigned int *reserved);
|
@ -1,8 +1,4 @@
|
||||
use core::{
|
||||
ffi::{c_uint, c_void},
|
||||
mem::MaybeUninit,
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
use core::sync::atomic::AtomicBool;
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
@ -14,7 +10,6 @@ use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::{
|
||||
base::{
|
||||
class::Class,
|
||||
@ -36,21 +31,13 @@ use crate::{
|
||||
sysfs::{file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport},
|
||||
vfs::syscall::ModeType,
|
||||
},
|
||||
include::bindings::bindings::{
|
||||
multiboot2_get_Framebuffer_info, multiboot2_iter, multiboot_tag_framebuffer_info_t,
|
||||
FRAME_BUFFER_MAPPING_OFFSET,
|
||||
},
|
||||
init::{boot_params, initcall::INITCALL_DEVICE},
|
||||
init::{boot::boot_callbacks, boot_params, initcall::INITCALL_DEVICE},
|
||||
libs::{
|
||||
align::page_align_up,
|
||||
once::Once,
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::SpinLock,
|
||||
},
|
||||
mm::{
|
||||
allocator::page_frame::PageFrameCount, no_init::pseudo_map_phys, MemoryManagementArch,
|
||||
PhysAddr, VirtAddr,
|
||||
},
|
||||
mm::{early_ioremap::EarlyIoRemap, PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
use super::base::{
|
||||
@ -933,68 +920,18 @@ pub fn vesa_fb_driver_init() -> Result<(), SystemError> {
|
||||
}
|
||||
|
||||
/// 在内存管理初始化之前,初始化vesafb
|
||||
pub fn vesafb_early_init() -> Result<VirtAddr, SystemError> {
|
||||
let mut _reserved: u32 = 0;
|
||||
pub fn vesafb_early_init() -> Result<(), SystemError> {
|
||||
let mut boot_params_guard = boot_params().write();
|
||||
boot_callbacks().early_init_framebuffer_info(&mut boot_params_guard.screen_info)?;
|
||||
|
||||
let mut fb_info: MaybeUninit<multiboot_tag_framebuffer_info_t> = MaybeUninit::uninit();
|
||||
//从multiboot2中读取帧缓冲区信息至fb_info
|
||||
|
||||
// todo: 换成rust的,并且检测是否成功获取
|
||||
unsafe {
|
||||
multiboot2_iter(
|
||||
Some(multiboot2_get_Framebuffer_info),
|
||||
fb_info.as_mut_ptr() as usize as *mut c_void,
|
||||
&mut _reserved as *mut c_uint,
|
||||
)
|
||||
};
|
||||
unsafe { fb_info.assume_init() };
|
||||
let fb_info: multiboot_tag_framebuffer_info_t = unsafe { core::mem::transmute(fb_info) };
|
||||
|
||||
// todo: 判断是否有vesa帧缓冲区,这里暂时直接设置true
|
||||
HAS_VESA_FB.store(true, core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let width = fb_info.framebuffer_width;
|
||||
let height = fb_info.framebuffer_height;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut boot_params_guard = boot_params().write();
|
||||
let boottime_screen_info = &mut boot_params_guard.screen_info;
|
||||
pub fn vesafb_early_map(paddr: PhysAddr, size: usize) -> Result<VirtAddr, SystemError> {
|
||||
let (buf_vaddr, _) = EarlyIoRemap::map(paddr, size, false)?;
|
||||
|
||||
boottime_screen_info.is_vga = true;
|
||||
|
||||
boottime_screen_info.lfb_base = PhysAddr::new(fb_info.framebuffer_addr as usize);
|
||||
|
||||
if fb_info.framebuffer_type == 2 {
|
||||
//当type=2时,width与height用字符数表示,故depth=8
|
||||
boottime_screen_info.origin_video_cols = width as u8;
|
||||
boottime_screen_info.origin_video_lines = height as u8;
|
||||
boottime_screen_info.video_type = BootTimeVideoType::Mda;
|
||||
boottime_screen_info.lfb_depth = 8;
|
||||
} else {
|
||||
//否则为图像模式,depth应参照帧缓冲区信息里面的每个像素的位数
|
||||
boottime_screen_info.lfb_width = width;
|
||||
boottime_screen_info.lfb_height = height;
|
||||
boottime_screen_info.video_type = BootTimeVideoType::Vlfb;
|
||||
boottime_screen_info.lfb_depth = fb_info.framebuffer_bpp as u8;
|
||||
}
|
||||
|
||||
boottime_screen_info.lfb_size =
|
||||
(width * height * ((fb_info.framebuffer_bpp as u32 + 7) / 8)) as usize;
|
||||
|
||||
// let buf_vaddr = VirtAddr::new(0xffff800003200000);
|
||||
let buf_vaddr = VirtAddr::new(
|
||||
crate::include::bindings::bindings::SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE as usize
|
||||
+ FRAME_BUFFER_MAPPING_OFFSET as usize,
|
||||
);
|
||||
boottime_screen_info.lfb_virt_base = Some(buf_vaddr);
|
||||
|
||||
let init_text = "Video driver to map.\n\0";
|
||||
send_to_default_serial8250_port(init_text.as_bytes());
|
||||
|
||||
// 地址映射
|
||||
let paddr = PhysAddr::new(fb_info.framebuffer_addr as usize);
|
||||
let count =
|
||||
PageFrameCount::new(page_align_up(boottime_screen_info.lfb_size) / MMArch::PAGE_SIZE);
|
||||
unsafe { pseudo_map_phys(buf_vaddr, paddr, count) };
|
||||
return Ok(buf_vaddr);
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,7 @@ use crate::{
|
||||
rwlock::{RwLock, RwLockReadGuard},
|
||||
spinlock::SpinLock,
|
||||
},
|
||||
mm::{
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, page::EntryFlags,
|
||||
MemoryManagementArch,
|
||||
},
|
||||
mm::{mmio_buddy::mmio_pool, page::EntryFlags},
|
||||
time::timer::{Timer, TimerFunction},
|
||||
};
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
@ -74,46 +71,33 @@ impl VideoRefreshManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief VBE帧缓存区的地址重新映射
|
||||
* 将帧缓存区映射到地址SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE处
|
||||
* VBE帧缓存区的地址重新映射
|
||||
*/
|
||||
fn init_frame_buffer(&self) {
|
||||
info!("Re-mapping VBE frame buffer...");
|
||||
let buf_vaddr = boot_params()
|
||||
.read_irqsave()
|
||||
.screen_info
|
||||
.lfb_virt_base
|
||||
.unwrap();
|
||||
let mut bp = boot_params().write_irqsave();
|
||||
let buf_size = bp.screen_info.lfb_size;
|
||||
|
||||
let mut frame_buffer_info_guard = self.device_buffer.write();
|
||||
let mmio_guard = mmio_pool().create_mmio(page_align_up(buf_size)).unwrap();
|
||||
let mmio_guard = Arc::new(mmio_guard);
|
||||
let buf_vaddr = mmio_guard.vaddr();
|
||||
bp.screen_info.lfb_virt_base = Some(buf_vaddr);
|
||||
|
||||
let mut frame_buffer_info_guard: crate::libs::rwlock::RwLockWriteGuard<ScmBufferInfo> =
|
||||
self.device_buffer.write();
|
||||
unsafe { frame_buffer_info_guard.set_device_buffer_mmio_guard(mmio_guard.clone()) };
|
||||
if let ScmBuffer::DeviceBuffer(vaddr) = &mut (frame_buffer_info_guard).buf {
|
||||
*vaddr = buf_vaddr;
|
||||
}
|
||||
|
||||
// 地址映射
|
||||
let mut paddr = boot_params().read().screen_info.lfb_base;
|
||||
let count = PageFrameCount::new(
|
||||
page_align_up(frame_buffer_info_guard.buf_size()) / MMArch::PAGE_SIZE,
|
||||
);
|
||||
let paddr = bp.screen_info.lfb_base;
|
||||
let page_flags: EntryFlags<MMArch> = EntryFlags::new().set_execute(true).set_write(true);
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let mut kernel_mapper = kernel_mapper.as_mut();
|
||||
assert!(kernel_mapper.is_some());
|
||||
let mut vaddr = buf_vaddr;
|
||||
unsafe {
|
||||
for _ in 0..count.data() {
|
||||
let flusher = kernel_mapper
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.map_phys(vaddr, paddr, page_flags)
|
||||
.unwrap();
|
||||
|
||||
flusher.flush();
|
||||
vaddr += MMArch::PAGE_SIZE;
|
||||
paddr += MMArch::PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
mmio_guard
|
||||
.map_phys_with_flags(paddr, page_align_up(buf_size), page_flags)
|
||||
.expect("Failed to map VBE frame buffer!")
|
||||
};
|
||||
|
||||
info!("VBE frame buffer successfully Re-mapped!");
|
||||
}
|
||||
@ -196,6 +180,7 @@ impl VideoRefreshManager {
|
||||
screen_info.lfb_depth.into(),
|
||||
buf_flag,
|
||||
buf_vaddr,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
@ -208,6 +193,7 @@ impl VideoRefreshManager {
|
||||
screen_info.lfb_depth.into(),
|
||||
buf_flag,
|
||||
buf_vaddr,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -10,19 +10,3 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <common/printk.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/stdio.h>
|
||||
#include <common/string.h>
|
||||
#include <common/time.h>
|
||||
#include <common/unistd.h>
|
||||
#include <driver/multiboot2/multiboot2.h>
|
||||
#include <libs/lib_ui/textui.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/mmio.h>
|
||||
#include <mm/slab.h>
|
||||
#include <process/process.h>
|
||||
#include <time/sleep.h>
|
||||
#include <common/errno.h>
|
||||
|
176
kernel/src/init/boot.rs
Normal file
176
kernel/src/init/boot.rs
Normal file
@ -0,0 +1,176 @@
|
||||
use core::cmp::min;
|
||||
|
||||
use acpi::rsdp::Rsdp;
|
||||
use alloc::string::String;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::init::ArchBootParams,
|
||||
driver::video::fbdev::base::BootTimeScreenInfo,
|
||||
libs::lazy_init::Lazy,
|
||||
mm::{PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
use super::boot_params;
|
||||
#[derive(Debug)]
|
||||
pub struct BootParams {
|
||||
pub screen_info: BootTimeScreenInfo,
|
||||
bootloader_name: Option<String>,
|
||||
#[allow(dead_code)]
|
||||
pub arch: ArchBootParams,
|
||||
boot_command_line: [u8; Self::BOOT_COMMAND_LINE_SIZE],
|
||||
pub acpi: BootloaderAcpiArg,
|
||||
}
|
||||
|
||||
impl BootParams {
|
||||
const DEFAULT: Self = BootParams {
|
||||
screen_info: BootTimeScreenInfo::DEFAULT,
|
||||
bootloader_name: None,
|
||||
arch: ArchBootParams::DEFAULT,
|
||||
boot_command_line: [0u8; Self::BOOT_COMMAND_LINE_SIZE],
|
||||
acpi: BootloaderAcpiArg::NotProvided,
|
||||
};
|
||||
|
||||
/// 开机命令行参数字符串最大大小
|
||||
pub const BOOT_COMMAND_LINE_SIZE: usize = 2048;
|
||||
|
||||
pub(super) const fn new() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
|
||||
/// 开机命令行参数(原始字节数组)
|
||||
#[allow(dead_code)]
|
||||
pub fn boot_cmdline(&self) -> &[u8] {
|
||||
&self.boot_command_line
|
||||
}
|
||||
|
||||
/// 开机命令行参数字符串
|
||||
pub fn boot_cmdline_str(&self) -> &str {
|
||||
core::str::from_utf8(self.boot_cmdline()).unwrap()
|
||||
}
|
||||
|
||||
pub fn bootloader_name(&self) -> Option<&str> {
|
||||
self.bootloader_name.as_deref()
|
||||
}
|
||||
|
||||
/// 追加开机命令行参数
|
||||
///
|
||||
/// 如果开机命令行参数已经满了,则不会追加。
|
||||
/// 如果超过了最大长度,则截断。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `data`:追加的数据
|
||||
pub fn boot_cmdline_append(&mut self, data: &[u8]) {
|
||||
if data.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut pos: Option<usize> = None;
|
||||
// 寻找结尾
|
||||
for (i, x) in self.boot_command_line.iter().enumerate() {
|
||||
if *x == 0 {
|
||||
pos = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let pos = pos.unwrap_or(self.boot_command_line.len() - 1) as isize;
|
||||
|
||||
let avail = self.boot_command_line.len() as isize - pos - 1;
|
||||
if avail <= 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let len = min(avail as usize, data.len());
|
||||
let pos = pos as usize;
|
||||
self.boot_command_line[pos..pos + len].copy_from_slice(&data[0..len]);
|
||||
|
||||
self.boot_command_line[pos + len] = 0;
|
||||
}
|
||||
|
||||
/// 获取FDT的虚拟地址
|
||||
#[allow(dead_code)]
|
||||
pub fn fdt(&self) -> Option<VirtAddr> {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
return Some(self.arch.arch_fdt());
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
return None;
|
||||
}
|
||||
|
||||
/// 获取FDT的物理地址
|
||||
#[allow(dead_code)]
|
||||
pub fn fdt_paddr(&self) -> Option<PhysAddr> {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
return Some(self.arch.fdt_paddr);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
/// 开机引导回调,用于初始化内核启动参数
|
||||
pub trait BootCallbacks: Send + Sync {
|
||||
/// 初始化引导程序名称
|
||||
fn init_bootloader_name(&self) -> Result<Option<String>, SystemError>;
|
||||
/// 初始化ACPI参数
|
||||
fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError>;
|
||||
/// 初始化内核命令行参数
|
||||
///
|
||||
/// 该函数应该把内核命令行参数追加到`boot_params().boot_cmdline`中
|
||||
fn init_kernel_cmdline(&self) -> Result<(), SystemError>;
|
||||
/// 初始化帧缓冲区信息
|
||||
///
|
||||
/// - 该函数应该把帧缓冲区信息写入`scinfo`中。
|
||||
/// - 该函数应该在内存管理初始化之前调用。
|
||||
fn early_init_framebuffer_info(
|
||||
&self,
|
||||
scinfo: &mut BootTimeScreenInfo,
|
||||
) -> Result<(), SystemError>;
|
||||
|
||||
/// 初始化内存块
|
||||
fn early_init_memory_blocks(&self) -> Result<(), SystemError>;
|
||||
}
|
||||
|
||||
static BOOT_CALLBACKS: Lazy<&'static dyn BootCallbacks> = Lazy::new();
|
||||
|
||||
/// 注册开机引导回调
|
||||
pub fn register_boot_callbacks(callbacks: &'static dyn BootCallbacks) {
|
||||
BOOT_CALLBACKS.init(callbacks);
|
||||
}
|
||||
|
||||
/// 获取开机引导回调
|
||||
pub fn boot_callbacks() -> &'static dyn BootCallbacks {
|
||||
let p = BOOT_CALLBACKS
|
||||
.try_get()
|
||||
.expect("Boot callbacks not initialized");
|
||||
|
||||
*p
|
||||
}
|
||||
|
||||
pub(super) fn boot_callback_except_early() {
|
||||
boot_callbacks()
|
||||
.init_kernel_cmdline()
|
||||
.expect("Failed to init kernel cmdline");
|
||||
let mut boot_params = boot_params().write();
|
||||
boot_params.bootloader_name = boot_callbacks()
|
||||
.init_bootloader_name()
|
||||
.expect("Failed to init bootloader name");
|
||||
boot_params.acpi = boot_callbacks()
|
||||
.init_acpi_args()
|
||||
.unwrap_or(BootloaderAcpiArg::NotProvided);
|
||||
}
|
||||
|
||||
/// ACPI information from the bootloader.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum BootloaderAcpiArg {
|
||||
/// The bootloader does not provide one, a manual search is needed.
|
||||
NotProvided,
|
||||
/// Physical address of the RSDP.
|
||||
#[allow(dead_code)]
|
||||
Rsdp(PhysAddr),
|
||||
/// Address of RSDT provided in RSDP v1.
|
||||
Rsdt(Rsdp),
|
||||
/// Address of XSDT provided in RSDP v2+.
|
||||
Xsdt(Rsdp),
|
||||
}
|
@ -4,7 +4,10 @@ use crate::{
|
||||
time::time_init,
|
||||
CurrentIrqArch, CurrentSMPArch, CurrentSchedArch,
|
||||
},
|
||||
driver::{base::init::driver_init, serial::serial_early_init, video::VideoRefreshManager},
|
||||
driver::{
|
||||
acpi::acpi_init, base::init::driver_init, serial::serial_early_init,
|
||||
video::VideoRefreshManager,
|
||||
},
|
||||
exception::{init::irq_init, softirq::softirq_init, InterruptArch},
|
||||
filesystem::vfs::core::vfs_init,
|
||||
init::init_intertrait,
|
||||
@ -26,6 +29,8 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::boot::boot_callback_except_early;
|
||||
|
||||
/// The entry point for the kernel
|
||||
///
|
||||
/// 前面可能会有一个架构相关的函数
|
||||
@ -52,15 +57,14 @@ fn do_start_kernel() {
|
||||
|
||||
scm_reinit().unwrap();
|
||||
textui_init().unwrap();
|
||||
|
||||
boot_callback_except_early();
|
||||
init_intertrait();
|
||||
|
||||
vfs_init().expect("vfs init failed");
|
||||
driver_init().expect("driver init failed");
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe {
|
||||
crate::include::bindings::bindings::acpi_init()
|
||||
};
|
||||
acpi_init().expect("acpi init failed");
|
||||
crate::sched::sched_init();
|
||||
process_init();
|
||||
early_smp_init().expect("early smp init failed");
|
||||
|
@ -1,11 +1,7 @@
|
||||
use core::cmp::min;
|
||||
use crate::libs::rwlock::RwLock;
|
||||
|
||||
use crate::{
|
||||
arch::init::ArchBootParams,
|
||||
driver::video::fbdev::base::BootTimeScreenInfo,
|
||||
libs::rwlock::RwLock,
|
||||
mm::{PhysAddr, VirtAddr},
|
||||
};
|
||||
use self::boot::BootParams;
|
||||
pub mod boot;
|
||||
#[allow(clippy::module_inception)]
|
||||
pub mod init;
|
||||
pub mod initcall;
|
||||
@ -23,92 +19,3 @@ pub fn boot_params() -> &'static RwLock<BootParams> {
|
||||
fn init_intertrait() {
|
||||
intertrait::init_caster_map();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BootParams {
|
||||
pub screen_info: BootTimeScreenInfo,
|
||||
#[allow(dead_code)]
|
||||
pub arch: ArchBootParams,
|
||||
boot_command_line: [u8; Self::BOOT_COMMAND_LINE_SIZE],
|
||||
}
|
||||
|
||||
impl BootParams {
|
||||
const DEFAULT: Self = BootParams {
|
||||
screen_info: BootTimeScreenInfo::DEFAULT,
|
||||
arch: ArchBootParams::DEFAULT,
|
||||
boot_command_line: [0u8; Self::BOOT_COMMAND_LINE_SIZE],
|
||||
};
|
||||
|
||||
/// 开机命令行参数字符串最大大小
|
||||
pub const BOOT_COMMAND_LINE_SIZE: usize = 2048;
|
||||
|
||||
const fn new() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
|
||||
/// 开机命令行参数(原始字节数组)
|
||||
#[allow(dead_code)]
|
||||
pub fn boot_cmdline(&self) -> &[u8] {
|
||||
&self.boot_command_line
|
||||
}
|
||||
|
||||
/// 开机命令行参数字符串
|
||||
pub fn boot_cmdline_str(&self) -> &str {
|
||||
core::str::from_utf8(self.boot_cmdline()).unwrap()
|
||||
}
|
||||
|
||||
/// 追加开机命令行参数
|
||||
///
|
||||
/// 如果开机命令行参数已经满了,则不会追加。
|
||||
/// 如果超过了最大长度,则截断。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `data`:追加的数据
|
||||
pub fn boot_cmdline_append(&mut self, data: &[u8]) {
|
||||
if data.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut pos: Option<usize> = None;
|
||||
// 寻找结尾
|
||||
for (i, x) in self.boot_command_line.iter().enumerate() {
|
||||
if *x == 0 {
|
||||
pos = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let pos = pos.unwrap_or(self.boot_command_line.len() - 1) as isize;
|
||||
|
||||
let avail = self.boot_command_line.len() as isize - pos - 1;
|
||||
if avail <= 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let len = min(avail as usize, data.len());
|
||||
let pos = pos as usize;
|
||||
self.boot_command_line[pos..pos + len].copy_from_slice(&data[0..len]);
|
||||
|
||||
self.boot_command_line[pos + len] = 0;
|
||||
}
|
||||
|
||||
/// 获取FDT的虚拟地址
|
||||
#[allow(dead_code)]
|
||||
pub fn fdt(&self) -> Option<VirtAddr> {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
return Some(self.arch.arch_fdt());
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
return None;
|
||||
}
|
||||
|
||||
/// 获取FDT的物理地址
|
||||
#[allow(dead_code)]
|
||||
pub fn fdt_paddr(&self) -> Option<PhysAddr> {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
return Some(self.arch.fdt_paddr);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use system_error::SystemError;
|
||||
use crate::{
|
||||
driver::{serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager},
|
||||
libs::{lib_ui::textui::textui_is_enable_put_to_window, rwlock::RwLock, spinlock::SpinLock},
|
||||
mm::VirtAddr,
|
||||
mm::{mmio_buddy::MMIOSpaceGuard, VirtAddr},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -56,6 +56,7 @@ pub struct ScmBufferInfo {
|
||||
height: u32, // 帧缓冲区高度(pixel或lines)
|
||||
size: u32, // 帧缓冲区大小(bytes)
|
||||
bit_depth: u32, // 像素点位深度
|
||||
device_buffer_mmio_guard: Option<Arc<MMIOSpaceGuard>>,
|
||||
pub buf: ScmBuffer,
|
||||
flags: ScmBufferFlag, // 帧缓冲区标志位
|
||||
}
|
||||
@ -100,6 +101,7 @@ impl ScmBufferInfo {
|
||||
bit_depth: device_buffer_guard.bit_depth,
|
||||
flags: buf_type,
|
||||
buf: ScmBuffer::DoubleBuffer(buf_space),
|
||||
device_buffer_mmio_guard: None,
|
||||
};
|
||||
drop(device_buffer_guard);
|
||||
|
||||
@ -107,6 +109,10 @@ impl ScmBufferInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn set_device_buffer_mmio_guard(&mut self, guard: Arc<MMIOSpaceGuard>) {
|
||||
self.device_buffer_mmio_guard = Some(guard);
|
||||
}
|
||||
|
||||
pub unsafe fn new_device_buffer(
|
||||
width: u32,
|
||||
height: u32,
|
||||
@ -114,7 +120,9 @@ impl ScmBufferInfo {
|
||||
bit_depth: u32,
|
||||
buf_type: ScmBufferFlag,
|
||||
vaddr: VirtAddr,
|
||||
mut device_buffer_mmio_guard: Option<MMIOSpaceGuard>,
|
||||
) -> Result<Self, SystemError> {
|
||||
let mmio_guard = device_buffer_mmio_guard.take().map(Arc::new);
|
||||
let buffer = Self {
|
||||
width,
|
||||
height,
|
||||
@ -122,6 +130,7 @@ impl ScmBufferInfo {
|
||||
bit_depth,
|
||||
flags: buf_type,
|
||||
buf: ScmBuffer::DeviceBuffer(vaddr),
|
||||
device_buffer_mmio_guard: mmio_guard,
|
||||
};
|
||||
return Ok(buffer);
|
||||
}
|
||||
|
@ -7,69 +7,23 @@ use hashbrown::HashMap;
|
||||
use log::error;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
include::bindings::bindings::{gfp_t, PAGE_U_S},
|
||||
libs::{align::page_align_up, spinlock::SpinLock},
|
||||
mm::MMArch,
|
||||
};
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, mmio_buddy::mmio_pool,
|
||||
no_init::pseudo_map_phys, page::EntryFlags, MemoryManagementArch, PhysAddr, VirtAddr,
|
||||
};
|
||||
use super::{mmio_buddy::mmio_pool, VirtAddr};
|
||||
|
||||
lazy_static! {
|
||||
// 用于记录内核分配给C的空间信息
|
||||
static ref C_ALLOCATION_MAP: SpinLock<HashMap<VirtAddr, (VirtAddr, usize, usize)>> = SpinLock::new(HashMap::new());
|
||||
}
|
||||
|
||||
/// [EXTERN TO C] Use pseudo mapper to map physical memory to virtual memory.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_pseudo_map_phys(vaddr: usize, paddr: usize, size: usize) {
|
||||
let vaddr = VirtAddr::new(vaddr);
|
||||
let paddr = PhysAddr::new(paddr);
|
||||
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
|
||||
pseudo_map_phys(vaddr, paddr, count);
|
||||
}
|
||||
|
||||
/// [EXTERN TO C] Use kernel mapper to map physical memory to virtual memory.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_map_phys(vaddr: usize, paddr: usize, size: usize, flags: usize) {
|
||||
let mut vaddr = VirtAddr::new(vaddr);
|
||||
let mut paddr = PhysAddr::new(paddr);
|
||||
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
|
||||
// debug!("rs_map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}");
|
||||
|
||||
let mut page_flags: EntryFlags<MMArch> = EntryFlags::new().set_execute(true).set_write(true);
|
||||
if flags & PAGE_U_S as usize != 0 {
|
||||
page_flags = page_flags.set_user(true);
|
||||
}
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let mut kernel_mapper = kernel_mapper.as_mut();
|
||||
assert!(kernel_mapper.is_some());
|
||||
for _i in 0..count.data() {
|
||||
let flusher = kernel_mapper
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.map_phys(vaddr, paddr, page_flags)
|
||||
.unwrap();
|
||||
|
||||
flusher.flush();
|
||||
|
||||
vaddr += MMArch::PAGE_SIZE;
|
||||
paddr += MMArch::PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn kzalloc(size: usize, _gfp: gfp_t) -> usize {
|
||||
pub unsafe extern "C" fn kzalloc(size: usize, _gfp: u64) -> usize {
|
||||
// debug!("kzalloc: size: {size}");
|
||||
return do_kmalloc(size, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn kmalloc(size: usize, _gfp: gfp_t) -> usize {
|
||||
pub unsafe extern "C" fn kmalloc(size: usize, _gfp: u64) -> usize {
|
||||
// debug!("kmalloc: size: {size}");
|
||||
// 由于C代码不规范,因此都全部清空
|
||||
return do_kmalloc(size, true);
|
||||
|
@ -3,18 +3,6 @@
|
||||
#include <common/glib.h>
|
||||
#include <process/process.h>
|
||||
|
||||
extern void rs_pseudo_map_phys(uint64_t virt_addr, uint64_t phys_addr, uint64_t size);
|
||||
extern void rs_map_phys(uint64_t virt_addr, uint64_t phys_addr, uint64_t size, uint64_t flags);
|
||||
extern uint64_t rs_unmap_at_low_addr();
|
||||
|
||||
// 内核层的起始地址
|
||||
#define PAGE_OFFSET 0xffff800000000000UL
|
||||
#define KERNEL_BASE_LINEAR_ADDR 0xffff800000000000UL
|
||||
#define USER_MAX_LINEAR_ADDR 0x00007fffffffffffUL
|
||||
// MMIO虚拟地址空间:1TB
|
||||
#define MMIO_BASE 0xffffa10000000000UL
|
||||
#define MMIO_TOP 0xffffa20000000000UL
|
||||
|
||||
#define PAGE_4K_SHIFT 12
|
||||
#define PAGE_2M_SHIFT 21
|
||||
#define PAGE_1G_SHIFT 30
|
||||
@ -30,19 +18,15 @@ extern uint64_t rs_unmap_at_low_addr();
|
||||
#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1))
|
||||
|
||||
// 将addr按照x的上边界对齐
|
||||
#define PAGE_4K_ALIGN(addr) (((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
|
||||
#define PAGE_2M_ALIGN(addr) (((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)
|
||||
#define PAGE_4K_ALIGN(addr) \
|
||||
(((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
|
||||
#define PAGE_2M_ALIGN(addr) \
|
||||
(((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)
|
||||
|
||||
// 虚拟地址与物理地址转换
|
||||
#define virt_2_phys(addr) ((unsigned long)(addr)-PAGE_OFFSET)
|
||||
#define phys_2_virt(addr) ((unsigned long *)((unsigned long)(addr) + PAGE_OFFSET))
|
||||
|
||||
// 在这个地址以上的虚拟空间,用来进行特殊的映射
|
||||
#define SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE 0xffffa00000000000UL
|
||||
#define FRAME_BUFFER_MAPPING_OFFSET 0x3000000UL
|
||||
#define IO_APIC_MAPPING_OFFSET 0xfec00000UL
|
||||
#define LOCAL_APIC_MAPPING_OFFSET 0xfee00000UL
|
||||
#define AHCI_MAPPING_OFFSET 0xff200000UL // AHCI 映射偏移量,之后使用了4M的地址
|
||||
#define phys_2_virt(addr) \
|
||||
((unsigned long *)((unsigned long)(addr) + PAGE_OFFSET))
|
||||
|
||||
// ===== 页面属性 =====
|
||||
// 页面在页表中已被映射 mapped=1 unmapped=0
|
||||
@ -123,22 +107,6 @@ extern uint64_t rs_unmap_at_low_addr();
|
||||
|
||||
#define PAGE_USER_4K_PAGE (PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
|
||||
|
||||
/**
|
||||
* @brief 刷新TLB的宏定义
|
||||
* 由于任何写入cr3的操作都会刷新TLB,因此这个宏定义可以刷新TLB
|
||||
*/
|
||||
#define flush_tlb() \
|
||||
do \
|
||||
{ \
|
||||
ul tmp; \
|
||||
io_mfence(); \
|
||||
__asm__ __volatile__("movq %%cr3, %0\n\t" \
|
||||
"movq %0, %%cr3\n\t" \
|
||||
: "=r"(tmp)::"memory"); \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
|
||||
// 导出内核程序的几个段的起止地址
|
||||
extern char _text;
|
||||
extern char _etext;
|
||||
@ -150,22 +118,6 @@ extern char _bss;
|
||||
extern char _ebss;
|
||||
extern char _end;
|
||||
|
||||
#if ARCH(I386) || ARCH(X86_64)
|
||||
/**
|
||||
* @brief 读取CR3寄存器的值(存储了页目录的基地址)
|
||||
*
|
||||
* @return unsigned* cr3的值的指针
|
||||
*/
|
||||
unsigned long *get_CR3()
|
||||
{
|
||||
ul *tmp;
|
||||
__asm__ __volatile__("movq %%cr3, %0\n\t"
|
||||
: "=r"(tmp)::"memory");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* vm_area_struct中的vm_flags的可选值
|
||||
* 对应的结构体请见mm-types.h
|
||||
|
@ -684,6 +684,34 @@ impl MMIOSpaceGuard {
|
||||
return r;
|
||||
}
|
||||
|
||||
/// 将物理地址填写到虚拟地址空间中
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// 传入的物理地址【一定要是设备的物理地址】。
|
||||
/// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
|
||||
pub unsafe fn map_phys_with_flags(
|
||||
&self,
|
||||
paddr: PhysAddr,
|
||||
length: usize,
|
||||
flags: EntryFlags<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
if length > self.size {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let check = self
|
||||
.mapped
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
|
||||
if check.is_err() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// # map_any_phys - 将任意物理地址映射到虚拟地址
|
||||
///
|
||||
/// 将指定的物理地址和长度映射到虚拟地址空间。
|
||||
|
@ -25,7 +25,7 @@ use crate::{
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
process::{ProcessControlBlock, ProcessManager},
|
||||
time::{sleep::usleep, PosixTimeSpec},
|
||||
time::{sleep::nanosleep, PosixTimeSpec},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -150,7 +150,7 @@ fn page_reclaim_thread() -> i32 {
|
||||
page_reclaimer_lock_irqsave().flush_dirty_pages();
|
||||
// 休眠5秒
|
||||
// log::info!("sleep");
|
||||
let _ = usleep(PosixTimeSpec::new(5, 0));
|
||||
let _ = nanosleep(PosixTimeSpec::new(5, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ use crate::{
|
||||
file::{File, FileMode},
|
||||
FilePrivateData, IndexNode, Metadata,
|
||||
},
|
||||
include::bindings::bindings::INT32_MAX,
|
||||
libs::{
|
||||
rbtree::RBTree,
|
||||
rwlock::RwLock,
|
||||
@ -53,7 +52,7 @@ pub struct EventPoll {
|
||||
}
|
||||
|
||||
impl EventPoll {
|
||||
pub const EP_MAX_EVENTS: u32 = INT32_MAX / (core::mem::size_of::<EPollEvent>() as u32);
|
||||
pub const EP_MAX_EVENTS: u32 = u32::MAX / (core::mem::size_of::<EPollEvent>() as u32);
|
||||
/// 用于获取inode中的epitem队列
|
||||
pub const ADD_EPOLLITEM: u32 = 0x7965;
|
||||
pub fn new() -> Self {
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <common/string.h>
|
||||
#include <mm/slab.h>
|
||||
#include <process/process.h>
|
||||
#include <time/sleep.h>
|
||||
|
||||
#if ARCH(I386) || ARCH(X86_64)
|
||||
// 导出系统调用入口函数,定义在entry.S中
|
||||
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <common/time.h>
|
||||
#include <process/ptrace.h>
|
||||
|
||||
/**
|
||||
* @brief 睡眠指定时间
|
||||
*
|
||||
* @param usec 微秒
|
||||
* @return int
|
||||
*/
|
||||
int rs_usleep(useconds_t usec);
|
@ -6,7 +6,6 @@ use system_error::SystemError;
|
||||
use crate::{
|
||||
arch::{CurrentIrqArch, CurrentTimeArch},
|
||||
exception::InterruptArch,
|
||||
include::bindings::bindings::useconds_t,
|
||||
process::ProcessManager,
|
||||
sched::{schedule, SchedMode},
|
||||
time::timekeeping::getnstimeofday,
|
||||
@ -63,42 +62,3 @@ pub fn nanosleep(sleep_time: PosixTimeSpec) -> Result<PosixTimeSpec, SystemError
|
||||
|
||||
return Ok(rm_time);
|
||||
}
|
||||
|
||||
/// @brief 休眠指定时间(单位:微秒)
|
||||
///
|
||||
/// @param usec 微秒
|
||||
///
|
||||
/// @return Ok(TimeSpec) 剩余休眠时间
|
||||
///
|
||||
/// @return Err(SystemError) 错误码
|
||||
pub fn usleep(sleep_time: PosixTimeSpec) -> Result<PosixTimeSpec, SystemError> {
|
||||
match nanosleep(sleep_time) {
|
||||
Ok(value) => return Ok(value),
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
}
|
||||
|
||||
//===== 以下为提供给C的接口 =====
|
||||
|
||||
/// @brief 休眠指定时间(单位:微秒)(提供给C的接口)
|
||||
///
|
||||
/// @param usec 微秒
|
||||
///
|
||||
/// @return Ok(i32) 0
|
||||
///
|
||||
/// @return Err(SystemError) 错误码
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_usleep(usec: useconds_t) -> i32 {
|
||||
let sleep_time = PosixTimeSpec {
|
||||
tv_sec: (usec / 1000000) as i64,
|
||||
tv_nsec: ((usec % 1000000) * 1000) as i64,
|
||||
};
|
||||
match usleep(sleep_time) {
|
||||
Ok(_) => {
|
||||
return 0;
|
||||
}
|
||||
Err(err) => {
|
||||
return err.to_posix_errno();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
// #include <sleep.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user