Index | Thread | Search

From:
Hans-Jörg Höxer <hshoexer@genua.de>
Subject:
SEV-ES: vmm(4): Allocate VMSA
To:
<tech@openbsd.org>
Cc:
<Hans-Joerg_Hoexer@genua.de>
Date:
Tue, 15 Apr 2025 14:52:59 +0200

Download raw body.

Thread
Hi,

as a first step towards SEV-ES let vmm(4) allocate the VM Save Area.
It will be used by the CPU to store and load encrypted vCPU state.

Non SEV-ES VMs are not affected by this change.

A seconde diff will provide the psp(4) related pieces to prepare the VMSA.

Comments?

Take care,
HJ.
---------------------------------------------------------------------------
commit ad3a54885df560a678b3dfb5112b19ed603b6bbc
Author: Hans-Joerg Hoexer <hshoexer@genua.de>
Date:   Mon Apr 14 16:41:14 2025 +0200

    vmm: provide VMSA
    
    For SEV-ES the hypervisor has to provide a VM Save Area (VMSA).  It
    will be used by the CPU to load and store encrypted guest CPU state.
    
    Also supply a helpfer function to retrieve the physical address of
    the VMSA.

diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c
index e3205f48eed..5a8c9a14612 100644
--- a/sys/arch/amd64/amd64/vmm_machdep.c
+++ b/sys/arch/amd64/amd64/vmm_machdep.c
@@ -138,6 +138,7 @@ void vmx_setmsrbw(struct vcpu *, uint32_t);
 void vmx_setmsrbrw(struct vcpu *, uint32_t);
 void svm_set_clean(struct vcpu *, uint32_t);
 void svm_set_dirty(struct vcpu *, uint32_t);
+int svm_get_vmsa_pa(uint32_t, uint32_t, uint64_t *);
 
 int vmm_gpa_is_valid(struct vcpu *vcpu, paddr_t gpa, size_t obj_size);
 void vmm_init_pvclock(struct vcpu *, paddr_t);
@@ -2849,8 +2850,31 @@ vcpu_init_svm(struct vcpu *vcpu, struct vm_create_params *vcp)
 	    (uint64_t)vcpu->vc_svm_ioio_va,
 	    (uint64_t)vcpu->vc_svm_ioio_pa);
 
-	/* Shall we enable SEV? */
+	/* Shall we enable SEV/SEV-ES? */
 	vcpu->vc_sev = vcp->vcp_sev;
+	vcpu->vc_seves = vcp->vcp_seves;
+
+	if (vcpu->vc_seves) {
+		/* Allocate VM save area VA */
+		vcpu->vc_svm_vmsa_va = (vaddr_t)km_alloc(PAGE_SIZE, &kv_page,
+		   &kp_zero, &kd_waitok);
+
+		if (!vcpu->vc_svm_vmsa_va) {
+			ret = ENOMEM;
+			goto exit;
+		}
+
+		/* Compute VM save area PA */
+		if (!pmap_extract(pmap_kernel(), vcpu->vc_svm_vmsa_va,
+		    &vcpu->vc_svm_vmsa_pa)) {
+			ret = ENOMEM;
+			goto exit;
+		}
+
+		DPRINTF("%s: VMSA va @ 0x%llx, pa @ 0x%llx\n", __func__,
+		    (uint64_t)vcpu->vc_svm_vmsa_va,
+		    (uint64_t)vcpu->vc_svm_vmsa_pa);
+	}
 
 	/* Inform vmd(8) about ASID and C bit position. */
 	vcp->vcp_poscbit = amd64_pos_cbit;
@@ -2957,6 +2981,11 @@ vcpu_deinit_svm(struct vcpu *vcpu)
 		    &kp_zero);
 		vcpu->vc_svm_hsa_va = 0;
 	}
+	if (vcpu->vc_svm_vmsa_va) {
+		km_free((void *)vcpu->vc_svm_vmsa_va, PAGE_SIZE, &kv_page,
+		    &kp_zero);
+		vcpu->vc_svm_vmsa_va = 0;
+	}
 	if (vcpu->vc_svm_ioio_va) {
 		km_free((void *)vcpu->vc_svm_ioio_va, 3 * PAGE_SIZE, &kv_any,
 		    &vmm_kp_contig);
@@ -6779,6 +6808,36 @@ vcpu_state_decode(u_int state)
 	}
 }
 
+/*
+ * svm_get_vmsa_pa
+ *
+ * Return physical address of VMSA for specified VCPU.
+ */
+int
+svm_get_vmsa_pa(uint32_t vmid, uint32_t vcpuid, uint64_t *vmsapa)
+{
+	struct vm	*vm;
+	struct vcpu	*vcpu;
+	int		 error, ret = 0;
+
+	error = vm_find(vmid, &vm);
+	if (error)
+		return (error);
+
+	vcpu = vm_find_vcpu(vm, vcpuid);
+	if (vcpu == NULL || !vcpu->vc_seves) {
+		ret = ENOENT;
+		goto out;
+	}
+
+	if (vmsapa)
+		*vmsapa = vcpu->vc_svm_vmsa_pa;
+
+out:
+	refcnt_rele_wake(&vm->vm_refcnt);
+	return (ret);
+}
+
 #ifdef VMM_DEBUG
 /*
  * dump_vcpu
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index cd04fe4f07b..b1a8451792f 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -668,6 +668,8 @@ struct vmcb {
 			uint64_t	v_pad5;			/* 0E8h-0EFh */
 			uint64_t	v_avic_logical_table;	/* 0F0h */
 			uint64_t	v_avic_phys;		/* 0F8h */
+			uint64_t	v_pad12;		/* 100h */
+			uint64_t	v_vmsa_pa;		/* 108h */
 
 		};
 		uint8_t			vmcb_control[0x400];
@@ -723,6 +725,128 @@ struct vmcb {
 	};
 };
 
+struct vmsa {
+		struct vmcb_segment	v_es;		/* 000h */
+		struct vmcb_segment	v_cs;		/* 010h */
+		struct vmcb_segment	v_ss;		/* 020h */
+		struct vmcb_segment	v_ds;		/* 030h */
+		struct vmcb_segment	v_fs;		/* 040h */
+		struct vmcb_segment	v_gs;		/* 050h */
+		struct vmcb_segment	v_gdtr;		/* 060h */
+		struct vmcb_segment	v_ldtr;		/* 070h */
+		struct vmcb_segment	v_idtr;		/* 080h */
+		struct vmcb_segment	v_tr;		/* 090h */
+		uint64_t		v_pl0_ssp;	/* 0A0h */
+		uint64_t		v_pl1_ssp;	/* 0A8h */
+		uint64_t		v_pl2_ssp;	/* 0B0h */
+		uint64_t		v_pl3_ssp;	/* 0B8h */
+		uint64_t		v_u_cet;	/* 0C0h */
+		uint8_t			v_pad1[0x2];	/* 0C8h-0C9h */
+		uint8_t			v_vmpl;		/* 0CAh */
+		uint8_t			v_cpl;		/* 0CBh */
+		uint8_t			v_pad2[0x4];	/* 0CCh-0CFh */
+		uint64_t		v_efer;		/* 0D0h */
+		uint8_t			v_pad3[0x68];	/* 0D8h-13Fh */
+		uint64_t		v_xss;		/* 140h */
+		uint64_t		v_cr4;		/* 148h */
+		uint64_t		v_cr3;		/* 150h */
+		uint64_t		v_cr0;		/* 158h */
+		uint64_t		v_dr7;		/* 160h */
+		uint64_t		v_dr6;		/* 168h */
+		uint64_t		v_rflags;	/* 170h */
+		uint64_t		v_rip;		/* 178h */
+		uint64_t		v_dr0;		/* 180h */
+		uint64_t		v_dr1;		/* 188h */
+		uint64_t		v_dr2;		/* 190h */
+		uint64_t		v_dr3;		/* 198h */
+		uint64_t		v_dr0_addr_msk;	/* 1A0h */
+		uint64_t		v_dr1_addr_msk;	/* 1A8h */
+		uint64_t		v_dr2_addr_msk; /* 1B0h */
+		uint64_t		v_dr3_addr_msk; /* 1B8h */
+		uint8_t			v_pad4[0x18];	/* 1C0h-1D7h */
+		uint64_t		v_rsp;		/* 1D8h */
+		uint64_t		v_s_cet;	/* 1E0h */
+		uint64_t		v_ssp;		/* 1E8h */
+		uint64_t		v_isst_addr;	/* 1F0h */
+		uint64_t		v_rax;		/* 1F8h */
+		uint64_t		v_star;		/* 200h */
+		uint64_t		v_lstar;	/* 208h */
+		uint64_t		v_cstar;	/* 210h */
+		uint64_t		v_sfmask;	/* 218h */
+		uint64_t		v_kgsbase;	/* 220h */
+		uint64_t		v_sysenter_cs;	/* 228h */
+		uint64_t		v_sysenter_esp;	/* 230h */
+		uint64_t		v_sysenter_eip;	/* 238h */
+		uint64_t		v_cr2;		/* 240h */
+		uint8_t			v_pad5[0x20];	/* 248h-267h */
+		uint64_t		v_g_pat;	/* 268h */
+		uint64_t		v_dbgctl;	/* 270h */
+		uint64_t		v_br_from;	/* 278h */
+		uint64_t		v_br_to;	/* 280h */
+		uint64_t		v_lastexcpfrom;	/* 288h */
+		uint64_t		v_lastexcpto;	/* 290h */
+		uint8_t			v_pad6[0x48];	/* 298h-2DFh */
+		uint8_t			v_pad7[0x8];	/* 2E0h-2E7h */
+		uint32_t		v_pkru;		/* 2E8h */
+		uint32_t		v_tsc_aux;	/* 2ECh */
+		uint64_t		v_gst_tsc_scale;/* 2F0h */
+		uint64_t		v_gst_tsc_off;	/* 2F8h */
+		uint64_t		v_reg_prot_nce;	/* 300h */
+		uint64_t		v_rcx;		/* 308h */
+		uint64_t		v_rdx;		/* 310h */
+		uint64_t		v_rbx;		/* 318h */
+		uint64_t		v_pad8;		/* 320h */
+		uint64_t		v_rbp;		/* 328h */
+		uint64_t		v_rsi;		/* 330h */
+		uint64_t		v_rdi;		/* 338h */
+		uint64_t		v_r8;		/* 340h */
+		uint64_t		v_r9;		/* 348h */
+		uint64_t		v_r10;		/* 350h */
+		uint64_t		v_r11;		/* 358h */
+		uint64_t		v_r12;		/* 360h */
+		uint64_t		v_r13;		/* 368h */
+		uint64_t		v_r14;		/* 370h */
+		uint64_t		v_r15;		/* 378h */
+		uint8_t			v_pad9[0x10];	/* 380h-38Fh */
+		uint64_t		v_gst_exitinfo1;/* 390h */
+		uint64_t		v_gst_exitinfo2;/* 398h */
+		uint64_t		v_gst_exitiinfo;/* 3A0h */
+		uint64_t		v_gst_nrip;	/* 3A8h */
+		uint64_t		v_sev_features;	/* 3B0h */
+		uint64_t		v_intr_ctrl;	/* 3B8h */
+		uint64_t		v_gst_exitcode;	/* 3C0h */
+		uint64_t		v_virtual_tom;	/* 3C8h */
+		uint64_t		v_tlb_id;	/* 3D0h */
+		uint64_t		v_pcup_id;	/* 3D8h */
+		uint64_t		v_eventinj;	/* 3E0h */
+		uint64_t		v_xcr0;		/* 3E8h */
+		uint8_t			v_pad10[0x10];	/* 3F0h-3FFh */
+		uint64_t		v_x87_dp;	/* 400h */
+		uint32_t		v_mxcsr;	/* 408h */
+		uint16_t		v_x87_ftw;	/* 40Ch */
+		uint16_t		v_x87_fsw;	/* 40Eh */
+		uint16_t		v_x87_fcw;	/* 410h */
+		uint16_t		v_x87_fop;	/* 412h */
+		uint16_t		v_x87_ds;	/* 414h */
+		uint16_t		v_x87_cs;	/* 416h */
+		uint64_t		v_x87_rip;	/* 418h */
+		uint8_t			v_fp_x87[0x50];	/* 420h-46Fh */
+		uint8_t			v_fp_xmm[0x100];/* 470h-56Fh */
+		uint8_t			v_fp_ymm[0x100];/* 570h-66fh */
+		uint8_t			v_lbr_st[0x100];/* 670h-76Fh */
+		uint64_t		v_lbr_select;	/* 770h */
+		uint64_t		v_ibs_fetch_ctl;/* 778h */
+		uint64_t		v_ibs_fetch_la;	/* 780h */
+		uint64_t		v_ibs_op_ctl;	/* 788h */
+		uint64_t		v_ibs_op_rip;	/* 790h */
+		uint64_t		v_ibs_op_data;	/* 798h */
+		uint64_t		v_ibs_op_data2;	/* 7A0h */
+		uint64_t		v_ibs_op_data3;	/* 7A8h */
+		uint64_t		v_ibs_dc_la;	/* 7B0h */
+		uint64_t		v_ibstgt_rip;	/* 7B8h */
+		uint64_t		v_ic_ibs_xtd_ct;/* 7C0h */
+};
+
 struct vmcs {
 	uint32_t	vmcs_revision;
 };
@@ -876,9 +1000,12 @@ struct vcpu {
 	/* SVM only (all requiring [v]) */
 	vaddr_t vc_svm_hsa_va;
 	paddr_t vc_svm_hsa_pa;
+	vaddr_t vc_svm_vmsa_va;
+	paddr_t vc_svm_vmsa_pa;
 	vaddr_t vc_svm_ioio_va;
 	paddr_t vc_svm_ioio_pa;
 	int vc_sev;				/* [I] */
+	int vc_seves;				/* [I] */
 };
 
 SLIST_HEAD(vcpu_head, vcpu);
@@ -911,6 +1038,7 @@ int	vcpu_init(struct vcpu *, struct vm_create_params *);
 void	vcpu_deinit(struct vcpu *);
 int	vm_rwregs(struct vm_rwregs_params *, int);
 int	vcpu_reset_regs(struct vcpu *, struct vcpu_reg_state *);
+int	svm_get_vmsa_pa(uint32_t, uint32_t, uint64_t *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/dev/vmm/vmm.h b/sys/dev/vmm/vmm.h
index ca5a152f550..886ff51760a 100644
--- a/sys/dev/vmm/vmm.h
+++ b/sys/dev/vmm/vmm.h
@@ -50,6 +50,7 @@ struct vm_create_params {
 	struct vm_mem_range	vcp_memranges[VMM_MAX_MEM_RANGES];
 	char			vcp_name[VMM_MAX_NAME_LEN];
 	int			vcp_sev;
+	int			vcp_seves;
 
         /* Output parameter from VMM_IOC_CREATE */
         uint32_t		vcp_id;