i386/kvm: Add save/restore support for CET MSRs

CET (architectural) MSRs include:
MSR_IA32_U_CET - user mode CET control bits.
MSR_IA32_S_CET - supervisor mode CET control bits.
MSR_IA32_PL{0,1,2,3}_SSP - linear addresses of SSPs for user/kernel modes.
MSR_IA32_INT_SSP_TAB - linear address of interrupt SSP table

Since FRED also needs to save/restore MSR_IA32_PL0_SSP, to avoid duplicate
operations, make FRED only save/restore MSR_IA32_PL0_SSP when CET-SHSTK
is not enumerated.

And considerring MSR_IA32_SSP_TBL_ADDR is only presented on 64 bit
processor, wrap it with TARGET_X86_64 macro.

For other MSRs, add save/restore support directly.

Tested-by: Farrah Chen <farrah.chen@intel.com>
Suggested-by: Xin Li (Intel) <xin@zytor.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-15-zhao1.liu@intel.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Yang Weijiang 2025-12-11 14:07:53 +08:00 committed by Paolo Bonzini
parent 0fa1025904
commit b6f85c5e45
2 changed files with 98 additions and 19 deletions

View file

@ -543,7 +543,7 @@ typedef enum X86Seg {
#define MSR_IA32_XFD 0x000001c4
#define MSR_IA32_XFD_ERR 0x000001c5
/* FRED MSRs */
/* FRED MSRs (MSR_IA32_FRED_SSP0 is defined as MSR_IA32_PL0_SSP in CET MSRs) */
#define MSR_IA32_FRED_RSP0 0x000001cc /* Stack level 0 regular stack pointer */
#define MSR_IA32_FRED_RSP1 0x000001cd /* Stack level 1 regular stack pointer */
#define MSR_IA32_FRED_RSP2 0x000001ce /* Stack level 2 regular stack pointer */
@ -554,9 +554,6 @@ typedef enum X86Seg {
#define MSR_IA32_FRED_SSP3 0x000001d3 /* Stack level 3 shadow stack pointer in ring 0 */
#define MSR_IA32_FRED_CONFIG 0x000001d4 /* FRED Entrypoint and interrupt stack level */
/* FRED and CET MSR */
#define MSR_IA32_PL0_SSP 0x000006a4 /* ring-0 shadow stack pointer (aka MSR_IA32_FRED_SSP0 for FRED) */
#define MSR_IA32_BNDCFGS 0x00000d90
#define MSR_IA32_XSS 0x00000da0
#define MSR_IA32_UMWAIT_CONTROL 0xe1
@ -583,6 +580,15 @@ typedef enum X86Seg {
#define MSR_APIC_START 0x00000800
#define MSR_APIC_END 0x000008ff
/* CET MSRs */
#define MSR_IA32_U_CET 0x000006a0 /* user mode cet */
#define MSR_IA32_S_CET 0x000006a2 /* kernel mode cet */
#define MSR_IA32_PL0_SSP 0x000006a4 /* ring-0 shadow stack pointer */
#define MSR_IA32_PL1_SSP 0x000006a5 /* ring-1 shadow stack pointer */
#define MSR_IA32_PL2_SSP 0x000006a6 /* ring-2 shadow stack pointer */
#define MSR_IA32_PL3_SSP 0x000006a7 /* ring-3 shadow stack pointer */
#define MSR_IA32_INT_SSP_TAB 0x000006a8 /* exception shadow stack table */
#define XSTATE_FP_BIT 0
#define XSTATE_SSE_BIT 1
#define XSTATE_YMM_BIT 2
@ -1973,8 +1979,16 @@ typedef struct CPUArchState {
uint64_t fred_config;
#endif
/* MSR used for both FRED and CET (SHSTK) */
uint64_t pl0_ssp;
/* CET MSRs */
uint64_t u_cet;
uint64_t s_cet;
uint64_t pl0_ssp; /* also used for FRED */
uint64_t pl1_ssp;
uint64_t pl2_ssp;
uint64_t pl3_ssp;
#ifdef TARGET_X86_64
uint64_t int_ssp_table;
#endif
uint64_t tsc_adjust;
uint64_t tsc_deadline;

View file

@ -4009,11 +4009,14 @@ static int kvm_put_msrs(X86CPU *cpu, KvmPutState level)
kvm_msr_entry_add(cpu, MSR_IA32_FRED_SSP2, env->fred_ssp2);
kvm_msr_entry_add(cpu, MSR_IA32_FRED_SSP3, env->fred_ssp3);
kvm_msr_entry_add(cpu, MSR_IA32_FRED_CONFIG, env->fred_config);
/*
* Aka MSR_IA32_FRED_SSP0. This MSR is accessible even if
* CET shadow stack is not supported.
*/
kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, env->pl0_ssp);
if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK)) {
/*
* Aka MSR_IA32_FRED_SSP0. This MSR is accessible even if
* CET shadow stack is not supported.
*/
kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, env->pl0_ssp);
}
}
}
#endif
@ -4267,6 +4270,26 @@ static int kvm_put_msrs(X86CPU *cpu, KvmPutState level)
}
}
if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK ||
env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_CET_IBT) {
kvm_msr_entry_add(cpu, MSR_IA32_U_CET, env->u_cet);
kvm_msr_entry_add(cpu, MSR_IA32_S_CET, env->s_cet);
if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK) {
kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, env->pl0_ssp);
kvm_msr_entry_add(cpu, MSR_IA32_PL1_SSP, env->pl1_ssp);
kvm_msr_entry_add(cpu, MSR_IA32_PL2_SSP, env->pl2_ssp);
kvm_msr_entry_add(cpu, MSR_IA32_PL3_SSP, env->pl3_ssp);
#ifdef TARGET_X86_64
if (lm_capable_kernel) {
kvm_msr_entry_add(cpu, MSR_IA32_INT_SSP_TAB,
env->int_ssp_table);
}
#endif
}
}
return kvm_buf_set_msrs(cpu);
}
@ -4501,11 +4524,14 @@ static int kvm_get_msrs(X86CPU *cpu)
kvm_msr_entry_add(cpu, MSR_IA32_FRED_SSP2, 0);
kvm_msr_entry_add(cpu, MSR_IA32_FRED_SSP3, 0);
kvm_msr_entry_add(cpu, MSR_IA32_FRED_CONFIG, 0);
/*
* Aka MSR_IA32_FRED_SSP0. This MSR is accessible even if
* CET shadow stack is not supported.
*/
kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, 0);
if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK)) {
/*
* Aka MSR_IA32_FRED_SSP0. This MSR is accessible even if
* CET shadow stack is not supported.
*/
kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, 0);
}
}
}
#endif
@ -4663,6 +4689,25 @@ static int kvm_get_msrs(X86CPU *cpu)
}
}
if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK ||
env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_CET_IBT) {
kvm_msr_entry_add(cpu, MSR_IA32_U_CET, 0);
kvm_msr_entry_add(cpu, MSR_IA32_S_CET, 0);
if (env->features[FEAT_7_0_EDX] & CPUID_7_0_ECX_CET_SHSTK) {
kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, 0);
kvm_msr_entry_add(cpu, MSR_IA32_PL1_SSP, 0);
kvm_msr_entry_add(cpu, MSR_IA32_PL2_SSP, 0);
kvm_msr_entry_add(cpu, MSR_IA32_PL3_SSP, 0);
#ifdef TARGET_X86_64
if (lm_capable_kernel) {
kvm_msr_entry_add(cpu, MSR_IA32_INT_SSP_TAB, 0);
}
#endif
}
}
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf);
if (ret < 0) {
return ret;
@ -4757,9 +4802,6 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_IA32_FRED_CONFIG:
env->fred_config = msrs[i].data;
break;
case MSR_IA32_PL0_SSP: /* aka MSR_IA32_FRED_SSP0 */
env->pl0_ssp = msrs[i].data;
break;
#endif
case MSR_IA32_TSC:
env->tsc = msrs[i].data;
@ -5013,6 +5055,29 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_ARCH_LBR_INFO_0 ... MSR_ARCH_LBR_INFO_0 + 31:
env->lbr_records[index - MSR_ARCH_LBR_INFO_0].info = msrs[i].data;
break;
case MSR_IA32_U_CET:
env->u_cet = msrs[i].data;
break;
case MSR_IA32_S_CET:
env->s_cet = msrs[i].data;
break;
case MSR_IA32_PL0_SSP: /* aka MSR_IA32_FRED_SSP0 */
env->pl0_ssp = msrs[i].data;
break;
case MSR_IA32_PL1_SSP:
env->pl1_ssp = msrs[i].data;
break;
case MSR_IA32_PL2_SSP:
env->pl2_ssp = msrs[i].data;
break;
case MSR_IA32_PL3_SSP:
env->pl3_ssp = msrs[i].data;
break;
#ifdef TARGET_X86_64
case MSR_IA32_INT_SSP_TAB:
env->int_ssp_table = msrs[i].data;
break;
#endif
case MSR_K7_HWCR:
env->msr_hwcr = msrs[i].data;
break;