Message ID | 20221117072841.240839-1-alexghiti@rivosinc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | riscv: Add RISCVCPUConfig.satp_mode to set sv48, sv57, etc. | expand |
On Wed, Nov 16, 2022 at 11:29 PM Alexandre Ghiti <alexghiti@rivosinc.com> wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > the machine's support at startup via the satp CSR register (done in > csr.c:validate_vm). > > As per the specification, sv64 must support sv57, which in turn must > support sv48...etc. So we can restrict machine support by simply setting the > "highest" supported mode in the satp_mode property. And the bare mode is > always supported. > > You can set this new property as follows: > -cpu rv64,satp-mode=sv48 # Linux will boot using sv48 scheme > -cpu rv64,satp-mode=sv39 # Linux will boot using sv39 scheme > > In addition, we now correctly set the device-tree entry 'mmu-type' using > this new satp_mode property. > > Co-Developed-by: Ludovic Henry <git@ludovic.dev> > Signed-off-by: Ludovic Henry <git@ludovic.dev> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com> > --- > hw/riscv/virt.c | 15 ++++++--------- > target/riscv/cpu.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ > target/riscv/cpu.h | 3 +++ > target/riscv/csr.c | 6 ++++-- > 4 files changed, 58 insertions(+), 11 deletions(-) > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > index a5bc7353b4..77484b5cae 100644 > --- a/hw/riscv/virt.c > +++ b/hw/riscv/virt.c > @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, > int cpu; > uint32_t cpu_phandle; > MachineState *mc = MACHINE(s); > - char *name, *cpu_name, *core_name, *intc_name; > + char *name, *cpu_name, *core_name, *intc_name, *sv_name; > > for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { > cpu_phandle = (*phandle)++; > @@ -236,14 +236,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, > cpu_name = g_strdup_printf("/cpus/cpu@%d", > s->soc[socket].hartid_base + cpu); > qemu_fdt_add_subnode(mc->fdt, cpu_name); > - if (riscv_feature(&s->soc[socket].harts[cpu].env, > - RISCV_FEATURE_MMU)) { > - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > - (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); > - } else { > - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > - "riscv,none"); > - } > + > + sv_name = g_strdup_printf("riscv,%s", > + s->soc[socket].harts[cpu].cfg.satp_mode_str); > + qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); > + > name = riscv_isa_string(&s->soc[socket].harts[cpu]); > qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); > g_free(name); > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index d14e95c9dc..efdb530ad9 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -907,6 +907,48 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) > } > #endif > > + /* > + * Either a cpu sets its supported satp_mode in XXX_cpu_init > + * or the user sets this value using satp_mode property. > + */ > + bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; > + if (cpu->cfg.satp_mode_str) { > + if (!g_strcmp0(cpu->cfg.satp_mode_str, "none")) > + cpu->cfg.satp_mode = VM_1_10_MBARE; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv32") && rv32) > + cpu->cfg.satp_mode = VM_1_10_SV32; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv39") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV39; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv48") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV48; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv57") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV57; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv64") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV64; > + else { > + error_report("Unknown option for satp_mode: %s", > + cpu->cfg.satp_mode_str); > + exit(EXIT_FAILURE); > + } > + } else { > + /* > + * If unset by both the user and the cpu, we fallback to sv32 for 32-bit > + * or sv57 for 64-bit when a MMU is present, and bare otherwise. > + */ > + if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) { > + if (rv32) { > + cpu->cfg.satp_mode_str = g_strdup("sv32"); > + cpu->cfg.satp_mode = VM_1_10_SV32; > + } else { > + cpu->cfg.satp_mode_str = g_strdup("sv57"); > + cpu->cfg.satp_mode = VM_1_10_SV57; > + } > + } else { > + cpu->cfg.satp_mode_str = g_strdup("none"); > + cpu->cfg.satp_mode = VM_1_10_MBARE; > + } > + } > + > riscv_cpu_register_gdb_regs_for_features(cs); > > qemu_init_vcpu(cs); > @@ -1094,6 +1136,9 @@ static Property riscv_cpu_properties[] = { > > DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false), > DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false), > + > + DEFINE_PROP_STRING("satp-mode", RISCVCPU, cfg.satp_mode_str), > + > DEFINE_PROP_END_OF_LIST(), > }; > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index 3a9e25053f..a6c229470b 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -480,6 +480,9 @@ struct RISCVCPUConfig { > bool debug; > > bool short_isa_string; > + > + uint8_t satp_mode; > + char *satp_mode_str; > }; > > typedef struct RISCVCPUConfig RISCVCPUConfig; > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index 5c9a7ee287..d26b830f1a 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -1109,10 +1109,12 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, > > static int validate_vm(CPURISCVState *env, target_ulong vm) > { > + vm &= 0xf; > + > if (riscv_cpu_mxl(env) == MXL_RV32) { > - return valid_vm_1_10_32[vm & 0xf]; > + return valid_vm_1_10_32[vm] && (vm <= RISCV_CPU(env_cpu(env))->cfg.satp_mode); > } else { > - return valid_vm_1_10_64[vm & 0xf]; > + return valid_vm_1_10_64[vm] && (vm <= RISCV_CPU(env_cpu(env))->cfg.satp_mode); > } > } > > -- > 2.37.2 > > LGTM. Reviewed-by: Atish Patra <atishp@rivosinc.com>
On Fri, Nov 18, 2022 at 12:26 AM Alexandre Ghiti <alexghiti@rivosinc.com> wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > the machine's support at startup via the satp CSR register (done in > csr.c:validate_vm). > > As per the specification, sv64 must support sv57, which in turn must > support sv48...etc. So we can restrict machine support by simply setting the > "highest" supported mode in the satp_mode property. And the bare mode is > always supported. > > You can set this new property as follows: > -cpu rv64,satp-mode=sv48 # Linux will boot using sv48 scheme > -cpu rv64,satp-mode=sv39 # Linux will boot using sv39 scheme > > In addition, we now correctly set the device-tree entry 'mmu-type' using > this new satp_mode property. > > Co-Developed-by: Ludovic Henry <git@ludovic.dev> > Signed-off-by: Ludovic Henry <git@ludovic.dev> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com> > --- > hw/riscv/virt.c | 15 ++++++--------- > target/riscv/cpu.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ > target/riscv/cpu.h | 3 +++ > target/riscv/csr.c | 6 ++++-- > 4 files changed, 58 insertions(+), 11 deletions(-) > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > index a5bc7353b4..77484b5cae 100644 > --- a/hw/riscv/virt.c > +++ b/hw/riscv/virt.c > @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, > int cpu; > uint32_t cpu_phandle; > MachineState *mc = MACHINE(s); > - char *name, *cpu_name, *core_name, *intc_name; > + char *name, *cpu_name, *core_name, *intc_name, *sv_name; > > for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { > cpu_phandle = (*phandle)++; > @@ -236,14 +236,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, > cpu_name = g_strdup_printf("/cpus/cpu@%d", > s->soc[socket].hartid_base + cpu); > qemu_fdt_add_subnode(mc->fdt, cpu_name); > - if (riscv_feature(&s->soc[socket].harts[cpu].env, > - RISCV_FEATURE_MMU)) { > - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > - (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); > - } else { > - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > - "riscv,none"); > - } > + > + sv_name = g_strdup_printf("riscv,%s", > + s->soc[socket].harts[cpu].cfg.satp_mode_str); > + qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); > + > name = riscv_isa_string(&s->soc[socket].harts[cpu]); > qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); > g_free(name); > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index d14e95c9dc..efdb530ad9 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -907,6 +907,48 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) > } > #endif > > + /* > + * Either a cpu sets its supported satp_mode in XXX_cpu_init > + * or the user sets this value using satp_mode property. > + */ > + bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; > + if (cpu->cfg.satp_mode_str) { > + if (!g_strcmp0(cpu->cfg.satp_mode_str, "none")) > + cpu->cfg.satp_mode = VM_1_10_MBARE; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv32") && rv32) > + cpu->cfg.satp_mode = VM_1_10_SV32; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv39") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV39; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv48") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV48; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv57") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV57; > + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv64") && !rv32) > + cpu->cfg.satp_mode = VM_1_10_SV64; > + else { > + error_report("Unknown option for satp_mode: %s", > + cpu->cfg.satp_mode_str); > + exit(EXIT_FAILURE); You should use error_setg() and return here instead Alistair > + } > + } else { > + /* > + * If unset by both the user and the cpu, we fallback to sv32 for 32-bit > + * or sv57 for 64-bit when a MMU is present, and bare otherwise. > + */ > + if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) { > + if (rv32) { > + cpu->cfg.satp_mode_str = g_strdup("sv32"); > + cpu->cfg.satp_mode = VM_1_10_SV32; > + } else { > + cpu->cfg.satp_mode_str = g_strdup("sv57"); > + cpu->cfg.satp_mode = VM_1_10_SV57; > + } > + } else { > + cpu->cfg.satp_mode_str = g_strdup("none"); > + cpu->cfg.satp_mode = VM_1_10_MBARE; > + } > + } > + > riscv_cpu_register_gdb_regs_for_features(cs); > > qemu_init_vcpu(cs); > @@ -1094,6 +1136,9 @@ static Property riscv_cpu_properties[] = { > > DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false), > DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false), > + > + DEFINE_PROP_STRING("satp-mode", RISCVCPU, cfg.satp_mode_str), > + > DEFINE_PROP_END_OF_LIST(), > }; > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index 3a9e25053f..a6c229470b 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -480,6 +480,9 @@ struct RISCVCPUConfig { > bool debug; > > bool short_isa_string; > + > + uint8_t satp_mode; > + char *satp_mode_str; > }; > > typedef struct RISCVCPUConfig RISCVCPUConfig; > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index 5c9a7ee287..d26b830f1a 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -1109,10 +1109,12 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, > > static int validate_vm(CPURISCVState *env, target_ulong vm) > { > + vm &= 0xf; > + > if (riscv_cpu_mxl(env) == MXL_RV32) { > - return valid_vm_1_10_32[vm & 0xf]; > + return valid_vm_1_10_32[vm] && (vm <= RISCV_CPU(env_cpu(env))->cfg.satp_mode); > } else { > - return valid_vm_1_10_64[vm & 0xf]; > + return valid_vm_1_10_64[vm] && (vm <= RISCV_CPU(env_cpu(env))->cfg.satp_mode); > } > } > > -- > 2.37.2 > >
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a5bc7353b4..77484b5cae 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); - char *name, *cpu_name, *core_name, *intc_name; + char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +236,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); - if (riscv_feature(&s->soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", - (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); - } else { - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", - "riscv,none"); - } + + sv_name = g_strdup_printf("riscv,%s", + s->soc[socket].harts[cpu].cfg.satp_mode_str); + qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); + name = riscv_isa_string(&s->soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d14e95c9dc..efdb530ad9 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -907,6 +907,48 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } #endif + /* + * Either a cpu sets its supported satp_mode in XXX_cpu_init + * or the user sets this value using satp_mode property. + */ + bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; + if (cpu->cfg.satp_mode_str) { + if (!g_strcmp0(cpu->cfg.satp_mode_str, "none")) + cpu->cfg.satp_mode = VM_1_10_MBARE; + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv32") && rv32) + cpu->cfg.satp_mode = VM_1_10_SV32; + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv39") && !rv32) + cpu->cfg.satp_mode = VM_1_10_SV39; + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv48") && !rv32) + cpu->cfg.satp_mode = VM_1_10_SV48; + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv57") && !rv32) + cpu->cfg.satp_mode = VM_1_10_SV57; + else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv64") && !rv32) + cpu->cfg.satp_mode = VM_1_10_SV64; + else { + error_report("Unknown option for satp_mode: %s", + cpu->cfg.satp_mode_str); + exit(EXIT_FAILURE); + } + } else { + /* + * If unset by both the user and the cpu, we fallback to sv32 for 32-bit + * or sv57 for 64-bit when a MMU is present, and bare otherwise. + */ + if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) { + if (rv32) { + cpu->cfg.satp_mode_str = g_strdup("sv32"); + cpu->cfg.satp_mode = VM_1_10_SV32; + } else { + cpu->cfg.satp_mode_str = g_strdup("sv57"); + cpu->cfg.satp_mode = VM_1_10_SV57; + } + } else { + cpu->cfg.satp_mode_str = g_strdup("none"); + cpu->cfg.satp_mode = VM_1_10_MBARE; + } + } + riscv_cpu_register_gdb_regs_for_features(cs); qemu_init_vcpu(cs); @@ -1094,6 +1136,9 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false), DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false), + + DEFINE_PROP_STRING("satp-mode", RISCVCPU, cfg.satp_mode_str), + DEFINE_PROP_END_OF_LIST(), }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 3a9e25053f..a6c229470b 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -480,6 +480,9 @@ struct RISCVCPUConfig { bool debug; bool short_isa_string; + + uint8_t satp_mode; + char *satp_mode_str; }; typedef struct RISCVCPUConfig RISCVCPUConfig; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 5c9a7ee287..d26b830f1a 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1109,10 +1109,12 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, static int validate_vm(CPURISCVState *env, target_ulong vm) { + vm &= 0xf; + if (riscv_cpu_mxl(env) == MXL_RV32) { - return valid_vm_1_10_32[vm & 0xf]; + return valid_vm_1_10_32[vm] && (vm <= RISCV_CPU(env_cpu(env))->cfg.satp_mode); } else { - return valid_vm_1_10_64[vm & 0xf]; + return valid_vm_1_10_64[vm] && (vm <= RISCV_CPU(env_cpu(env))->cfg.satp_mode); } }