RISC-V仿真系统学习
缩写
- ISS
- instruction set simulator
- PK
- proxy kernel
- bbl
- berkeley boot loader
- fesvr
- front end server
- htif
- host target interface
- DPI
- direct programming interface
- dtm
- debug transport module
- AEE
- application execution environment
- SBI
- supervisor binary interface
系统调用如何被处理
RISC-V软件栈如下:

前面我在SoC裸机 (bare metal)上运行了llama2应用,当时没有AEE,需要自己实现ABI。(前面是通过实现内存管理、文件读取函数的方式,也可以通过自己写系统调用过程而不用修改应用源码)
The RISC-V Proxy Kernel, pk, is a lightweight application execution environment that can host statically-linked RISC-V ELF binaries. It is designed to support tethered RISC-V implementations with limited I/O capability and thus handles I/O-related system calls by proxying them to a host computer.
pk是一个轻量级的应用执行环境 (AEE),可以托管静态链接的 RISC-V ELF 二进制文件。它旨在支持具有有限I/O能力的RISC-V实现,并通过代理将与I/O相关的系统调用传送到主机计算机。
通常会使用spike pk hello、work-ver/Variane_testharness $RISCV/riscv64-unknown-elf/bin/pk hello.elf等方式来将pk作为模拟器的输入elf,然后来加载用户程序,这个用户程序就不用精心地链接,也可以直接使用系统调用函数。
下图展示了pk是如何从入口函数开始一路处理系统调用:
链接脚本中指定了entry,mentry.S中会从init_first_hart C函数开始boot,在其中最后会调用boot_loader,在其中会将trap_entry地址写入csr寄存器stvec,当发生trap时pc会被设置为stvec,也就是跳转到trap_entry。
然后会调用handle_syscall、do_syscall,根据系统调用类型调用相应的函数,最终会调用frontend_syscall,其中会调用htif_syscall、do_tohost_fromhost、__set_tohost,然后会往tohost写入由参数组成的值。
volatile uint64_t tohost attribute((section(".htif"))); 会将变量tohost放入.htif section,并且用volatile修饰,保证每次读写都会访存。
而在fesvr的htif.cc中
int htif_t::run()
{
start();
auto enq_func = [](std::queue<reg_t>* q, uint64_t x) { q->push(x); };
std::queue<reg_t> fromhost_queue;
std::function<void(reg_t)> fromhost_callback =
std::bind(enq_func, &fromhost_queue, std::placeholders::_1);
if (tohost_addr == 0) {
while (!signal_exit)
idle();
}
while (!signal_exit && exitcode == 0)
{
uint64_t tohost;
try {
if ((tohost = from_target(mem.read_uint64(tohost_addr))) != 0)
mem.write_uint64(tohost_addr, target_endian<uint64_t>::zero);
} catch (mem_trap_t& t) {
bad_address("accessing tohost", t.get_tval());
}
try {
if (tohost != 0) {
command_t cmd(mem, tohost, fromhost_callback);
device_list.handle_command(cmd);
} else {
idle();
}
device_list.tick();
} catch (mem_trap_t& t) {
std::stringstream tohost_hex;
tohost_hex << std::hex << tohost;
bad_address("host was accessing memory on behalf of target (tohost = 0x" + tohost_hex.str() + ")", t.get_tval());
}
try {
if (!fromhost_queue.empty() && !mem.read_uint64(fromhost_addr)) {
mem.write_uint64(fromhost_addr, to_target(fromhost_queue.front()));
fromhost_queue.pop();
}
} catch (mem_trap_t& t) {
bad_address("accessing fromhost", t.get_tval());
}
}
stop();
return exit_code();
}
会从tohost_addr再读取出写入的值,并进行处理,执行对应的系统调用。

浙公网安备 33010602011771号