mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
riscv: 完成UEFI初始化,能正确设置memblock的信息 (#501)
* riscv: 完成UEFI初始化,能正确设置memblock的信息 * sbi增加reset功能 * 把虚拟CPU修改为sifive-u54,使qemu能更正确地模拟硬件行为 * 修复内存页面映射未设置“DIRTY”、”ACCESSED“、”GLOBAL“位,导致真机page fault的问题
This commit is contained in:
parent
a381e482cb
commit
9284987850
@ -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
|
||||
|
@ -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
|
||||
///
|
||||
|
85
kernel/src/arch/riscv64/driver/sbi/reset.rs
Normal file
85
kernel/src/arch/riscv64/driver/sbi/reset.rs
Normal file
@ -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<core::convert::Infallible, SbiError> {
|
||||
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),
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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<PhysAddr> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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<MMA: MemoryManagementArch> BumpAllocator<MMA> {
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
35
kernel/src/driver/firmware/efi/guid.rs
Normal file
35
kernel/src/driver/firmware/efi/guid.rs
Normal file
@ -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()
|
||||
}
|
||||
}
|
@ -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::<uefi_raw::table::system::SystemTable>();
|
||||
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::<uefi_raw::table::configuration::ConfigurationTable>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<VirtAddr> {
|
||||
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<Self::Item> {
|
||||
if self.offset + size_of::<Self::Item>() > 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::<Self::Item>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<PhysAddr>,
|
||||
/// runtime services的版本号
|
||||
pub runtime_service_version: Option<uefi_raw::table::Revision>,
|
||||
pub dragonstub_load_info: Option<DragonStubPayloadEFI>,
|
||||
}
|
||||
|
||||
impl EFIManager {
|
||||
@ -42,6 +45,7 @@ impl EFIManager {
|
||||
init_flags: EFIInitFlags::empty(),
|
||||
runtime_paddr: None,
|
||||
runtime_service_version: None,
|
||||
dragonstub_load_info: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
167
kernel/src/driver/firmware/efi/tables.rs
Normal file
167
kernel/src/driver/firmware/efi/tables.rs
Normal file
@ -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::<u16>(), 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::<DragonStubPayloadEFI>(),
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
// #[cfg(target_arch = "riscv64")]
|
||||
pub mod fdt;
|
||||
|
@ -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)]
|
||||
|
@ -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<VirtAddr, SystemError> {
|
||||
// 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);
|
||||
}
|
||||
|
||||
/// 把物理内存映射到虚拟内存中
|
||||
///
|
||||
/// ## 说明
|
||||
|
@ -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<usize, SystemError> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -111,14 +111,13 @@ impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> {
|
||||
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);
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 773f7fd31fb85ce22f0fc442fd2c13a8d0602a8c
|
||||
Subproject commit 8515606674058ca81cd1c0b99453e326875c5c0d
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user