Skip to content

Commit 9ac56fb

Browse files
danielhbMichael Tokarev
authored andcommitted
target/riscv/kvm: do not read unavailable CSRs
[1] reports that commit 4db19d5 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_cfg() to reflect that the function is also dealing with CSRs. [1] https://lore.kernel.org/qemu-riscv/CABJz62OfUDHYkQ0T3rGHStQprf1c7_E0qBLbLKhfv=+jb0SYAw@mail.gmail.com/ Fixes: 4db19d5 ("target/riscv/kvm: add missing KVM CSRs") Reported-by: Andrea Bolognani <[email protected]> Signed-off-by: Daniel Henrique Barboza <[email protected]> Reviewed-by: Andrew Jones <[email protected]> Acked-by: Alistair Francis <[email protected]> Message-ID: <[email protected]> Signed-off-by: Alistair Francis <[email protected]> Cc: [email protected] (cherry picked from commit f396c21) Signed-off-by: Michael Tokarev <[email protected]>
1 parent 6ba14ba commit 9ac56fb

File tree

1 file changed

+59
-3
lines changed

1 file changed

+59
-3
lines changed

target/riscv/kvm/kvm-cpu.c

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,10 @@ static int kvm_riscv_get_regs_csr(CPUState *cs)
636636
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
637637
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
638638

639+
if (!csr_cfg->supported) {
640+
continue;
641+
}
642+
639643
ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, &reg);
640644
if (ret) {
641645
return ret;
@@ -662,6 +666,10 @@ static int kvm_riscv_put_regs_csr(CPUState *cs)
662666
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
663667
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
664668

669+
if (!csr_cfg->supported) {
670+
continue;
671+
}
672+
665673
if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) {
666674
reg = kvm_cpu_csr_get_u32(cpu, csr_cfg);
667675
} else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) {
@@ -1090,6 +1098,32 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
10901098
}
10911099
}
10921100

1101+
static void kvm_riscv_read_csr_cfg_legacy(KVMScratchCPU *kvmcpu)
1102+
{
1103+
uint64_t val;
1104+
int i, ret;
1105+
1106+
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
1107+
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
1108+
struct kvm_one_reg reg;
1109+
1110+
reg.id = csr_cfg->kvm_reg_id;
1111+
reg.addr = (uint64_t)&val;
1112+
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
1113+
if (ret != 0) {
1114+
if (errno == EINVAL) {
1115+
csr_cfg->supported = false;
1116+
} else {
1117+
error_report("Unable to read KVM CSR %s: %s",
1118+
csr_cfg->name, strerror(errno));
1119+
exit(EXIT_FAILURE);
1120+
}
1121+
} else {
1122+
csr_cfg->supported = true;
1123+
}
1124+
}
1125+
}
1126+
10931127
static int uint64_cmp(const void *a, const void *b)
10941128
{
10951129
uint64_t val1 = *(const uint64_t *)a;
@@ -1146,7 +1180,26 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
11461180
}
11471181
}
11481182

1149-
static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
1183+
static void kvm_riscv_read_csr_cfg(struct kvm_reg_list *reglist)
1184+
{
1185+
struct kvm_reg_list *reg_search;
1186+
uint64_t reg_id;
1187+
1188+
for (int i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
1189+
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
1190+
1191+
reg_id = csr_cfg->kvm_reg_id;
1192+
reg_search = bsearch(&reg_id, reglist->reg, reglist->n,
1193+
sizeof(uint64_t), uint64_cmp);
1194+
if (!reg_search) {
1195+
continue;
1196+
}
1197+
1198+
csr_cfg->supported = true;
1199+
}
1200+
}
1201+
1202+
static void kvm_riscv_init_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
11501203
{
11511204
g_autofree struct kvm_reg_list *reglist = NULL;
11521205
KVMCPUConfig *multi_ext_cfg;
@@ -1163,7 +1216,9 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
11631216
* (EINVAL). Use read_legacy() in this case.
11641217
*/
11651218
if (errno == EINVAL) {
1166-
return kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
1219+
kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
1220+
kvm_riscv_read_csr_cfg_legacy(kvmcpu);
1221+
return;
11671222
} else if (errno != E2BIG) {
11681223
/*
11691224
* E2BIG is an expected error message for the API since we
@@ -1226,6 +1281,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
12261281
}
12271282

12281283
kvm_riscv_check_sbi_dbcn_support(cpu, reglist);
1284+
kvm_riscv_read_csr_cfg(reglist);
12291285
}
12301286

12311287
static void riscv_init_kvm_registers(Object *cpu_obj)
@@ -1239,7 +1295,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj)
12391295

12401296
kvm_riscv_init_machine_ids(cpu, &kvmcpu);
12411297
kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
1242-
kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
1298+
kvm_riscv_init_cfg(cpu, &kvmcpu);
12431299

12441300
kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
12451301
}

0 commit comments

Comments
 (0)