Recently, I try to write a virtual memory init program like linux does, in linux:
1. it first map DRAM to high address,
2. then calculate the offset between physic address and virtual address,
3. add the offset to the address of the next instruction after write satp, and write the result to stvec
4. when machine write satp, it will trap a instruction page fault, and pc will set to the value in stvec,
By this way, it change the physic pc to virtual pc.
But there is a strange thing is that before write satp, it first execute a sfence.vma, like following:
```
// suppose pc in 0x8000xxxx
call setup_vm // mapping early_pgtbl 0x8xxx xxxx -> 0xffffffff 8xxx xxxx
li t0, VM_START
la t1, _start
sub a0, t0, t1 // a0 = 0xffffffff 0000 0000
la t0, 1f
add t0, t0, a0
csrw stvec, t0
# set early_pgtbl to satp
la t0, early_pgtbl
srl t0, t0, PAGE_SHIFT
li t1, SATP_MODE
or t0, t1, t0
sfence.vma
csrw satp, t0
1:
...
```
Why the sfence execute before write satp ? I swap them (or delete sfence) find the program crashed ...
So I log qemu's in_asm stream, I find that:
```
sfence.vma
----------------
IN:
...
0x00000000800000f4: 18029073 csrrw zero,satp,t0
----------------
IN:
0x00000000800000f8: 0000 illegal
0x00000000800000fa: 0000 illegal
0x00000000800000fc: 0000 illegal
0x00000000800000fe: 0000 illegal
0x0000000080000100: 0000 illegal
0x0000000080000102: 0000 illegal
0x0000000080000104: 0000 illegal
0x0000000080000106: 0000 illegal
0x0000000080000108: 0000 illegal
0x000000008000010a: 0000 illegal
0x000000008000010c: 0000 illegal
0x000000008000010e: 0000 illegal
```
For the origin:
```
sfence.vma
csrw satp, t0
1:
----------------
IN:
...
0x00000000800000f4: 12000073 sfence.vma zero,zero
0x00000000800000f8: 18029073 csrrw zero,satp,t0
----------------
IN:
0xffffffff800000fc: 0000a117 auipc sp,40960 # 0xffffffff8000a0fc
...
```
I view sfence as a TLB flush, so in this case, because stap is empty before, we directly write early page table in it. However, it seems when swap or delete sfence, qemu will not throw a page fault, I'm true the page mapping is corret, so is this a bug of qemu or I missunderstanding the sfence.