diff mbox series

[v6,5/5] riscv: Introduce satp mode hw capabilities

Message ID 20230123090324.732681-6-alexghiti@rivosinc.com (mailing list archive)
State New, archived
Headers show
Series riscv: Allow user to set the satp mode | expand

Commit Message

Alexandre Ghiti Jan. 23, 2023, 9:03 a.m. UTC
Currently, the max satp mode is set with the only constraint that it must be
implemented in qemu, i.e. set in valid_vm_1_10_[32|64].

But we actually need to add another level of constraint: what the hw is
actually capable of, because currently, a linux booting on a sifive-u54
boots in sv57 mode which is incompatible with the cpu's sv39 max
capability.

So add a new bitmap to RISCVSATPMap which contains this capability and
initialize it in every XXX_cpu_init.

Finally, we have the following chain of constraints:

Qemu capability > HW capability > User choice > Software capability

Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
---
 target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
 target/riscv/cpu.h |  8 +++--
 2 files changed, 59 insertions(+), 27 deletions(-)

Comments

Andrew Jones Jan. 23, 2023, 10:51 a.m. UTC | #1
On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> Currently, the max satp mode is set with the only constraint that it must be
> implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> 
> But we actually need to add another level of constraint: what the hw is
> actually capable of, because currently, a linux booting on a sifive-u54
> boots in sv57 mode which is incompatible with the cpu's sv39 max
> capability.
> 
> So add a new bitmap to RISCVSATPMap which contains this capability and
> initialize it in every XXX_cpu_init.
> 
> Finally, we have the following chain of constraints:
> 
> Qemu capability > HW capability > User choice > Software capability

                                                  ^ What software is this?
                         I'd think the user's choice would always be last.

> 
> Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> ---
>  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
>  target/riscv/cpu.h |  8 +++--
>  2 files changed, 59 insertions(+), 27 deletions(-)
> 
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index e409e6ab64..19a37fee2b 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
>      g_assert_not_reached();
>  }
>  
> -/* Sets the satp mode to the max supported */
> -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> +                                        const char *satp_mode_str,
> +                                        bool is_32_bit)
>  {
> -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> -        cpu->cfg.satp_mode.map |=
> -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> -    } else {
> -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> +
> +    for (int i = 0; i <= satp_mode; ++i) {
> +        if (valid_vm[i]) {
> +            cpu->cfg.satp_mode.supported |= (1 << i);

I don't think we need a new 'supported' bitmap, I think each board that
needs to further constrain va-bits from what QEMU supports should just set
valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init
function something like

 #define QEMU_SATP_MODE_MAX VM_1_10_SV64

 void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max)
 {
     bool is_32_bit = cpu->env.misa_mxl == MXL_RV32;
     bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;

     g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX);
     g_assert(!is_32_bit || satp_mode_max < 2);

     memset(valid_vm, 0, sizeof(*valid_vm));

     for (int i = 0; i <= satp_mode_max; i++) {
         valid_vm[i] = true;
     }
 }

The valid_vm[] checks already in finalize should then manage the
validation needed to constrain boards. Only boards that care about
this need to call this function, otherwise they'll get the default.

Also, this patch should come before the patch that changes the default
for all boards to sv57 in order to avoid breaking bisection.

Thanks,
drew
Alexandre Ghiti Jan. 23, 2023, 11:15 a.m. UTC | #2
On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones <ajones@ventanamicro.com> wrote:
>
> On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> > Currently, the max satp mode is set with the only constraint that it must be
> > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> >
> > But we actually need to add another level of constraint: what the hw is
> > actually capable of, because currently, a linux booting on a sifive-u54
> > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > capability.
> >
> > So add a new bitmap to RISCVSATPMap which contains this capability and
> > initialize it in every XXX_cpu_init.
> >
> > Finally, we have the following chain of constraints:
> >
> > Qemu capability > HW capability > User choice > Software capability
>
>                                                   ^ What software is this?
>                          I'd think the user's choice would always be last.
>
> >
> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > ---
> >  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
> >  target/riscv/cpu.h |  8 +++--
> >  2 files changed, 59 insertions(+), 27 deletions(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index e409e6ab64..19a37fee2b 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
> >      g_assert_not_reached();
> >  }
> >
> > -/* Sets the satp mode to the max supported */
> > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> > +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> > +                                        const char *satp_mode_str,
> > +                                        bool is_32_bit)
> >  {
> > -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> > -        cpu->cfg.satp_mode.map |=
> > -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> > -    } else {
> > -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> > +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> > +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > +
> > +    for (int i = 0; i <= satp_mode; ++i) {
> > +        if (valid_vm[i]) {
> > +            cpu->cfg.satp_mode.supported |= (1 << i);
>
> I don't think we need a new 'supported' bitmap, I think each board that
> needs to further constrain va-bits from what QEMU supports should just set
> valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init
> function something like

This was my first idea too, but those arrays are global and I have to
admit that I thought it was possible to emulate a cpu with different
cores. Anyway, isn't it a bit weird to store this into some global
array whereas it is intimately linked to the CPU? To me, it makes
sense to keep those variables as a way to know what qemu is able to
emulate and have a CPU specific map like in this patch for the hw
capabilities. Does it make sense to you?

>
>  #define QEMU_SATP_MODE_MAX VM_1_10_SV64
>
>  void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max)
>  {
>      bool is_32_bit = cpu->env.misa_mxl == MXL_RV32;
>      bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
>
>      g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX);
>      g_assert(!is_32_bit || satp_mode_max < 2);
>
>      memset(valid_vm, 0, sizeof(*valid_vm));
>
>      for (int i = 0; i <= satp_mode_max; i++) {
>          valid_vm[i] = true;
>      }
>  }
>
> The valid_vm[] checks already in finalize should then manage the
> validation needed to constrain boards. Only boards that care about
> this need to call this function, otherwise they'll get the default.
>
> Also, this patch should come before the patch that changes the default
> for all boards to sv57 in order to avoid breaking bisection.

As I explained earlier, I didn't change the default to sv57! Just
fixed what was passed via the device tree, which should not be used
anyway :)

Alex

>
> Thanks,
> drew
Andrew Jones Jan. 23, 2023, 1:31 p.m. UTC | #3
On Mon, Jan 23, 2023 at 12:15:08PM +0100, Alexandre Ghiti wrote:
> On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones <ajones@ventanamicro.com> wrote:
> >
> > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> > > Currently, the max satp mode is set with the only constraint that it must be
> > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> > >
> > > But we actually need to add another level of constraint: what the hw is
> > > actually capable of, because currently, a linux booting on a sifive-u54
> > > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > > capability.
> > >
> > > So add a new bitmap to RISCVSATPMap which contains this capability and
> > > initialize it in every XXX_cpu_init.
> > >
> > > Finally, we have the following chain of constraints:
> > >
> > > Qemu capability > HW capability > User choice > Software capability
> >
> >                                                   ^ What software is this?
> >                          I'd think the user's choice would always be last.
> >
> > >
> > > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > > ---
> > >  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
> > >  target/riscv/cpu.h |  8 +++--
> > >  2 files changed, 59 insertions(+), 27 deletions(-)
> > >
> > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > index e409e6ab64..19a37fee2b 100644
> > > --- a/target/riscv/cpu.c
> > > +++ b/target/riscv/cpu.c
> > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
> > >      g_assert_not_reached();
> > >  }
> > >
> > > -/* Sets the satp mode to the max supported */
> > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> > > +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> > > +                                        const char *satp_mode_str,
> > > +                                        bool is_32_bit)
> > >  {
> > > -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> > > -        cpu->cfg.satp_mode.map |=
> > > -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> > > -    } else {
> > > -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> > > +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> > > +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > > +
> > > +    for (int i = 0; i <= satp_mode; ++i) {
> > > +        if (valid_vm[i]) {
> > > +            cpu->cfg.satp_mode.supported |= (1 << i);
> >
> > I don't think we need a new 'supported' bitmap, I think each board that
> > needs to further constrain va-bits from what QEMU supports should just set
> > valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init
> > function something like
> 
> This was my first idea too, but those arrays are global and I have to
> admit that I thought it was possible to emulate a cpu with different
> cores. Anyway, isn't it a bit weird to store this into some global
> array whereas it is intimately linked to the CPU? To me, it makes
> sense to keep those variables as a way to know what qemu is able to
> emulate and have a CPU specific map like in this patch for the hw
> capabilities. Does it make sense to you?

Ah, yes, to support heterogeneous configs it's best to keep this
information per-cpu. I'll take another look at the patch.

> 
> >
> >  #define QEMU_SATP_MODE_MAX VM_1_10_SV64
> >
> >  void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max)
> >  {
> >      bool is_32_bit = cpu->env.misa_mxl == MXL_RV32;
> >      bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> >
> >      g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX);
> >      g_assert(!is_32_bit || satp_mode_max < 2);
> >
> >      memset(valid_vm, 0, sizeof(*valid_vm));
> >
> >      for (int i = 0; i <= satp_mode_max; i++) {
> >          valid_vm[i] = true;
> >      }
> >  }
> >
> > The valid_vm[] checks already in finalize should then manage the
> > validation needed to constrain boards. Only boards that care about
> > this need to call this function, otherwise they'll get the default.
> >
> > Also, this patch should come before the patch that changes the default
> > for all boards to sv57 in order to avoid breaking bisection.
> 
> As I explained earlier, I didn't change the default to sv57! Just
> fixed what was passed via the device tree, which should not be used
> anyway :)

OK, I keep misunderstanding how we're "fixing" something which is
is wrong, but apparently doesn't exhibit any symptoms. So, assuming
it doesn't matter, then I guess it can come anywhere in the series.

Thanks,
drew
Andrew Jones Jan. 23, 2023, 1:51 p.m. UTC | #4
On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> Currently, the max satp mode is set with the only constraint that it must be
> implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> 
> But we actually need to add another level of constraint: what the hw is
> actually capable of, because currently, a linux booting on a sifive-u54
> boots in sv57 mode which is incompatible with the cpu's sv39 max
> capability.
> 
> So add a new bitmap to RISCVSATPMap which contains this capability and
> initialize it in every XXX_cpu_init.
> 
> Finally, we have the following chain of constraints:
> 
> Qemu capability > HW capability > User choice > Software capability
> 
> Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> ---
>  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
>  target/riscv/cpu.h |  8 +++--
>  2 files changed, 59 insertions(+), 27 deletions(-)
> 
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index e409e6ab64..19a37fee2b 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
>      g_assert_not_reached();
>  }
>  
> -/* Sets the satp mode to the max supported */
> -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> +                                        const char *satp_mode_str,
> +                                        bool is_32_bit)

I'd drop 'is_32_bit' and get it from 'cpu', which would "clean up" all the
callsites by getting rid of all the true/false stuff. Also, why take the
string instead of the VM_1_10_SV* define?

>  {
> -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> -        cpu->cfg.satp_mode.map |=
> -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> -    } else {
> -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> +
> +    for (int i = 0; i <= satp_mode; ++i) {
> +        if (valid_vm[i]) {
> +            cpu->cfg.satp_mode.supported |= (1 << i);
> +        }
>      }
>  }
>  
> +/* Sets the satp mode to the max supported */
> +static void set_satp_mode_default(RISCVCPU *cpu)
> +{
> +    uint8_t satp_mode = satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
> +
> +    cpu->cfg.satp_mode.map |= (1 << satp_mode);

Let's do 'cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported' to make
sure 'map' has all supported bits set for property probing.

> +}
> +
>  static void riscv_any_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>  #if defined(TARGET_RISCV32)
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> +    set_satp_mode_max_supported(cpu, "sv32", true);
>  #elif defined(TARGET_RISCV64)
>      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> +    set_satp_mode_max_supported(cpu, "sv57", false);
>  #endif
>      set_priv_version(env, PRIV_VERSION_1_12_0);
>      register_cpu_props(obj);
> @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj)
>  static void rv64_base_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>      /* We set this in the realise function */
>      set_misa(env, MXL_RV64, 0);
>      register_cpu_props(obj);
>      /* Set latest version of privileged specification */
>      set_priv_version(env, PRIV_VERSION_1_12_0);
> +    set_satp_mode_max_supported(cpu, "sv57", false);
>  }
>  
>  static void rv64_sifive_u_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
> +    set_satp_mode_max_supported(cpu, "sv39", false);
>  }
>  
>  static void rv64_sifive_e_cpu_init(Object *obj)
> @@ -341,6 +362,7 @@ static void rv64_sifive_e_cpu_init(Object *obj)
>      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", false);
>  }
>  
>  static void rv128_base_cpu_init(Object *obj)
> @@ -352,11 +374,13 @@ static void rv128_base_cpu_init(Object *obj)
>          exit(EXIT_FAILURE);
>      }
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
>      /* We set this in the realise function */
>      set_misa(env, MXL_RV128, 0);
>      register_cpu_props(obj);
>      /* Set latest version of privileged specification */
>      set_priv_version(env, PRIV_VERSION_1_12_0);
> +    set_satp_mode_max_supported(cpu, "sv57", false);
>  }
>  #else
>  static void rv32_base_cpu_init(Object *obj)
> @@ -367,13 +391,17 @@ static void rv32_base_cpu_init(Object *obj)
>      register_cpu_props(obj);
>      /* Set latest version of privileged specification */
>      set_priv_version(env, PRIV_VERSION_1_12_0);
> +    set_satp_mode_max_supported(cpu, "sv32", true);
>  }
>  
>  static void rv32_sifive_u_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
> +    set_satp_mode_max_supported(cpu, "sv32", true);
>  }
>  
>  static void rv32_sifive_e_cpu_init(Object *obj)
> @@ -384,6 +412,7 @@ static void rv32_sifive_e_cpu_init(Object *obj)
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", true);
>  }
>  
>  static void rv32_ibex_cpu_init(Object *obj)
> @@ -394,6 +423,7 @@ static void rv32_ibex_cpu_init(Object *obj)
>      set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_11_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", true);
>      cpu->cfg.epmp = true;
>  }
>  
> @@ -405,6 +435,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", true);
>  }
>  #endif
>  
> @@ -696,7 +727,9 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
>  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>  {
>      bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
> -    const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
> +    uint8_t satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> +    uint8_t satp_mode_supported_max =
> +                        satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
>  
>      if (cpu->cfg.satp_mode.map == 0) {
>          /*
> @@ -704,7 +737,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>           * satp mode.
>           */
>          if (cpu->cfg.satp_mode.init == 0) {
> -            set_satp_mode_default(cpu, rv32);
> +            set_satp_mode_default(cpu);
>          } else {
>              /*
>               * Find the lowest level that was disabled and then enable the
> @@ -714,9 +747,9 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>              for (int i = 1; i < 16; ++i) {
>                  if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
>                      (cpu->cfg.satp_mode.init & (1 << i)) &&
> -                    valid_vm[i]) {
> +                    (cpu->cfg.satp_mode.supported & (1 << i))) {
>                      for (int j = i - 1; j >= 0; --j) {
> -                        if (valid_vm[j]) {
> +                        if (cpu->cfg.satp_mode.supported & (1 << j)) {
>                              cpu->cfg.satp_mode.map |= (1 << j);
>                              break;
>                          }
> @@ -727,13 +760,12 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>          }
>      }
>  
> -    /* Make sure the configuration asked is supported by qemu */
> -    for (int i = 0; i < 16; ++i) {
> -        if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) {
> -            error_setg(errp, "satp_mode %s is not valid",
> -                       satp_mode_str(i, rv32));
> -            return;
> -        }
> +    /* Make sure the user asked for a supported configuration (HW and qemu) */
> +    if (satp_mode_map_max > satp_mode_supported_max) {
> +        error_setg(errp, "satp_mode %s is higher than hw max capability %s",
> +                   satp_mode_str(satp_mode_map_max, rv32),
> +                   satp_mode_str(satp_mode_supported_max, rv32));
> +        return;
>      }
>  
>      /*
> @@ -741,17 +773,13 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>       * the specification.
>       */
>      if (!rv32) {
> -        uint8_t satp_mode_max;
> -
> -        satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> -
> -        for (int i = satp_mode_max - 1; i >= 0; --i) {
> +        for (int i = satp_mode_map_max - 1; i >= 0; --i) {
>              if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
>                  (cpu->cfg.satp_mode.init & (1 << i)) &&
> -                valid_vm[i]) {
> +                (cpu->cfg.satp_mode.supported & (1 << i))) {
>                  error_setg(errp, "cannot disable %s satp mode if %s "
>                             "is enabled", satp_mode_str(i, false),
> -                           satp_mode_str(satp_mode_max, false));
> +                           satp_mode_str(satp_mode_map_max, false));
>                  return;
>              }
>          }
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index e37177db5c..b591122099 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -416,13 +416,17 @@ struct RISCVCPUClass {
>  
>  /*
>   * map is a 16-bit bitmap: the most significant set bit in map is the maximum
> - * satp mode that is supported.
> + * satp mode that is supported. It may be chosen by the user and must respect
> + * what qemu implements (valid_1_10_32/64) and what the hw is capable of
> + * (supported bitmap below).
>   *
>   * init is a 16-bit bitmap used to make sure the user selected a correct
>   * configuration as per the specification.
> + *
> + * supported is a 16-bit bitmap used to reflect the hw capabilities.
>   */
>  typedef struct {
> -    uint16_t map, init;
> +    uint16_t map, init, supported;
>  } RISCVSATPMap;
>  
>  struct RISCVCPUConfig {
> -- 
> 2.37.2
>

Thanks,
drew
Alistair Francis Jan. 24, 2023, 12:41 a.m. UTC | #5
On Mon, Jan 23, 2023 at 7:09 PM Alexandre Ghiti <alexghiti@rivosinc.com> wrote:
>
> Currently, the max satp mode is set with the only constraint that it must be
> implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
>
> But we actually need to add another level of constraint: what the hw is
> actually capable of, because currently, a linux booting on a sifive-u54
> boots in sv57 mode which is incompatible with the cpu's sv39 max
> capability.
>
> So add a new bitmap to RISCVSATPMap which contains this capability and
> initialize it in every XXX_cpu_init.
>
> Finally, we have the following chain of constraints:
>
> Qemu capability > HW capability > User choice > Software capability
>
> Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> ---
>  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
>  target/riscv/cpu.h |  8 +++--
>  2 files changed, 59 insertions(+), 27 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index e409e6ab64..19a37fee2b 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
>      g_assert_not_reached();
>  }
>
> -/* Sets the satp mode to the max supported */
> -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> +                                        const char *satp_mode_str,
> +                                        bool is_32_bit)
>  {
> -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> -        cpu->cfg.satp_mode.map |=
> -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> -    } else {
> -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> +
> +    for (int i = 0; i <= satp_mode; ++i) {
> +        if (valid_vm[i]) {
> +            cpu->cfg.satp_mode.supported |= (1 << i);
> +        }
>      }
>  }
>
> +/* Sets the satp mode to the max supported */
> +static void set_satp_mode_default(RISCVCPU *cpu)
> +{
> +    uint8_t satp_mode = satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
> +
> +    cpu->cfg.satp_mode.map |= (1 << satp_mode);
> +}
> +
>  static void riscv_any_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>  #if defined(TARGET_RISCV32)
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> +    set_satp_mode_max_supported(cpu, "sv32", true);
>  #elif defined(TARGET_RISCV64)
>      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> +    set_satp_mode_max_supported(cpu, "sv57", false);
>  #endif
>      set_priv_version(env, PRIV_VERSION_1_12_0);
>      register_cpu_props(obj);
> @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj)
>  static void rv64_base_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>      /* We set this in the realise function */
>      set_misa(env, MXL_RV64, 0);
>      register_cpu_props(obj);
>      /* Set latest version of privileged specification */
>      set_priv_version(env, PRIV_VERSION_1_12_0);
> +    set_satp_mode_max_supported(cpu, "sv57", false);
>  }
>
>  static void rv64_sifive_u_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
> +    set_satp_mode_max_supported(cpu, "sv39", false);

Can we just not expose the properties on these vendor CPUs and then
not worry about setting maximums?

Alistair

>  }
>
>  static void rv64_sifive_e_cpu_init(Object *obj)
> @@ -341,6 +362,7 @@ static void rv64_sifive_e_cpu_init(Object *obj)
>      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", false);
>  }
>
>  static void rv128_base_cpu_init(Object *obj)
> @@ -352,11 +374,13 @@ static void rv128_base_cpu_init(Object *obj)
>          exit(EXIT_FAILURE);
>      }
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
>      /* We set this in the realise function */
>      set_misa(env, MXL_RV128, 0);
>      register_cpu_props(obj);
>      /* Set latest version of privileged specification */
>      set_priv_version(env, PRIV_VERSION_1_12_0);
> +    set_satp_mode_max_supported(cpu, "sv57", false);
>  }
>  #else
>  static void rv32_base_cpu_init(Object *obj)
> @@ -367,13 +391,17 @@ static void rv32_base_cpu_init(Object *obj)
>      register_cpu_props(obj);
>      /* Set latest version of privileged specification */
>      set_priv_version(env, PRIV_VERSION_1_12_0);
> +    set_satp_mode_max_supported(cpu, "sv32", true);
>  }
>
>  static void rv32_sifive_u_cpu_init(Object *obj)
>  {
>      CPURISCVState *env = &RISCV_CPU(obj)->env;
> +    RISCVCPU *cpu = RISCV_CPU(obj);
> +
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
> +    set_satp_mode_max_supported(cpu, "sv32", true);
>  }
>
>  static void rv32_sifive_e_cpu_init(Object *obj)
> @@ -384,6 +412,7 @@ static void rv32_sifive_e_cpu_init(Object *obj)
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", true);
>  }
>
>  static void rv32_ibex_cpu_init(Object *obj)
> @@ -394,6 +423,7 @@ static void rv32_ibex_cpu_init(Object *obj)
>      set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_11_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", true);
>      cpu->cfg.epmp = true;
>  }
>
> @@ -405,6 +435,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
>      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
>      set_priv_version(env, PRIV_VERSION_1_10_0);
>      cpu->cfg.mmu = false;
> +    set_satp_mode_max_supported(cpu, "mbare", true);
>  }
>  #endif
>
> @@ -696,7 +727,9 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
>  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>  {
>      bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
> -    const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
> +    uint8_t satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> +    uint8_t satp_mode_supported_max =
> +                        satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
>
>      if (cpu->cfg.satp_mode.map == 0) {
>          /*
> @@ -704,7 +737,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>           * satp mode.
>           */
>          if (cpu->cfg.satp_mode.init == 0) {
> -            set_satp_mode_default(cpu, rv32);
> +            set_satp_mode_default(cpu);
>          } else {
>              /*
>               * Find the lowest level that was disabled and then enable the
> @@ -714,9 +747,9 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>              for (int i = 1; i < 16; ++i) {
>                  if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
>                      (cpu->cfg.satp_mode.init & (1 << i)) &&
> -                    valid_vm[i]) {
> +                    (cpu->cfg.satp_mode.supported & (1 << i))) {
>                      for (int j = i - 1; j >= 0; --j) {
> -                        if (valid_vm[j]) {
> +                        if (cpu->cfg.satp_mode.supported & (1 << j)) {
>                              cpu->cfg.satp_mode.map |= (1 << j);
>                              break;
>                          }
> @@ -727,13 +760,12 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>          }
>      }
>
> -    /* Make sure the configuration asked is supported by qemu */
> -    for (int i = 0; i < 16; ++i) {
> -        if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) {
> -            error_setg(errp, "satp_mode %s is not valid",
> -                       satp_mode_str(i, rv32));
> -            return;
> -        }
> +    /* Make sure the user asked for a supported configuration (HW and qemu) */
> +    if (satp_mode_map_max > satp_mode_supported_max) {
> +        error_setg(errp, "satp_mode %s is higher than hw max capability %s",
> +                   satp_mode_str(satp_mode_map_max, rv32),
> +                   satp_mode_str(satp_mode_supported_max, rv32));
> +        return;
>      }
>
>      /*
> @@ -741,17 +773,13 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
>       * the specification.
>       */
>      if (!rv32) {
> -        uint8_t satp_mode_max;
> -
> -        satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> -
> -        for (int i = satp_mode_max - 1; i >= 0; --i) {
> +        for (int i = satp_mode_map_max - 1; i >= 0; --i) {
>              if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
>                  (cpu->cfg.satp_mode.init & (1 << i)) &&
> -                valid_vm[i]) {
> +                (cpu->cfg.satp_mode.supported & (1 << i))) {
>                  error_setg(errp, "cannot disable %s satp mode if %s "
>                             "is enabled", satp_mode_str(i, false),
> -                           satp_mode_str(satp_mode_max, false));
> +                           satp_mode_str(satp_mode_map_max, false));
>                  return;
>              }
>          }
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index e37177db5c..b591122099 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -416,13 +416,17 @@ struct RISCVCPUClass {
>
>  /*
>   * map is a 16-bit bitmap: the most significant set bit in map is the maximum
> - * satp mode that is supported.
> + * satp mode that is supported. It may be chosen by the user and must respect
> + * what qemu implements (valid_1_10_32/64) and what the hw is capable of
> + * (supported bitmap below).
>   *
>   * init is a 16-bit bitmap used to make sure the user selected a correct
>   * configuration as per the specification.
> + *
> + * supported is a 16-bit bitmap used to reflect the hw capabilities.
>   */
>  typedef struct {
> -    uint16_t map, init;
> +    uint16_t map, init, supported;
>  } RISCVSATPMap;
>
>  struct RISCVCPUConfig {
> --
> 2.37.2
>
>
Alexandre Ghiti Jan. 24, 2023, 9:13 a.m. UTC | #6
Hi Alistair,

On Tue, Jan 24, 2023 at 1:41 AM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Mon, Jan 23, 2023 at 7:09 PM Alexandre Ghiti <alexghiti@rivosinc.com> wrote:
> >
> > Currently, the max satp mode is set with the only constraint that it must be
> > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> >
> > But we actually need to add another level of constraint: what the hw is
> > actually capable of, because currently, a linux booting on a sifive-u54
> > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > capability.
> >
> > So add a new bitmap to RISCVSATPMap which contains this capability and
> > initialize it in every XXX_cpu_init.
> >
> > Finally, we have the following chain of constraints:
> >
> > Qemu capability > HW capability > User choice > Software capability
> >
> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > ---
> >  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
> >  target/riscv/cpu.h |  8 +++--
> >  2 files changed, 59 insertions(+), 27 deletions(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index e409e6ab64..19a37fee2b 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
> >      g_assert_not_reached();
> >  }
> >
> > -/* Sets the satp mode to the max supported */
> > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> > +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> > +                                        const char *satp_mode_str,
> > +                                        bool is_32_bit)
> >  {
> > -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> > -        cpu->cfg.satp_mode.map |=
> > -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> > -    } else {
> > -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> > +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> > +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > +
> > +    for (int i = 0; i <= satp_mode; ++i) {
> > +        if (valid_vm[i]) {
> > +            cpu->cfg.satp_mode.supported |= (1 << i);
> > +        }
> >      }
> >  }
> >
> > +/* Sets the satp mode to the max supported */
> > +static void set_satp_mode_default(RISCVCPU *cpu)
> > +{
> > +    uint8_t satp_mode = satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
> > +
> > +    cpu->cfg.satp_mode.map |= (1 << satp_mode);
> > +}
> > +
> >  static void riscv_any_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >  #if defined(TARGET_RISCV32)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> > +    set_satp_mode_max_supported(cpu, "sv32", true);
> >  #elif defined(TARGET_RISCV64)
> >      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> > +    set_satp_mode_max_supported(cpu, "sv57", false);
> >  #endif
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> >      register_cpu_props(obj);
> > @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj)
> >  static void rv64_base_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >      /* We set this in the realise function */
> >      set_misa(env, MXL_RV64, 0);
> >      register_cpu_props(obj);
> >      /* Set latest version of privileged specification */
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> > +    set_satp_mode_max_supported(cpu, "sv57", false);
> >  }
> >
> >  static void rv64_sifive_u_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> > +    set_satp_mode_max_supported(cpu, "sv39", false);
>
> Can we just not expose the properties on these vendor CPUs and then
> not worry about setting maximums?
>

I'm not sure I understand: the properties are actually not exposed to
the vendor cpus from what I see (no calls to register_cpu_props).

The problem this patch fixes is that the only constraint on satp is
valid_vm_1_10_32/64, which reflects the qemu capabilities: as said in
the commit log, a sifive-u54 will allow a kernel to boot in sv57, and
not sv39 as it should.

This patch only takes advantage of the newly introduced RISCVSATPMap
structure to fix this issue, I should maybe emphasize in the commit
description that this is a fix.

Alex

> Alistair
>
> >  }
> >
> >  static void rv64_sifive_e_cpu_init(Object *obj)
> > @@ -341,6 +362,7 @@ static void rv64_sifive_e_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", false);
> >  }
> >
> >  static void rv128_base_cpu_init(Object *obj)
> > @@ -352,11 +374,13 @@ static void rv128_base_cpu_init(Object *obj)
> >          exit(EXIT_FAILURE);
> >      }
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> >      /* We set this in the realise function */
> >      set_misa(env, MXL_RV128, 0);
> >      register_cpu_props(obj);
> >      /* Set latest version of privileged specification */
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> > +    set_satp_mode_max_supported(cpu, "sv57", false);
> >  }
> >  #else
> >  static void rv32_base_cpu_init(Object *obj)
> > @@ -367,13 +391,17 @@ static void rv32_base_cpu_init(Object *obj)
> >      register_cpu_props(obj);
> >      /* Set latest version of privileged specification */
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> > +    set_satp_mode_max_supported(cpu, "sv32", true);
> >  }
> >
> >  static void rv32_sifive_u_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> > +    set_satp_mode_max_supported(cpu, "sv32", true);
> >  }
> >
> >  static void rv32_sifive_e_cpu_init(Object *obj)
> > @@ -384,6 +412,7 @@ static void rv32_sifive_e_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", true);
> >  }
> >
> >  static void rv32_ibex_cpu_init(Object *obj)
> > @@ -394,6 +423,7 @@ static void rv32_ibex_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_11_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", true);
> >      cpu->cfg.epmp = true;
> >  }
> >
> > @@ -405,6 +435,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", true);
> >  }
> >  #endif
> >
> > @@ -696,7 +727,9 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
> >  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >  {
> >      bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
> > -    const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > +    uint8_t satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> > +    uint8_t satp_mode_supported_max =
> > +                        satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
> >
> >      if (cpu->cfg.satp_mode.map == 0) {
> >          /*
> > @@ -704,7 +737,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >           * satp mode.
> >           */
> >          if (cpu->cfg.satp_mode.init == 0) {
> > -            set_satp_mode_default(cpu, rv32);
> > +            set_satp_mode_default(cpu);
> >          } else {
> >              /*
> >               * Find the lowest level that was disabled and then enable the
> > @@ -714,9 +747,9 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >              for (int i = 1; i < 16; ++i) {
> >                  if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
> >                      (cpu->cfg.satp_mode.init & (1 << i)) &&
> > -                    valid_vm[i]) {
> > +                    (cpu->cfg.satp_mode.supported & (1 << i))) {
> >                      for (int j = i - 1; j >= 0; --j) {
> > -                        if (valid_vm[j]) {
> > +                        if (cpu->cfg.satp_mode.supported & (1 << j)) {
> >                              cpu->cfg.satp_mode.map |= (1 << j);
> >                              break;
> >                          }
> > @@ -727,13 +760,12 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >          }
> >      }
> >
> > -    /* Make sure the configuration asked is supported by qemu */
> > -    for (int i = 0; i < 16; ++i) {
> > -        if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) {
> > -            error_setg(errp, "satp_mode %s is not valid",
> > -                       satp_mode_str(i, rv32));
> > -            return;
> > -        }
> > +    /* Make sure the user asked for a supported configuration (HW and qemu) */
> > +    if (satp_mode_map_max > satp_mode_supported_max) {
> > +        error_setg(errp, "satp_mode %s is higher than hw max capability %s",
> > +                   satp_mode_str(satp_mode_map_max, rv32),
> > +                   satp_mode_str(satp_mode_supported_max, rv32));
> > +        return;
> >      }
> >
> >      /*
> > @@ -741,17 +773,13 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >       * the specification.
> >       */
> >      if (!rv32) {
> > -        uint8_t satp_mode_max;
> > -
> > -        satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> > -
> > -        for (int i = satp_mode_max - 1; i >= 0; --i) {
> > +        for (int i = satp_mode_map_max - 1; i >= 0; --i) {
> >              if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
> >                  (cpu->cfg.satp_mode.init & (1 << i)) &&
> > -                valid_vm[i]) {
> > +                (cpu->cfg.satp_mode.supported & (1 << i))) {
> >                  error_setg(errp, "cannot disable %s satp mode if %s "
> >                             "is enabled", satp_mode_str(i, false),
> > -                           satp_mode_str(satp_mode_max, false));
> > +                           satp_mode_str(satp_mode_map_max, false));
> >                  return;
> >              }
> >          }
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index e37177db5c..b591122099 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -416,13 +416,17 @@ struct RISCVCPUClass {
> >
> >  /*
> >   * map is a 16-bit bitmap: the most significant set bit in map is the maximum
> > - * satp mode that is supported.
> > + * satp mode that is supported. It may be chosen by the user and must respect
> > + * what qemu implements (valid_1_10_32/64) and what the hw is capable of
> > + * (supported bitmap below).
> >   *
> >   * init is a 16-bit bitmap used to make sure the user selected a correct
> >   * configuration as per the specification.
> > + *
> > + * supported is a 16-bit bitmap used to reflect the hw capabilities.
> >   */
> >  typedef struct {
> > -    uint16_t map, init;
> > +    uint16_t map, init, supported;
> >  } RISCVSATPMap;
> >
> >  struct RISCVCPUConfig {
> > --
> > 2.37.2
> >
> >
Alexandre Ghiti Jan. 24, 2023, 10:07 a.m. UTC | #7
On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones <ajones@ventanamicro.com> wrote:
>
> On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> > Currently, the max satp mode is set with the only constraint that it must be
> > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> >
> > But we actually need to add another level of constraint: what the hw is
> > actually capable of, because currently, a linux booting on a sifive-u54
> > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > capability.
> >
> > So add a new bitmap to RISCVSATPMap which contains this capability and
> > initialize it in every XXX_cpu_init.
> >
> > Finally, we have the following chain of constraints:
> >
> > Qemu capability > HW capability > User choice > Software capability
>
>                                                   ^ What software is this?
>                          I'd think the user's choice would always be last.

Hmm maybe that's not clear, but I meant that the last constraint was
what the emulated software is capable of handling.

>
> >
> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > ---
> >  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
> >  target/riscv/cpu.h |  8 +++--
> >  2 files changed, 59 insertions(+), 27 deletions(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index e409e6ab64..19a37fee2b 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
> >      g_assert_not_reached();
> >  }
> >
> > -/* Sets the satp mode to the max supported */
> > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> > +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> > +                                        const char *satp_mode_str,
> > +                                        bool is_32_bit)
> >  {
> > -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> > -        cpu->cfg.satp_mode.map |=
> > -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> > -    } else {
> > -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> > +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> > +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > +
> > +    for (int i = 0; i <= satp_mode; ++i) {
> > +        if (valid_vm[i]) {
> > +            cpu->cfg.satp_mode.supported |= (1 << i);
>
> I don't think we need a new 'supported' bitmap, I think each board that
> needs to further constrain va-bits from what QEMU supports should just set
> valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init
> function something like
>
>  #define QEMU_SATP_MODE_MAX VM_1_10_SV64
>
>  void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max)
>  {
>      bool is_32_bit = cpu->env.misa_mxl == MXL_RV32;
>      bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
>
>      g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX);
>      g_assert(!is_32_bit || satp_mode_max < 2);
>
>      memset(valid_vm, 0, sizeof(*valid_vm));
>
>      for (int i = 0; i <= satp_mode_max; i++) {
>          valid_vm[i] = true;
>      }
>  }
>
> The valid_vm[] checks already in finalize should then manage the
> validation needed to constrain boards. Only boards that care about
> this need to call this function, otherwise they'll get the default.
>
> Also, this patch should come before the patch that changes the default
> for all boards to sv57 in order to avoid breaking bisection.
>
> Thanks,
> drew
Alexandre Ghiti Jan. 24, 2023, 1:13 p.m. UTC | #8
On Mon, Jan 23, 2023 at 2:31 PM Andrew Jones <ajones@ventanamicro.com> wrote:
>
> On Mon, Jan 23, 2023 at 12:15:08PM +0100, Alexandre Ghiti wrote:
> > On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones <ajones@ventanamicro.com> wrote:
> > >
> > > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> > > > Currently, the max satp mode is set with the only constraint that it must be
> > > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> > > >
> > > > But we actually need to add another level of constraint: what the hw is
> > > > actually capable of, because currently, a linux booting on a sifive-u54
> > > > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > > > capability.
> > > >
> > > > So add a new bitmap to RISCVSATPMap which contains this capability and
> > > > initialize it in every XXX_cpu_init.
> > > >
> > > > Finally, we have the following chain of constraints:
> > > >
> > > > Qemu capability > HW capability > User choice > Software capability
> > >
> > >                                                   ^ What software is this?
> > >                          I'd think the user's choice would always be last.
> > >
> > > >
> > > > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > > > ---
> > > >  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
> > > >  target/riscv/cpu.h |  8 +++--
> > > >  2 files changed, 59 insertions(+), 27 deletions(-)
> > > >
> > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > index e409e6ab64..19a37fee2b 100644
> > > > --- a/target/riscv/cpu.c
> > > > +++ b/target/riscv/cpu.c
> > > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
> > > >      g_assert_not_reached();
> > > >  }
> > > >
> > > > -/* Sets the satp mode to the max supported */
> > > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> > > > +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> > > > +                                        const char *satp_mode_str,
> > > > +                                        bool is_32_bit)
> > > >  {
> > > > -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> > > > -        cpu->cfg.satp_mode.map |=
> > > > -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> > > > -    } else {
> > > > -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> > > > +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> > > > +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > > > +
> > > > +    for (int i = 0; i <= satp_mode; ++i) {
> > > > +        if (valid_vm[i]) {
> > > > +            cpu->cfg.satp_mode.supported |= (1 << i);
> > >
> > > I don't think we need a new 'supported' bitmap, I think each board that
> > > needs to further constrain va-bits from what QEMU supports should just set
> > > valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init
> > > function something like
> >
> > This was my first idea too, but those arrays are global and I have to
> > admit that I thought it was possible to emulate a cpu with different
> > cores. Anyway, isn't it a bit weird to store this into some global
> > array whereas it is intimately linked to the CPU? To me, it makes
> > sense to keep those variables as a way to know what qemu is able to
> > emulate and have a CPU specific map like in this patch for the hw
> > capabilities. Does it make sense to you?
>
> Ah, yes, to support heterogeneous configs it's best to keep this
> information per-cpu. I'll take another look at the patch.
>
> >
> > >
> > >  #define QEMU_SATP_MODE_MAX VM_1_10_SV64
> > >
> > >  void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max)
> > >  {
> > >      bool is_32_bit = cpu->env.misa_mxl == MXL_RV32;
> > >      bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > >
> > >      g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX);
> > >      g_assert(!is_32_bit || satp_mode_max < 2);
> > >
> > >      memset(valid_vm, 0, sizeof(*valid_vm));
> > >
> > >      for (int i = 0; i <= satp_mode_max; i++) {
> > >          valid_vm[i] = true;
> > >      }
> > >  }
> > >
> > > The valid_vm[] checks already in finalize should then manage the
> > > validation needed to constrain boards. Only boards that care about
> > > this need to call this function, otherwise they'll get the default.
> > >
> > > Also, this patch should come before the patch that changes the default
> > > for all boards to sv57 in order to avoid breaking bisection.
> >
> > As I explained earlier, I didn't change the default to sv57! Just
> > fixed what was passed via the device tree, which should not be used
> > anyway :)
>
> OK, I keep misunderstanding how we're "fixing" something which is
> is wrong, but apparently doesn't exhibit any symptoms. So, assuming
> it doesn't matter, then I guess it can come anywhere in the series.

Actually *I* think it should not matter, but I can't be sure so I'll
do what you ask.

>
> Thanks,
> drew
Alexandre Ghiti Jan. 24, 2023, 1:24 p.m. UTC | #9
On Mon, Jan 23, 2023 at 2:51 PM Andrew Jones <ajones@ventanamicro.com> wrote:
>
> On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> > Currently, the max satp mode is set with the only constraint that it must be
> > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> >
> > But we actually need to add another level of constraint: what the hw is
> > actually capable of, because currently, a linux booting on a sifive-u54
> > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > capability.
> >
> > So add a new bitmap to RISCVSATPMap which contains this capability and
> > initialize it in every XXX_cpu_init.
> >
> > Finally, we have the following chain of constraints:
> >
> > Qemu capability > HW capability > User choice > Software capability
> >
> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > ---
> >  target/riscv/cpu.c | 78 +++++++++++++++++++++++++++++++---------------
> >  target/riscv/cpu.h |  8 +++--
> >  2 files changed, 59 insertions(+), 27 deletions(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index e409e6ab64..19a37fee2b 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
> >      g_assert_not_reached();
> >  }
> >
> > -/* Sets the satp mode to the max supported */
> > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
> > +static void set_satp_mode_max_supported(RISCVCPU *cpu,
> > +                                        const char *satp_mode_str,
> > +                                        bool is_32_bit)
>
> I'd drop 'is_32_bit' and get it from 'cpu', which would "clean up" all the
> callsites by getting rid of all the true/false stuff.

Indeed, better this way

> Also, why take the string instead of the VM_1_10_SV* define?

No particular reason, but I changed it to VM_1_10_SV*, thanks

>
> >  {
> > -    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
> > -        cpu->cfg.satp_mode.map |=
> > -                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
> > -    } else {
> > -        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
> > +    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
> > +    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > +
> > +    for (int i = 0; i <= satp_mode; ++i) {
> > +        if (valid_vm[i]) {
> > +            cpu->cfg.satp_mode.supported |= (1 << i);
> > +        }
> >      }
> >  }
> >
> > +/* Sets the satp mode to the max supported */
> > +static void set_satp_mode_default(RISCVCPU *cpu)
> > +{
> > +    uint8_t satp_mode = satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
> > +
> > +    cpu->cfg.satp_mode.map |= (1 << satp_mode);
>
> Let's do 'cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported' to make
> sure 'map' has all supported bits set for property probing.

Indeed now the map is fully set.

>
> > +}
> > +
> >  static void riscv_any_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >  #if defined(TARGET_RISCV32)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> > +    set_satp_mode_max_supported(cpu, "sv32", true);
> >  #elif defined(TARGET_RISCV64)
> >      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
> > +    set_satp_mode_max_supported(cpu, "sv57", false);
> >  #endif
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> >      register_cpu_props(obj);
> > @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj)
> >  static void rv64_base_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >      /* We set this in the realise function */
> >      set_misa(env, MXL_RV64, 0);
> >      register_cpu_props(obj);
> >      /* Set latest version of privileged specification */
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> > +    set_satp_mode_max_supported(cpu, "sv57", false);
> >  }
> >
> >  static void rv64_sifive_u_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> > +    set_satp_mode_max_supported(cpu, "sv39", false);
> >  }
> >
> >  static void rv64_sifive_e_cpu_init(Object *obj)
> > @@ -341,6 +362,7 @@ static void rv64_sifive_e_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", false);
> >  }
> >
> >  static void rv128_base_cpu_init(Object *obj)
> > @@ -352,11 +374,13 @@ static void rv128_base_cpu_init(Object *obj)
> >          exit(EXIT_FAILURE);
> >      }
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> >      /* We set this in the realise function */
> >      set_misa(env, MXL_RV128, 0);
> >      register_cpu_props(obj);
> >      /* Set latest version of privileged specification */
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> > +    set_satp_mode_max_supported(cpu, "sv57", false);
> >  }
> >  #else
> >  static void rv32_base_cpu_init(Object *obj)
> > @@ -367,13 +391,17 @@ static void rv32_base_cpu_init(Object *obj)
> >      register_cpu_props(obj);
> >      /* Set latest version of privileged specification */
> >      set_priv_version(env, PRIV_VERSION_1_12_0);
> > +    set_satp_mode_max_supported(cpu, "sv32", true);
> >  }
> >
> >  static void rv32_sifive_u_cpu_init(Object *obj)
> >  {
> >      CPURISCVState *env = &RISCV_CPU(obj)->env;
> > +    RISCVCPU *cpu = RISCV_CPU(obj);
> > +
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> > +    set_satp_mode_max_supported(cpu, "sv32", true);
> >  }
> >
> >  static void rv32_sifive_e_cpu_init(Object *obj)
> > @@ -384,6 +412,7 @@ static void rv32_sifive_e_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", true);
> >  }
> >
> >  static void rv32_ibex_cpu_init(Object *obj)
> > @@ -394,6 +423,7 @@ static void rv32_ibex_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_11_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", true);
> >      cpu->cfg.epmp = true;
> >  }
> >
> > @@ -405,6 +435,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
> >      set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
> >      set_priv_version(env, PRIV_VERSION_1_10_0);
> >      cpu->cfg.mmu = false;
> > +    set_satp_mode_max_supported(cpu, "mbare", true);
> >  }
> >  #endif
> >
> > @@ -696,7 +727,9 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
> >  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >  {
> >      bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
> > -    const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
> > +    uint8_t satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> > +    uint8_t satp_mode_supported_max =
> > +                        satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
> >
> >      if (cpu->cfg.satp_mode.map == 0) {
> >          /*
> > @@ -704,7 +737,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >           * satp mode.
> >           */
> >          if (cpu->cfg.satp_mode.init == 0) {
> > -            set_satp_mode_default(cpu, rv32);
> > +            set_satp_mode_default(cpu);
> >          } else {
> >              /*
> >               * Find the lowest level that was disabled and then enable the
> > @@ -714,9 +747,9 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >              for (int i = 1; i < 16; ++i) {
> >                  if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
> >                      (cpu->cfg.satp_mode.init & (1 << i)) &&
> > -                    valid_vm[i]) {
> > +                    (cpu->cfg.satp_mode.supported & (1 << i))) {
> >                      for (int j = i - 1; j >= 0; --j) {
> > -                        if (valid_vm[j]) {
> > +                        if (cpu->cfg.satp_mode.supported & (1 << j)) {
> >                              cpu->cfg.satp_mode.map |= (1 << j);
> >                              break;
> >                          }
> > @@ -727,13 +760,12 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >          }
> >      }
> >
> > -    /* Make sure the configuration asked is supported by qemu */
> > -    for (int i = 0; i < 16; ++i) {
> > -        if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) {
> > -            error_setg(errp, "satp_mode %s is not valid",
> > -                       satp_mode_str(i, rv32));
> > -            return;
> > -        }
> > +    /* Make sure the user asked for a supported configuration (HW and qemu) */
> > +    if (satp_mode_map_max > satp_mode_supported_max) {
> > +        error_setg(errp, "satp_mode %s is higher than hw max capability %s",
> > +                   satp_mode_str(satp_mode_map_max, rv32),
> > +                   satp_mode_str(satp_mode_supported_max, rv32));
> > +        return;
> >      }
> >
> >      /*
> > @@ -741,17 +773,13 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> >       * the specification.
> >       */
> >      if (!rv32) {
> > -        uint8_t satp_mode_max;
> > -
> > -        satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
> > -
> > -        for (int i = satp_mode_max - 1; i >= 0; --i) {
> > +        for (int i = satp_mode_map_max - 1; i >= 0; --i) {
> >              if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
> >                  (cpu->cfg.satp_mode.init & (1 << i)) &&
> > -                valid_vm[i]) {
> > +                (cpu->cfg.satp_mode.supported & (1 << i))) {
> >                  error_setg(errp, "cannot disable %s satp mode if %s "
> >                             "is enabled", satp_mode_str(i, false),
> > -                           satp_mode_str(satp_mode_max, false));
> > +                           satp_mode_str(satp_mode_map_max, false));
> >                  return;
> >              }
> >          }
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index e37177db5c..b591122099 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -416,13 +416,17 @@ struct RISCVCPUClass {
> >
> >  /*
> >   * map is a 16-bit bitmap: the most significant set bit in map is the maximum
> > - * satp mode that is supported.
> > + * satp mode that is supported. It may be chosen by the user and must respect
> > + * what qemu implements (valid_1_10_32/64) and what the hw is capable of
> > + * (supported bitmap below).
> >   *
> >   * init is a 16-bit bitmap used to make sure the user selected a correct
> >   * configuration as per the specification.
> > + *
> > + * supported is a 16-bit bitmap used to reflect the hw capabilities.
> >   */
> >  typedef struct {
> > -    uint16_t map, init;
> > +    uint16_t map, init, supported;
> >  } RISCVSATPMap;
> >
> >  struct RISCVCPUConfig {
> > --
> > 2.37.2
> >
>
> Thanks,
> drew
Andrew Jones Jan. 24, 2023, 3:31 p.m. UTC | #10
On Tue, Jan 24, 2023 at 11:07:53AM +0100, Alexandre Ghiti wrote:
> On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones <ajones@ventanamicro.com> wrote:
> >
> > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote:
> > > Currently, the max satp mode is set with the only constraint that it must be
> > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64].
> > >
> > > But we actually need to add another level of constraint: what the hw is
> > > actually capable of, because currently, a linux booting on a sifive-u54
> > > boots in sv57 mode which is incompatible with the cpu's sv39 max
> > > capability.
> > >
> > > So add a new bitmap to RISCVSATPMap which contains this capability and
> > > initialize it in every XXX_cpu_init.
> > >
> > > Finally, we have the following chain of constraints:
> > >
> > > Qemu capability > HW capability > User choice > Software capability
> >
> >                                                   ^ What software is this?
> >                          I'd think the user's choice would always be last.
> 
> Hmm maybe that's not clear, but I meant that the last constraint was
> what the emulated software is capable of handling.

Assuming "emulated software" is the guest OS, then OK. How about rewording
as

target/riscv's general satp mode support constrains what the boards
support and the boards constrain what the user may select. The user's
selection will then constrain what's available to the guest OS.

Thanks,
drew
diff mbox series

Patch

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e409e6ab64..19a37fee2b 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -292,24 +292,39 @@  const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
     g_assert_not_reached();
 }
 
-/* Sets the satp mode to the max supported */
-static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit)
+static void set_satp_mode_max_supported(RISCVCPU *cpu,
+                                        const char *satp_mode_str,
+                                        bool is_32_bit)
 {
-    if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
-        cpu->cfg.satp_mode.map |=
-                        (1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57"));
-    } else {
-        cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare"));
+    uint8_t satp_mode = satp_mode_from_str(satp_mode_str);
+    const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64;
+
+    for (int i = 0; i <= satp_mode; ++i) {
+        if (valid_vm[i]) {
+            cpu->cfg.satp_mode.supported |= (1 << i);
+        }
     }
 }
 
+/* Sets the satp mode to the max supported */
+static void set_satp_mode_default(RISCVCPU *cpu)
+{
+    uint8_t satp_mode = satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
+
+    cpu->cfg.satp_mode.map |= (1 << satp_mode);
+}
+
 static void riscv_any_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
+    RISCVCPU *cpu = RISCV_CPU(obj);
+
 #if defined(TARGET_RISCV32)
     set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+    set_satp_mode_max_supported(cpu, "sv32", true);
 #elif defined(TARGET_RISCV64)
     set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+    set_satp_mode_max_supported(cpu, "sv57", false);
 #endif
     set_priv_version(env, PRIV_VERSION_1_12_0);
     register_cpu_props(obj);
@@ -319,18 +334,24 @@  static void riscv_any_cpu_init(Object *obj)
 static void rv64_base_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
+    RISCVCPU *cpu = RISCV_CPU(obj);
+
     /* We set this in the realise function */
     set_misa(env, MXL_RV64, 0);
     register_cpu_props(obj);
     /* Set latest version of privileged specification */
     set_priv_version(env, PRIV_VERSION_1_12_0);
+    set_satp_mode_max_supported(cpu, "sv57", false);
 }
 
 static void rv64_sifive_u_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
+    RISCVCPU *cpu = RISCV_CPU(obj);
+
     set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
+    set_satp_mode_max_supported(cpu, "sv39", false);
 }
 
 static void rv64_sifive_e_cpu_init(Object *obj)
@@ -341,6 +362,7 @@  static void rv64_sifive_e_cpu_init(Object *obj)
     set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     cpu->cfg.mmu = false;
+    set_satp_mode_max_supported(cpu, "mbare", false);
 }
 
 static void rv128_base_cpu_init(Object *obj)
@@ -352,11 +374,13 @@  static void rv128_base_cpu_init(Object *obj)
         exit(EXIT_FAILURE);
     }
     CPURISCVState *env = &RISCV_CPU(obj)->env;
+    RISCVCPU *cpu = RISCV_CPU(obj);
     /* We set this in the realise function */
     set_misa(env, MXL_RV128, 0);
     register_cpu_props(obj);
     /* Set latest version of privileged specification */
     set_priv_version(env, PRIV_VERSION_1_12_0);
+    set_satp_mode_max_supported(cpu, "sv57", false);
 }
 #else
 static void rv32_base_cpu_init(Object *obj)
@@ -367,13 +391,17 @@  static void rv32_base_cpu_init(Object *obj)
     register_cpu_props(obj);
     /* Set latest version of privileged specification */
     set_priv_version(env, PRIV_VERSION_1_12_0);
+    set_satp_mode_max_supported(cpu, "sv32", true);
 }
 
 static void rv32_sifive_u_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
+    RISCVCPU *cpu = RISCV_CPU(obj);
+
     set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
+    set_satp_mode_max_supported(cpu, "sv32", true);
 }
 
 static void rv32_sifive_e_cpu_init(Object *obj)
@@ -384,6 +412,7 @@  static void rv32_sifive_e_cpu_init(Object *obj)
     set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     cpu->cfg.mmu = false;
+    set_satp_mode_max_supported(cpu, "mbare", true);
 }
 
 static void rv32_ibex_cpu_init(Object *obj)
@@ -394,6 +423,7 @@  static void rv32_ibex_cpu_init(Object *obj)
     set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_11_0);
     cpu->cfg.mmu = false;
+    set_satp_mode_max_supported(cpu, "mbare", true);
     cpu->cfg.epmp = true;
 }
 
@@ -405,6 +435,7 @@  static void rv32_imafcu_nommu_cpu_init(Object *obj)
     set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     cpu->cfg.mmu = false;
+    set_satp_mode_max_supported(cpu, "mbare", true);
 }
 #endif
 
@@ -696,7 +727,9 @@  static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
 static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
 {
     bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
-    const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
+    uint8_t satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
+    uint8_t satp_mode_supported_max =
+                        satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
 
     if (cpu->cfg.satp_mode.map == 0) {
         /*
@@ -704,7 +737,7 @@  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
          * satp mode.
          */
         if (cpu->cfg.satp_mode.init == 0) {
-            set_satp_mode_default(cpu, rv32);
+            set_satp_mode_default(cpu);
         } else {
             /*
              * Find the lowest level that was disabled and then enable the
@@ -714,9 +747,9 @@  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
             for (int i = 1; i < 16; ++i) {
                 if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
                     (cpu->cfg.satp_mode.init & (1 << i)) &&
-                    valid_vm[i]) {
+                    (cpu->cfg.satp_mode.supported & (1 << i))) {
                     for (int j = i - 1; j >= 0; --j) {
-                        if (valid_vm[j]) {
+                        if (cpu->cfg.satp_mode.supported & (1 << j)) {
                             cpu->cfg.satp_mode.map |= (1 << j);
                             break;
                         }
@@ -727,13 +760,12 @@  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
         }
     }
 
-    /* Make sure the configuration asked is supported by qemu */
-    for (int i = 0; i < 16; ++i) {
-        if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) {
-            error_setg(errp, "satp_mode %s is not valid",
-                       satp_mode_str(i, rv32));
-            return;
-        }
+    /* Make sure the user asked for a supported configuration (HW and qemu) */
+    if (satp_mode_map_max > satp_mode_supported_max) {
+        error_setg(errp, "satp_mode %s is higher than hw max capability %s",
+                   satp_mode_str(satp_mode_map_max, rv32),
+                   satp_mode_str(satp_mode_supported_max, rv32));
+        return;
     }
 
     /*
@@ -741,17 +773,13 @@  static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
      * the specification.
      */
     if (!rv32) {
-        uint8_t satp_mode_max;
-
-        satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
-
-        for (int i = satp_mode_max - 1; i >= 0; --i) {
+        for (int i = satp_mode_map_max - 1; i >= 0; --i) {
             if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
                 (cpu->cfg.satp_mode.init & (1 << i)) &&
-                valid_vm[i]) {
+                (cpu->cfg.satp_mode.supported & (1 << i))) {
                 error_setg(errp, "cannot disable %s satp mode if %s "
                            "is enabled", satp_mode_str(i, false),
-                           satp_mode_str(satp_mode_max, false));
+                           satp_mode_str(satp_mode_map_max, false));
                 return;
             }
         }
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e37177db5c..b591122099 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -416,13 +416,17 @@  struct RISCVCPUClass {
 
 /*
  * map is a 16-bit bitmap: the most significant set bit in map is the maximum
- * satp mode that is supported.
+ * satp mode that is supported. It may be chosen by the user and must respect
+ * what qemu implements (valid_1_10_32/64) and what the hw is capable of
+ * (supported bitmap below).
  *
  * init is a 16-bit bitmap used to make sure the user selected a correct
  * configuration as per the specification.
+ *
+ * supported is a 16-bit bitmap used to reflect the hw capabilities.
  */
 typedef struct {
-    uint16_t map, init;
+    uint16_t map, init, supported;
 } RISCVSATPMap;
 
 struct RISCVCPUConfig {