@@ -515,6 +515,7 @@ int riscv_cpu_max_xlen(RISCVCPUClass *mcc);
bool riscv_cpu_option_set(const char *optname);
#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,
@@ -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);
}
@@ -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",
@@ -220,7 +220,6 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu];
- g_autofree char *name = NULL;
g_autofree char *cpu_name = NULL;
g_autofree char *core_name = NULL;
g_autofree char *intc_name = NULL;
@@ -239,8 +238,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name);
}
- name = riscv_isa_string(cpu_ptr);
- qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", 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",
@@ -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"
@@ -2381,6 +2382,59 @@ 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)
+{
+ RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
+ 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(mcc);
+
+ 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, misa_mxl_max, initfn) \
{ \
.name = (type_name), \