diff options
Diffstat (limited to 'target/i386/kvm')
-rw-r--r-- | target/i386/kvm/kvm-cpu.c | 9 | ||||
-rw-r--r-- | target/i386/kvm/kvm.c | 11 | ||||
-rw-r--r-- | target/i386/kvm/tdx-quote-generator.c | 4 | ||||
-rw-r--r-- | target/i386/kvm/tdx-stub.c | 4 | ||||
-rw-r--r-- | target/i386/kvm/tdx.c | 73 | ||||
-rw-r--r-- | target/i386/kvm/tdx.h | 7 | ||||
-rw-r--r-- | target/i386/kvm/vmsr_energy.c | 9 | ||||
-rw-r--r-- | target/i386/kvm/vmsr_energy.h | 1 |
8 files changed, 94 insertions, 24 deletions
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 16bde4d..89a7953 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -41,6 +41,7 @@ static void kvm_set_guest_phys_bits(CPUState *cs) static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) { X86CPU *cpu = X86_CPU(cs); + X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu); CPUX86State *env = &cpu->env; bool ret; @@ -63,7 +64,7 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) * check/update ucode_rev, phys_bits, guest_phys_bits, mwait * cpu_common_realizefn() (via xcc->parent_realize) */ - if (cpu->max_features) { + if (xcc->max_features) { if (enable_cpu_pm) { if (kvm_has_waitpkg()) { env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; @@ -72,7 +73,7 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) if (env->features[FEAT_1_ECX] & CPUID_EXT_MONITOR) { host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, &cpu->mwait.ecx, &cpu->mwait.edx); - } + } } if (cpu->ucode_rev == 0) { cpu->ucode_rev = @@ -108,7 +109,7 @@ static void kvm_cpu_max_instance_init(X86CPU *cpu) CPUX86State *env = &cpu->env; KVMState *s = kvm_state; - host_cpu_max_instance_init(cpu); + object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort); if (lmce_supported()) { object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort); @@ -216,7 +217,7 @@ static void kvm_cpu_instance_init(CPUState *cs) x86_cpu_apply_props(cpu, kvm_default_props); } - if (cpu->max_features) { + if (xcc->max_features) { kvm_cpu_max_instance_init(cpu); } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 234878c..369626f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -503,8 +503,12 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, * Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts. * We can detect the bug by checking if MSR_IA32_ARCH_CAPABILITIES is * returned by KVM_GET_MSR_INDEX_LIST. + * + * But also, because Windows does not like ARCH_CAPABILITIES on AMD + * mcahines at all, do not show the fake ARCH_CAPABILITIES MSR that + * KVM sets up. */ - if (!has_msr_arch_capabs) { + if (!has_msr_arch_capabs || !(edx & CPUID_7_0_EDX_ARCH_CAPABILITIES)) { ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES; } } else if (function == 7 && index == 1 && reg == R_EAX) { @@ -2259,7 +2263,7 @@ int kvm_arch_init_vcpu(CPUState *cs) cpuid_i = kvm_x86_build_cpuid(env, cpuid_data.entries, cpuid_i); cpuid_data.cpuid.nent = cpuid_i; - if (((env->cpuid_version >> 8)&0xF) >= 6 + if (x86_cpu_family(env->cpuid_version) >= 6 && (env->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) == (CPUID_MCE | CPUID_MCA)) { uint64_t mcg_cap, unsupported_caps; @@ -6182,6 +6186,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) case TDVMCALL_GET_TD_VM_CALL_INFO: tdx_handle_get_tdvmcall_info(cpu, run); break; + case TDVMCALL_SETUP_EVENT_NOTIFY_INTERRUPT: + tdx_handle_setup_event_notify_interrupt(cpu, run); + break; } ret = 0; break; diff --git a/target/i386/kvm/tdx-quote-generator.c b/target/i386/kvm/tdx-quote-generator.c index f59715f..dee8334 100644 --- a/target/i386/kvm/tdx-quote-generator.c +++ b/target/i386/kvm/tdx-quote-generator.c @@ -75,7 +75,9 @@ static void tdx_generate_quote_cleanup(TdxGenerateQuoteTask *task) { timer_del(&task->timer); - g_source_remove(task->watch); + if (task->watch) { + g_source_remove(task->watch); + } qio_channel_close(QIO_CHANNEL(task->sioc), NULL); object_unref(OBJECT(task->sioc)); diff --git a/target/i386/kvm/tdx-stub.c b/target/i386/kvm/tdx-stub.c index 76fee49..1f0e108 100644 --- a/target/i386/kvm/tdx-stub.c +++ b/target/i386/kvm/tdx-stub.c @@ -26,3 +26,7 @@ void tdx_handle_get_quote(X86CPU *cpu, struct kvm_run *run) void tdx_handle_get_tdvmcall_info(X86CPU *cpu, struct kvm_run *run) { } + +void tdx_handle_setup_event_notify_interrupt(X86CPU *cpu, struct kvm_run *run) +{ +} diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index e809e4b..dbf0fa2 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -28,10 +28,13 @@ #include "cpu.h" #include "cpu-internal.h" #include "host-cpu.h" +#include "hw/i386/apic_internal.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" #include "hw/i386/x86.h" #include "hw/i386/tdvf-hob.h" +#include "hw/pci/msi.h" #include "kvm_i386.h" #include "tdx.h" #include "tdx-quote-generator.h" @@ -1123,6 +1126,33 @@ int tdx_parse_tdvf(void *flash_ptr, int size) return tdvf_parse_metadata(&tdx_guest->tdvf, flash_ptr, size); } +static void tdx_inject_interrupt(TdxGuest *tdx) +{ + int ret; + uint32_t apicid, vector; + + qemu_mutex_lock(&tdx->lock); + vector = tdx->event_notify_vector; + apicid = tdx->event_notify_apicid; + qemu_mutex_unlock(&tdx->lock); + if (vector < 32 || vector > 255) { + return; + } + + MSIMessage msg = { + .address = ((apicid & 0xff) << MSI_ADDR_DEST_ID_SHIFT) | + (((uint64_t)apicid & 0xffffff00) << 32), + .data = vector | (APIC_DM_FIXED << MSI_DATA_DELIVERY_MODE_SHIFT), + }; + + ret = kvm_irqchip_send_msi(kvm_state, msg); + if (ret < 0) { + /* In this case, no better way to tell it to guest. Log it. */ + error_report("TDX: injection interrupt %d failed, interrupt lost (%s).", + vector, strerror(-ret)); + } +} + static void tdx_get_quote_completion(TdxGenerateQuoteTask *task) { TdxGuest *tdx = task->opaque; @@ -1154,6 +1184,8 @@ static void tdx_get_quote_completion(TdxGenerateQuoteTask *task) error_report("TDX: get-quote: failed to update GetQuote header."); } + tdx_inject_interrupt(tdx); + g_free(task->send_data); g_free(task->receive_buf); g_free(task); @@ -1256,20 +1288,45 @@ out_free: g_free(task); } +#define SUPPORTED_TDVMCALLINFO_1_R11 (TDG_VP_VMCALL_SUBFUNC_SET_EVENT_NOTIFY_INTERRUPT) +#define SUPPORTED_TDVMCALLINFO_1_R12 (0) + void tdx_handle_get_tdvmcall_info(X86CPU *cpu, struct kvm_run *run) { if (run->tdx.get_tdvmcall_info.leaf != 1) { - return; + return; } - run->tdx.get_tdvmcall_info.r11 = TDG_VP_VMCALL_SUBFUNC_GET_QUOTE; - run->tdx.get_tdvmcall_info.r12 = 0; + run->tdx.get_tdvmcall_info.r11 = (tdx_caps->user_tdvmcallinfo_1_r11 & + SUPPORTED_TDVMCALLINFO_1_R11) | + tdx_caps->kernel_tdvmcallinfo_1_r11; + run->tdx.get_tdvmcall_info.r12 = (tdx_caps->user_tdvmcallinfo_1_r12 & + SUPPORTED_TDVMCALLINFO_1_R12) | + tdx_caps->kernel_tdvmcallinfo_1_r12; run->tdx.get_tdvmcall_info.r13 = 0; run->tdx.get_tdvmcall_info.r14 = 0; + + run->tdx.get_tdvmcall_info.ret = TDG_VP_VMCALL_SUCCESS; +} + +void tdx_handle_setup_event_notify_interrupt(X86CPU *cpu, struct kvm_run *run) +{ + uint64_t vector = run->tdx.setup_event_notify.vector; + + if (vector >= 32 && vector < 256) { + qemu_mutex_lock(&tdx_guest->lock); + tdx_guest->event_notify_vector = vector; + tdx_guest->event_notify_apicid = cpu->apic_id; + qemu_mutex_unlock(&tdx_guest->lock); + run->tdx.setup_event_notify.ret = TDG_VP_VMCALL_SUCCESS; + } else { + run->tdx.setup_event_notify.ret = TDG_VP_VMCALL_INVALID_OPERAND; + } } static void tdx_panicked_on_fatal_error(X86CPU *cpu, uint64_t error_code, - char *message, uint64_t gpa) + char *message, bool has_gpa, + uint64_t gpa) { GuestPanicInformation *panic_info; @@ -1278,6 +1335,7 @@ static void tdx_panicked_on_fatal_error(X86CPU *cpu, uint64_t error_code, panic_info->u.tdx.error_code = (uint32_t) error_code; panic_info->u.tdx.message = message; panic_info->u.tdx.gpa = gpa; + panic_info->u.tdx.has_gpa = has_gpa; qemu_system_guest_panicked(panic_info); } @@ -1297,6 +1355,7 @@ int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run) char *message = NULL; uint64_t *tmp; uint64_t gpa = -1ull; + bool has_gpa = false; if (error_code & 0xffff) { error_report("TDX: REPORT_FATAL_ERROR: invalid error code: 0x%"PRIx64, @@ -1329,9 +1388,10 @@ int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run) if (error_code & TDX_REPORT_FATAL_ERROR_GPA_VALID) { gpa = run->system_event.data[R_R13]; + has_gpa = true; } - tdx_panicked_on_fatal_error(cpu, error_code, message, gpa); + tdx_panicked_on_fatal_error(cpu, error_code, message, has_gpa, gpa); return -1; } @@ -1467,7 +1527,8 @@ static void tdx_guest_init(Object *obj) tdx_guest_set_qgs, NULL, NULL); - qemu_mutex_init(&tdx->lock); + tdx->event_notify_vector = -1; + tdx->event_notify_apicid = -1; } static void tdx_guest_finalize(Object *obj) diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index 35a09c1..1c38faf 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -25,6 +25,7 @@ typedef struct TdxGuestClass { #define TDVMCALL_GET_TD_VM_CALL_INFO 0x10000 #define TDVMCALL_GET_QUOTE 0x10002 +#define TDVMCALL_SETUP_EVENT_NOTIFY_INTERRUPT 0x10004 #define TDG_VP_VMCALL_SUCCESS 0x0000000000000000ULL #define TDG_VP_VMCALL_RETRY 0x0000000000000001ULL @@ -32,7 +33,7 @@ typedef struct TdxGuestClass { #define TDG_VP_VMCALL_GPA_INUSE 0x8000000000000001ULL #define TDG_VP_VMCALL_ALIGN_ERROR 0x8000000000000002ULL -#define TDG_VP_VMCALL_SUBFUNC_GET_QUOTE 0x0000000000000001ULL +#define TDG_VP_VMCALL_SUBFUNC_SET_EVENT_NOTIFY_INTERRUPT BIT_ULL(1) enum TdxRamType { TDX_RAM_UNACCEPTED, @@ -66,6 +67,9 @@ typedef struct TdxGuest { /* GetQuote */ SocketAddress *qg_sock_addr; int num; + + uint32_t event_notify_vector; + uint32_t event_notify_apicid; } TdxGuest; #ifdef CONFIG_TDX @@ -80,5 +84,6 @@ int tdx_parse_tdvf(void *flash_ptr, int size); int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run); void tdx_handle_get_quote(X86CPU *cpu, struct kvm_run *run); void tdx_handle_get_tdvmcall_info(X86CPU *cpu, struct kvm_run *run); +void tdx_handle_setup_event_notify_interrupt(X86CPU *cpu, struct kvm_run *run); #endif /* QEMU_I386_TDX_H */ diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c index d6aad52..58ce3df 100644 --- a/target/i386/kvm/vmsr_energy.c +++ b/target/i386/kvm/vmsr_energy.c @@ -27,15 +27,6 @@ char *vmsr_compute_default_paths(void) return g_build_filename(state, "run", "qemu-vmsr-helper.sock", NULL); } -bool is_host_cpu_intel(void) -{ - char vendor[CPUID_VENDOR_SZ + 1]; - - host_cpu_vendor_fms(vendor, NULL, NULL, NULL); - - return g_str_equal(vendor, CPUID_VENDOR_INTEL); -} - int is_rapl_enabled(void) { const char *path = "/sys/class/powercap/intel-rapl/enabled"; diff --git a/target/i386/kvm/vmsr_energy.h b/target/i386/kvm/vmsr_energy.h index 16cc1f4..151bcbd 100644 --- a/target/i386/kvm/vmsr_energy.h +++ b/target/i386/kvm/vmsr_energy.h @@ -94,6 +94,5 @@ double vmsr_get_ratio(uint64_t e_delta, unsigned long long delta_ticks, unsigned int maxticks); void vmsr_init_topo_info(X86CPUTopoInfo *topo_info, const MachineState *ms); -bool is_host_cpu_intel(void); int is_rapl_enabled(void); #endif /* VMSR_ENERGY_H */ |