解决QEMU执行mret指令无法跳转到0x80200000

解决QEMU执行mret指令无法跳转到0x80200000

1 背景介绍

在使用NEMU与QEMU做DiffTest的场景下,运行的固件为《RISC-V体系结构编程与实践》中示例代码chapter_2,编译出来的固件二进制文件为:benos_payload.bin

将benos_payload.bin,分别放置在NEMU与QEMU中的内存0x80000000处,并计划两者同时从0x80000000开始运行,期间运行到0x800000a8处(mret指令)时,下一条指令,预期均会跳转到0x80200000处,继续取指执行。

2 问题描述

NEMU执行mret指令后,PC可正常跳转到0x80200000处;
而QEMU执行mret指令后,却无法跳转到0x80200000处,QEMU直接跳转到了0x80200100处(f8000793 addi a5,zero,-128),因此NEMU与QEMU中PC值不等,造成DiffTest提示错误。

NEMU与QEMU都从0x80000000开始运行benos_payload.bin,得到的日志:

0x80000000: 0x1117
0x80000004: 0x00010113
0x80000008: 0x12b7
0x8000000c: 0x00510133
0x80000010: 0x0040006f
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000014:   13 01 01 fc                 c_addi  sp,-64,sp
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000018:   23 3c 81 02                 sd  56(sp),s0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000001c:   f3 27 00 30                 csrrs  $0,0x300,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000020:   13 84 07 00                 c_mv  a5,s0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000024:   93 07 04 00                 c_mv  s0,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000028:   23 34 f1 02                 sd  40(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000002c:   03 37 81 02                 ld  40(sp),a4
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000030:   b7 e7 ff ff                 lui  0xffffffffffffe000,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000034:   93 87 f7 7f                 c_addi  a5,2047,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000038:   33 77 f7 00                 c_and  a4,a5,a4
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000003c:   b7 17 00 00                 lui  0x1000,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000040:   93 87 07 80                 c_addi  a5,-2048,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000044:   b3 67 f7 00                 or  a4,a5,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000048:   23 34 f1 02                 sd  40(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000004c:   83 37 81 02                 ld  40(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000050:   93 f7 f7 f7                 c_andi  a5,-129,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000054:   23 34 f1 02                 sd  40(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000058:   83 37 81 02                 ld  40(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000005c:   23 30 f1 02                 sd  32(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000060:   83 37 01 02                 ld  32(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000064:   73 90 07 30                 csrrw  a5,0x300,$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000068:   93 07 10 40                 c_li  $0,1025,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000006c:   93 97 57 01                 c_slli  a5,21,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000070:   23 3c f1 00                 sd  24(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000074:   83 37 81 01                 ld  24(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000078:   73 90 17 34                 csrrw  a5,0x341,$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000007c:   93 07 10 40                 c_li  $0,1025,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000080:   93 97 57 01                 c_slli  a5,21,a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000084:   23 38 f1 00                 sd  16(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000088:   83 37 01 01                 ld  16(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000008c:   73 90 57 10                 csrrw  a5,0x105,$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000090:   23 34 01 00                 sd  8(sp),$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000094:   83 37 81 00                 ld  8(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x0000000080000098:   73 90 47 10                 csrrw  a5,0x104,$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x000000008000009c:   23 30 01 00                 sd  0(sp),$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x00000000800000a0:   83 37 01 00                 ld  0(sp),a5
[src/cpu/cpu-exec.c:578,fetch_decode] 0x00000000800000a4:   73 90 07 18                 csrrw  a5,0x180,$0
[src/cpu/cpu-exec.c:578,fetch_decode] 0x00000000800000a8:   73 00 20 30                 mret
[/home/higon/huangchao/NEMU/NEMU/include/cpu/difftest.h:49,difftest_check_reg] pc is different after executing instruction at pc = 0x00000000800000a8, right = 0x0000000000000000, wrong = 0x0000000080200000

3 原因分析

对于低版本QEMU(4.2.1),似乎不检查PMP配置,因此可正常运行。
对于高版本QEMU(我用的7.1.0),会检查PMP配置,因此需要在SBI中初始化PMP才能运行。
书作者的声明,参考链接:
https://github.com/runninglinuxkernel/riscv_programming_practice/tree/master/chapter_2,打开链接中的必读.txt查看。

至于PMP配置的具体原理,可以去翻翻spec和文末的代码。

4 解决办法

在chapter_2/benos/sbi/sbi_main.c的sbi_main函数中,添加2行sbi_set_pmp函数调用,如下所示:

/*
 * 运行在M模式
 */
void sbi_main(void)
{
	unsigned long val;
    /*
     * 配置PMP
     * 所有地址空间都可以访问
     */
    sbi_set_pmp(0, 0, -1UL, PMP_RWX);
    sbi_set_pmp(1, 0x80000000, 0x40000, PMP_RWX);

	/* 设置跳转模式为S模式 */
	val = read_csr(mstatus);
	val = INSERT_FIELD(val, MSTATUS_MPP, PRV_S);
	val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
	write_csr(mstatus, val);

	/* 设置M模式的Exception Program Counter,用于mret跳转 */
	write_csr(mepc, FW_JUMP_ADDR);
	/* 设置S模式异常向量表入口*/
	write_csr(stvec, FW_JUMP_ADDR);
	/* 关闭S模式的中断*/
	write_csr(sie, 0);
	/* 关闭S模式的页表转换 */
	write_csr(satp, 0);

	/* 切换到S模式 */
	asm volatile("mret");
}

当然还有其他一些修改,都比较简单,修改好的代码,可从这里获取:
https://gitee.com/bailiyang/cdemo/tree/master/riscv_programming_practice/chapter_2/benos


参考文档:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值