diff --git a/kernel/src/arch/riscv64/asm/head.S b/kernel/src/arch/riscv64/asm/head.S index 5bdd75f9..eb3939e3 100644 --- a/kernel/src/arch/riscv64/asm/head.S +++ b/kernel/src/arch/riscv64/asm/head.S @@ -17,9 +17,9 @@ #define SR_VS 0x00000600 #define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */ -#define SATP_MODE_39 0x8000000000000000UL -#define SATP_MODE_48 0x9000000000000000UL -#define SATP_MODE_57 0xa000000000000000UL +#define SATP_MODE_39 0x8000000000000000ULL +#define SATP_MODE_48 0x9000000000000000ULL +#define SATP_MODE_57 0xa000000000000000ULL #define PAGE_OFFSET 0xffffffc000000000 #define KERNEL_LINK_OFFSET 0x1000000 @@ -84,7 +84,6 @@ ENTRY(_start) call initial_map_1g_identical __init_set_pgtable_loop_end: - call __initial_reloacate_enable_mmu .option push @@ -119,6 +118,7 @@ __initial_reloacate_enable_mmu: // 计算起始物理地址与内核高虚拟地址的偏移量 la t0, __initial_start_load_paddr ld t0, 0(t0) + li t1, KERNEL_VIRT_START sub t1, t1, t0 @@ -128,18 +128,27 @@ __initial_reloacate_enable_mmu: /* Point stvec to virtual address of intruction after satp write */ /* Set trap vector to spin forever to help debug */ - la a2, __initial_Lsecondary_park + la a2, 1f add a2, a2, t1 csrw CSR_TVEC, a2 - // enable MMU la a2, __initial_pgtable srli a2, a2, 12 la a0, __initial_satp_mode ld a0, 0(a0) or a2, a2, a0 + + sfence.vma csrw satp, a2 + +1: + la a0, __initial_Lsecondary_park + add a0, a0, t1 + csrw CSR_TVEC, a0 + + csrw satp, a2 + sfence.vma ret @@ -165,7 +174,7 @@ initial_map_256M_phys_addr: and t2, t2, t1 // 计算L0页表项的索引 - srl t2, t2, 30 + srli t2, t2, 30 andi t2, t2, 511 @@ -220,7 +229,7 @@ __initial_set_l1_pgtable_loop: li t1, 0x3FFFFFFFFFFFFF and t3, t3, t1 // t3 = t3 & 0x3FFFFFFFFFFFFF slli t3, t3, 10 // t3 = t3 << 10 - ori t3, t3, 0xf // 设置L1页表项属性,R/W/X/V = 1 + ori t3, t3, 0xEF // 设置L1页表项属性,set R/W/X/V/A/D/G = 1 // 设置L1页表项的值 sd t3, 0(t0) @@ -262,41 +271,55 @@ initial_map_1g_identical: // 计算起始物理地址,存放在t0中 and t0, t0, a0 - + // 把起始虚拟地址存储到t2中 mv t2, a1 // 按照1g对齐 li t1, -0x40000000 and t2, t2, t1 + // 右移30位,得到L0页表项的索引 - srl t2, t2, 30 + srli t2, t2, 30 // 与511进行与运算,得到L0页表项的索引 andi t2, t2, 511 // 填写页表项 - // li t2, 0xf // 页表项属性, R/W/X/V = 1 la t4, __initial_pgtable slli t3, t2, 3 // t3 = t2 * 8 add t4, t4, t3 // t4 = t4 + t3 + mv t3, t0 srli t3, t3, 12 // t3 = t0 >> 12 (page frame number) slli t3, t3, 10 // t3 = t3 << 10 - ori t3, t3, 0xf // set R/W/X/V = 1 - // 设置t0地址在L0页表中的值 + ori t3, t3, 0xEF // set R/W/X/V/A/D/G = 1 + + // 计算delta的pfn + li t2, 0x40000000 + srli t2, t2, 12 + // 把delta pfn移位到页表项的第10位的位置 + slli t2, t2, 10 + li t1, 2 + +__loop_set_8g: + + sd t3, 0(t4) // 增加 t4 的值 addi t4, t4, 8 - // 增加 t3 的值(1G) - li t2, 0x40000000 + // 增加1G的pfn add t3, t3, t2 - sd t3, 0(t4) + + + addi t1, t1, -1 + bnez t1, __loop_set_8g ret + // 用于清空页表的空间 // 参数: // a0: page table address diff --git a/kernel/src/arch/riscv64/driver/sbi/mod.rs b/kernel/src/arch/riscv64/driver/sbi/mod.rs index f79bb46f..15f117cb 100644 --- a/kernel/src/arch/riscv64/driver/sbi/mod.rs +++ b/kernel/src/arch/riscv64/driver/sbi/mod.rs @@ -5,6 +5,7 @@ use self::legacy::console_putchar; /// Some code takes from `https://github.com/repnop/sbi.git` mod ecall; pub mod legacy; +pub mod reset; /// Error codes returned by SBI calls /// diff --git a/kernel/src/arch/riscv64/driver/sbi/reset.rs b/kernel/src/arch/riscv64/driver/sbi/reset.rs new file mode 100644 index 00000000..f8b5b3d1 --- /dev/null +++ b/kernel/src/arch/riscv64/driver/sbi/reset.rs @@ -0,0 +1,85 @@ +#![allow(dead_code)] +use super::{ecall::ecall2, SbiError}; + +/// System reset extension ID +pub const EXTENSION_ID: usize = 0x53525354; + +/// The type of reset to perform +#[derive(Debug, Clone, Copy)] +pub enum ResetType { + /// Shutdown the system + Shutdown, + /// Power off all hardware and perform a cold boot + ColdReboot, + /// Reset processors and some hardware + WarmReboot, + /// Platform specific reset type. The variant value is a value within the + /// range `0x00000000..=0x0FFFFFFF`. A value outside of that range will be + /// clamped to the maximum possible valid value for this reset type. + PlatformSpecific(u32), +} + +impl ResetType { + fn to_u32(self) -> u32 { + match self { + ResetType::Shutdown => 0, + ResetType::ColdReboot => 1, + ResetType::WarmReboot => 2, + ResetType::PlatformSpecific(n) => n.min(0x0FFFFFFF) + 0xF0000000, + } + } +} + +/// The reason for performing the reset +#[derive(Debug, Clone, Copy)] +pub enum ResetReason { + /// No reason for reset + NoReason, + /// System failure + SystemFailure, + /// SBI implementation specific reset reason. The variant value is a value + /// within the range `0x00000000..=0x0FFFFFFF`. A value outside of that + /// range will be clamped to the maximum possible valid value for this reset + /// reason type. + SbiSpecific(u32), + /// Platform specific reset reason. The variant value is a value within the + /// range `0x00000000..=0x0FFFFFFF`. A value outside of that range will be + /// clamped to the maximum possible valid value for this reset reason type. + PlatformSpecific(u32), +} + +impl ResetReason { + fn to_u32(self) -> u32 { + match self { + ResetReason::NoReason => 0, + ResetReason::SystemFailure => 1, + ResetReason::SbiSpecific(n) => n.min(0x0FFFFFFF) + 0xE0000000, + ResetReason::PlatformSpecific(n) => n.min(0x0FFFFFFF) + 0xF0000000, + } + } +} + +/// Attempt to reset the system in the provided method, with a reason for the +/// reset. +/// +/// ### Possible errors +/// +/// [`SbiError::NotSupported`]: The [`ResetType`] is valid but not implemented. +/// +/// [`SbiError::Failed`]: The system reset request failed for an unknown reason. +pub fn system_reset( + kind: ResetType, + reason: ResetReason, +) -> Result { + match unsafe { + ecall2( + kind.to_u32() as usize, + reason.to_u32() as usize, + EXTENSION_ID, + 0, + ) + } { + Ok(_) => unreachable!("SBI returned `Ok` after a system reset call"), + Err(e) => Err(e), + } +} diff --git a/kernel/src/arch/riscv64/init/mod.rs b/kernel/src/arch/riscv64/init/mod.rs index fd253813..1c8edb6d 100644 --- a/kernel/src/arch/riscv64/init/mod.rs +++ b/kernel/src/arch/riscv64/init/mod.rs @@ -3,14 +3,11 @@ use core::intrinsics::unreachable; use fdt::node::FdtNode; use crate::{ - arch::{mm::init::mm_early_init, MMArch}, - driver::{ - firmware::efi::init::efi_init, open_firmware::fdt::open_firmware_fdt_driver, - tty::serial::serial8250::send_to_default_serial8250_port, - }, + arch::mm::init::mm_early_init, + driver::{firmware::efi::init::efi_init, open_firmware::fdt::open_firmware_fdt_driver}, init::{boot_params, init_before_mem_init}, kdebug, kinfo, - mm::{MemoryManagementArch, PhysAddr, VirtAddr}, + mm::{PhysAddr, VirtAddr}, print, println, }; @@ -39,14 +36,8 @@ impl ArchBootParams { #[no_mangle] unsafe extern "C" fn kernel_main(hartid: usize, fdt_paddr: usize) -> ! { let fdt_paddr = PhysAddr::new(fdt_paddr); - + // system_reset(sbi::reset::ResetType::Shutdown, sbi::reset::ResetReason::NoReason); init_before_mem_init(); - extern "C" { - fn BSP_IDLE_STACK_SPACE(); - } - kdebug!("BSP_IDLE_STACK_SPACE={:#x}", BSP_IDLE_STACK_SPACE as u64); - kdebug!("PAGE_ADDRESS_SIZE={}", MMArch::PAGE_ADDRESS_SIZE); - kdebug!("PAGE_ADDRESS_SHIFT={}", MMArch::PAGE_ADDRESS_SHIFT); boot_params().write().arch.fdt_paddr = fdt_paddr; kinfo!( @@ -58,7 +49,7 @@ unsafe extern "C" fn kernel_main(hartid: usize, fdt_paddr: usize) -> ! { mm_early_init(); let fdt = fdt::Fdt::from_ptr(fdt_paddr.data() as *const u8).expect("Failed to parse fdt!"); - print_node(fdt.find_node("/").unwrap(), 0); + // print_node(fdt.find_node("/").unwrap(), 0); parse_dtb(); diff --git a/kernel/src/arch/riscv64/mm/init.rs b/kernel/src/arch/riscv64/mm/init.rs index 77245783..62e81e6f 100644 --- a/kernel/src/arch/riscv64/mm/init.rs +++ b/kernel/src/arch/riscv64/mm/init.rs @@ -1,17 +1,7 @@ -use system_error::SystemError; - use crate::{ - arch::{ - mm::{KERNEL_BEGIN_PA, KERNEL_BEGIN_VA, KERNEL_END_PA, KERNEL_END_VA}, - MMArch, - }, + arch::mm::{KERNEL_BEGIN_PA, KERNEL_BEGIN_VA, KERNEL_END_PA, KERNEL_END_VA}, kdebug, - mm::{ - allocator::page_frame::PageFrameCount, - no_init::{pseudo_map_phys, EARLY_IOREMAP_PAGES}, - page::{PageEntry, PageMapper, PageTable}, - MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, - }, + mm::{PhysAddr, VirtAddr}, }; #[inline(never)] diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index 5f5d48d2..5afd5036 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/kernel/src/arch/riscv64/mm/mod.rs @@ -1,13 +1,10 @@ use riscv::register::satp; use system_error::SystemError; -use crate::{ - kdebug, - mm::{ - allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage, PhysPageFrame}, - page::PageFlags, - MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, - }, +use crate::mm::{ + allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage, PhysPageFrame}, + page::PageFlags, + MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr, }; pub mod bump; @@ -28,6 +25,9 @@ pub(self) static mut KERNEL_END_VA: VirtAddr = VirtAddr::new(0); #[derive(Debug, Clone, Copy, Hash)] pub struct RiscV64MMArch; +impl RiscV64MMArch { + pub const ENTRY_FLAG_GLOBAL: usize = 1 << 5; +} impl MemoryManagementArch for RiscV64MMArch { const PAGE_SHIFT: usize = 12; @@ -38,13 +38,17 @@ impl MemoryManagementArch for RiscV64MMArch { const ENTRY_ADDRESS_SHIFT: usize = 39; - const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT; + const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_READWRITE + | Self::ENTRY_FLAG_DIRTY + | Self::ENTRY_FLAG_ACCESSED + | Self::ENTRY_FLAG_GLOBAL; const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT; const ENTRY_FLAG_PRESENT: usize = 1 << 0; - const ENTRY_FLAG_READONLY: usize = 1 << 1; + const ENTRY_FLAG_READONLY: usize = 0; const ENTRY_FLAG_READWRITE: usize = (1 << 2) | (1 << 1); @@ -57,6 +61,8 @@ impl MemoryManagementArch for RiscV64MMArch { const ENTRY_FLAG_NO_EXEC: usize = 0; const ENTRY_FLAG_EXEC: usize = (1 << 3); + const ENTRY_FLAG_ACCESSED: usize = (1 << 6); + const ENTRY_FLAG_DIRTY: usize = (1 << 7); const PHYS_OFFSET: usize = 0xffff_ffc0_0000_0000; @@ -89,14 +95,11 @@ impl MemoryManagementArch for RiscV64MMArch { let paddr = PhysPageFrame::from_ppn(ppn).phys_address(); - kdebug!("table(): {paddr:?}, ppn: {ppn}"); - return paddr; } unsafe fn set_table(_table_kind: PageTableKind, table: PhysAddr) { let ppn = PhysPageFrame::new(table).ppn(); - kdebug!("set_table(): {table:?}, ppn:{ppn}"); riscv::asm::sfence_vma_all(); satp::set(satp::Mode::Sv39, 0, ppn); } @@ -131,13 +134,11 @@ impl MemoryManagementArch for RiscV64MMArch { unsafe fn virt_2_phys(virt: VirtAddr) -> Option { if virt >= KERNEL_BEGIN_VA && virt < KERNEL_END_VA { let r = KERNEL_BEGIN_PA + (virt - KERNEL_BEGIN_VA); - kdebug!("virt_2_phys: kernel address: virt = {virt:?}, paddr = {r:?}"); return Some(r); } if let Some(paddr) = virt.data().checked_sub(Self::PHYS_OFFSET) { let r = PhysAddr::new(paddr); - kdebug!("virt_2_phys: non-kernel address: virt = {virt:?}, paddr = {r:?}"); return Some(r); } else { return None; @@ -147,8 +148,6 @@ impl MemoryManagementArch for RiscV64MMArch { fn make_entry(paddr: PhysAddr, page_flags: usize) -> usize { let ppn = PhysPageFrame::new(paddr).ppn(); let r = ((ppn & ((1 << 44) - 1)) << 10) | page_flags; - - kdebug!("make entry: r={r:#x}"); return r; } } diff --git a/kernel/src/arch/x86_64/mm/bump.rs b/kernel/src/arch/x86_64/mm/bump.rs index d5273dc6..4d2cba63 100644 --- a/kernel/src/arch/x86_64/mm/bump.rs +++ b/kernel/src/arch/x86_64/mm/bump.rs @@ -1,8 +1,9 @@ use crate::{ libs::align::{page_align_down, page_align_up}, mm::{ - allocator::bump::BumpAllocator, memblock::mem_block_manager, MemoryManagementArch, - PhysAddr, PhysMemoryArea, VirtAddr, + allocator::bump::BumpAllocator, + memblock::{mem_block_manager, MemoryAreaAttr}, + MemoryManagementArch, PhysAddr, PhysMemoryArea, VirtAddr, }, }; @@ -41,8 +42,11 @@ impl BumpAllocator { continue; } - ret_areas[res_count] = - PhysMemoryArea::new(PhysAddr::new(new_start), new_end - new_start); + ret_areas[res_count] = PhysMemoryArea::new( + PhysAddr::new(new_start), + new_end - new_start, + MemoryAreaAttr::empty(), + ); res_count += 1; } diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 06afe3f1..6341a91e 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -108,6 +108,9 @@ impl MemoryManagementArch for X86_64MMArch { /// x86_64不存在EXEC标志位,只有NO_EXEC(XD)标志位 const ENTRY_FLAG_EXEC: usize = 0; + const ENTRY_FLAG_ACCESSED: usize = 0; + const ENTRY_FLAG_DIRTY: usize = 0; + /// 物理地址与虚拟地址的偏移量 /// 0xffff_8000_0000_0000 const PHYS_OFFSET: usize = Self::PAGE_NEGATIVE_MASK + (Self::PAGE_ADDRESS_SIZE >> 1); diff --git a/kernel/src/driver/firmware/efi/guid.rs b/kernel/src/driver/firmware/efi/guid.rs new file mode 100644 index 00000000..31334025 --- /dev/null +++ b/kernel/src/driver/firmware/efi/guid.rs @@ -0,0 +1,35 @@ +use core::{fmt, mem}; + +use uefi_raw::Guid; + +/// 由DragonStub设置的,用于描述内核被放置在的地址的GUID +pub static DRAGONSTUB_EFI_PAYLOAD_EFI_GUID: Guid = Guid::new( + unsafe { mem::transmute_copy(&0xddf1d47cu32) }, + unsafe { mem::transmute_copy(&0x102cu32) }, + unsafe { mem::transmute_copy(&0xaaf9u32) }, + 0xce, + 0x34, + [0xbc, 0xef, 0x98, 0x12, 0x00, 0x31], +); + +/// 表示内核被加载到的地址的信息。 +/// +/// 对应 `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID` +#[derive(Clone, Copy)] +#[repr(C)] +pub struct DragonStubPayloadEFI { + /// 内核文件被加载到的物理地址 + pub paddr: u64, + + /// 占用的空间的大小 + pub size: u64, +} + +impl fmt::Debug for DragonStubPayloadEFI { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DragonStubPayloadEFI") + .field("paddr", &format_args!("0x{:x}", self.paddr)) + .field("size", &self.size) + .finish() + } +} diff --git a/kernel/src/driver/firmware/efi/init.rs b/kernel/src/driver/firmware/efi/init.rs index 1efdb525..d7727707 100644 --- a/kernel/src/driver/firmware/efi/init.rs +++ b/kernel/src/driver/firmware/efi/init.rs @@ -1,11 +1,16 @@ use core::{intrinsics::unlikely, mem::size_of}; use system_error::SystemError; +use uefi_raw::table::boot::{MemoryAttribute, MemoryType}; use crate::{ - driver::firmware::efi::EFIInitFlags, - libs::align::page_align_down, - mm::{early_ioremap::EarlyIoRemap, PhysAddr, VirtAddr}, + arch::MMArch, + driver::{firmware::efi::EFIInitFlags, open_firmware::fdt::open_firmware_fdt_driver}, + libs::align::{page_align_down, page_align_up}, + mm::{ + allocator::page_frame::PhysPageFrame, early_ioremap::EarlyIoRemap, + memblock::mem_block_manager, MemoryManagementArch, PhysAddr, VirtAddr, + }, }; use super::efi_manager; @@ -13,6 +18,7 @@ use super::efi_manager; #[allow(dead_code)] #[inline(never)] pub fn efi_init() { + kinfo!("Initializing efi..."); let data_from_fdt = efi_manager() .get_fdt_params() .expect("Failed to get fdt params"); @@ -22,7 +28,7 @@ pub fn efi_init() { return; } - kdebug!("to map memory table"); + // kdebug!("to map memory table"); // 映射mmap table if efi_manager().memmap_init_early(&data_from_fdt).is_err() { @@ -42,15 +48,36 @@ pub fn efi_init() { kwarn!("Unexpected EFI memory map version: {}", desc_version); } - // todo: 映射table,初始化runtime services - let r = uefi_init(PhysAddr::new(data_from_fdt.systable.unwrap() as usize)); - - if let Err(r) = r { - kerror!("Failed to initialize UEFI: {:?}", r); + if let Err(e) = r { + kerror!("Failed to initialize UEFI: {:?}", e); + efi_manager().efi_memmap_unmap(); + return; } - loop {} + reserve_memory_regions(); + // todo: 由于上面的`uefi_init`里面,按照UEFI的数据,初始化了内存块, + // 但是UEFI给的数据可能不全,这里Linux会再次从设备树检测可用内存,从而填补完全相应的内存信息 + + // 并且,Linux还对EFI BootService提供的Mokvar表进行了检测以及空间保留。 + + // todo: 模仿Linux的行为,做好接下来的几步工作: + // 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/firmware/efi/efi-init.c#217 + + // 保留mmap table的内存 + let base = page_align_down(data_from_fdt.mmap_base.unwrap() as usize); + let offset = data_from_fdt.mmap_base.unwrap() as usize - base; + + mem_block_manager() + .reserve_block( + PhysAddr::new(base), + data_from_fdt.mmap_size.unwrap() as usize + offset, + ) + .expect("Failed to reserve memory for EFI mmap table"); + + // todo: Initialize screen info + + kinfo!("UEFI init done!"); } #[inline(never)] @@ -69,18 +96,11 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> { // 映射system table let st_size = size_of::(); - kdebug!("system table: {system_table:?}, size: {st_size}"); - let st_map_phy_base = PhysAddr::new(page_align_down(system_table.data())); - let st_map_offset = system_table.data() - st_map_phy_base.data(); - let st_map_size = st_size + st_map_offset; - let (st_vaddr, _st_map_size) = - EarlyIoRemap::map(st_map_phy_base, st_map_size, true).map_err(|e| { - kwarn!("Unable to map EFI system table, e:{e:?}"); - e - })?; - - let st_vaddr = st_vaddr + st_map_offset; + let st_vaddr = EarlyIoRemap::map_not_aligned(system_table, st_size, true).map_err(|e| { + kwarn!("Unable to map EFI system table, e:{e:?}"); + e + })?; efi_manager() .inner @@ -94,8 +114,6 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> { .init_flags .set(EFIInitFlags::EFI_64BIT, true); - kdebug!("to parse EFI system table: p: {st_vaddr:?}"); - if st_vaddr.is_null() { return Err(SystemError::EINVAL); } @@ -109,21 +127,113 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> { e })?; - kdebug!("parse ok!"); - let mut inner_write_guard = efi_manager().inner.write(); let st_ref = unsafe { st_ptr.as_ref().unwrap() }; - inner_write_guard.runtime_paddr = Some(PhysAddr::new(st_ref.runtime_services as usize)); + + let runtime_service_paddr = efi_vaddr_2_paddr(st_ref.runtime_services as usize); + let mut inner_write_guard = efi_manager().inner.write(); + inner_write_guard.runtime_paddr = Some(runtime_service_paddr); inner_write_guard.runtime_service_version = Some(st_ref.header.revision); - kdebug!( - "runtime service paddr: {:?}", - inner_write_guard.runtime_paddr.unwrap() - ); - kdebug!( - "runtime service version: {}", - inner_write_guard.runtime_service_version.unwrap() + drop(inner_write_guard); + efi_manager().report_systable_header( + &st_ref.header, + efi_vaddr_2_paddr(st_ref.firmware_vendor as usize), ); - unimplemented!("report header"); - // return Ok(()); + { + // 映射configuration table + let table_size = st_ref.number_of_configuration_table_entries + * size_of::(); + let config_table_vaddr = EarlyIoRemap::map_not_aligned( + efi_vaddr_2_paddr(st_ref.configuration_table as usize), + table_size, + true, + ) + .map_err(|e| { + kwarn!("Unable to map EFI configuration table, e:{e:?}"); + err_unmap_systable(st_vaddr); + e + })?; + let cfg_tables = unsafe { + core::slice::from_raw_parts( + config_table_vaddr.data() + as *const uefi_raw::table::configuration::ConfigurationTable, + st_ref.number_of_configuration_table_entries, + ) + }; + // 解析configuration table + let r = efi_manager().parse_config_tables(cfg_tables); + + EarlyIoRemap::unmap(config_table_vaddr).expect("Failed to unmap EFI config table"); + return r; + } +} + +/// 把EFI固件提供的虚拟地址转换为物理地址。 +/// +/// 因为在调用SetVirtualAddressMap()之后,`EFI SystemTable` 的一些数据成员会被虚拟重映射 +/// +/// ## 锁 +/// +/// 在进入该函数前,请不要持有`efi_manager().inner`的写锁 +fn efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr { + let guard = efi_manager().inner.read(); + let mmap = &guard.mmap; + + let efi_vaddr: u64 = efi_vaddr as u64; + for md in mmap.iter() { + if !md.att.contains(MemoryAttribute::RUNTIME) { + continue; + } + + if md.virt_start == 0 { + // no virtual mapping has been installed by the DragonStub + break; + } + + if md.virt_start <= efi_vaddr + && ((efi_vaddr - md.virt_start) < (md.page_count << (MMArch::PAGE_SHIFT as u64))) + { + return PhysAddr::new((md.phys_start + (efi_vaddr - md.virt_start)) as usize); + } + } + + return PhysAddr::new(efi_vaddr as usize); +} + +/// 根据UEFI提供的内存描述符的信息,填写内存区域信息 +fn reserve_memory_regions() { + // 忽略之前已经发现的任何内存块。因为之前发现的内存块来自平坦设备树, + // 但是UEFI有自己的内存映射表,我们以UEFI提供的为准 + mem_block_manager() + .remove_block(PhysAddr::new(0), PhysAddr::MAX.data()) + .expect("Failed to remove all memblocks!"); + + let inner_guard = efi_manager().inner.read_irqsave(); + for md in inner_guard.mmap.iter() { + let page_count = (PhysPageFrame::new(PhysAddr::new(page_align_up( + (md.phys_start + md.page_count << (MMArch::PAGE_SHIFT as u64)) as usize, + ))) + .ppn() + - PhysPageFrame::new(PhysAddr::new(page_align_down(md.phys_start as usize))).ppn()) + as u64; + let phys_start = page_align_down(md.phys_start as usize); + let size = (page_count << (MMArch::PAGE_SHIFT as u64)) as usize; + + if md.is_memory() { + open_firmware_fdt_driver().early_init_dt_add_memory(phys_start as u64, size as u64); + if !md.is_usable_memory() { + mem_block_manager() + .mark_nomap(PhysAddr::new(phys_start), size) + .unwrap(); + } + + // keep ACPI reclaim memory intact for kexec etc. + if md.ty == MemoryType::ACPI_RECLAIM { + mem_block_manager() + .reserve_block(PhysAddr::new(phys_start), size) + .unwrap(); + } + } + } } diff --git a/kernel/src/driver/firmware/efi/memmap.rs b/kernel/src/driver/firmware/efi/memmap.rs index 86f305ae..1bfea15f 100644 --- a/kernel/src/driver/firmware/efi/memmap.rs +++ b/kernel/src/driver/firmware/efi/memmap.rs @@ -1,3 +1,5 @@ +use core::{intrinsics::unlikely, mem::size_of}; + use system_error::SystemError; use crate::{ @@ -6,7 +8,7 @@ use crate::{ mm::{early_ioremap::EarlyIoRemap, PhysAddr, VirtAddr}, }; -use super::{fdt::EFIFdtParams, EFIManager}; +use super::{fdt::EFIFdtParams, tables::MemoryDescriptor, EFIManager}; #[derive(Debug)] pub struct EFIMemoryMapInfo { @@ -22,6 +24,11 @@ pub struct EFIMemoryMapInfo { pub(super) desc_size: usize, /// EFI Memory Map的描述信息的版本 pub(super) desc_version: usize, + /// 当前是否在内存管理已经完成初始化后,对该结构体进行操作 + /// + /// true: 内存管理已经完成初始化 + /// false: 内存管理还未完成初始化 + pub(super) late: bool, } impl EFIMemoryMapInfo { @@ -32,6 +39,7 @@ impl EFIMemoryMapInfo { nr_map: 0, desc_size: 0, desc_version: 0, + late: false, }; /// 获取EFI Memory Map的虚拟的结束地址 @@ -39,6 +47,43 @@ impl EFIMemoryMapInfo { pub fn map_end_vaddr(&self) -> Option { return self.vaddr.map(|v| v + self.size); } + + /// 迭代所有的内存描述符 + pub fn iter(&self) -> EFIMemoryDescIter { + EFIMemoryDescIter::new(self) + } +} + +/// UEFI 内存描述符的迭代器 +pub struct EFIMemoryDescIter<'a> { + inner: &'a EFIMemoryMapInfo, + offset: usize, +} + +impl<'a> EFIMemoryDescIter<'a> { + fn new(inner: &'a EFIMemoryMapInfo) -> Self { + Self { inner, offset: 0 } + } +} + +impl<'a> Iterator for EFIMemoryDescIter<'a> { + type Item = MemoryDescriptor; + + fn next(&mut self) -> Option { + if self.offset + size_of::() > self.inner.size { + return None; + } + + // 如果是空指针,返回None + if unlikely(self.inner.vaddr.unwrap_or(VirtAddr::new(0)).is_null()) { + return None; + } + + let vaddr = self.inner.vaddr? + self.offset; + self.offset += size_of::(); + let res = unsafe { *(vaddr.data() as *const Self::Item) }; + return Some(res); + } } impl EFIManager { @@ -59,13 +104,14 @@ impl EFIManager { fn do_efi_memmap_init(&self, data: &EFIFdtParams, early: bool) -> Result<(), SystemError> { let paddr = data.mmap_base.expect("mmap_base is not set"); let paddr = PhysAddr::new(paddr as usize); - kdebug!("do_efi_memmap_init: paddr={paddr:?}"); + let mut inner_guard = self.inner.write(); if early { let offset = paddr.data() - page_align_down(paddr.data()); let map_size = data.mmap_size.unwrap() as usize + offset; - kdebug!("do_efi_memmap_init: map_size={map_size:#x}"); + // kdebug!("do_efi_memmap_init: map_size={map_size:#x}"); + // 映射内存 let mut vaddr = EarlyIoRemap::map( PhysAddr::new(page_align_down(paddr.data())), @@ -77,7 +123,9 @@ impl EFIManager { vaddr += offset; inner_guard.mmap.vaddr = Some(vaddr); + inner_guard.mmap.late = false; } else { + inner_guard.mmap.late = true; unimplemented!("efi_memmap_init_late") } @@ -97,4 +145,21 @@ impl EFIManager { return Ok(()); } + + /// 清除EFI Memory Table在内存中的映射 + pub fn efi_memmap_unmap(&self) { + let mut inner_guard = self.inner.write_irqsave(); + + // 没有启用memmap + if !inner_guard.init_flags.contains(EFIInitFlags::MEMMAP) { + return; + } + + if !inner_guard.mmap.late { + EarlyIoRemap::unmap(inner_guard.mmap.vaddr.take().unwrap()).unwrap(); + } else { + unimplemented!("efi_memmap_unmap"); + } + inner_guard.init_flags.set(EFIInitFlags::MEMMAP, false); + } } diff --git a/kernel/src/driver/firmware/efi/mod.rs b/kernel/src/driver/firmware/efi/mod.rs index 86a91e6e..23370ff2 100644 --- a/kernel/src/driver/firmware/efi/mod.rs +++ b/kernel/src/driver/firmware/efi/mod.rs @@ -2,11 +2,13 @@ use system_error::SystemError; use crate::{libs::rwlock::RwLock, mm::PhysAddr}; -use self::memmap::EFIMemoryMapInfo; +use self::{guid::DragonStubPayloadEFI, memmap::EFIMemoryMapInfo}; mod fdt; +pub mod guid; pub mod init; pub mod memmap; +pub mod tables; static EFI_MANAGER: EFIManager = EFIManager::new(); @@ -32,6 +34,7 @@ struct InnerEFIManager { pub runtime_paddr: Option, /// runtime services的版本号 pub runtime_service_version: Option, + pub dragonstub_load_info: Option, } impl EFIManager { @@ -42,6 +45,7 @@ impl EFIManager { init_flags: EFIInitFlags::empty(), runtime_paddr: None, runtime_service_version: None, + dragonstub_load_info: None, }), } } diff --git a/kernel/src/driver/firmware/efi/tables.rs b/kernel/src/driver/firmware/efi/tables.rs new file mode 100644 index 00000000..8c00c2aa --- /dev/null +++ b/kernel/src/driver/firmware/efi/tables.rs @@ -0,0 +1,167 @@ +use core::{ffi::CStr, mem::size_of}; + +use hashbrown::Equivalent; +use system_error::SystemError; +use uefi_raw::table::{ + boot::{MemoryAttribute, MemoryType}, + configuration::ConfigurationTable, +}; + +use crate::{ + driver::firmware::efi::{ + efi_manager, + guid::{DragonStubPayloadEFI, DRAGONSTUB_EFI_PAYLOAD_EFI_GUID}, + }, + mm::{early_ioremap::EarlyIoRemap, PhysAddr}, +}; + +use super::EFIManager; + +impl EFIManager { + /// 显示EFI系统表头的信息 + /// + /// ## 参数 + /// + /// - header: system table表头 + /// - firmware_vendor: firmware vendor字符串的物理地址 + #[inline(never)] + pub fn report_systable_header( + &self, + header: &uefi_raw::table::Header, + firmware_vendor: PhysAddr, + ) { + const TMPBUF_SIZE: usize = 100; + + let mut tmp_buf = [0u8; TMPBUF_SIZE]; + + let fw_ptr = + EarlyIoRemap::map_not_aligned(firmware_vendor, TMPBUF_SIZE * size_of::(), true); + if let Ok(fw_ptr) = fw_ptr { + let slice = + unsafe { core::slice::from_raw_parts(fw_ptr.data() as *const u16, TMPBUF_SIZE) }; + for i in 0..(TMPBUF_SIZE - 1) { + let val = slice[i]; + + if (val & 0xff) == 0 { + break; + } + tmp_buf[i] = (val & 0xff) as u8; + } + + EarlyIoRemap::unmap(fw_ptr).map_err(|e|{ + kerror!("report systable header: failed to unmap systable header, fw_ptr: {fw_ptr:?}, err: {e:?}"); + e + }).ok(); + } else { + kwarn!("report systable header: failed to map systable header, err: {fw_ptr:?}"); + } + + let s = CStr::from_bytes_with_nul(&tmp_buf) + .unwrap_or_else(|_| CStr::from_bytes_with_nul(b"Unknown\0").unwrap()); + kinfo!("EFI version: {:?}, vendor: {:?}", header.revision, s); + } + + /// 解析EFI config table + pub fn parse_config_tables(&self, tables: &[ConfigurationTable]) -> Result<(), SystemError> { + for table in tables { + if table + .vendor_guid + .equivalent(&DRAGONSTUB_EFI_PAYLOAD_EFI_GUID) + { + let table_paddr: PhysAddr = PhysAddr::new(table.vendor_table as usize); + let vaddr = EarlyIoRemap::map_not_aligned( + table_paddr, + size_of::(), + true, + )?; + + let data = unsafe { *(vaddr.data() as *const DragonStubPayloadEFI) }; + + efi_manager().inner.write().dragonstub_load_info = Some(data); + + EarlyIoRemap::unmap(vaddr).unwrap(); + } + } + + return Ok(()); + } +} + +/// A structure describing a region of memory. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(C)] +pub struct MemoryDescriptor { + /// Type of memory occupying this range. + pub ty: MemoryType, + /// Starting physical address. + pub phys_start: uefi_raw::PhysicalAddress, + /// Starting virtual address. + pub virt_start: uefi_raw::VirtualAddress, + /// Number of 4 KiB pages contained in this range. + pub page_count: u64, + /// The capability attributes of this memory range. + pub att: MemoryAttribute, +} + +#[allow(dead_code)] +impl MemoryDescriptor { + /// Memory descriptor version number. + pub const VERSION: u32 = 1; + + /// 当前内存描述符是否表示真实的内存 + #[inline] + pub fn is_memory(&self) -> bool { + if self.att.contains( + MemoryAttribute::WRITE_BACK + | MemoryAttribute::WRITE_THROUGH + | MemoryAttribute::WRITE_COMBINE, + ) { + return true; + } + + return false; + } + + /// 判断当前内存描述符所表示的区域是否能被作为系统内存使用 + /// + /// ## 返回 + /// + /// - `true` - 可以 + /// - `false` - 不可以 + pub fn is_usable_memory(&self) -> bool { + match self.ty { + MemoryType::LOADER_CODE + | MemoryType::LOADER_DATA + | MemoryType::ACPI_RECLAIM + | MemoryType::BOOT_SERVICES_CODE + | MemoryType::BOOT_SERVICES_DATA + | MemoryType::CONVENTIONAL + | MemoryType::PERSISTENT_MEMORY => { + // SPECIAL_PURPOSE的内存是“软保留”的,这意味着它最初被留出, + // 但在启动后可以通过热插拔再次使用,或者分配给dax驱动程序。 + if self.att.contains(MemoryAttribute::SPECIAL_PURPOSE) { + return false; + } + + // 根据规范,在调用ExitBootServices()之后,这些区域就不再被保留了。 + // 然而,只有当它们可以被映射为WRITE_BACK缓存时,我们才能将它们用作系统内存 + return self.att.contains(MemoryAttribute::WRITE_BACK); + } + _ => { + return false; + } + } + } +} + +impl Default for MemoryDescriptor { + fn default() -> MemoryDescriptor { + MemoryDescriptor { + ty: MemoryType::RESERVED, + phys_start: 0, + virt_start: 0, + page_count: 0, + att: MemoryAttribute::empty(), + } + } +} diff --git a/kernel/src/driver/open_firmware/fdt.rs b/kernel/src/driver/open_firmware/fdt.rs index e95fc9ee..db6de24a 100644 --- a/kernel/src/driver/open_firmware/fdt.rs +++ b/kernel/src/driver/open_firmware/fdt.rs @@ -4,15 +4,7 @@ use fdt::{ }; use system_error::SystemError; -use crate::{ - arch::MMArch, - init::boot_params, - libs::{align::page_align_down, rwlock::RwLock}, - mm::{ - memblock::{mem_block_manager, MemBlockManager}, - MemoryManagementArch, PhysAddr, - }, -}; +use crate::{init::boot_params, libs::rwlock::RwLock}; #[inline(always)] pub fn open_firmware_fdt_driver() -> &'static OpenFirmwareFdtDriver { @@ -45,6 +37,7 @@ impl FdtGlobalData { pub struct OpenFirmwareFdtDriver; impl OpenFirmwareFdtDriver { + #[allow(dead_code)] pub fn early_scan_device_tree(&self) -> Result<(), SystemError> { let fdt_vaddr = boot_params().read().fdt().unwrap(); let fdt = unsafe { @@ -207,7 +200,22 @@ impl OpenFirmwareFdtDriver { return found_memory; } - fn early_init_dt_add_memory(&self, base: u64, size: u64) { + #[cfg(target_arch = "x86_64")] + pub fn early_init_dt_add_memory(&self, _base: u64, _size: u64) { + kBUG!("x86_64 should not call early_init_dt_add_memory"); + } + + #[cfg(not(target_arch = "x86_64"))] + pub fn early_init_dt_add_memory(&self, base: u64, size: u64) { + use crate::{ + arch::MMArch, + libs::align::page_align_down, + mm::{ + memblock::{mem_block_manager, MemBlockManager}, + MemoryManagementArch, PhysAddr, + }, + }; + let mut base = base as usize; let mut size = size as usize; diff --git a/kernel/src/driver/open_firmware/mod.rs b/kernel/src/driver/open_firmware/mod.rs index 4c30d74a..8492a059 100644 --- a/kernel/src/driver/open_firmware/mod.rs +++ b/kernel/src/driver/open_firmware/mod.rs @@ -1,2 +1,2 @@ -#[cfg(target_arch = "riscv64")] +// #[cfg(target_arch = "riscv64")] pub mod fdt; diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 8a47c2bb..3ea26851 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -6,6 +6,7 @@ #![feature(const_for)] #![feature(const_mut_refs)] #![feature(const_trait_impl)] +#![feature(const_transmute_copy)] #![feature(const_refs_to_cell)] #![feature(core_intrinsics)] #![feature(c_void_variant)] diff --git a/kernel/src/mm/early_ioremap.rs b/kernel/src/mm/early_ioremap.rs index 1b579a63..0bf652b1 100644 --- a/kernel/src/mm/early_ioremap.rs +++ b/kernel/src/mm/early_ioremap.rs @@ -2,7 +2,10 @@ use system_error::SystemError; use crate::{ arch::MMArch, - libs::{align::page_align_up, spinlock::SpinLock}, + libs::{ + align::{page_align_down, page_align_up}, + spinlock::SpinLock, + }, mm::no_init::{pseudo_map_phys, pseudo_map_phys_ro, pseudo_unmap_phys}, }; @@ -24,6 +27,34 @@ pub struct EarlyIoRemap; impl EarlyIoRemap { const SLOT_CNT: usize = MMArch::FIXMAP_SIZE / MMArch::PAGE_SIZE; + /// 把物理内存映射到虚拟内存中(物理地址不要求对齐 + /// + /// ## 参数 + /// + /// - phys: 物理内存地址(不需要对齐) + /// - size: 映射的内存大小 + /// - read_only: 映射区与是否只读 + /// + /// ## 返回值 + /// + /// - 成功: (phys对应的虚拟内存地址) + /// - Err(SystemError::ENOMEM): 可用的slot不足 + #[allow(dead_code)] + pub fn map_not_aligned( + mut phys: PhysAddr, + mut size: usize, + read_only: bool, + ) -> Result { + // kdebug!("map not aligned phys:{phys:?}, size:{size:?}, read_only:{read_only:?}"); + + let offset = phys.data() - page_align_down(phys.data()); + size += offset; + phys -= offset; + + let (map_vaddr, _) = Self::map(phys, size, read_only)?; + return Ok(map_vaddr + offset); + } + /// 把物理内存映射到虚拟内存中 /// /// ## 说明 diff --git a/kernel/src/mm/memblock.rs b/kernel/src/mm/memblock.rs index 76c47f59..ab68bb92 100644 --- a/kernel/src/mm/memblock.rs +++ b/kernel/src/mm/memblock.rs @@ -1,3 +1,5 @@ +use core::intrinsics::unlikely; + use system_error::SystemError; use crate::libs::spinlock::{SpinLock, SpinLockGuard}; @@ -48,6 +50,18 @@ impl MemBlockManager { /// 如果添加的区域与已有区域有重叠,会将重叠的区域合并 #[allow(dead_code)] pub fn add_block(&self, base: PhysAddr, size: usize) -> Result<(), SystemError> { + return self.add_range(base, size, MemoryAreaAttr::empty()); + } + + /// 添加内存区域 + /// + /// 如果添加的区域与已有区域有重叠,会将重叠的区域合并 + fn add_range( + &self, + base: PhysAddr, + size: usize, + flags: MemoryAreaAttr, + ) -> Result<(), SystemError> { if size == 0 { return Ok(()); } @@ -56,7 +70,7 @@ impl MemBlockManager { panic!("Too many memory regions!"); } - let block = PhysMemoryArea::new(base, size); + let block = PhysMemoryArea::new(base, size, MemoryAreaAttr::empty()); // 特判第一个区域 if inner.initial_memory_regions_num == 0 { inner.initial_memory_regions[0] = block; @@ -66,7 +80,7 @@ impl MemBlockManager { // 先计算需要添加的区域数量 let blocks_to_add = self - .do_add_block(&mut inner, block, false) + .do_add_block(&mut inner, block, false, flags) .expect("Failed to count blocks to add!"); if inner.initial_memory_regions_num + blocks_to_add > INITIAL_MEMORY_REGIONS_NUM { @@ -75,7 +89,7 @@ impl MemBlockManager { } // 然后添加区域 - self.do_add_block(&mut inner, block, true) + self.do_add_block(&mut inner, block, true, flags) .expect("Failed to add block!"); return Ok(()); @@ -86,6 +100,7 @@ impl MemBlockManager { inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, block: PhysMemoryArea, insert: bool, + flags: MemoryAreaAttr, ) -> Result { let mut base = block.base; let end = block.base + block.size; @@ -117,7 +132,7 @@ impl MemBlockManager { start_index = i as isize; } end_index = (i + 1) as isize; - self.do_insert_area(inner, i, base, range_base - base); + self.do_insert_area(inner, i, base, range_base - base, flags); i += 1; } } @@ -133,7 +148,7 @@ impl MemBlockManager { start_index = i as isize; } end_index = (i + 1) as isize; - self.do_insert_area(inner, i, base, end - base); + self.do_insert_area(inner, i, base, end - base, flags); } } @@ -153,12 +168,13 @@ impl MemBlockManager { index: usize, base: PhysAddr, size: usize, + flags: MemoryAreaAttr, ) { let copy_elements = inner.initial_memory_regions_num - index; inner .initial_memory_regions .copy_within(index..index + copy_elements, index + 1); - inner.initial_memory_regions[index] = PhysMemoryArea::new(base, size); + inner.initial_memory_regions[index] = PhysMemoryArea::new(base, size, flags); inner.initial_memory_regions_num += 1; } @@ -178,10 +194,13 @@ impl MemBlockManager { { let next_base = inner.initial_memory_regions[(i + 1) as usize].base; let next_size = inner.initial_memory_regions[(i + 1) as usize].size; + let next_flags = inner.initial_memory_regions[(i + 1) as usize].flags; let this = &mut inner.initial_memory_regions[i as usize]; - if this.base + this.size != next_base { - // BUG_ON(this->base + this->size > next->base); + if this.base + this.size != next_base || this.flags != next_flags { + if unlikely(this.base + this.size > next_base) { + kBUG!("this->base + this->size > next->base"); + } i += 1; continue; } @@ -236,6 +255,15 @@ impl MemBlockManager { } } + /// 在一个内存块管理器中找到一个物理地址范围内的 + /// 空闲块,并隔离出所需的内存大小 + /// + /// ## 返回值 + /// + /// - Ok((start_index, end_index)) 表示成功找到了一个连续的内存区域来满足所需的 size。这里: + /// - start_index 是指定的起始内存区域的索引。 + /// - end_index 是指定的结束内存区域的索引,它实际上不包含在返回的连续区域中,但它标志着下一个可能的不连续区域的开始。 + /// - Err(SystemError) 则表示没有找到足够的空间来满足请求的 size,可能是因为内存区域不足或存在其他系统错误 fn isolate_range( &self, inner: &mut SpinLockGuard<'_, InnerMemBlockManager>, @@ -269,13 +297,25 @@ impl MemBlockManager { // regions[idx] intersects from below inner.initial_memory_regions[idx].base = base; inner.initial_memory_regions[idx].size -= base - range_base; - self.do_insert_area(inner, idx, range_base, base - range_base); + self.do_insert_area( + inner, + idx, + range_base, + base - range_base, + inner.initial_memory_regions[idx].flags, + ); } else if range_end > end { // regions[idx] intersects from above inner.initial_memory_regions[idx].base = end; inner.initial_memory_regions[idx].size -= end - range_base; - self.do_insert_area(inner, idx, range_base, end - range_base); + self.do_insert_area( + inner, + idx, + range_base, + end - range_base, + inner.initial_memory_regions[idx].flags, + ); if idx == 0 { idx = usize::MAX; } else { @@ -295,6 +335,46 @@ impl MemBlockManager { return Ok((start_index, end_index)); } + /// mark_nomap - 用`MemoryAreaAttr::NOMAP`标志标记内存区域 + /// + /// ## 参数 + /// + /// - base: 区域的物理基地址 + /// - size: 区域的大小 + /// + /// 使用`MemoryAreaAttr::NOMAP`标志标记的内存区域将不会被添加到物理内存的直接映射中。这些区域仍然会被内存映射所覆盖。内存映射中代表NOMAP内存帧的struct page将被PageReserved()。 + /// 注意:如果被标记为`MemoryAreaAttr::NOMAP`的内存是从memblock分配的,调用者必须忽略该内存 + pub fn mark_nomap(&self, base: PhysAddr, size: usize) -> Result<(), SystemError> { + return self.set_or_clear_flags(base, size, true, MemoryAreaAttr::NOMAP); + } + + fn set_or_clear_flags( + &self, + base: PhysAddr, + size: usize, + set: bool, + flags: MemoryAreaAttr, + ) -> Result<(), SystemError> { + let mut inner = self.inner.lock(); + let (start_index, end_index) = self.isolate_range(&mut inner, base, size)?; + for i in start_index..end_index { + if set { + inner.initial_memory_regions[i].flags |= flags; + } else { + inner.initial_memory_regions[i].flags &= !flags; + } + } + + let num = inner.initial_memory_regions_num as isize; + self.do_merge_blocks(&mut inner, 0, num); + return Ok(()); + } + + /// 标记内存区域为保留区域 + pub fn reserve_block(&self, base: PhysAddr, size: usize) -> Result<(), SystemError> { + return self.set_or_clear_flags(base, size, true, MemoryAreaAttr::RESERVED); + } + /// 生成迭代器 pub fn to_iter(&self) -> MemBlockIter { let inner = self.inner.lock(); @@ -349,3 +429,21 @@ impl<'a> Iterator for MemBlockIter<'a> { return Some(ret); } } + +bitflags! { + /// 内存区域属性 + pub struct MemoryAreaAttr: u32 { + /// No special request + const NONE = 0x0; + /// Hotpluggable region + const HOTPLUG = (1 << 0); + /// Mirrored region + const MIRROR = (1 << 1); + /// do not add to kenrel direct mapping + const NOMAP = (1 << 2); + /// Always detected via a driver + const DRIVER_MANAGED = (1 << 3); + /// Memory is reserved + const RESERVED = (1 << 4); + } +} diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index be32aaab..86c2b869 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -14,6 +14,7 @@ use core::{ use self::{ allocator::page_frame::{VirtPageFrame, VirtPageFrameIter}, + memblock::MemoryAreaAttr, page::round_up_to_page_size, ucontext::{AddressSpace, UserMapper}, }; @@ -87,6 +88,9 @@ pub enum PageTableKind { pub struct PhysAddr(usize); impl PhysAddr { + /// 最大物理地址 + pub const MAX: Self = PhysAddr(usize::MAX); + #[inline(always)] pub const fn new(address: usize) -> Self { Self(address) @@ -331,16 +335,19 @@ pub struct PhysMemoryArea { pub base: PhysAddr, /// 该区域的物理内存大小 pub size: usize, + + pub flags: MemoryAreaAttr, } impl PhysMemoryArea { pub const DEFAULT: Self = Self { base: PhysAddr::new(0), size: 0, + flags: MemoryAreaAttr::empty(), }; - pub fn new(base: PhysAddr, size: usize) -> Self { - Self { base, size } + pub fn new(base: PhysAddr, size: usize, flags: MemoryAreaAttr) -> Self { + Self { base, size, flags } } /// 返回向上页面对齐的区域起始物理地址 @@ -392,6 +399,10 @@ pub trait MemoryManagementArch: Clone + Copy + Debug { const ENTRY_FLAG_NO_EXEC: usize; /// 标记当前页面可执行的标志位(Execute enable) const ENTRY_FLAG_EXEC: usize; + /// 当该位为1时,标明这是一个脏页 + const ENTRY_FLAG_DIRTY: usize; + /// 当该位为1时,代表这个页面被处理器访问过 + const ENTRY_FLAG_ACCESSED: usize; /// 虚拟地址与物理地址的偏移量 const PHYS_OFFSET: usize; diff --git a/kernel/src/mm/no_init.rs b/kernel/src/mm/no_init.rs index be115bcc..ce9fbef7 100644 --- a/kernel/src/mm/no_init.rs +++ b/kernel/src/mm/no_init.rs @@ -111,14 +111,13 @@ impl FrameAllocator for PseudoAllocator { assert!(count.data() == 1); let vaddr = EARLY_IOREMAP_PAGES.lock_irqsave().allocate_page()?; let paddr = MMA::virt_2_phys(vaddr)?; - kdebug!("allocate page: vaddr={:?}, paddr={:?}", vaddr, paddr); return Some((paddr, count)); } unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount) { assert_eq!(count.data(), 1); assert!(address.check_aligned(MMA::PAGE_SIZE)); - kdebug!("free page: paddr={:?}", address); + let vaddr = MMA::phys_2_virt(address); if let Some(vaddr) = vaddr { EARLY_IOREMAP_PAGES.lock_irqsave().free_page(vaddr); diff --git a/kernel/submodules/DragonStub b/kernel/submodules/DragonStub index 773f7fd3..85156066 160000 --- a/kernel/submodules/DragonStub +++ b/kernel/submodules/DragonStub @@ -1 +1 @@ -Subproject commit 773f7fd31fb85ce22f0fc442fd2c13a8d0602a8c +Subproject commit 8515606674058ca81cd1c0b99453e326875c5c0d diff --git a/tools/run-qemu.sh b/tools/run-qemu.sh index 69b8cca4..f1e21154 100644 --- a/tools/run-qemu.sh +++ b/tools/run-qemu.sh @@ -87,8 +87,7 @@ if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then QEMU_CPU_FEATURES+="-cpu IvyBridge,apic,x2apic,+fpu,check,+vmx,${allflags}" QEMU_RTC_CLOCK+=" -rtc clock=host,base=localtime" else - QEMU_MACHINE=" -machine virt,memory-backend=${QEMU_MEMORY_BACKEND} " - + QEMU_MACHINE=" -machine virt,memory-backend=${QEMU_MEMORY_BACKEND} -cpu sifive-u54 " fi if [ ${ARCH} == "riscv64" ]; then