[PATCH] target/riscv: add satp mode for kvm host cpu

Meng Zhuo posted 1 patch 6 months, 3 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20250427132557.1589276-1-mengzhuo@iscas.ac.cn
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
target/riscv/kvm/kvm-cpu.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
[PATCH] target/riscv: add satp mode for kvm host cpu
Posted by Meng Zhuo 6 months, 3 weeks ago
This patch adds host satp mode while kvm/host cpu satp mode is not
set.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2931
Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
---
 target/riscv/kvm/kvm-cpu.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 5315134e08..942f942b25 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -953,6 +953,21 @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
     close(scratch->kvmfd);
 }
 
+static void kvm_riscv_init_satp_mode(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
+{
+    CPURISCVState *env = &cpu->env;
+    struct kvm_one_reg reg;
+    int ret;
+    uint64_t val;
+    reg.id = RISCV_CONFIG_REG(env, satp_mode);
+    reg.addr = (uint64_t)&val;
+    ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
+    if (ret != 0) {
+        error_report("Unable to retrieve satp from host, error %d", ret);
+    }
+    env->satp = 1 << val;
+}
+
 static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
 {
     CPURISCVState *env = &cpu->env;
@@ -1212,6 +1227,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj)
     kvm_riscv_init_machine_ids(cpu, &kvmcpu);
     kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
     kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
+    kvm_riscv_init_satp_mode(cpu, &kvmcpu);
 
     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
 }
@@ -1891,7 +1907,16 @@ static bool kvm_cpu_realize(CPUState *cs, Error **errp)
         }
     }
 
-   return true;
+    RISCVSATPMap *satp_mode = &cpu->cfg.satp_mode;
+    CPURISCVState *env = &cpu->env;
+
+    if (!satp_mode->init && env->satp) {
+        satp_mode->init = env->satp;
+        satp_mode->map = env->satp;
+        satp_mode->supported = env->satp;
+    }
+
+    return true;
 }
 
 void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
-- 
2.39.5
Re: [PATCH] target/riscv: add satp mode for kvm host cpu
Posted by Andrew Jones 6 months, 3 weeks ago
On Sun, Apr 27, 2025 at 09:25:57PM +0800, Meng Zhuo wrote:
> This patch adds host satp mode while kvm/host cpu satp mode is not
> set.

Huh, the KVM side[1] was written for this purpose, but it appears we never
got a QEMU side merged.

[1] commit 2776421e6839 ("RISC-V: KVM: provide UAPI for host SATP mode")

> 
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2931
> Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
> ---
>  target/riscv/kvm/kvm-cpu.c | 27 ++++++++++++++++++++++++++-
>  1 file changed, 26 insertions(+), 1 deletion(-)
> 
> diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
> index 5315134e08..942f942b25 100644
> --- a/target/riscv/kvm/kvm-cpu.c
> +++ b/target/riscv/kvm/kvm-cpu.c
> @@ -953,6 +953,21 @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
>      close(scratch->kvmfd);
>  }
>  
> +static void kvm_riscv_init_satp_mode(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
> +{
> +    CPURISCVState *env = &cpu->env;
> +    struct kvm_one_reg reg;
> +    int ret;
> +    uint64_t val;

Please add a blank line here.

> +    reg.id = RISCV_CONFIG_REG(env, satp_mode);
> +    reg.addr = (uint64_t)&val;
> +    ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
> +    if (ret != 0) {
> +        error_report("Unable to retrieve satp from host, error %d", ret);
> +    }
> +    env->satp = 1 << val;

We need to expose set_satp_mode_max_supported() and then call it here
instead of setting env->satp. At this phase we're just figuring out what's
supported by KVM. riscv_cpu_finalize_features() will then sort out what's
supported by KVM and what's selected by the user (if anything) in order
to determine what mode should be used.

> +}
> +
>  static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
>  {
>      CPURISCVState *env = &cpu->env;
> @@ -1212,6 +1227,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj)
>      kvm_riscv_init_machine_ids(cpu, &kvmcpu);
>      kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
>      kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
> +    kvm_riscv_init_satp_mode(cpu, &kvmcpu);
>  
>      kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
>  }
> @@ -1891,7 +1907,16 @@ static bool kvm_cpu_realize(CPUState *cs, Error **errp)
>          }
>      }
>  
> -   return true;
> +    RISCVSATPMap *satp_mode = &cpu->cfg.satp_mode;
> +    CPURISCVState *env = &cpu->env;
> +
> +    if (!satp_mode->init && env->satp) {
> +        satp_mode->init = env->satp;
> +        satp_mode->map = env->satp;
> +        satp_mode->supported = env->satp;
> +    }
> +
> +    return true;

Other than the indentation fix, none of the above hunk is correct or
needed.

Thanks,
drew

>  }
>  
>  void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
> -- 
> 2.39.5
> 
>
Re: [PATCH] target/riscv: add satp mode for kvm host cpu
Posted by Radim Krčmář 6 months, 3 weeks ago
2025-04-28T09:00:55+02:00, Andrew Jones <ajones@ventanamicro.com>:
> On Sun, Apr 27, 2025 at 09:25:57PM +0800, Meng Zhuo wrote:
>> This patch adds host satp mode while kvm/host cpu satp mode is not
>> set.
>
> Huh, the KVM side[1] was written for this purpose, but it appears we never
> got a QEMU side merged.
>
> [1] commit 2776421e6839 ("RISC-V: KVM: provide UAPI for host SATP mode")

KVM satp_mode is the current SATP.mode and I don't think the other
SATP.modes can generally be guessed from the host SATP mode.

Can't QEMU use the host capabilities from cpuinfo or something?

Do we need to return a bitmask from KVM?
(e.g. WARL all modes in vsatp and return what sticks.)

Thanks.
Re: [PATCH] target/riscv: add satp mode for kvm host cpu
Posted by Andrew Jones 6 months, 3 weeks ago
On Mon, Apr 28, 2025 at 11:30:36AM +0200, Radim Krčmář wrote:
> 2025-04-28T09:00:55+02:00, Andrew Jones <ajones@ventanamicro.com>:
> > On Sun, Apr 27, 2025 at 09:25:57PM +0800, Meng Zhuo wrote:
> >> This patch adds host satp mode while kvm/host cpu satp mode is not
> >> set.
> >
> > Huh, the KVM side[1] was written for this purpose, but it appears we never
> > got a QEMU side merged.
> >
> > [1] commit 2776421e6839 ("RISC-V: KVM: provide UAPI for host SATP mode")
> 
> KVM satp_mode is the current SATP.mode and I don't think the other
> SATP.modes can generally be guessed from the host SATP mode.
> 
> Can't QEMU use the host capabilities from cpuinfo or something?
> 
> Do we need to return a bitmask from KVM?
> (e.g. WARL all modes in vsatp and return what sticks.)
>

The widest supported is sufficient because all narrower must also be
supported. Linux should be figuring out the widest and capturing that
at boot time and we should be returing that info for the KVM satp_mode
get-one-reg call.

If the satp_mode we're currently returning isn't the widest possible,
then we should fix that in KVM.

Thanks,
drew

Re: [PATCH] target/riscv: add satp mode for kvm host cpu
Posted by Radim Krčmář 6 months, 3 weeks ago
2025-04-28T14:08:59+02:00, Andrew Jones <ajones@ventanamicro.com>:
> On Mon, Apr 28, 2025 at 11:30:36AM +0200, Radim Krčmář wrote:
>> 2025-04-28T09:00:55+02:00, Andrew Jones <ajones@ventanamicro.com>:
>> > On Sun, Apr 27, 2025 at 09:25:57PM +0800, Meng Zhuo wrote:
>> >> This patch adds host satp mode while kvm/host cpu satp mode is not
>> >> set.
>> >
>> > Huh, the KVM side[1] was written for this purpose, but it appears we never
>> > got a QEMU side merged.
>> >
>> > [1] commit 2776421e6839 ("RISC-V: KVM: provide UAPI for host SATP mode")
>> 
>> KVM satp_mode is the current SATP.mode and I don't think the other
>> SATP.modes can generally be guessed from the host SATP mode.
>> 
>> Can't QEMU use the host capabilities from cpuinfo or something?
>> 
>> Do we need to return a bitmask from KVM?
>> (e.g. WARL all modes in vsatp and return what sticks.)
>>
>
> The widest supported is sufficient because all narrower must also be
> supported. Linux should be figuring out the widest and capturing that
> at boot time and we should be returing that info for the KVM satp_mode
> get-one-reg call.

Linux has command line overrides for the mode (no4lvl and no5vlv), so
the active mode in Linux might not be the widest supported by the cpu.

Let's say Linux decides to use 9 on a host cpu that has 0,8,9,10.
set_satp_mode_max_supported() will set supported vcpu modes to 0,8,9.

Should "-cpu host" contain the 10?

> If the satp_mode we're currently returning isn't the widest possible,
> then we should fix that in KVM.

The numbers are even more complicated... Pasting the values from manual:

  0      Bare
  1-7    Reserved for standard use
  8      Sv39
  9      Sv48
  10     Sv57
  11     Reserved for Sv64
  12-13  Reserved for standard use
  14-15  Designated for custom use

The reserved values make this extra juicy, let's say Linux uses 14 on
machine that has 0,8,9,14.  QEMU sees 14 and sets the vcpu modes to
0,8,9,10 -- it's not even a subset of the host CPU.
(There might be similar problems even with future standard extensions.)
Re: [PATCH] target/riscv: add satp mode for kvm host cpu
Posted by Andrew Jones 6 months, 3 weeks ago
On Mon, Apr 28, 2025 at 03:37:26PM +0200, Radim Krčmář wrote:
> 2025-04-28T14:08:59+02:00, Andrew Jones <ajones@ventanamicro.com>:
> > On Mon, Apr 28, 2025 at 11:30:36AM +0200, Radim Krčmář wrote:
> >> 2025-04-28T09:00:55+02:00, Andrew Jones <ajones@ventanamicro.com>:
> >> > On Sun, Apr 27, 2025 at 09:25:57PM +0800, Meng Zhuo wrote:
> >> >> This patch adds host satp mode while kvm/host cpu satp mode is not
> >> >> set.
> >> >
> >> > Huh, the KVM side[1] was written for this purpose, but it appears we never
> >> > got a QEMU side merged.
> >> >
> >> > [1] commit 2776421e6839 ("RISC-V: KVM: provide UAPI for host SATP mode")
> >> 
> >> KVM satp_mode is the current SATP.mode and I don't think the other
> >> SATP.modes can generally be guessed from the host SATP mode.
> >> 
> >> Can't QEMU use the host capabilities from cpuinfo or something?
> >> 
> >> Do we need to return a bitmask from KVM?
> >> (e.g. WARL all modes in vsatp and return what sticks.)
> >>
> >
> > The widest supported is sufficient because all narrower must also be
> > supported. Linux should be figuring out the widest and capturing that
> > at boot time and we should be returing that info for the KVM satp_mode
> > get-one-reg call.
> 
> Linux has command line overrides for the mode (no4lvl and no5vlv), so
> the active mode in Linux might not be the widest supported by the cpu.
> 
> Let's say Linux decides to use 9 on a host cpu that has 0,8,9,10.
> set_satp_mode_max_supported() will set supported vcpu modes to 0,8,9.
> 
> Should "-cpu host" contain the 10?

If the architecture allows it and the host kernel/KVM is aware of it. If,
OTOH, the boot options / hardware description has hidden the platform's
capabilities from KVM, then it won't know 10 is supported, so it won't
tell the vmm it is and the vmm shouldn't second guess that.

> 
> > If the satp_mode we're currently returning isn't the widest possible,
> > then we should fix that in KVM.
> 
> The numbers are even more complicated... Pasting the values from manual:
> 
>   0      Bare
>   1-7    Reserved for standard use
>   8      Sv39
>   9      Sv48
>   10     Sv57
>   11     Reserved for Sv64
>   12-13  Reserved for standard use
>   14-15  Designated for custom use
> 
> The reserved values make this extra juicy, let's say Linux uses 14 on
> machine that has 0,8,9,14.  QEMU sees 14 and sets the vcpu modes to
> 0,8,9,10 -- it's not even a subset of the host CPU.
> (There might be similar problems even with future standard extensions.)

Currently QEMU won't recognize anything higher than 10 and it knows how
to skip 1-7. If we need to add more standard support (or custom support)
we'll have to modify set_satp_mode_max_supported(). But let's burn that
bridge later. We should probably sanity check the input to that function
with something like the (untested) diff below, though.

Thanks,
drew

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 09ded6829a2c..a9088c7b1770 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -435,10 +435,18 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
 }
 
 static void set_satp_mode_max_supported(RISCVCPU *cpu,
-                                        uint8_t satp_mode)
+                                        uint8_t satp_mode,
+                                        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;
+    int satp_max = rv32 ? VM_1_10_SV32 : VM_1_10_MAX;
+
+    if (satp_mode > satp_max) {
+        error_setg(errp, "satp_mode %s is higher than the supported max %s",
+                   satp_mode_str(satp_max, rv32),
+                   satp_mode_str(satp_max, rv32));
+    }
 
     for (int i = 0; i <= satp_mode; ++i) {
         if (valid_vm[i]) {
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index a30317c61781..46d206abba97 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -662,6 +662,7 @@ typedef enum {
 #define VM_1_10_SV48        9
 #define VM_1_10_SV57        10
 #define VM_1_10_SV64        11
+#define VM_1_10_MAX         VM_1_10_SV64
 
 /* Page table entry (PTE) fields */
 #define PTE_V               0x001 /* Valid */