Commit 3dd2775b authored by Tom Lendacky's avatar Tom Lendacky Committed by Borislav Petkov
Browse files

KVM: SVM: Create a separate mapping for the SEV-ES save area



The save area for SEV-ES/SEV-SNP guests, as used by the hardware, is
different from the save area of a non SEV-ES/SEV-SNP guest.

This is the first step in defining the multiple save areas to keep them
separate and ensuring proper operation amongst the different types of
guests. Create an SEV-ES/SEV-SNP save area and adjust usage to the new
save area definition where needed.

Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarBrijesh Singh <brijesh.singh@amd.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarVenu Busireddy <venu.busireddy@oracle.com>
Link: https://lore.kernel.org/r/20220405182743.308853-1-brijesh.singh@amd.com
parent 046f773b
Loading
Loading
Loading
Loading
+67 −20
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ struct vmcb_seg {
	u64 base;
} __packed;

/* Save area definition for legacy and SEV-MEM guests */
struct vmcb_save_area {
	struct vmcb_seg es;
	struct vmcb_seg cs;
@@ -287,8 +288,58 @@ struct vmcb_save_area {
	u8 cpl;
	u8 reserved_2[4];
	u64 efer;
	u8 reserved_3[112];
	u64 cr4;
	u64 cr3;
	u64 cr0;
	u64 dr7;
	u64 dr6;
	u64 rflags;
	u64 rip;
	u8 reserved_4[88];
	u64 rsp;
	u64 s_cet;
	u64 ssp;
	u64 isst_addr;
	u64 rax;
	u64 star;
	u64 lstar;
	u64 cstar;
	u64 sfmask;
	u64 kernel_gs_base;
	u64 sysenter_cs;
	u64 sysenter_esp;
	u64 sysenter_eip;
	u64 cr2;
	u8 reserved_5[32];
	u64 g_pat;
	u64 dbgctl;
	u64 br_from;
	u64 br_to;
	u64 last_excp_from;
	u64 last_excp_to;
	u8 reserved_6[72];
	u32 spec_ctrl;		/* Guest version of SPEC_CTRL at 0x2E0 */
} __packed;

/* Save area definition for SEV-ES and SEV-SNP guests */
struct sev_es_save_area {
	struct vmcb_seg es;
	struct vmcb_seg cs;
	struct vmcb_seg ss;
	struct vmcb_seg ds;
	struct vmcb_seg fs;
	struct vmcb_seg gs;
	struct vmcb_seg gdtr;
	struct vmcb_seg ldtr;
	struct vmcb_seg idtr;
	struct vmcb_seg tr;
	u8 reserved_1[43];
	u8 cpl;
	u8 reserved_2[4];
	u64 efer;
	u8 reserved_3[104];
	u64 xss;		/* Valid for SEV-ES only */
	u64 xss;
	u64 cr4;
	u64 cr3;
	u64 cr0;
@@ -316,22 +367,14 @@ struct vmcb_save_area {
	u64 br_to;
	u64 last_excp_from;
	u64 last_excp_to;

	/*
	 * The following part of the save area is valid only for
	 * SEV-ES guests when referenced through the GHCB or for
	 * saving to the host save area.
	 */
	u8 reserved_7[72];
	u32 spec_ctrl;		/* Guest version of SPEC_CTRL at 0x2E0 */
	u8 reserved_7b[4];
	u8 reserved_7[80];
	u32 pkru;
	u8 reserved_7a[20];
	u64 reserved_8;		/* rax already available at 0x01f8 */
	u8 reserved_9[20];
	u64 reserved_10;	/* rax already available at 0x01f8 */
	u64 rcx;
	u64 rdx;
	u64 rbx;
	u64 reserved_9;		/* rsp already available at 0x01d8 */
	u64 reserved_11;	/* rsp already available at 0x01d8 */
	u64 rbp;
	u64 rsi;
	u64 rdi;
@@ -343,23 +386,25 @@ struct vmcb_save_area {
	u64 r13;
	u64 r14;
	u64 r15;
	u8 reserved_10[16];
	u8 reserved_12[16];
	u64 sw_exit_code;
	u64 sw_exit_info_1;
	u64 sw_exit_info_2;
	u64 sw_scratch;
	u64 sev_features;
	u8 reserved_11[48];
	u8 reserved_13[48];
	u64 xcr0;
	u8 valid_bitmap[16];
	u64 x87_state_gpa;
} __packed;

#define GHCB_SHARED_BUF_SIZE	2032

struct ghcb {
	struct vmcb_save_area save;
	u8 reserved_save[2048 - sizeof(struct vmcb_save_area)];
	struct sev_es_save_area save;
	u8 reserved_save[2048 - sizeof(struct sev_es_save_area)];

	u8 shared_buffer[2032];
	u8 shared_buffer[GHCB_SHARED_BUF_SIZE];

	u8 reserved_1[10];
	u16 protocol_version;	/* negotiated SEV-ES/GHCB protocol version */
@@ -367,13 +412,15 @@ struct ghcb {
} __packed;


#define EXPECTED_VMCB_SAVE_AREA_SIZE		1032
#define EXPECTED_VMCB_SAVE_AREA_SIZE		740
#define EXPECTED_SEV_ES_SAVE_AREA_SIZE		1032
#define EXPECTED_VMCB_CONTROL_AREA_SIZE		1024
#define EXPECTED_GHCB_SIZE			PAGE_SIZE

static inline void __unused_size_checks(void)
{
	BUILD_BUG_ON(sizeof(struct vmcb_save_area)	!= EXPECTED_VMCB_SAVE_AREA_SIZE);
	BUILD_BUG_ON(sizeof(struct sev_es_save_area)	!= EXPECTED_SEV_ES_SAVE_AREA_SIZE);
	BUILD_BUG_ON(sizeof(struct vmcb_control_area)	!= EXPECTED_VMCB_CONTROL_AREA_SIZE);
	BUILD_BUG_ON(sizeof(struct ghcb)		!= EXPECTED_GHCB_SIZE);
}
@@ -443,7 +490,7 @@ struct vmcb {
/* GHCB Accessor functions */

#define GHCB_BITMAP_IDX(field)							\
	(offsetof(struct vmcb_save_area, field) / sizeof(u64))
	(offsetof(struct sev_es_save_area, field) / sizeof(u64))

#define DEFINE_GHCB_ACCESSORS(field)						\
	static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb)	\
+11 −11
Original line number Diff line number Diff line
@@ -559,12 +559,20 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)

static int sev_es_sync_vmsa(struct vcpu_svm *svm)
{
	struct vmcb_save_area *save = &svm->vmcb->save;
	struct sev_es_save_area *save = svm->sev_es.vmsa;

	/* Check some debug related fields before encrypting the VMSA */
	if (svm->vcpu.guest_debug || (save->dr7 & ~DR7_FIXED_1))
	if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1))
		return -EINVAL;

	/*
	 * SEV-ES will use a VMSA that is pointed to by the VMCB, not
	 * the traditional VMSA that is part of the VMCB. Copy the
	 * traditional VMSA as it has been built so far (in prep
	 * for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state.
	 */
	memcpy(save, &svm->vmcb->save, sizeof(svm->vmcb->save));

	/* Sync registgers */
	save->rax = svm->vcpu.arch.regs[VCPU_REGS_RAX];
	save->rbx = svm->vcpu.arch.regs[VCPU_REGS_RBX];
@@ -592,14 +600,6 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm)
	save->xss  = svm->vcpu.arch.ia32_xss;
	save->dr6  = svm->vcpu.arch.dr6;

	/*
	 * SEV-ES will use a VMSA that is pointed to by the VMCB, not
	 * the traditional VMSA that is part of the VMCB. Copy the
	 * traditional VMSA as it has been built so far (in prep
	 * for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state.
	 */
	memcpy(svm->sev_es.vmsa, save, sizeof(*save));

	return 0;
}

@@ -2932,7 +2932,7 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm)
					    sev_enc_bit));
}

void sev_es_prepare_switch_to_guest(struct vmcb_save_area *hostsa)
void sev_es_prepare_switch_to_guest(struct sev_es_save_area *hostsa)
{
	/*
	 * As an SEV-ES guest, hardware will restore the host state on VMEXIT,
+2 −2
Original line number Diff line number Diff line
@@ -1270,8 +1270,8 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
	 */
	vmsave(__sme_page_pa(sd->save_area));
	if (sev_es_guest(vcpu->kvm)) {
		struct vmcb_save_area *hostsa;
		hostsa = (struct vmcb_save_area *)(page_address(sd->save_area) + 0x400);
		struct sev_es_save_area *hostsa;
		hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400);

		sev_es_prepare_switch_to_guest(hostsa);
	}
+2 −2
Original line number Diff line number Diff line
@@ -181,7 +181,7 @@ struct svm_nested_state {

struct vcpu_sev_es_state {
	/* SEV-ES support */
	struct vmcb_save_area *vmsa;
	struct sev_es_save_area *vmsa;
	struct ghcb *ghcb;
	struct kvm_host_map ghcb_map;
	bool received_first_sipi;
@@ -620,7 +620,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);
void sev_es_init_vmcb(struct vcpu_svm *svm);
void sev_es_vcpu_reset(struct vcpu_svm *svm);
void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
void sev_es_prepare_switch_to_guest(struct vmcb_save_area *hostsa);
void sev_es_prepare_switch_to_guest(struct sev_es_save_area *hostsa);
void sev_es_unmap_ghcb(struct vcpu_svm *svm);

/* vmenter.S */