On Thu, Apr 17, 2025 at 09:48:37AM -0300, Daniel Henrique Barboza wrote: > [1] reports that commit 4db19d5b21 broke a KVM guest running kernel 6.6. > This happens because the kernel does not know 'senvcfg', making it > unable to boot because QEMU is reading/wriiting it without any checks. > > After converting the CSRs to do "automated" get/put reg procedures in > the previous patch we can now scan for availability. Two functions are > created: > > - kvm_riscv_read_csr_cfg_legacy() will check if the CSR exists by brute > forcing KVM_GET_ONE_REG in each one of them, interpreting an EINVAL > return as indication that the CSR isn't available. This will be use in > absence of KVM_GET_REG_LIST; > > - kvm_riscv_read_csr_cfg() will use the existing result of get_reg_list > to check if the CSRs ids are present. > > kvm_riscv_init_multiext_cfg() is now kvm_riscv_init_multiext_csr_cfg() > to reflect that the function is also dealing with CSRs. > > [1] > https://lore.kernel.org/qemu-riscv/CABJz62OfUDHYkQ0T3rGHStQprf1c7_E0qBLbLKhfv=+jb0s...@mail.gmail.com/ > > Fixes: 4db19d5b21 ("target/riscv/kvm: add missing KVM CSRs") > Reported-by: Andrea Bolognani <abolo...@redhat.com> > Signed-off-by: Daniel Henrique Barboza <dbarb...@ventanamicro.com> > --- > target/riscv/kvm/kvm-cpu.c | 63 ++++++++++++++++++++++++++++++++++++-- > 1 file changed, 60 insertions(+), 3 deletions(-) > > diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c > index 99a4f01b15..ec74520872 100644 > --- a/target/riscv/kvm/kvm-cpu.c > +++ b/target/riscv/kvm/kvm-cpu.c > @@ -638,6 +638,10 @@ static int kvm_riscv_get_regs_csr(CPUState *cs) > for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { > KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; > > + if (!csr_cfg->supported) { > + continue; > + } > + > ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, ®); > if (ret) { > return ret; > @@ -662,6 +666,10 @@ static int kvm_riscv_put_regs_csr(CPUState *cs) > for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { > KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; > > + if (!csr_cfg->supported) { > + continue; > + } > + > if (csr_cfg->prop_size == sizeof(uint32_t)) { > reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); > } else { > @@ -1088,6 +1096,32 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU > *cpu, > } > } > > +static void kvm_riscv_read_csr_cfg_legacy(KVMScratchCPU *kvmcpu) > +{ > + uint64_t val; > + int i, ret; > + > + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { > + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; > + struct kvm_one_reg reg; > + > + reg.id = csr_cfg->kvm_reg_id; > + reg.addr = (uint64_t)&val; > + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); > + if (ret != 0) { > + if (errno == EINVAL) { > + csr_cfg->supported = false; > + } else { > + error_report("Unable to read KVM CSR %s: %s", > + csr_cfg->name, strerror(errno)); > + exit(EXIT_FAILURE); > + } > + } else { > + csr_cfg->supported = true; > + } > + } > +} > + > static int uint64_cmp(const void *a, const void *b) > { > uint64_t val1 = *(const uint64_t *)a; > @@ -1144,7 +1178,27 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, > KVMScratchCPU *kvmcpu, > } > } > > -static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) > +static void kvm_riscv_read_csr_cfg(struct kvm_reg_list *reglist) > +{ > + struct kvm_reg_list *reg_search; > + uint64_t reg_id; > + > + for (int i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { > + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; > + > + reg_id = csr_cfg->kvm_reg_id; > + reg_search = bsearch(®_id, reglist->reg, reglist->n, > + sizeof(uint64_t), uint64_cmp); > + if (!reg_search) { > + continue; > + } > + > + csr_cfg->supported = true; > + } > +} > + > +static void kvm_riscv_init_multiext_csr_cfg(RISCVCPU *cpu, > + KVMScratchCPU *kvmcpu)
I'm not sure we want to keep extending the name of this function with each thing it does (and it does SBI as well, which isn't in the name). Maybe just shorten it instead to kvm_riscv_init_cfg()? > { > KVMCPUConfig *multi_ext_cfg; > struct kvm_one_reg reg; > @@ -1161,7 +1215,9 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, > KVMScratchCPU *kvmcpu) > * (EINVAL). Use read_legacy() in this case. > */ > if (errno == EINVAL) { > - return kvm_riscv_read_multiext_legacy(cpu, kvmcpu); > + kvm_riscv_read_multiext_legacy(cpu, kvmcpu); > + kvm_riscv_read_csr_cfg_legacy(kvmcpu); > + return; > } else if (errno != E2BIG) { > /* > * E2BIG is an expected error message for the API since we > @@ -1224,6 +1280,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, > KVMScratchCPU *kvmcpu) > } > > kvm_riscv_check_sbi_dbcn_support(cpu, reglist); > + kvm_riscv_read_csr_cfg(reglist); Shouldn't there be a g_free(reglist) here? > } > > static void riscv_init_kvm_registers(Object *cpu_obj) > @@ -1237,7 +1294,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_multiext_csr_cfg(cpu, &kvmcpu); > > kvm_riscv_destroy_scratch_vcpu(&kvmcpu); > } > -- > 2.49.0 > > Thanks, drew