Download raw body.
SEV-ES: vmm(4): Allocate VMSA
Hans-Jörg Höxer <hshoexer@genua.de> writes:
> 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?
This looks good to me. We can always iterate on it. ok dv@
>
> 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;
SEV-ES: vmm(4): Allocate VMSA