Browse Source

i386/kvm: Add save/restore support for KVM_REG_GUEST_SSP

CET provides a new architectural register, shadow stack pointer (SSP),
which cannot be directly encoded as a source, destination or memory
operand in instructions. But Intel VMCS & VMCB provide fields to
save/load guest & host's ssp.

It's necessary to save & restore Guest's ssp before & after migration.
To support this, KVM implements Guest's SSP as a special KVM internal
register - KVM_REG_GUEST_SSP, and allows QEMU to save & load it via
KVM_GET_ONE_REG/KVM_SET_ONE_REG.

Cache KVM_REG_GUEST_SSP in X86CPUState.

Tested-by: Farrah Chen <farrah.chen@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
Co-developed-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Co-developed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Link: https://lore.kernel.org/r/20251211060801.3600039-16-zhao1.liu@intel.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
pull/316/head
Yang Weijiang 8 months ago
committed by Paolo Bonzini
parent
commit
b775eff300
  1. 3
      target/i386/cpu.h
  2. 39
      target/i386/kvm/kvm.c

3
target/i386/cpu.h

@ -1979,7 +1979,7 @@ typedef struct CPUArchState {
uint64_t fred_config;
#endif
/* CET MSRs */
/* CET MSRs and register */
uint64_t u_cet;
uint64_t s_cet;
uint64_t pl0_ssp; /* also used for FRED */
@ -1989,6 +1989,7 @@ typedef struct CPUArchState {
#ifdef TARGET_X86_64
uint64_t int_ssp_table;
#endif
uint64_t guest_ssp;
uint64_t tsc_adjust;
uint64_t tsc_deadline;

39
target/i386/kvm/kvm.c

@ -4293,6 +4293,35 @@ static int kvm_put_msrs(X86CPU *cpu, KvmPutState level)
return kvm_buf_set_msrs(cpu);
}
static int kvm_put_kvm_regs(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
int ret;
if ((env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK)) {
ret = kvm_set_one_reg(CPU(cpu), KVM_X86_REG_KVM(KVM_REG_GUEST_SSP),
&env->guest_ssp);
if (ret) {
return ret;
}
}
return 0;
}
static int kvm_get_kvm_regs(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
int ret;
if ((env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK)) {
ret = kvm_get_one_reg(CPU(cpu), KVM_X86_REG_KVM(KVM_REG_GUEST_SSP),
&env->guest_ssp);
if (ret) {
return ret;
}
}
return 0;
}
static int kvm_get_xsave(X86CPU *cpu)
{
@ -5446,6 +5475,11 @@ int kvm_arch_put_registers(CPUState *cpu, KvmPutState level, Error **errp)
error_setg_errno(errp, -ret, "Failed to set MSRs");
return ret;
}
ret = kvm_put_kvm_regs(x86_cpu);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to set KVM type registers");
return ret;
}
ret = kvm_put_vcpu_events(x86_cpu, level);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to set vCPU events");
@ -5518,6 +5552,11 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
error_setg_errno(errp, -ret, "Failed to get MSRs");
goto out;
}
ret = kvm_get_kvm_regs(cpu);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to get KVM type registers");
goto out;
}
ret = kvm_get_apic(cpu);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to get APIC");

Loading…
Cancel
Save