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 hellowork-ver/Variane_testharness $RISCV/riscv64-unknown-elf/bin/pk hello.elf等方式来将pk作为模拟器的输入elf,然后来加载用户程序,这个用户程序就不用精心地链接,也可以直接使用系统调用函数。

下图展示了pk是如何从入口函数开始一路处理系统调用:

pk系统调用过程

链接脚本中指定了entry,mentry.S中会从init_first_hart C函数开始boot,在其中最后会调用boot_loader,在其中会将trap_entry地址写入csr寄存器stvec,当发生trap时pc会被设置为stvec,也就是跳转到trap_entry
然后会调用handle_syscalldo_syscall,根据系统调用类型调用相应的函数,最终会调用frontend_syscall,其中会调用htif_syscalldo_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再读取出写入的值,并进行处理,执行对应的系统调用。
htif处理系统调用

posted @ 2024-06-07 19:21  一鸣惊人_001  阅读(105)  评论(0)    收藏  举报