OS: Ubuntu 24.04 LTS on Windows 10 x8
QEMU: qemu-system-riscv64 version 8.2.2
gdb: GNU gdb (GDB) 15.2
I'm study write a kernel for Risc-V in Rust, running in QEMU, but it's crashed when setting Page Table. I have no idea.
This is the Source Code, it's pretty simple, just setup the Page Table.
I launched and debug it by: make debug
, and used gdb debug it: bash debug.sh
,
The app would be frozen while executing at src/lib.rs line:109
:
pub fn use_sv39(&self) {
// let satp: usize = self.page_table.satp_token().into();
// riscv::register::satp::write(satp);
// let ppn = self.page_table.address.into();
unsafe {
let tok: usize = self.page_table.satp_token().into();
109: ---> asm!(concat!("csrw satp, {0}"), in(reg) tok);
// let res = riscv::register::satp::try_set(Mode::Sv39, 0, ppn);
println!("set satp");
asm!("SFENCE.VMA");
}
}
I've tried debug the assembly, but while it run at csrw satp, a0
and be frozen.
I've checked the satp value, it's 0x0 before.
I don't have any idea, Thank you. If you need more message, let me know.
NEW, Debug Message:
I've breakpoint at symbol __alltraps
as in file src/trap/trap.S/ line:12
, that is trap_handler entry, have been set to stvec
register.
and when executing at src/lib.rs line:109
above, gdb stopped at symbol __alltraps
:
That's indicate rise a exception, and I checked sstatus
register, the SPP
bit was 1
, that indicated it was S-Mode before.
And the value of scause
was 0xc
, means Instruction page fault
BUT! if I type si
to execute next instruction, it was reenter the __alltraps
, the stvec
! the breakpoint already hit 2 times! The $sstatus
still was 0x200000100
and $scause
was 0xc
That's very weird. That's Why? How to solve it?
You just misunderstood the meaning of the PPN field. To generate a physical address, the PPN needs to be shifted 12 bits to the left and the VPN needs to be concatenated.
Here:
impl PTE {
pub(crate) fn new(frame: Frame, flags: Flags) -> Self {
// Here: >> 12
let pte = ((frame.value() >> 12) & ((1 << 44) - 1)) << 10 | flags.bits() as usize;
PTE(pte)
}
pub fn is_valid(&self) -> bool {
self.0 as u8 & Flags::V.bits() == Flags::V.bits()
}
/// get the physical page number,
/// if this is not a leaf page table, the return is [PhysicalAddress](crate::mm::PhysicalAddress), or a [Frame]
pub fn ppn(&self) -> Frame {
// Here: << 12
(((self.0 >> 10) & ((1 << 44) - 1)) << 12).into()
}
}
And:
// page_tables.rs:79 map
frame = match block.map_type {
MapType::Identical => (block.vpn.value() << 12).into(),
MapType::UseFrame(f) => f,
};
By the way, the BSS address is incorrect. Modify it as follows:
. = ALIGN(4K);
edata = .;
.bss : {
sbss = .;
*(.bss.stack)
;- sbss = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
}
Now it should execute the following code correctly.