Convert TDG.VP.VMCALL<ReportFatalError> to KVM_EXIT_SYSTEM_EVENT with a new type KVM_SYSTEM_EVENT_TDX_FATAL and forward it to userspace for handling. TD guest can use TDG.VP.VMCALL<ReportFatalError> to report the fatal error it has experienced. This hypercall is special because TD guest is requesting a termination with the error information, KVM needs to forward the hypercall to userspace anyway, KVM doesn't do parsing or conversion, it just dumps the 16 general-purpose registers to userspace and let userspace decide what to do.
Unified · Split
| @@ -6823,6 +6823,7 @@ should put the acknowledged interrupt vector into the 'epr' field. · 6822 unmodified lines | ||
| 6823 | 6823 | #define KVM_SYSTEM_EVENT_WAKEUP 4 |
| 6824 | 6824 | #define KVM_SYSTEM_EVENT_SUSPEND 5 |
| 6825 | 6825 | #define KVM_SYSTEM_EVENT_SEV_TERM 6 |
| 6826 | + #define KVM_SYSTEM_EVENT_TDX_FATAL 7 | |
| 6826 | 6827 | __u32 type; |
| 6827 | 6828 | __u32 ndata; |
| 6828 | 6829 | __u64 data[16]; |
| @@ -6849,6 +6850,11 @@ Valid values for 'type' are: · 20 unmodified lines | ||
| 6849 | 6850 | reset/shutdown of the VM. |
| 6850 | 6851 | - KVM_SYSTEM_EVENT_SEV_TERM -- an AMD SEV guest requested termination. |
| 6851 | 6852 | The guest physical address of the guest's GHCB is stored in `data[0]`. |
| 6853 | + - KVM_SYSTEM_EVENT_TDX_FATAL -- a TDX guest reported a fatal error state. | |
| 6854 | + KVM doesn't do any parsing or conversion, it just dumps 16 general-purpose | |
| 6855 | + registers to userspace, in ascending order of the 4-bit indices for x86-64 | |
| 6856 | + general-purpose registers in instruction encoding, as defined in the Intel | |
| 6857 | + SDM. | |
| 6852 | 6858 | - KVM_SYSTEM_EVENT_WAKEUP -- the exiting vCPU is in a suspended state and |
| 6853 | 6859 | KVM has recognized a wakeup event. Userspace may honor this event by |
| 6854 | 6860 | marking the exiting vCPU as runnable, or deny it and call KVM_RUN again. |
| @@ -1104,11 +1104,39 @@ error: · 1103 unmodified lines | ||
| 1104 | 1104 | return 1; |
| 1105 | 1105 | } |
| 1106 | 1106 | |
| 1107 | +static int tdx_report_fatal_error(struct kvm_vcpu *vcpu) | |
| 1108 | +{ | |
| 1109 | + struct vcpu_tdx *tdx = to_tdx(vcpu); | |
| 1110 | + u64 *regs = vcpu->run->system_event.data; | |
| 1111 | + u64 *module_regs = &tdx->vp_enter_args.r8; | |
| 1112 | + int index = VCPU_REGS_RAX; | |
| 1113 | + | |
| 1114 | + vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; | |
| 1115 | + vcpu->run->system_event.type = KVM_SYSTEM_EVENT_TDX_FATAL; | |
| 1116 | + vcpu->run->system_event.ndata = 16; | |
| 1117 | + | |
| 1118 | + /* Dump 16 general-purpose registers to userspace in ascending order. */ | |
| 1119 | + regs[index++] = tdx->vp_enter_ret; | |
| 1120 | + regs[index++] = tdx->vp_enter_args.rcx; | |
| 1121 | + regs[index++] = tdx->vp_enter_args.rdx; | |
| 1122 | + regs[index++] = tdx->vp_enter_args.rbx; | |
| 1123 | + regs[index++] = 0; | |
| 1124 | + regs[index++] = 0; | |
| 1125 | + regs[index++] = tdx->vp_enter_args.rsi; | |
| 1126 | + regs[index] = tdx->vp_enter_args.rdi; | |
| 1127 | + for (index = 0; index < 8; index++) | |
| 1128 | + regs[VCPU_REGS_R8 + index] = module_regs[index]; | |
| 1129 | + | |
| 1130 | + return 0; | |
| 1131 | +} | |
| 1132 | + | |
| 1107 | 1133 | static int handle_tdvmcall(struct kvm_vcpu *vcpu) |
| 1108 | 1134 | { |
| 1109 | 1135 | switch (tdvmcall_leaf(vcpu)) { |
| 1110 | 1136 | case TDVMCALL_MAP_GPA: |
| 1111 | 1137 | return tdx_map_gpa(vcpu); |
| 1138 | + case TDVMCALL_REPORT_FATAL_ERROR: | |
| 1139 | + return tdx_report_fatal_error(vcpu); | |
| 1112 | 1140 | default: |
| 1113 | 1141 | break; |
| 1114 | 1142 | } |
| @@ -375,6 +375,7 @@ struct kvm_run { · 374 unmodified lines | ||
| 375 | 375 | #define KVM_SYSTEM_EVENT_WAKEUP 4 |
| 376 | 376 | #define KVM_SYSTEM_EVENT_SUSPEND 5 |
| 377 | 377 | #define KVM_SYSTEM_EVENT_SEV_TERM 6 |
| 378 | +#define KVM_SYSTEM_EVENT_TDX_FATAL 7 | |
| 378 | 379 | __u32 type; |
| 379 | 380 | __u32 ndata; |
| 380 | 381 | union { |