Save/restore the SGX Launch Enclave Public Key Hash MSRs if SGX Launch Control (LC) is exposed to the guest. KVM advertises SGX LC via CPUID if and only if the MSRs are writable. KVM also resets the MSRs to a constant value (Intel's Skylake era key) when SGX LC is fully enabled, i.e. the vCPU MSRs won't be set to a random or hardware specific value. Likewise, migrate the MSRs if they are exposed to the guest. Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> --- target/i386/cpu.h | 1 + target/i386/kvm.c | 21 +++++++++++++++++++++ target/i386/machine.c | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 4139c94669..a4161b6d2b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1247,6 +1247,7 @@ typedef struct CPUX86State { uint64_t mcg_status; uint64_t msr_ia32_misc_enable; uint64_t msr_ia32_feature_control; + uint64_t msr_ia32_sgxlepubkeyhash[4]; uint64_t msr_fixed_ctr_ctrl; uint64_t msr_global_ctrl; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index dbbb13772a..07565820bd 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -2643,6 +2643,17 @@ static int kvm_put_msrs(X86CPU *cpu, int level) } } + if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC) { + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH0, + env->msr_ia32_sgxlepubkeyhash[0]); + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH1, + env->msr_ia32_sgxlepubkeyhash[1]); + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH2, + env->msr_ia32_sgxlepubkeyhash[2]); + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3, + env->msr_ia32_sgxlepubkeyhash[3]); + } + /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see * kvm_put_msr_feature_control. */ } @@ -2978,6 +2989,13 @@ static int kvm_get_msrs(X86CPU *cpu) } } + if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC) { + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH0, 0); + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH1, 0); + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH2, 0); + kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3, 0); + } + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); if (ret < 0) { return ret; @@ -3251,6 +3269,9 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B: env->msr_rtit_addrs[index - MSR_IA32_RTIT_ADDR0_A] = msrs[i].data; break; + case MSR_IA32_SGXLEPUBKEYHASH0 ... MSR_IA32_SGXLEPUBKEYHASH3: + env->msr_ia32_sgxlepubkeyhash[index - MSR_IA32_SGXLEPUBKEYHASH0] = msrs[i].data; + break; } } diff --git a/target/i386/machine.c b/target/i386/machine.c index b1146093b5..12e93c5b73 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1257,6 +1257,25 @@ static const VMStateDescription vmstate_efer32 = { }; #endif +static bool intel_sgx_msrs_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return !!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC); +} + +static const VMStateDescription vmstate_msr_intel_sgx = { + .name = "cpu/intel_sgx", + .version_id = 1, + .minimum_version_id = 1, + .needed = intel_sgx_msrs_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64_ARRAY(env.msr_ia32_sgxlepubkeyhash, X86CPU, 4), + VMSTATE_END_OF_LIST() + } +}; + VMStateDescription vmstate_x86_cpu = { .name = "cpu", .version_id = 12, @@ -1389,6 +1408,7 @@ VMStateDescription vmstate_x86_cpu = { #ifdef CONFIG_KVM &vmstate_nested_state, #endif + &vmstate_msr_intel_sgx, NULL } }; -- 2.22.0