Kernel boot: MMU initialization on RISCV

57 Views Asked by At

I'm trying to implement SV39 on a RISCV64 emulator that already is able to run a non-mmu linux kernel.

However, I run into a strange behavior where priv = 3 (machine mode) but satp.mode = 8 (SV39) shortly after boot. From what I understand, priv=3 should mean that the MMU is still disabled. But no matter if I interpret it as such, or not, memory lookups fail soon after.

I've been trying to find the linux kernel code that sets the priv mode and the satp.mode, but with no luck. The most likely candidate seems to be in arch/riscv/mm/init.c:paging_init, but a printk here never gets executed.

More importantly, the code that does get executed starts at address 0, not ffffffff80000000, which is where the kernel gets loaded.

So, this must be set up by the loader? But arch/riscv/boot/loader.S is nearly empty, no code there to set up page tables or enable the right satp mode. arch/riscv/kernel/head.S also seems suspicious, but how does it get linked in? So where is this code coming from?

This is how I build my kernel image:

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- loader riscv64-unknown-elf-objcopy -O binary arch/riscv/boot/loader loader_64.bin

For reference:

$ riscv64-unknown-elf-readelf -s arch/riscv/boot/loader

Symbol table '.symtab' contains 8 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: ffffffff80000000     0 SECTION LOCAL  DEFAULT    1 .payload
     2: ffffffff80a64b40     0 SECTION LOCAL  DEFAULT    2 .text
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 .riscv.attributes
     4: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS loader.o
     5: ffffffff80a64b40     0 NOTYPE  LOCAL  DEFAULT    2 $xrv64i2p1_m2p0_[...]
     6: ffffffff80000000     0 NOTYPE  LOCAL  DEFAULT    1 $d
     7: ffffffff80000000     0 NOTYPE  GLOBAL DEFAULT    1 _start

$ riscv64-unknown-elf-readelf -s arch/riscv/boot/loader.o 

Symbol table '.symtab' contains 9 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .text
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 .data
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 .bss
     4: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    1 $xrv64i2p1_m2p0_[...]
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 .payload
     6: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    5 $d
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 .riscv.attributes
     8: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT    5 _start

Where does the _start in loader.o come from?

priv = 3, satp.mode=8
Invalid Address, or no valid write pointer found, write not executed!: Addr: ffffffff80001084 Len: 8 Cycle: 63697  PC: ffffffff80001084

ffffffff80001084 is clearly a virtual address. While priv=3 (machine mode).

0

There are 0 best solutions below