From: Hans-Jörg Höxer Subject: SEV-ES: vmm(4): Allocate VMSA To: Cc: Date: Tue, 15 Apr 2025 14:52:59 +0200 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 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;