mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 12:16:31 +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:
@ -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);
|
||||
|
Reference in New Issue
Block a user