orangepi rv2启动xv6时,开启分页硬件出现异常

楼主尝试在orangepi rv2上运行xv6,通过在u-boot加载bin文件到指定内核指定地址,然后再运行go命令,使其在指定地址上开始运行。当程序运行到写入分页硬件satp寄存器时,CPU似乎停止了工作,不再有任何输出。通过gdb调试发现此时内核出现异常,并跳转到kernelvec函数,然而它只会一直停留在第一条指令,不会继续往下运行。
作为对比,我在QEMU上运行一样的程序时,并没有发现相同的错误。
我怀疑可能对于K1芯片来说,写入分页硬件需要进行额外的操作。如果有朋友遇到类似的问题,希望不吝赐教。不胜感激!

GDB

(gdb) target remote localhost:3333
Remote debugging using localhost:3333
wait_debugger () at kernel/entry.S:30
30                          bnez t0, wait_debugger
(gdb) info threads
  Id   Target Id                                                  Frame
* 1    Thread 1 "k1.cpu.0" (Name: k1.cpu.0, state: debug-request) wait_debugger ()
    at kernel/entry.S:30
(gdb) break vm.c:106
Breakpoint 1 at 0x8000d5c: file kernel/vm.c, line 106.
(gdb) set $t0=0
(gdb) continue
Continuing.
Disabling abstract command writes to CSRs.

Breakpoint 1, kvminithart () at kernel/vm.c:106
106       sbi_console_puts("kvminithart: make satp\n");
(gdb) info registers mstatus stvec
mstatus        0x8000000a00006680       SD:1 VM:00 MXR:0 PUM:0 MPRV:0 XS:0 FS:3 MPP:0 HPP:3 SPP:0 MPIE:1 HPIE:0 SPIE:0 UPIE:0 MIE:0 HIE:0 SIE:0 UIE:0
stvec          0x80052c0        134238912
(gdb) next
[k1.cpu.0] Found 8 triggers
108       w_satp(satp_value);
(gdb) si
109       sbi_console_puts("kvminithart: write satp\n");
(gdb) si
kernelvec () at kernel/kernelvec.S:18
18              addi sp, sp, -256
(gdb) info registers mstatus
mstatus        0x8000000a00006780       SD:1 VM:00 MXR:0 PUM:0 MPRV:0 XS:0 FS:3 MPP:0 HPP:3 SPP:1 MPIE:1 HPIE:0 SPIE:0 UPIE:0 MIE:0 HIE:0 SIE:0 UIE:0
(gdb) info registers scause
scause         0xc      12
(gdb) si
18              addi sp, sp, -256
(gdb) si
18              addi sp, sp, -256
(gdb) si
18              addi sp, sp, -256
(gdb) info registers all
zero           0x0      0
ra             0x8000d68        0x8000d68 <kvminithart+54>
sp             0x8009af0        0x8009af0 <stack0+8112>
gp             0x7de9cd50       0x7de9cd50
tp             0x1      0x1
t0             0x2000   8192
t1             0x9000001        150994945
t2             0x80028c0        134228160
fp             0x8009b10        0x8009b10 <stack0+8144>
s1             0x800000000000ffff       -9223372036854710273
a0             0x0      0
a1             0x0      0
a2             0x0      0
a3             0x0      0
a4             0x6      6
a5             0x8000000000000000       -9223372036854775808
a6             0x0      0
a7             0x1      1
s2             0x7dfbbf20       2113650464
s3             0x2      2
s4             0x7dfbbf20       2113650464
s5             0x7efe420c       2130592268
s6             0x0      0
s7             0x0      0
s8             0x0      0
s9             0x7dfbb0d0       2113646800
s10            0x0      0
s11            0x0      0
t3             0x0      0
t4             0x0      0
t5             0x8004af6        134236918
t6             0x7de938d0       2112436432
pc             0x80052c0        0x80052c0 <kernelvec>

QEMU


OpenSBI v1.5.1
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : riscv-virtio,qemu
Platform Features         : medeleg
Platform HART Count       : 3
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 10000000Hz
Platform Console Device   : uart8250
Platform HSM Device       : ---
Platform PMU Device       : ---
Platform Reboot Device    : syscon-reboot
Platform Shutdown Device  : syscon-poweroff
Platform Suspend Device   : ---
Platform CPPC Device      : ---
Firmware Base             : 0x80000000
Firmware Size             : 347 KB
Firmware RW Offset        : 0x40000
Firmware RW Size          : 91 KB
Firmware Heap Offset      : 0x4d000
Firmware Heap Size        : 39 KB (total), 2 KB (reserved), 11 KB (used), 25 KB (free)
Firmware Scratch Size     : 4096 B (total), 416 B (used), 3680 B (free)
Runtime SBI Version       : 2.0

Domain0 Name              : root
Domain0 Boot HART         : 0
Domain0 HARTs             : 0*,1*,2*
Domain0 Region00          : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W)
Domain0 Region01          : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W)
Domain0 Region02          : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
Domain0 Region03          : 0x0000000080040000-0x000000008005ffff M: (R,W) S/U: ()
Domain0 Region04          : 0x0000000080000000-0x000000008003ffff M: (R,X) S/U: ()
Domain0 Region05          : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W)
Domain0 Region06          : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W)
Domain0 Region07          : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
Domain0 Next Address      : 0x0000000080200000
Domain0 Next Arg1         : 0x0000000087e00000
Domain0 Next Mode         : S-mode
Domain0 SysReset          : yes
Domain0 SysSuspend        : yes

Boot HART ID              : 0
Boot HART Domain          : root
Boot HART Priv Version    : v1.12
Boot HART Base ISA        : rv64imafdch
Boot HART ISA Extensions  : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu
Boot HART PMP Count       : 16
Boot HART PMP Granularity : 2 bits
Boot HART PMP Address Bits: 54
Boot HART MHPM Info       : 16 (0x0007fff8)
Boot HART Debug Triggers  : 2 triggers
Boot HART MIDELEG         : 0x0000000000001666
Boot HART MEDELEG         : 0x0000000000f0b509
hart0

xv6 kernel is booting

freerange
kinit done
kvminit done
kvminithart done
6 个赞

xv6 我记得需要m-mode启动吧?

2 个赞

从u-boot进入内核,此时已经处于S模式。只要保证不访问M模式下的寄存器,就不会报错。使用qemu启动,修改Makefile使其先加载opensbi同理,进入内核时已经处于S模式,但是没有类似的问题。

1 个赞
(gdb) info registers scause
scause         0xc      12

scause = 0xc 是 Instruction page fault,如果 fault 的指令正好是写 satp 的指令的话,建议检查一下页表对写 satp 指令的所在的页面有没有正确映射过去。我能想到的一个可能的原因是,QEMU 中和 OPI RV2 真机上加载的地址可能有所偏差,导致加载的页表中对写 satp 指令的所在的页面的映射并没有建立起来。

1 个赞

感谢回复。

是的,QEMU和OPI RV2上的地址映射存在区别。但是更多的体现在外设上的区别。

目前我只映射了text段,date段和bss段以及trampoline页,串口的输出使用sbi的接口,但是仍然出现错误。

我也尝试过修改内核加载到内存的地址,一样会出现错误。

2 个赞

对了,需要补充的是,我在OPI RV2上使用的映射方法与标准的xv6上的一致,没有做任何的修改,都是恒等映射。

1 个赞

没用过K1, 但你可能遇到了这个问题:

3 个赞

不是停留在第一条指令,而其实是不断page-fault,执行trap handler自己也触发page-fault,导致trap handler的第一条指令永远无法执行。

2 个赞

感谢大佬!确实是这个问题,分页成功了。

源代码

void
kvminithart()
{
  sfence_vma();
  sbi_console_puts("kvminithart: pre-sfence done\n");

  uint64 satp_value = MAKE_SATP(kernel_pagetable);
  sbi_console_puts("kvminithart: make satp\n");

  w_satp(satp_value);
  sbi_console_puts("kvminithart: write satp\n");

  sfence_vma();
  sbi_console_puts("kvminithart: after-sfence done\n");

  printf("paging enabled\n");
}

控制台输出

kinit done
kvmmake: start
kvmmake: root page table allocated
kvmmake: root page table cleared
kvmmake: mapping UART...
kvmmake: UART mapped
kvmmake: mapping kernel text...
kvmmake: kernel text mapped
kvmmake: mapping kernel data...
kvmmake: kernel data mapped
kvmmake: mapping trampoline...
kvmmake: trampoline mapped
kvmmake: mapping kernel stacks...
kvmmake: kernel stacks mapped
kvmmake: done
kvminithart: pre-sfence done
kvminithart: make satp
kvminithart: write satp
kvminithart: after-sfence done
paging enabled
6 个赞