From: Pierrick Bouvier Date: Tue, 10 Feb 2026 20:13:44 +0000 (-0800) Subject: contrib/plugins/uftrace: add riscv64 support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e82d8af3da05e5315a11d0841e40ff0ed0ce53c8;p=thirdparty%2Fqemu.git contrib/plugins/uftrace: add riscv64 support Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260210201344.1403613-5-pierrick.bouvier@linaro.org Signed-off-by: Pierrick Bouvier --- diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c index 21ac140204..e3c65a1c93 100644 --- a/contrib/plugins/uftrace.c +++ b/contrib/plugins/uftrace.c @@ -99,6 +99,19 @@ typedef struct { struct qemu_plugin_register *reg_cr0; } X64Cpu; +typedef struct { + struct qemu_plugin_register *reg_fp; + struct qemu_plugin_register *reg_priv; +} Riscv64Cpu; + +typedef enum { + RISCV64_USER, + RISCV64_SUPERVISOR, + RISCV64_RESERVED, + RISCV64_MACHINE, + RISCV64_PRIVILEGE_LEVEL_MAX, +} Riscv64PrivilegeLevel; + typedef struct { uint64_t timestamp; uint64_t data; @@ -681,6 +694,78 @@ static CpuOps x64_ops = { .does_insn_modify_frame_pointer = x64_does_insn_modify_frame_pointer, }; +static uint8_t riscv64_num_privilege_levels(void) +{ + return RISCV64_PRIVILEGE_LEVEL_MAX; +} + +static const char *riscv64_get_privilege_level_name(uint8_t pl) +{ + switch (pl) { + case RISCV64_USER: return "User"; + case RISCV64_SUPERVISOR: return "Supervisor"; + case RISCV64_RESERVED: return "Unknown"; + case RISCV64_MACHINE: return "Machine"; + default: + g_assert_not_reached(); + } +} + +static uint8_t riscv64_get_privilege_level(Cpu *cpu_) +{ + Riscv64Cpu *cpu = cpu_->arch; + return cpu_read_register64(cpu_, cpu->reg_priv); +} + +static uint64_t riscv64_get_frame_pointer(Cpu *cpu_) +{ + Riscv64Cpu *cpu = cpu_->arch; + return cpu_read_register64(cpu_, cpu->reg_fp); +} + +static uint64_t riscv64_get_next_frame_pointer(Cpu *cpu_, uint64_t fp) +{ + return cpu_read_memory64(cpu_, fp - 16); +} + +static uint64_t riscv64_get_next_return_address(Cpu *cpu_, uint64_t fp) +{ + return cpu_read_memory64(cpu_, fp - 8); +} + +static void riscv64_init(Cpu *cpu_) +{ + Riscv64Cpu *cpu = g_new0(Riscv64Cpu, 1); + cpu_->arch = cpu; + cpu->reg_fp = plugin_find_register("fp"); + g_assert(cpu->reg_fp); + cpu->reg_priv = plugin_find_register("priv"); + g_assert(cpu->reg_priv); +} + +static void riscv64_end(Cpu *cpu) +{ + g_free(cpu->arch); +} + +static bool riscv64_does_insn_modify_frame_pointer(const char *disas) +{ + /* fp is s0 in disassembly */ + return strstr(disas, "s0"); +} + +static CpuOps riscv64_ops = { + .init = riscv64_init, + .end = riscv64_end, + .get_frame_pointer = riscv64_get_frame_pointer, + .get_next_frame_pointer = riscv64_get_next_frame_pointer, + .get_next_return_address = riscv64_get_next_return_address, + .get_privilege_level = riscv64_get_privilege_level, + .num_privilege_levels = riscv64_num_privilege_levels, + .get_privilege_level_name = riscv64_get_privilege_level_name, + .does_insn_modify_frame_pointer = riscv64_does_insn_modify_frame_pointer, +}; + static void track_privilege_change(unsigned int cpu_index, void *udata) { Cpu *cpu = qemu_plugin_scoreboard_find(score, cpu_index); @@ -890,6 +975,8 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, arch_ops = aarch64_ops; } else if (!strcmp(info->target_name, "x86_64")) { arch_ops = x64_ops; + } else if (!strcmp(info->target_name, "riscv64")) { + arch_ops = riscv64_ops; } else { fprintf(stderr, "plugin uftrace: %s target is not supported\n", info->target_name); diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst index f547e118ee..76c6ea92ca 100644 --- a/docs/about/emulation.rst +++ b/docs/about/emulation.rst @@ -836,8 +836,8 @@ Uftrace This plugin generates a binary trace compatible with `uftrace `_. -Plugin supports aarch64 and x64, and works in user and system mode, allowing to -trace a system boot, which is not something possible usually. +Plugin supports aarch64, x64 and riscv64, and works in user and system mode, +allowing to trace a system boot, which is not something possible usually. In user mode, the memory mapping is directly copied from ``/proc/self/maps`` at the end of execution. Uftrace should be able to retrieve symbols by itself, @@ -872,7 +872,7 @@ Performance wise, overhead compared to normal tcg execution is around x5-x15. - Description * - trace-privilege-level=[on|off] - Generate separate traces for each privilege level (Exception Level + - Security State on aarch64, Rings on x64). + Security State on aarch64, Privilege levels on riscv64 and Rings on x64). .. list-table:: uftrace_symbols.py arguments :widths: 20 80 @@ -976,6 +976,10 @@ You can follow the exact same instructions for a x64 system, combining edk2, Linux, and Ubuntu, simply by switching to `x86_64 `_ branch. +You can follow the exact same instructions for a riscv64 system, combining +opensbi, Linux, and Ubuntu, simply by switching to +`riscv64 `_ branch. + To build and run the system:: # Install dependencies