hw/riscv/sifive_u.c | 7 ++----
hw/riscv/spike.c | 6 ++---
hw/riscv/virt.c | 6 ++---
target/riscv/cpu.c | 53 +++++++++++++++++++++++++++++++++++++++++++++
target/riscv/cpu.h | 1 +
5 files changed, 60 insertions(+), 13 deletions(-)
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index ec76dce6c9..2f227f15bc 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -171,7 +171,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry
*memmap,
int cpu_phandle = phandle++;
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller",
cpu);
- char *isa;
qemu_fdt_add_subnode(fdt, nodename);
/* cpu 0 is the management hart that does not have mmu */
if (cpu != 0) {
@@ -180,11 +179,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry
*memmap,
} else {
qemu_fdt_setprop_string(fdt, nodename, "mmu-type",
"riscv,sv48");
}
- isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]);
+ riscv_isa_write_fdt(&s->soc.u_cpus.harts[cpu - 1], fdt, nodename);
} else {
- isa = riscv_isa_string(&s->soc.e_cpus.harts[0]);
+ riscv_isa_write_fdt(&s->soc.e_cpus.harts[0], fdt, nodename);
}
- qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
@@ -194,7 +192,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry
*memmap,
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
- g_free(isa);
g_free(intc);
g_free(nodename);
}
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 81f7e53aed..64074395bc 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -59,7 +59,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry
*memmap,
MachineState *ms = MACHINE(s);
uint32_t *clint_cells;
uint32_t cpu_phandle, intc_phandle, phandle = 1;
- char *name, *mem_name, *clint_name, *clust_name;
+ char *mem_name, *clint_name, *clust_name;
char *core_name, *cpu_name, *intc_name;
static const char * const clint_compat[2] = {
"sifive,clint0", "riscv,clint0"
@@ -113,9 +113,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry
*memmap,
} else {
qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type",
"riscv,sv48");
}
- name = riscv_isa_string(&s->soc[socket].harts[cpu]);
- qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
- g_free(name);
+ riscv_isa_write_fdt(&s->soc[socket].harts[cpu], fdt, cpu_name);
qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index f9fd1341fc..c47b2d397a 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -215,7 +215,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int
socket,
int cpu;
uint32_t cpu_phandle;
MachineState *ms = MACHINE(s);
- char *name, *cpu_name, *core_name, *intc_name, *sv_name;
+ char *cpu_name, *core_name, *intc_name, *sv_name;
bool is_32_bit = riscv_is_32bit(&s->soc[0]);
uint8_t satp_mode_max;
@@ -236,9 +236,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
g_free(sv_name);
}
- name = riscv_isa_string(cpu_ptr);
- qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name);
- g_free(name);
+ riscv_isa_write_fdt(cpu_ptr, ms->fdt, cpu_name);
if (cpu_ptr->cfg.ext_zicbom) {
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size",
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 4aa4b2e988..0d6000f2a8 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -32,6 +32,7 @@
#include "hw/core/qdev-prop-internal.h"
#include "migration/vmstate.h"
#include "fpu/softfloat-helpers.h"
+#include "sysemu/device_tree.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "kvm/kvm_riscv.h"
@@ -2352,6 +2353,58 @@ char *riscv_isa_string(RISCVCPU *cpu)
return isa_str;
}
+#ifndef CONFIG_USER_ONLY
+static char **riscv_isa_extensions_list(RISCVCPU *cpu, int *count)
+{
+ int maxlen = ARRAY_SIZE(riscv_single_letter_exts) +
ARRAY_SIZE(isa_edata_arr);
+ char **extensions = g_new(char *, maxlen);
+
+ for (int i = 0; i < sizeof(riscv_single_letter_exts) - 1; i++) {
+ if (cpu->env.misa_ext & RV(riscv_single_letter_exts[i])) {
+ extensions[*count] = g_new(char, 2);
+ snprintf(extensions[*count], 2, "%c",
+ qemu_tolower(riscv_single_letter_exts[i]));
+ (*count)++;
+ }
+ }
+
+ for (const RISCVIsaExtData *edata = isa_edata_arr; edata->name; edata++) {
+ if (isa_ext_is_enabled(cpu, edata->ext_enable_offset)) {
+ extensions[*count] = g_strdup(edata->name);
+ (*count)++;
+ }
+ }
+
+ return extensions;
+}
+
+void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename)
+{
+ const size_t maxlen = sizeof("rv128i");
+ g_autofree char *isa_base = g_new(char, maxlen);
+ g_autofree char *riscv_isa;
+ char **isa_extensions;
+ int count = 0;
+ int xlen = riscv_cpu_max_xlen(cpu->env);
+
+ riscv_isa = riscv_isa_string(cpu);
+ qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", riscv_isa);
+
+ snprintf(isa_base, maxlen, "rv%di", xlen);
+ qemu_fdt_setprop_string(fdt, nodename, "riscv,isa-base", isa_base);
+
+ isa_extensions = riscv_isa_extensions_list(cpu, &count);
+ qemu_fdt_setprop_string_array(fdt, nodename, "riscv,isa-extensions",
+ isa_extensions, count);
+
+ for (int i = 0; i < count; i++) {
+ g_free(isa_extensions[i]);
+ }
+
+ g_free(isa_extensions);
+}
+#endif
+
#define DEFINE_CPU(type_name, initfn) \
{ \
.name = type_name, \
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index aacc031397..ce03d91b01 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -517,6 +517,7 @@ bool riscv_cpu_option_set(const char *optname);
#define cpu_mmu_index riscv_cpu_mmu_index
#ifndef CONFIG_USER_ONLY
+void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename);
void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
vaddr addr, unsigned size,
MMUAccessType access_type,