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.

KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM

Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
value. Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
full-virtualisation abstractions.") (which is arguably more trustworthy
than KVM), offset 0x70 is a single 64-bit value:

070h 63:0 EXITCODE

Track exit_code as a single u64 to prevent reintroducing bugs where KVM
neglects to correctly set bits 63:32.

Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
Cc: Jim Mattson <jmattson@google.com>
Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>
Link: https://patch.msgid.link/20251230211347.4099600-6-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

+42 -69
+1 -2
arch/x86/include/asm/svm.h
··· 137 137 u32 int_vector; 138 138 u32 int_state; 139 139 u8 reserved_3[4]; 140 - u32 exit_code; 141 - u32 exit_code_hi; 140 + u64 exit_code; 142 141 u64 exit_info_1; 143 142 u64 exit_info_2; 144 143 u32 exit_int_info;
+16 -16
arch/x86/include/uapi/asm/svm.h
··· 103 103 #define SVM_EXIT_VMGEXIT 0x403 104 104 105 105 /* SEV-ES software-defined VMGEXIT events */ 106 - #define SVM_VMGEXIT_MMIO_READ 0x80000001 107 - #define SVM_VMGEXIT_MMIO_WRITE 0x80000002 108 - #define SVM_VMGEXIT_NMI_COMPLETE 0x80000003 109 - #define SVM_VMGEXIT_AP_HLT_LOOP 0x80000004 110 - #define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005 106 + #define SVM_VMGEXIT_MMIO_READ 0x80000001ull 107 + #define SVM_VMGEXIT_MMIO_WRITE 0x80000002ull 108 + #define SVM_VMGEXIT_NMI_COMPLETE 0x80000003ull 109 + #define SVM_VMGEXIT_AP_HLT_LOOP 0x80000004ull 110 + #define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005ull 111 111 #define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0 112 112 #define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 113 - #define SVM_VMGEXIT_PSC 0x80000010 114 - #define SVM_VMGEXIT_GUEST_REQUEST 0x80000011 115 - #define SVM_VMGEXIT_EXT_GUEST_REQUEST 0x80000012 116 - #define SVM_VMGEXIT_AP_CREATION 0x80000013 113 + #define SVM_VMGEXIT_PSC 0x80000010ull 114 + #define SVM_VMGEXIT_GUEST_REQUEST 0x80000011ull 115 + #define SVM_VMGEXIT_EXT_GUEST_REQUEST 0x80000012ull 116 + #define SVM_VMGEXIT_AP_CREATION 0x80000013ull 117 117 #define SVM_VMGEXIT_AP_CREATE_ON_INIT 0 118 118 #define SVM_VMGEXIT_AP_CREATE 1 119 119 #define SVM_VMGEXIT_AP_DESTROY 2 120 - #define SVM_VMGEXIT_SNP_RUN_VMPL 0x80000018 121 - #define SVM_VMGEXIT_SAVIC 0x8000001a 120 + #define SVM_VMGEXIT_SNP_RUN_VMPL 0x80000018ull 121 + #define SVM_VMGEXIT_SAVIC 0x8000001aull 122 122 #define SVM_VMGEXIT_SAVIC_REGISTER_GPA 0 123 123 #define SVM_VMGEXIT_SAVIC_UNREGISTER_GPA 1 124 124 #define SVM_VMGEXIT_SAVIC_SELF_GPA ~0ULL 125 - #define SVM_VMGEXIT_HV_FEATURES 0x8000fffd 126 - #define SVM_VMGEXIT_TERM_REQUEST 0x8000fffe 125 + #define SVM_VMGEXIT_HV_FEATURES 0x8000fffdull 126 + #define SVM_VMGEXIT_TERM_REQUEST 0x8000fffeull 127 127 #define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code) \ 128 128 /* SW_EXITINFO1[3:0] */ \ 129 129 (((((u64)reason_set) & 0xf)) | \ 130 130 /* SW_EXITINFO1[11:4] */ \ 131 131 ((((u64)reason_code) & 0xff) << 4)) 132 - #define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff 132 + #define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffffull 133 133 134 134 /* Exit code reserved for hypervisor/software use */ 135 - #define SVM_EXIT_SW 0xf0000000 135 + #define SVM_EXIT_SW 0xf0000000ull 136 136 137 - #define SVM_EXIT_ERR -1 137 + #define SVM_EXIT_ERR -1ull 138 138 139 139 #define SVM_EXIT_REASONS \ 140 140 { SVM_EXIT_READ_CR0, "read_cr0" }, \
-1
arch/x86/kvm/svm/hyperv.c
··· 11 11 struct vcpu_svm *svm = to_svm(vcpu); 12 12 13 13 svm->vmcb->control.exit_code = HV_SVM_EXITCODE_ENL; 14 - svm->vmcb->control.exit_code_hi = 0; 15 14 svm->vmcb->control.exit_info_1 = HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH; 16 15 svm->vmcb->control.exit_info_2 = 0; 17 16 nested_svm_vmexit(svm);
+3 -10
arch/x86/kvm/svm/nested.c
··· 45 45 * correctly fill in the high bits of exit_info_1. 46 46 */ 47 47 vmcb->control.exit_code = SVM_EXIT_NPF; 48 - vmcb->control.exit_code_hi = 0; 49 48 vmcb->control.exit_info_1 = (1ULL << 32); 50 49 vmcb->control.exit_info_2 = fault->address; 51 50 } ··· 440 441 to->int_vector = from->int_vector; 441 442 to->int_state = from->int_state; 442 443 to->exit_code = from->exit_code; 443 - to->exit_code_hi = from->exit_code_hi; 444 444 to->exit_info_1 = from->exit_info_1; 445 445 to->exit_info_2 = from->exit_info_2; 446 446 to->exit_int_info = from->exit_int_info; ··· 745 747 enter_guest_mode(vcpu); 746 748 747 749 /* 748 - * Filled at exit: exit_code, exit_code_hi, exit_info_1, exit_info_2, 749 - * exit_int_info, exit_int_info_err, next_rip, insn_len, insn_bytes. 750 + * Filled at exit: exit_code, exit_info_1, exit_info_2, exit_int_info, 751 + * exit_int_info_err, next_rip, insn_len, insn_bytes. 750 752 */ 751 753 752 754 if (guest_cpu_cap_has(vcpu, X86_FEATURE_VGIF) && ··· 1016 1018 if (!nested_vmcb_check_save(vcpu) || 1017 1019 !nested_vmcb_check_controls(vcpu)) { 1018 1020 vmcb12->control.exit_code = SVM_EXIT_ERR; 1019 - vmcb12->control.exit_code_hi = -1u; 1020 1021 vmcb12->control.exit_info_1 = 0; 1021 1022 vmcb12->control.exit_info_2 = 0; 1022 1023 goto out; ··· 1048 1051 svm->soft_int_injected = false; 1049 1052 1050 1053 svm->vmcb->control.exit_code = SVM_EXIT_ERR; 1051 - svm->vmcb->control.exit_code_hi = -1u; 1052 1054 svm->vmcb->control.exit_info_1 = 0; 1053 1055 svm->vmcb->control.exit_info_2 = 0; 1054 1056 ··· 1159 1163 1160 1164 vmcb12->control.int_state = vmcb02->control.int_state; 1161 1165 vmcb12->control.exit_code = vmcb02->control.exit_code; 1162 - vmcb12->control.exit_code_hi = vmcb02->control.exit_code_hi; 1163 1166 vmcb12->control.exit_info_1 = vmcb02->control.exit_info_1; 1164 1167 vmcb12->control.exit_info_2 = vmcb02->control.exit_info_2; 1165 1168 ··· 1455 1460 1456 1461 static int nested_svm_intercept(struct vcpu_svm *svm) 1457 1462 { 1458 - u32 exit_code = svm->vmcb->control.exit_code; 1463 + u64 exit_code = svm->vmcb->control.exit_code; 1459 1464 int vmexit = NESTED_EXIT_HOST; 1460 1465 1461 1466 if (svm_is_vmrun_failure(exit_code)) ··· 1527 1532 struct vmcb *vmcb = svm->vmcb; 1528 1533 1529 1534 vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + ex->vector; 1530 - vmcb->control.exit_code_hi = 0; 1531 1535 1532 1536 if (ex->has_error_code) 1533 1537 vmcb->control.exit_info_1 = ex->error_code; ··· 1702 1708 dst->int_vector = from->int_vector; 1703 1709 dst->int_state = from->int_state; 1704 1710 dst->exit_code = from->exit_code; 1705 - dst->exit_code_hi = from->exit_code_hi; 1706 1711 dst->exit_info_1 = from->exit_info_1; 1707 1712 dst->exit_info_2 = from->exit_info_2; 1708 1713 dst->exit_int_info = from->exit_int_info;
+12 -24
arch/x86/kvm/svm/sev.c
··· 3270 3270 kvfree(svm->sev_es.ghcb_sa); 3271 3271 } 3272 3272 3273 - static u64 kvm_get_cached_sw_exit_code(struct vmcb_control_area *control) 3274 - { 3275 - return (((u64)control->exit_code_hi) << 32) | control->exit_code; 3276 - } 3277 - 3278 3273 static void dump_ghcb(struct vcpu_svm *svm) 3279 3274 { 3280 3275 struct vmcb_control_area *control = &svm->vmcb->control; ··· 3291 3296 */ 3292 3297 pr_err("GHCB (GPA=%016llx) snapshot:\n", svm->vmcb->control.ghcb_gpa); 3293 3298 pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code", 3294 - kvm_get_cached_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm)); 3299 + control->exit_code, kvm_ghcb_sw_exit_code_is_valid(svm)); 3295 3300 pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1", 3296 3301 control->exit_info_1, kvm_ghcb_sw_exit_info_1_is_valid(svm)); 3297 3302 pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2", ··· 3325 3330 struct vmcb_control_area *control = &svm->vmcb->control; 3326 3331 struct kvm_vcpu *vcpu = &svm->vcpu; 3327 3332 struct ghcb *ghcb = svm->sev_es.ghcb; 3328 - u64 exit_code; 3329 3333 3330 3334 /* 3331 3335 * The GHCB protocol so far allows for the following data ··· 3358 3364 __kvm_emulate_msr_write(vcpu, MSR_IA32_XSS, kvm_ghcb_get_xss(svm)); 3359 3365 3360 3366 /* Copy the GHCB exit information into the VMCB fields */ 3361 - exit_code = kvm_ghcb_get_sw_exit_code(svm); 3362 - control->exit_code = lower_32_bits(exit_code); 3363 - control->exit_code_hi = upper_32_bits(exit_code); 3367 + control->exit_code = kvm_ghcb_get_sw_exit_code(svm); 3364 3368 control->exit_info_1 = kvm_ghcb_get_sw_exit_info_1(svm); 3365 3369 control->exit_info_2 = kvm_ghcb_get_sw_exit_info_2(svm); 3366 3370 svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm); ··· 3371 3379 { 3372 3380 struct vmcb_control_area *control = &svm->vmcb->control; 3373 3381 struct kvm_vcpu *vcpu = &svm->vcpu; 3374 - u64 exit_code; 3375 3382 u64 reason; 3376 - 3377 - /* 3378 - * Retrieve the exit code now even though it may not be marked valid 3379 - * as it could help with debugging. 3380 - */ 3381 - exit_code = kvm_get_cached_sw_exit_code(control); 3382 3383 3383 3384 /* Only GHCB Usage code 0 is supported */ 3384 3385 if (svm->sev_es.ghcb->ghcb_usage) { ··· 3386 3401 !kvm_ghcb_sw_exit_info_2_is_valid(svm)) 3387 3402 goto vmgexit_err; 3388 3403 3389 - switch (exit_code) { 3404 + switch (control->exit_code) { 3390 3405 case SVM_EXIT_READ_DR7: 3391 3406 break; 3392 3407 case SVM_EXIT_WRITE_DR7: ··· 3487 3502 return 0; 3488 3503 3489 3504 vmgexit_err: 3505 + /* 3506 + * Print the exit code even though it may not be marked valid as it 3507 + * could help with debugging. 3508 + */ 3490 3509 if (reason == GHCB_ERR_INVALID_USAGE) { 3491 3510 vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n", 3492 3511 svm->sev_es.ghcb->ghcb_usage); 3493 3512 } else if (reason == GHCB_ERR_INVALID_EVENT) { 3494 3513 vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n", 3495 - exit_code); 3514 + control->exit_code); 3496 3515 } else { 3497 3516 vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n", 3498 - exit_code); 3517 + control->exit_code); 3499 3518 dump_ghcb(svm); 3500 3519 } 3501 3520 ··· 4338 4349 { 4339 4350 struct vcpu_svm *svm = to_svm(vcpu); 4340 4351 struct vmcb_control_area *control = &svm->vmcb->control; 4341 - u64 ghcb_gpa, exit_code; 4352 + u64 ghcb_gpa; 4342 4353 int ret; 4343 4354 4344 4355 /* Validate the GHCB */ ··· 4380 4391 4381 4392 svm_vmgexit_success(svm, 0); 4382 4393 4383 - exit_code = kvm_get_cached_sw_exit_code(control); 4384 - switch (exit_code) { 4394 + switch (control->exit_code) { 4385 4395 case SVM_VMGEXIT_MMIO_READ: 4386 4396 ret = setup_vmgexit_scratch(svm, true, control->exit_info_2); 4387 4397 if (ret) ··· 4472 4484 ret = -EINVAL; 4473 4485 break; 4474 4486 default: 4475 - ret = svm_invoke_exit_handler(vcpu, exit_code); 4487 + ret = svm_invoke_exit_handler(vcpu, control->exit_code); 4476 4488 } 4477 4489 4478 4490 return ret;
+2 -5
arch/x86/kvm/svm/svm.c
··· 2466 2466 2467 2467 if (cr0 ^ val) { 2468 2468 svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE; 2469 - svm->vmcb->control.exit_code_hi = 0; 2470 2469 ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE); 2471 2470 } 2472 2471 ··· 3298 3299 pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl); 3299 3300 pr_err("%-20s%08x\n", "int_vector:", control->int_vector); 3300 3301 pr_err("%-20s%08x\n", "int_state:", control->int_state); 3301 - pr_err("%-20s%08x\n", "exit_code:", control->exit_code); 3302 + pr_err("%-20s%016llx\n", "exit_code:", control->exit_code); 3302 3303 pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1); 3303 3304 pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2); 3304 3305 pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info); ··· 3548 3549 { 3549 3550 struct vcpu_svm *svm = to_svm(vcpu); 3550 3551 struct kvm_run *kvm_run = vcpu->run; 3551 - u32 exit_code = svm->vmcb->control.exit_code; 3552 3552 3553 3553 /* SEV-ES guests must use the CR write traps to track CR registers. */ 3554 3554 if (!sev_es_guest(vcpu->kvm)) { ··· 3583 3585 if (exit_fastpath != EXIT_FASTPATH_NONE) 3584 3586 return 1; 3585 3587 3586 - return svm_invoke_exit_handler(vcpu, exit_code); 3588 + return svm_invoke_exit_handler(vcpu, svm->vmcb->control.exit_code); 3587 3589 } 3588 3590 3589 3591 static int pre_svm_run(struct kvm_vcpu *vcpu) ··· 4668 4670 if (static_cpu_has(X86_FEATURE_NRIPS)) 4669 4671 vmcb->control.next_rip = info->next_rip; 4670 4672 vmcb->control.exit_code = icpt_info.exit_code; 4671 - vmcb->control.exit_code_hi = 0; 4672 4673 vmexit = nested_svm_exit_handled(svm); 4673 4674 4674 4675 ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
+1 -3
arch/x86/kvm/svm/svm.h
··· 160 160 u32 int_ctl; 161 161 u32 int_vector; 162 162 u32 int_state; 163 - u32 exit_code; 164 - u32 exit_code_hi; 163 + u64 exit_code; 165 164 u64 exit_info_1; 166 165 u64 exit_info_2; 167 166 u32 exit_int_info; ··· 786 787 static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code) 787 788 { 788 789 svm->vmcb->control.exit_code = exit_code; 789 - svm->vmcb->control.exit_code_hi = 0; 790 790 svm->vmcb->control.exit_info_1 = 0; 791 791 svm->vmcb->control.exit_info_2 = 0; 792 792 return nested_svm_vmexit(svm);
+3 -3
arch/x86/kvm/trace.h
··· 383 383 #define kvm_print_exit_reason(exit_reason, isa) \ 384 384 (isa == KVM_ISA_VMX) ? \ 385 385 __print_symbolic(exit_reason & 0xffff, VMX_EXIT_REASONS) : \ 386 - __print_symbolic(exit_reason, SVM_EXIT_REASONS), \ 386 + __print_symbolic_u64(exit_reason, SVM_EXIT_REASONS), \ 387 387 (isa == KVM_ISA_VMX && exit_reason & ~0xffff) ? " " : "", \ 388 388 (isa == KVM_ISA_VMX) ? \ 389 - __print_flags(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : "" 389 + __print_flags_u64(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : "" 390 390 391 391 #define TRACE_EVENT_KVM_EXIT(name) \ 392 392 TRACE_EVENT(name, \ ··· 781 781 * Tracepoint for #VMEXIT reinjected to the guest 782 782 */ 783 783 TRACE_EVENT(kvm_nested_vmexit_inject, 784 - TP_PROTO(__u32 exit_code, 784 + TP_PROTO(__u64 exit_code, 785 785 __u64 exit_info1, __u64 exit_info2, 786 786 __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa), 787 787 TP_ARGS(exit_code, exit_info1, exit_info2,
+1 -1
include/hyperv/hvgdk.h
··· 281 281 #define HV_VMCB_NESTED_ENLIGHTENMENTS 31 282 282 283 283 /* Synthetic VM-Exit */ 284 - #define HV_SVM_EXITCODE_ENL 0xf0000000 284 + #define HV_SVM_EXITCODE_ENL 0xf0000000ull 285 285 #define HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH (1) 286 286 287 287 /* VM_PARTITION_ASSIST_PAGE */
+1 -2
tools/testing/selftests/kvm/include/x86/svm.h
··· 92 92 u32 int_vector; 93 93 u32 int_state; 94 94 u8 reserved_3[4]; 95 - u32 exit_code; 96 - u32 exit_code_hi; 95 + u64 exit_code; 97 96 u64 exit_info_1; 98 97 u64 exit_info_2; 99 98 u32 exit_int_info;
+2 -2
tools/testing/selftests/kvm/x86/svm_nested_soft_inject_test.c
··· 103 103 104 104 run_guest(vmcb, svm->vmcb_gpa); 105 105 __GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL, 106 - "Expected VMMCAL #VMEXIT, got '0x%x', info1 = '0x%lx, info2 = '0x%lx'", 106 + "Expected VMMCAL #VMEXIT, got '0x%lx', info1 = '0x%lx, info2 = '0x%lx'", 107 107 vmcb->control.exit_code, 108 108 vmcb->control.exit_info_1, vmcb->control.exit_info_2); 109 109 ··· 133 133 134 134 run_guest(vmcb, svm->vmcb_gpa); 135 135 __GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_HLT, 136 - "Expected HLT #VMEXIT, got '0x%x', info1 = '0x%lx, info2 = '0x%lx'", 136 + "Expected HLT #VMEXIT, got '0x%lx', info1 = '0x%lx, info2 = '0x%lx'", 137 137 vmcb->control.exit_code, 138 138 vmcb->control.exit_info_1, vmcb->control.exit_info_2); 139 139