1 /* $OpenBSD: sev.c,v 1.5 2024/11/06 22:06:16 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2023, 2024 Hans-Joerg Hoexer <hshoexer@genua.de> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/param.h> /* roundup */ 21 22 #include <crypto/xform.h> 23 #include <dev/ic/pspvar.h> 24 25 #include <string.h> 26 27 #include "vmd.h" 28 29 extern struct vmd_vm *current_vm; 30 31 /* 32 * Prepare guest to use SEV. 33 * 34 * This asks the PSP to create a new crypto context including a 35 * memory encryption key and assign a handle to the context. 36 * 37 * When the PSP driver psp(4) attaches, it initializes the platform. 38 * If this fails for whatever reason we can not run a guest using SEV. 39 */ 40 int 41 sev_init(struct vmd_vm *vm) 42 { 43 struct vmop_create_params *vmc = &vm->vm_params; 44 struct vm_create_params *vcp = &vmc->vmc_params; 45 uint32_t handle; 46 uint16_t pstate; 47 uint8_t gstate; 48 49 if (!vcp->vcp_sev) 50 return (0); 51 52 if (psp_get_pstate(&pstate, NULL, NULL, NULL, NULL)) { 53 log_warnx("%s: failed to get platform state", __func__); 54 return (-1); 55 } 56 if (pstate == PSP_PSTATE_UNINIT) { 57 log_warnx("%s: platform uninitialized", __func__); 58 return (-1); 59 } 60 61 if (psp_launch_start(&handle) < 0) { 62 log_warnx("%s: launch failed", __func__); 63 return (-1); 64 } 65 vm->vm_sev_handle = handle; 66 67 if (psp_get_gstate(vm->vm_sev_handle, NULL, NULL, &gstate)) { 68 log_warnx("%s: failed to get guest state", __func__); 69 return (-1); 70 } 71 if (gstate != PSP_GSTATE_LUPDATE) { 72 log_warnx("%s: invalid guest state: 0x%hx", __func__, gstate); 73 return (-1); 74 } 75 76 return (0); 77 } 78 79 /* 80 * Record memory segments to be encrypted for SEV. 81 */ 82 int 83 sev_register_encryption(vaddr_t addr, size_t size) 84 { 85 struct vmop_create_params *vmc; 86 struct vm_create_params *vcp; 87 struct vm_mem_range *vmr; 88 size_t off; 89 int i; 90 91 vmc = ¤t_vm->vm_params; 92 vcp = &vmc->vmc_params; 93 94 if (!vcp->vcp_sev) 95 return (0); 96 97 if (size == 0) 98 return (0); 99 100 /* Adjust address and size to be aligend to AES_XTS_BLOCKSIZE. */ 101 if (addr & (AES_XTS_BLOCKSIZE - 1)) { 102 size += (addr & (AES_XTS_BLOCKSIZE - 1)); 103 addr &= ~(AES_XTS_BLOCKSIZE - 1); 104 } 105 106 vmr = find_gpa_range(¤t_vm->vm_params.vmc_params, addr, size); 107 if (vmr == NULL) { 108 log_warnx("%s: failed - invalid memory range addr = 0x%lx, " 109 "len = 0x%zx", __func__, addr, size); 110 return (-1); 111 } 112 if (current_vm->vm_sev_nmemsegments == 113 nitems(current_vm->vm_sev_memsegments)) { 114 log_warnx("%s: failed - out of SEV memory segments", __func__); 115 return (-1); 116 } 117 i = current_vm->vm_sev_nmemsegments++; 118 119 off = addr - vmr->vmr_gpa; 120 121 current_vm->vm_sev_memsegments[i].vmr_va = vmr->vmr_va + off; 122 current_vm->vm_sev_memsegments[i].vmr_size = size; 123 current_vm->vm_sev_memsegments[i].vmr_gpa = vmr->vmr_gpa + off; 124 125 log_debug("%s: i %d addr 0x%lx size 0x%lx vmr_va 0x%lx vmr_gpa 0x%lx " 126 "vmr_size 0x%lx", __func__, i, addr, size, 127 current_vm->vm_sev_memsegments[i].vmr_va, 128 current_vm->vm_sev_memsegments[i].vmr_gpa, 129 current_vm->vm_sev_memsegments[i].vmr_size); 130 131 return (0); 132 } 133 134 /* 135 * Encrypt and measure previously recorded memroy segments. 136 * 137 * This encrypts the memory initially used by the guest. This 138 * includes the kernel or BIOS image, initial stack, boot arguments 139 * and page tables. 140 * 141 * We also ask the PSP to provide a measurement. However, right 142 * now we can not really verify it. 143 */ 144 int 145 sev_encrypt_memory(struct vmd_vm *vm) 146 { 147 struct vmop_create_params *vmc = &vm->vm_params; 148 struct vm_create_params *vcp = &vmc->vmc_params; 149 struct vm_mem_range *vmr; 150 size_t i; 151 uint8_t gstate; 152 153 if (!vcp->vcp_sev) 154 return (0); 155 156 for (i = 0; i < vm->vm_sev_nmemsegments; i++) { 157 vmr = &vm->vm_sev_memsegments[i]; 158 159 /* tell PSP to encrypt this range */ 160 if (psp_launch_update(vm->vm_sev_handle, vmr->vmr_va, 161 roundup(vmr->vmr_size, AES_XTS_BLOCKSIZE))) { 162 log_warnx("%s: failed to launch update page " 163 "%zu:0x%lx", __func__, i, vmr->vmr_va); 164 return (-1); 165 } 166 167 log_debug("%s: encrypted %zu:0x%lx size 0x%lx", __func__, i, 168 vmr->vmr_va, vmr->vmr_size); 169 } 170 if (psp_launch_measure(vm->vm_sev_handle)) { 171 log_warnx("%s: failed to launch measure", __func__); 172 return (-1); 173 } 174 if (psp_launch_finish(vm->vm_sev_handle)) { 175 log_warnx("%s: failed to launch finish", __func__); 176 return (-1); 177 } 178 179 if (psp_get_gstate(vm->vm_sev_handle, NULL, NULL, &gstate)) { 180 log_warnx("%s: failed to get guest state", __func__); 181 return (-1); 182 } 183 if (gstate != PSP_GSTATE_RUNNING) { 184 log_warnx("%s: invalid guest state: 0x%hx", __func__, gstate); 185 return (-1); 186 } 187 188 return (0); 189 } 190 191 192 /* 193 * Activate a guest's SEV crypto state. 194 */ 195 int 196 sev_activate(struct vmd_vm *vm, int vcpu_id) 197 { 198 struct vmop_create_params *vmc = &vm->vm_params; 199 struct vm_create_params *vcp = &vmc->vmc_params; 200 uint8_t gstate; 201 202 if (!vcp->vcp_sev) 203 return (0); 204 205 if (psp_df_flush() || 206 psp_activate(vm->vm_sev_handle, vm->vm_sev_asid[vcpu_id])) { 207 log_warnx("%s: failed to activate guest: 0x%x:0x%x", __func__, 208 vm->vm_sev_handle, vm->vm_sev_asid[vcpu_id]); 209 return (-1); 210 } 211 212 if (psp_get_gstate(vm->vm_sev_handle, NULL, NULL, &gstate)) { 213 log_warnx("%s: failed to get guest state", __func__); 214 return (-1); 215 } 216 if (gstate != PSP_GSTATE_LUPDATE) { 217 log_warnx("%s: invalid guest state: 0x%hx", __func__, gstate); 218 return (-1); 219 } 220 221 return (0); 222 } 223 224 225 /* 226 * Deactivate and decommission a guest's SEV crypto state. 227 */ 228 int 229 sev_shutdown(struct vmd_vm *vm) 230 { 231 struct vmop_create_params *vmc = &vm->vm_params; 232 struct vm_create_params *vcp = &vmc->vmc_params; 233 234 if (!vcp->vcp_sev) 235 return (0); 236 237 if (psp_guest_shutdown(vm->vm_sev_handle)) { 238 log_warnx("failed to deactivate guest"); 239 return (-1); 240 } 241 vm->vm_sev_handle = 0; 242 243 return (0); 244 } 245