Skip to content

Commit 376c6d2

Browse files
tlendackybonzini
authored andcommitted
KVM: SVM: Provide support for SEV-ES vCPU creation/loading
An SEV-ES vCPU requires additional VMCB initialization requirements for vCPU creation and vCPU load/put requirements. This includes: General VMCB initialization changes: - Set a VMCB control bit to enable SEV-ES support on the vCPU. - Set the VMCB encrypted VM save area address. - CRx registers are part of the encrypted register state and cannot be updated. Remove the CRx register read and write intercepts and replace them with CRx register write traps to track the CRx register values. - Certain MSR values are part of the encrypted register state and cannot be updated. Remove certain MSR intercepts (EFER, CR_PAT, etc.). - Remove the #GP intercept (no support for "enable_vmware_backdoor"). - Remove the XSETBV intercept since the hypervisor cannot modify XCR0. General vCPU creation changes: - Set the initial GHCB gpa value as per the GHCB specification. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Message-Id: <3a8aef366416eddd5556dfa3fdc212aafa1ad0a2.1607620209.git.thomas.lendacky@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 80675b3 commit 376c6d2

4 files changed

Lines changed: 92 additions & 5 deletions

File tree

arch/x86/include/asm/svm.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ enum {
9898
INTERCEPT_MWAIT_COND,
9999
INTERCEPT_XSETBV,
100100
INTERCEPT_RDPRU,
101+
TRAP_EFER_WRITE,
102+
TRAP_CR0_WRITE,
103+
TRAP_CR1_WRITE,
104+
TRAP_CR2_WRITE,
105+
TRAP_CR3_WRITE,
106+
TRAP_CR4_WRITE,
107+
TRAP_CR5_WRITE,
108+
TRAP_CR6_WRITE,
109+
TRAP_CR7_WRITE,
110+
TRAP_CR8_WRITE,
101111
/* Byte offset 014h (word 5) */
102112
INTERCEPT_INVLPGB = 160,
103113
INTERCEPT_INVLPGB_ILLEGAL,
@@ -144,6 +154,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
144154
u8 reserved_6[8]; /* Offset 0xe8 */
145155
u64 avic_logical_id; /* Offset 0xf0 */
146156
u64 avic_physical_id; /* Offset 0xf8 */
157+
u8 reserved_7[8];
158+
u64 vmsa_pa; /* Used for an SEV-ES guest */
147159
};
148160

149161

@@ -198,6 +210,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
198210

199211
#define SVM_NESTED_CTL_NP_ENABLE BIT(0)
200212
#define SVM_NESTED_CTL_SEV_ENABLE BIT(1)
213+
#define SVM_NESTED_CTL_SEV_ES_ENABLE BIT(2)
201214

202215
struct vmcb_seg {
203216
u16 selector;
@@ -295,7 +308,7 @@ struct ghcb {
295308

296309

297310
#define EXPECTED_VMCB_SAVE_AREA_SIZE 1032
298-
#define EXPECTED_VMCB_CONTROL_AREA_SIZE 256
311+
#define EXPECTED_VMCB_CONTROL_AREA_SIZE 272
299312
#define EXPECTED_GHCB_SIZE PAGE_SIZE
300313

301314
static inline void __unused_size_checks(void)

arch/x86/kvm/svm/sev.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,3 +1796,59 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
17961796
return kvm_sev_es_string_io(&svm->vcpu, size, port,
17971797
svm->ghcb_sa, svm->ghcb_sa_len, in);
17981798
}
1799+
1800+
void sev_es_init_vmcb(struct vcpu_svm *svm)
1801+
{
1802+
struct kvm_vcpu *vcpu = &svm->vcpu;
1803+
1804+
svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ES_ENABLE;
1805+
svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK;
1806+
1807+
/*
1808+
* An SEV-ES guest requires a VMSA area that is a separate from the
1809+
* VMCB page. Do not include the encryption mask on the VMSA physical
1810+
* address since hardware will access it using the guest key.
1811+
*/
1812+
svm->vmcb->control.vmsa_pa = __pa(svm->vmsa);
1813+
1814+
/* Can't intercept CR register access, HV can't modify CR registers */
1815+
svm_clr_intercept(svm, INTERCEPT_CR0_READ);
1816+
svm_clr_intercept(svm, INTERCEPT_CR4_READ);
1817+
svm_clr_intercept(svm, INTERCEPT_CR8_READ);
1818+
svm_clr_intercept(svm, INTERCEPT_CR0_WRITE);
1819+
svm_clr_intercept(svm, INTERCEPT_CR4_WRITE);
1820+
svm_clr_intercept(svm, INTERCEPT_CR8_WRITE);
1821+
1822+
svm_clr_intercept(svm, INTERCEPT_SELECTIVE_CR0);
1823+
1824+
/* Track EFER/CR register changes */
1825+
svm_set_intercept(svm, TRAP_EFER_WRITE);
1826+
svm_set_intercept(svm, TRAP_CR0_WRITE);
1827+
svm_set_intercept(svm, TRAP_CR4_WRITE);
1828+
svm_set_intercept(svm, TRAP_CR8_WRITE);
1829+
1830+
/* No support for enable_vmware_backdoor */
1831+
clr_exception_intercept(svm, GP_VECTOR);
1832+
1833+
/* Can't intercept XSETBV, HV can't modify XCR0 directly */
1834+
svm_clr_intercept(svm, INTERCEPT_XSETBV);
1835+
1836+
/* Clear intercepts on selected MSRs */
1837+
set_msr_interception(vcpu, svm->msrpm, MSR_EFER, 1, 1);
1838+
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_CR_PAT, 1, 1);
1839+
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1);
1840+
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1);
1841+
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 1, 1);
1842+
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 1, 1);
1843+
}
1844+
1845+
void sev_es_create_vcpu(struct vcpu_svm *svm)
1846+
{
1847+
/*
1848+
* Set the GHCB MSR value as per the GHCB specification when creating
1849+
* a vCPU for an SEV-ES guest.
1850+
*/
1851+
set_ghcb_msr(svm, GHCB_MSR_SEV_INFO(GHCB_VERSION_MAX,
1852+
GHCB_VERSION_MIN,
1853+
sev_enc_bit));
1854+
}

arch/x86/kvm/svm/svm.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static DEFINE_PER_CPU(u64, current_tsc_ratio);
9090

9191
static const struct svm_direct_access_msrs {
9292
u32 index; /* Index of the MSR */
93-
bool always; /* True if intercept is always on */
93+
bool always; /* True if intercept is initially cleared */
9494
} direct_access_msrs[MAX_DIRECT_ACCESS_MSRS] = {
9595
{ .index = MSR_STAR, .always = true },
9696
{ .index = MSR_IA32_SYSENTER_CS, .always = true },
@@ -108,6 +108,9 @@ static const struct svm_direct_access_msrs {
108108
{ .index = MSR_IA32_LASTBRANCHTOIP, .always = false },
109109
{ .index = MSR_IA32_LASTINTFROMIP, .always = false },
110110
{ .index = MSR_IA32_LASTINTTOIP, .always = false },
111+
{ .index = MSR_EFER, .always = false },
112+
{ .index = MSR_IA32_CR_PAT, .always = false },
113+
{ .index = MSR_AMD64_SEV_ES_GHCB, .always = true },
111114
{ .index = MSR_INVALID, .always = false },
112115
};
113116

@@ -676,8 +679,8 @@ static void set_msr_interception_bitmap(struct kvm_vcpu *vcpu, u32 *msrpm,
676679
msrpm[offset] = tmp;
677680
}
678681

679-
static void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
680-
int read, int write)
682+
void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
683+
int read, int write)
681684
{
682685
set_shadow_msr_intercept(vcpu, msr, read, write);
683686
set_msr_interception_bitmap(vcpu, msrpm, msr, read, write);
@@ -1263,6 +1266,11 @@ static void init_vmcb(struct vcpu_svm *svm)
12631266
if (sev_guest(svm->vcpu.kvm)) {
12641267
svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ENABLE;
12651268
clr_exception_intercept(svm, UD_VECTOR);
1269+
1270+
if (sev_es_guest(svm->vcpu.kvm)) {
1271+
/* Perform SEV-ES specific VMCB updates */
1272+
sev_es_init_vmcb(svm);
1273+
}
12661274
}
12671275

12681276
vmcb_mark_all_dirty(svm->vmcb);
@@ -1356,6 +1364,10 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
13561364
svm_init_osvw(vcpu);
13571365
vcpu->arch.microcode_version = 0x01000065;
13581366

1367+
if (sev_es_guest(svm->vcpu.kvm))
1368+
/* Perform SEV-ES specific VMCB creation updates */
1369+
sev_es_create_vcpu(svm);
1370+
13591371
return 0;
13601372

13611373
error_free_vmsa_page:
@@ -1451,6 +1463,7 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
14511463
loadsegment(gs, svm->host.gs);
14521464
#endif
14531465
#endif
1466+
14541467
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
14551468
wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
14561469
}
@@ -3101,6 +3114,7 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
31013114
pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page);
31023115
pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id);
31033116
pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id);
3117+
pr_err("%-20s%016llx\n", "vmsa_pa:", control->vmsa_pa);
31043118
pr_err("VMCB State Save Area:\n");
31053119
pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
31063120
"es:",

arch/x86/kvm/svm/svm.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static const u32 host_save_user_msrs[] = {
3434

3535
#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
3636

37-
#define MAX_DIRECT_ACCESS_MSRS 15
37+
#define MAX_DIRECT_ACCESS_MSRS 18
3838
#define MSRPM_OFFSETS 16
3939
extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
4040
extern bool npt_enabled;
@@ -417,6 +417,8 @@ bool svm_nmi_blocked(struct kvm_vcpu *vcpu);
417417
bool svm_interrupt_blocked(struct kvm_vcpu *vcpu);
418418
void svm_set_gif(struct vcpu_svm *svm, bool value);
419419
int svm_invoke_exit_handler(struct vcpu_svm *svm, u64 exit_code);
420+
void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
421+
int read, int write);
420422

421423
/* nested.c */
422424

@@ -576,5 +578,7 @@ void sev_hardware_teardown(void);
576578
void sev_free_vcpu(struct kvm_vcpu *vcpu);
577579
int sev_handle_vmgexit(struct vcpu_svm *svm);
578580
int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);
581+
void sev_es_init_vmcb(struct vcpu_svm *svm);
582+
void sev_es_create_vcpu(struct vcpu_svm *svm);
579583

580584
#endif

0 commit comments

Comments
 (0)