feat: 添加对内核引导协议的抽象 (#913)

* 添加multiboot header

* head.S传参增加bootloader类型

* feat: 添加引导加载协议的抽象,并为multiboot2实现这个抽象.

* 把framebuffer的映射地址改为从early ioremap和mmio pool分配

* riscv64能运行
This commit is contained in:
LoGin 2024-09-05 21:12:20 +08:00 committed by GitHub
parent cf7f801e1d
commit 2b7818e80e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 826 additions and 1327 deletions

View File

@ -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",

View File

@ -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或者是其他的一些数据结构。
内核启动时,自动根据引导加载程序的类型,注册回调。并且在适当的时候,会调用这些回调函数。
## 参考资料

View File

@ -8,4 +8,3 @@
:caption: 目录
bootloader
multiboot2

View File

@ -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的需要定义了一些迭代器工作函数。

View File

@ -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"

View File

@ -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 {

View 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(),
}
}

View 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(())
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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/

View 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!();
}
}
}

View File

@ -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();

View 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(());
}

View File

@ -13,6 +13,7 @@ SECTIONS
.boot.text :
{
KEEP(*(.multiboot_header))
KEEP(*(.multiboot2_header))
*(.bootstrap)
*(.bootstrap.code64)
*(.bootstrap.data)

View File

@ -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();

View File

@ -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);
}
}

View File

@ -1,7 +1,7 @@
CFLAGS += -I .
kernel_driver_subdirs:=acpi multiboot2
kernel_driver_subdirs:=
ECHO:
@echo "$@"

View File

@ -1,10 +0,0 @@
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
CFLAGS += -I .
.PHONY: all
all: $(OBJ)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

View File

@ -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;
}

View File

@ -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();

View File

@ -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");
}

View File

@ -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(());
}
}

View File

@ -1,10 +0,0 @@
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
CFLAGS += -I .
.PHONY: all
all: $(OBJ)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

View File

@ -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;
}

View File

@ -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. DSSSESFS 和 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);

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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
View 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),
}

View File

@ -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");

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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的操作都会刷新TLBTLB
*/
#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

View File

@ -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 - 将任意物理地址映射到虚拟地址
///
/// 将指定的物理地址和长度映射到虚拟地址空间。

View File

@ -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));
}
}
}

View File

@ -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 {

View File

@ -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中

View File

@ -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);

View File

@ -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();
}
};
}

View File

@ -1,7 +1,6 @@
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
// #include <sleep.h>
#include <unistd.h>
#include <time.h>