monitor负责将客户程序读入客户计算机。
init_monitor()
init_isa(): * 将内置客户程序读入内存 * 用uint8_t模拟内存地址 * 读入位置:RESET_VECTOR(于nemu/include/memory/paddr.h) * 初始化寄存器 * restart() * 用结构体CPU_state模拟寄存器(于nemu/src/isa/$ISA/include/isa-def.h) * 在nemu/src/cpu/cpu-exec.c定义全局变量cpu保存寄存器 > x86的物理内存是从0开始编址的, 但对于一些ISA来说却不是这样, 例如mips32和riscv32的物理地址均0x80000000开始. 因此对于mips32和riscv32, 其CONFIG_MBASE将会被定义成0x80000000. 将来CPU访问内存时, 我们会将CPU将要访问的内存地址映射到pmem中的相应偏移位置, 这是通过nemu/src/memory/paddr.c中的guest_to_host()函数实现的. 例如如果mips32的CPU打算访问内存地址0x80000000, 我们会让它最终访问pmem[0], 从而可以正确访问客户程序的第一条指令. 这种机制有一个专门的名字, 叫地址映射
在
cmd_c()函数中, 调用cpu_exec()的时候传入了参数-1, 你知道这是什么意思吗?cpu_exec()支持的参数是64位无符号整型,其将这一参数再传递给execute()函数,表示最大可运行的指令数,这里给一个极大值(有符号强制转换无符号)用以表示我们不断运行指令直到客户程序结束。优美地退出 退出时发生错误的原因:
nemu-main.c中主函数退出时返回is_exit_status_bad()(定义于src/utils/state.c)检测的返回状态是否正常的值,当nemu_state.state为NEMU_END(客户程序程序正常结束)且nemu_state.halt_ret为假(不是因为断电返回)时,或nemu_state.state为为NEMU_QUIT时才会返回0,而src/monitor/sdb/sdb.c中在q退出NEMU时没有重设nemu_state.state,故被视为异常退出。 解决方式: 在cmd_q()函数中加入一行nemu_state.state = NEMU_QUIT;。关于内置客户程序运行后
x 1 0x80000000输出0x0单步运行到这里打印内存没有问题,怀疑是后面覆盖掉了这个内存 第一句语句lui t0 524288524288转换为16进制是80000,lui将这个数加载到寄存器t0的高位(末位为0不变) 第二句语句sw zero 0(t0)将零寄存器(自然是全零)的值保存到0(t0)(计算后为0x80000000)wp_pool为什么加static本地化变量,防止外部的意外访问/修改
RISC-V ISA
如何解决立即数的位数问题 通过
lui(在高20位存数)和addi(在低12位做加法)两条指令同时运用,我们可以表示32位下的任意数字。静态指令和动态指令 在程序分析领域中, 静态指令是指程序代码中的指令, 动态指令是指程序运行过程中的指令. 例如对于以下指令序列
1 | 100: jmp 102 |
jmp指令的下一条静态指令是add指令, 而下一条动态指令则是xor指令.
SEXT:对立即数进行符号扩展,故一般只在最高位出现的部分使用
在riscv32中, 如果mstatus中的MIE位为0, 则CPU处于关中断状态