riscv: 完成UEFI初始化,能正确设置memblock的信息 (#501)

* riscv: 完成UEFI初始化,能正确设置memblock的信息

* sbi增加reset功能

* 把虚拟CPU修改为sifive-u54,使qemu能更正确地模拟硬件行为

* 修复内存页面映射未设置“DIRTY”、”ACCESSED“、”GLOBAL“位,导致真机page fault的问题
This commit is contained in:
LoGin
2024-01-26 18:08:39 +08:00
committed by GitHub
parent a381e482cb
commit 9284987850
22 changed files with 754 additions and 130 deletions

View File

@ -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 // L1R/W/X/V = 1
ori t3, t3, 0xEF // L1set 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
// 30L0
srl t2, t2, 30
srli t2, t2, 30
// 511L0
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
// t0L0
ori t3, t3, 0xEF // set R/W/X/V/A/D/G = 1
// deltapfn
li t2, 0x40000000
srli t2, t2, 12
// delta pfn10
slli t2, t2, 10
li t1, 2
__loop_set_8g:
sd t3, 0(t4)
// t4
addi t4, t4, 8
// t3 (1G)
li t2, 0x40000000
// 1Gpfn
add t3, t3, t2
sd t3, 0(t4)
addi t1, t1, -1
bnez t1, __loop_set_8g
ret
//
//
// a0: page table address

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -108,6 +108,9 @@ impl MemoryManagementArch for X86_64MMArch {
/// x86_64不存在EXEC标志位只有NO_EXECXD标志位
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);