Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

RISC-V: KVM: Introduce optional ONE_REG callbacks for SBI extensions

SBI extensions can have per-VCPU state which needs to be saved/restored
through ONE_REG interface for Guest/VM migration. Introduce optional
ONE_REG callbacks for SBI extensions so that ONE_REG implementation
for an SBI extenion is part of the extension sources.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Link: https://lore.kernel.org/r/20250823155947.1354229-4-apatel@ventanamicro.com
Signed-off-by: Anup Patel <anup@brainfault.org>

authored by

Anup Patel and committed by
Anup Patel
699a53ae a6250b18

+188 -95
+11 -9
arch/riscv/include/asm/kvm_vcpu_sbi.h
··· 59 59 void (*deinit)(struct kvm_vcpu *vcpu); 60 60 61 61 void (*reset)(struct kvm_vcpu *vcpu); 62 + 63 + unsigned long state_reg_subtype; 64 + unsigned long (*get_state_reg_count)(struct kvm_vcpu *vcpu); 65 + int (*get_state_reg_id)(struct kvm_vcpu *vcpu, int index, u64 *reg_id); 66 + int (*get_state_reg)(struct kvm_vcpu *vcpu, unsigned long reg_num, 67 + unsigned long reg_size, void *reg_val); 68 + int (*set_state_reg)(struct kvm_vcpu *vcpu, unsigned long reg_num, 69 + unsigned long reg_size, const void *reg_val); 62 70 }; 63 71 64 72 void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run); ··· 81 73 const struct kvm_one_reg *reg); 82 74 int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, 83 75 const struct kvm_one_reg *reg); 84 - int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, 85 - const struct kvm_one_reg *reg); 86 - int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, 87 - const struct kvm_one_reg *reg); 76 + int kvm_riscv_vcpu_reg_indices_sbi(struct kvm_vcpu *vcpu, u64 __user *uindices); 77 + int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); 78 + int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); 88 79 const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( 89 80 struct kvm_vcpu *vcpu, unsigned long extid); 90 81 bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx); ··· 91 84 void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu); 92 85 void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu); 93 86 void kvm_riscv_vcpu_sbi_reset(struct kvm_vcpu *vcpu); 94 - 95 - int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, 96 - unsigned long *reg_val); 97 - int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, 98 - unsigned long reg_val); 99 87 100 88 #ifdef CONFIG_RISCV_SBI_V01 101 89 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
+2 -29
arch/riscv/kvm/vcpu_onereg.c
··· 1112 1112 return copy_sbi_ext_reg_indices(vcpu, NULL); 1113 1113 } 1114 1114 1115 - static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 1116 - { 1117 - struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; 1118 - int total = 0; 1119 - 1120 - if (scontext->ext_status[KVM_RISCV_SBI_EXT_STA] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) { 1121 - u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; 1122 - int n = sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long); 1123 - 1124 - for (int i = 0; i < n; i++) { 1125 - u64 reg = KVM_REG_RISCV | size | 1126 - KVM_REG_RISCV_SBI_STATE | 1127 - KVM_REG_RISCV_SBI_STA | i; 1128 - 1129 - if (uindices) { 1130 - if (put_user(reg, uindices)) 1131 - return -EFAULT; 1132 - uindices++; 1133 - } 1134 - } 1135 - 1136 - total += n; 1137 - } 1138 - 1139 - return total; 1140 - } 1141 - 1142 1115 static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu) 1143 1116 { 1144 - return copy_sbi_reg_indices(vcpu, NULL); 1117 + return kvm_riscv_vcpu_reg_indices_sbi(vcpu, NULL); 1145 1118 } 1146 1119 1147 1120 static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu) ··· 1242 1269 return ret; 1243 1270 uindices += ret; 1244 1271 1245 - ret = copy_sbi_reg_indices(vcpu, uindices); 1272 + ret = kvm_riscv_vcpu_reg_indices_sbi(vcpu, uindices); 1246 1273 if (ret < 0) 1247 1274 return ret; 1248 1275 uindices += ret;
+133 -34
arch/riscv/kvm/vcpu_sbi.c
··· 364 364 return 0; 365 365 } 366 366 367 - int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, 368 - const struct kvm_one_reg *reg) 367 + int kvm_riscv_vcpu_reg_indices_sbi(struct kvm_vcpu *vcpu, u64 __user *uindices) 369 368 { 370 - unsigned long __user *uaddr = 371 - (unsigned long __user *)(unsigned long)reg->addr; 372 - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 373 - KVM_REG_SIZE_MASK | 374 - KVM_REG_RISCV_SBI_STATE); 375 - unsigned long reg_subtype, reg_val; 369 + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; 370 + const struct kvm_riscv_sbi_extension_entry *entry; 371 + const struct kvm_vcpu_sbi_extension *ext; 372 + unsigned long state_reg_count; 373 + int i, j, rc, count = 0; 374 + u64 reg; 376 375 377 - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) 378 - return -EINVAL; 376 + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { 377 + entry = &sbi_ext[i]; 378 + ext = entry->ext_ptr; 379 379 380 - if (copy_from_user(&reg_val, uaddr, KVM_REG_SIZE(reg->id))) 381 - return -EFAULT; 380 + if (!ext->get_state_reg_count || 381 + scontext->ext_status[entry->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_ENABLED) 382 + continue; 382 383 383 - reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; 384 - reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; 384 + state_reg_count = ext->get_state_reg_count(vcpu); 385 + if (!uindices) 386 + goto skip_put_user; 385 387 386 - switch (reg_subtype) { 387 - case KVM_REG_RISCV_SBI_STA: 388 - return kvm_riscv_vcpu_set_reg_sbi_sta(vcpu, reg_num, reg_val); 389 - default: 390 - return -EINVAL; 388 + for (j = 0; j < state_reg_count; j++) { 389 + if (ext->get_state_reg_id) { 390 + rc = ext->get_state_reg_id(vcpu, j, &reg); 391 + if (rc) 392 + return rc; 393 + } else { 394 + reg = KVM_REG_RISCV | 395 + (IS_ENABLED(CONFIG_32BIT) ? 396 + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64) | 397 + KVM_REG_RISCV_SBI_STATE | 398 + ext->state_reg_subtype | j; 399 + } 400 + 401 + if (put_user(reg, uindices)) 402 + return -EFAULT; 403 + uindices++; 404 + } 405 + 406 + skip_put_user: 407 + count += state_reg_count; 391 408 } 392 409 393 - return 0; 410 + return count; 394 411 } 395 412 396 - int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, 397 - const struct kvm_one_reg *reg) 413 + static const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext_withstate(struct kvm_vcpu *vcpu, 414 + unsigned long subtype) 415 + { 416 + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; 417 + const struct kvm_riscv_sbi_extension_entry *entry; 418 + const struct kvm_vcpu_sbi_extension *ext; 419 + int i; 420 + 421 + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { 422 + entry = &sbi_ext[i]; 423 + ext = entry->ext_ptr; 424 + 425 + if (ext->get_state_reg_count && 426 + ext->state_reg_subtype == subtype && 427 + scontext->ext_status[entry->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) 428 + return ext; 429 + } 430 + 431 + return NULL; 432 + } 433 + 434 + int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 398 435 { 399 436 unsigned long __user *uaddr = 400 437 (unsigned long __user *)(unsigned long)reg->addr; 401 438 unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 402 439 KVM_REG_SIZE_MASK | 403 440 KVM_REG_RISCV_SBI_STATE); 404 - unsigned long reg_subtype, reg_val; 405 - int ret; 441 + const struct kvm_vcpu_sbi_extension *ext; 442 + unsigned long reg_subtype; 443 + void *reg_val; 444 + u64 data64; 445 + u32 data32; 446 + u16 data16; 447 + u8 data8; 406 448 407 - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) 408 - return -EINVAL; 409 - 410 - reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; 411 - reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; 412 - 413 - switch (reg_subtype) { 414 - case KVM_REG_RISCV_SBI_STA: 415 - ret = kvm_riscv_vcpu_get_reg_sbi_sta(vcpu, reg_num, &reg_val); 449 + switch (KVM_REG_SIZE(reg->id)) { 450 + case 1: 451 + reg_val = &data8; 452 + break; 453 + case 2: 454 + reg_val = &data16; 455 + break; 456 + case 4: 457 + reg_val = &data32; 458 + break; 459 + case 8: 460 + reg_val = &data64; 416 461 break; 417 462 default: 418 463 return -EINVAL; 419 464 } 420 465 466 + if (copy_from_user(reg_val, uaddr, KVM_REG_SIZE(reg->id))) 467 + return -EFAULT; 468 + 469 + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; 470 + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; 471 + 472 + ext = kvm_vcpu_sbi_find_ext_withstate(vcpu, reg_subtype); 473 + if (!ext || !ext->set_state_reg) 474 + return -EINVAL; 475 + 476 + return ext->set_state_reg(vcpu, reg_num, KVM_REG_SIZE(reg->id), reg_val); 477 + } 478 + 479 + int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 480 + { 481 + unsigned long __user *uaddr = 482 + (unsigned long __user *)(unsigned long)reg->addr; 483 + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 484 + KVM_REG_SIZE_MASK | 485 + KVM_REG_RISCV_SBI_STATE); 486 + const struct kvm_vcpu_sbi_extension *ext; 487 + unsigned long reg_subtype; 488 + void *reg_val; 489 + u64 data64; 490 + u32 data32; 491 + u16 data16; 492 + u8 data8; 493 + int ret; 494 + 495 + switch (KVM_REG_SIZE(reg->id)) { 496 + case 1: 497 + reg_val = &data8; 498 + break; 499 + case 2: 500 + reg_val = &data16; 501 + break; 502 + case 4: 503 + reg_val = &data32; 504 + break; 505 + case 8: 506 + reg_val = &data64; 507 + break; 508 + default: 509 + return -EINVAL; 510 + } 511 + 512 + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; 513 + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; 514 + 515 + ext = kvm_vcpu_sbi_find_ext_withstate(vcpu, reg_subtype); 516 + if (!ext || !ext->get_state_reg) 517 + return -EINVAL; 518 + 519 + ret = ext->get_state_reg(vcpu, reg_num, KVM_REG_SIZE(reg->id), reg_val); 421 520 if (ret) 422 521 return ret; 423 522 424 - if (copy_to_user(uaddr, &reg_val, KVM_REG_SIZE(reg->id))) 523 + if (copy_to_user(uaddr, reg_val, KVM_REG_SIZE(reg->id))) 425 524 return -EFAULT; 426 525 427 526 return 0;
+42 -23
arch/riscv/kvm/vcpu_sbi_sta.c
··· 151 151 return !!sched_info_on(); 152 152 } 153 153 154 - const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = { 155 - .extid_start = SBI_EXT_STA, 156 - .extid_end = SBI_EXT_STA, 157 - .handler = kvm_sbi_ext_sta_handler, 158 - .probe = kvm_sbi_ext_sta_probe, 159 - .reset = kvm_riscv_vcpu_sbi_sta_reset, 160 - }; 161 - 162 - int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, 163 - unsigned long reg_num, 164 - unsigned long *reg_val) 154 + static unsigned long kvm_sbi_ext_sta_get_state_reg_count(struct kvm_vcpu *vcpu) 165 155 { 156 + return sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long); 157 + } 158 + 159 + static int kvm_sbi_ext_sta_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, 160 + unsigned long reg_size, void *reg_val) 161 + { 162 + unsigned long *value; 163 + 164 + if (reg_size != sizeof(unsigned long)) 165 + return -EINVAL; 166 + value = reg_val; 167 + 166 168 switch (reg_num) { 167 169 case KVM_REG_RISCV_SBI_STA_REG(shmem_lo): 168 - *reg_val = (unsigned long)vcpu->arch.sta.shmem; 170 + *value = (unsigned long)vcpu->arch.sta.shmem; 169 171 break; 170 172 case KVM_REG_RISCV_SBI_STA_REG(shmem_hi): 171 173 if (IS_ENABLED(CONFIG_32BIT)) 172 - *reg_val = upper_32_bits(vcpu->arch.sta.shmem); 174 + *value = upper_32_bits(vcpu->arch.sta.shmem); 173 175 else 174 - *reg_val = 0; 176 + *value = 0; 175 177 break; 176 178 default: 177 - return -EINVAL; 179 + return -ENOENT; 178 180 } 179 181 180 182 return 0; 181 183 } 182 184 183 - int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, 184 - unsigned long reg_num, 185 - unsigned long reg_val) 185 + static int kvm_sbi_ext_sta_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, 186 + unsigned long reg_size, const void *reg_val) 186 187 { 188 + unsigned long value; 189 + 190 + if (reg_size != sizeof(unsigned long)) 191 + return -EINVAL; 192 + value = *(const unsigned long *)reg_val; 193 + 187 194 switch (reg_num) { 188 195 case KVM_REG_RISCV_SBI_STA_REG(shmem_lo): 189 196 if (IS_ENABLED(CONFIG_32BIT)) { 190 197 gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem); 191 198 192 - vcpu->arch.sta.shmem = reg_val; 199 + vcpu->arch.sta.shmem = value; 193 200 vcpu->arch.sta.shmem |= hi << 32; 194 201 } else { 195 - vcpu->arch.sta.shmem = reg_val; 202 + vcpu->arch.sta.shmem = value; 196 203 } 197 204 break; 198 205 case KVM_REG_RISCV_SBI_STA_REG(shmem_hi): 199 206 if (IS_ENABLED(CONFIG_32BIT)) { 200 207 gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem); 201 208 202 - vcpu->arch.sta.shmem = ((gpa_t)reg_val << 32); 209 + vcpu->arch.sta.shmem = ((gpa_t)value << 32); 203 210 vcpu->arch.sta.shmem |= lo; 204 - } else if (reg_val != 0) { 211 + } else if (value != 0) { 205 212 return -EINVAL; 206 213 } 207 214 break; 208 215 default: 209 - return -EINVAL; 216 + return -ENOENT; 210 217 } 211 218 212 219 return 0; 213 220 } 221 + 222 + const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = { 223 + .extid_start = SBI_EXT_STA, 224 + .extid_end = SBI_EXT_STA, 225 + .handler = kvm_sbi_ext_sta_handler, 226 + .probe = kvm_sbi_ext_sta_probe, 227 + .reset = kvm_riscv_vcpu_sbi_sta_reset, 228 + .state_reg_subtype = KVM_REG_RISCV_SBI_STA, 229 + .get_state_reg_count = kvm_sbi_ext_sta_get_state_reg_count, 230 + .get_state_reg = kvm_sbi_ext_sta_get_reg, 231 + .set_state_reg = kvm_sbi_ext_sta_set_reg, 232 + };