Brijesh Singh | b38defd | 2017-12-04 10:57:23 -0600 | [diff] [blame] | 1 | ====================================== |
| 2 | Secure Encrypted Virtualization (SEV) |
| 3 | ====================================== |
| 4 | |
| 5 | Overview |
| 6 | ======== |
| 7 | |
| 8 | Secure Encrypted Virtualization (SEV) is a feature found on AMD processors. |
| 9 | |
| 10 | SEV is an extension to the AMD-V architecture which supports running |
| 11 | virtual machines (VMs) under the control of a hypervisor. When enabled, |
| 12 | the memory contents of a VM will be transparently encrypted with a key |
| 13 | unique to that VM. |
| 14 | |
| 15 | The hypervisor can determine the SEV support through the CPUID |
| 16 | instruction. The CPUID function 0x8000001f reports information related |
| 17 | to SEV:: |
| 18 | |
| 19 | 0x8000001f[eax]: |
| 20 | Bit[1] indicates support for SEV |
| 21 | ... |
| 22 | [ecx]: |
| 23 | Bits[31:0] Number of encrypted guests supported simultaneously |
| 24 | |
| 25 | If support for SEV is present, MSR 0xc001_0010 (MSR_K8_SYSCFG) and MSR 0xc001_0015 |
| 26 | (MSR_K7_HWCR) can be used to determine if it can be enabled:: |
| 27 | |
| 28 | 0xc001_0010: |
| 29 | Bit[23] 1 = memory encryption can be enabled |
| 30 | 0 = memory encryption can not be enabled |
| 31 | |
| 32 | 0xc001_0015: |
| 33 | Bit[0] 1 = memory encryption can be enabled |
| 34 | 0 = memory encryption can not be enabled |
| 35 | |
| 36 | When SEV support is available, it can be enabled in a specific VM by |
| 37 | setting the SEV bit before executing VMRUN.:: |
| 38 | |
| 39 | VMCB[0x90]: |
| 40 | Bit[1] 1 = SEV is enabled |
| 41 | 0 = SEV is disabled |
| 42 | |
| 43 | SEV hardware uses ASIDs to associate a memory encryption key with a VM. |
| 44 | Hence, the ASID for the SEV-enabled guests must be from 1 to a maximum value |
| 45 | defined in the CPUID 0x8000001f[ecx] field. |
Brijesh Singh | dc48bae | 2017-12-04 10:57:33 -0600 | [diff] [blame] | 46 | |
| 47 | SEV Key Management |
| 48 | ================== |
| 49 | |
| 50 | The SEV guest key management is handled by a separate processor called the AMD |
| 51 | Secure Processor (AMD-SP). Firmware running inside the AMD-SP provides a secure |
| 52 | key management interface to perform common hypervisor activities such as |
| 53 | encrypting bootstrap code, snapshot, migrating and debugging the guest. For more |
| 54 | information, see the SEV Key Management spec [api-spec]_ |
| 55 | |
Connor Kuehl | 46ca9ee | 2020-08-19 16:19:52 -0500 | [diff] [blame] | 56 | The main ioctl to access SEV is KVM_MEMORY_ENCRYPT_OP. If the argument |
| 57 | to KVM_MEMORY_ENCRYPT_OP is NULL, the ioctl returns 0 if SEV is enabled |
Paolo Bonzini | 2da1ed6 | 2020-03-20 13:34:50 -0400 | [diff] [blame] | 58 | and ``ENOTTY` if it is disabled (on some older versions of Linux, |
| 59 | the ioctl runs normally even with a NULL argument, and therefore will |
Connor Kuehl | 46ca9ee | 2020-08-19 16:19:52 -0500 | [diff] [blame] | 60 | likely return ``EFAULT``). If non-NULL, the argument to KVM_MEMORY_ENCRYPT_OP |
Paolo Bonzini | 2da1ed6 | 2020-03-20 13:34:50 -0400 | [diff] [blame] | 61 | must be a struct kvm_sev_cmd:: |
| 62 | |
| 63 | struct kvm_sev_cmd { |
| 64 | __u32 id; |
| 65 | __u64 data; |
| 66 | __u32 error; |
| 67 | __u32 sev_fd; |
| 68 | }; |
| 69 | |
| 70 | |
| 71 | The ``id`` field contains the subcommand, and the ``data`` field points to |
| 72 | another struct containing arguments specific to command. The ``sev_fd`` |
| 73 | should point to a file descriptor that is opened on the ``/dev/sev`` |
| 74 | device, if needed (see individual commands). |
| 75 | |
| 76 | On output, ``error`` is zero on success, or an error code. Error codes |
Stephen Kitt | 2ad9a84 | 2020-04-24 17:26:37 +0200 | [diff] [blame] | 77 | are defined in ``<linux/psp-dev.h>``. |
Paolo Bonzini | 2da1ed6 | 2020-03-20 13:34:50 -0400 | [diff] [blame] | 78 | |
Brijesh Singh | dc48bae | 2017-12-04 10:57:33 -0600 | [diff] [blame] | 79 | KVM implements the following commands to support common lifecycle events of SEV |
| 80 | guests, such as launching, running, snapshotting, migrating and decommissioning. |
| 81 | |
| 82 | 1. KVM_SEV_INIT |
| 83 | --------------- |
| 84 | |
| 85 | The KVM_SEV_INIT command is used by the hypervisor to initialize the SEV platform |
| 86 | context. In a typical workflow, this command should be the first command issued. |
| 87 | |
| 88 | Returns: 0 on success, -negative on error |
| 89 | |
| 90 | 2. KVM_SEV_LAUNCH_START |
| 91 | ----------------------- |
| 92 | |
| 93 | The KVM_SEV_LAUNCH_START command is used for creating the memory encryption |
| 94 | context. To create the encryption context, user must provide a guest policy, |
| 95 | the owner's public Diffie-Hellman (PDH) key and session information. |
| 96 | |
| 97 | Parameters: struct kvm_sev_launch_start (in/out) |
| 98 | |
| 99 | Returns: 0 on success, -negative on error |
| 100 | |
| 101 | :: |
| 102 | |
| 103 | struct kvm_sev_launch_start { |
| 104 | __u32 handle; /* if zero then firmware creates a new handle */ |
| 105 | __u32 policy; /* guest's policy */ |
| 106 | |
| 107 | __u64 dh_uaddr; /* userspace address pointing to the guest owner's PDH key */ |
| 108 | __u32 dh_len; |
| 109 | |
| 110 | __u64 session_addr; /* userspace address which points to the guest session information */ |
| 111 | __u32 session_len; |
| 112 | }; |
| 113 | |
| 114 | On success, the 'handle' field contains a new handle and on error, a negative value. |
| 115 | |
Paolo Bonzini | 2da1ed6 | 2020-03-20 13:34:50 -0400 | [diff] [blame] | 116 | KVM_SEV_LAUNCH_START requires the ``sev_fd`` field to be valid. |
| 117 | |
Brijesh Singh | dc48bae | 2017-12-04 10:57:33 -0600 | [diff] [blame] | 118 | For more details, see SEV spec Section 6.2. |
| 119 | |
| 120 | 3. KVM_SEV_LAUNCH_UPDATE_DATA |
| 121 | ----------------------------- |
| 122 | |
| 123 | The KVM_SEV_LAUNCH_UPDATE_DATA is used for encrypting a memory region. It also |
| 124 | calculates a measurement of the memory contents. The measurement is a signature |
| 125 | of the memory contents that can be sent to the guest owner as an attestation |
| 126 | that the memory was encrypted correctly by the firmware. |
| 127 | |
| 128 | Parameters (in): struct kvm_sev_launch_update_data |
| 129 | |
| 130 | Returns: 0 on success, -negative on error |
| 131 | |
| 132 | :: |
| 133 | |
| 134 | struct kvm_sev_launch_update { |
| 135 | __u64 uaddr; /* userspace address to be encrypted (must be 16-byte aligned) */ |
| 136 | __u32 len; /* length of the data to be encrypted (must be 16-byte aligned) */ |
| 137 | }; |
| 138 | |
| 139 | For more details, see SEV spec Section 6.3. |
| 140 | |
| 141 | 4. KVM_SEV_LAUNCH_MEASURE |
| 142 | ------------------------- |
| 143 | |
| 144 | The KVM_SEV_LAUNCH_MEASURE command is used to retrieve the measurement of the |
| 145 | data encrypted by the KVM_SEV_LAUNCH_UPDATE_DATA command. The guest owner may |
| 146 | wait to provide the guest with confidential information until it can verify the |
| 147 | measurement. Since the guest owner knows the initial contents of the guest at |
| 148 | boot, the measurement can be verified by comparing it to what the guest owner |
| 149 | expects. |
| 150 | |
Paolo Bonzini | c265878 | 2021-04-20 04:57:06 -0400 | [diff] [blame] | 151 | If len is zero on entry, the measurement blob length is written to len and |
| 152 | uaddr is unused. |
| 153 | |
Brijesh Singh | dc48bae | 2017-12-04 10:57:33 -0600 | [diff] [blame] | 154 | Parameters (in): struct kvm_sev_launch_measure |
| 155 | |
| 156 | Returns: 0 on success, -negative on error |
| 157 | |
| 158 | :: |
| 159 | |
| 160 | struct kvm_sev_launch_measure { |
| 161 | __u64 uaddr; /* where to copy the measurement */ |
| 162 | __u32 len; /* length of measurement blob */ |
| 163 | }; |
| 164 | |
| 165 | For more details on the measurement verification flow, see SEV spec Section 6.4. |
| 166 | |
| 167 | 5. KVM_SEV_LAUNCH_FINISH |
| 168 | ------------------------ |
| 169 | |
| 170 | After completion of the launch flow, the KVM_SEV_LAUNCH_FINISH command can be |
| 171 | issued to make the guest ready for the execution. |
| 172 | |
| 173 | Returns: 0 on success, -negative on error |
| 174 | |
| 175 | 6. KVM_SEV_GUEST_STATUS |
| 176 | ----------------------- |
| 177 | |
| 178 | The KVM_SEV_GUEST_STATUS command is used to retrieve status information about a |
| 179 | SEV-enabled guest. |
| 180 | |
| 181 | Parameters (out): struct kvm_sev_guest_status |
| 182 | |
| 183 | Returns: 0 on success, -negative on error |
| 184 | |
| 185 | :: |
| 186 | |
| 187 | struct kvm_sev_guest_status { |
| 188 | __u32 handle; /* guest handle */ |
| 189 | __u32 policy; /* guest policy */ |
| 190 | __u8 state; /* guest state (see enum below) */ |
| 191 | }; |
| 192 | |
| 193 | SEV guest state: |
| 194 | |
| 195 | :: |
| 196 | |
| 197 | enum { |
| 198 | SEV_STATE_INVALID = 0; |
| 199 | SEV_STATE_LAUNCHING, /* guest is currently being launched */ |
| 200 | SEV_STATE_SECRET, /* guest is being launched and ready to accept the ciphertext data */ |
| 201 | SEV_STATE_RUNNING, /* guest is fully launched and running */ |
| 202 | SEV_STATE_RECEIVING, /* guest is being migrated in from another SEV machine */ |
| 203 | SEV_STATE_SENDING /* guest is getting migrated out to another SEV machine */ |
| 204 | }; |
| 205 | |
| 206 | 7. KVM_SEV_DBG_DECRYPT |
| 207 | ---------------------- |
| 208 | |
| 209 | The KVM_SEV_DEBUG_DECRYPT command can be used by the hypervisor to request the |
| 210 | firmware to decrypt the data at the given memory region. |
| 211 | |
| 212 | Parameters (in): struct kvm_sev_dbg |
| 213 | |
| 214 | Returns: 0 on success, -negative on error |
| 215 | |
| 216 | :: |
| 217 | |
| 218 | struct kvm_sev_dbg { |
| 219 | __u64 src_uaddr; /* userspace address of data to decrypt */ |
| 220 | __u64 dst_uaddr; /* userspace address of destination */ |
| 221 | __u32 len; /* length of memory region to decrypt */ |
| 222 | }; |
| 223 | |
| 224 | The command returns an error if the guest policy does not allow debugging. |
| 225 | |
| 226 | 8. KVM_SEV_DBG_ENCRYPT |
| 227 | ---------------------- |
| 228 | |
| 229 | The KVM_SEV_DEBUG_ENCRYPT command can be used by the hypervisor to request the |
| 230 | firmware to encrypt the data at the given memory region. |
| 231 | |
| 232 | Parameters (in): struct kvm_sev_dbg |
| 233 | |
| 234 | Returns: 0 on success, -negative on error |
| 235 | |
| 236 | :: |
| 237 | |
| 238 | struct kvm_sev_dbg { |
| 239 | __u64 src_uaddr; /* userspace address of data to encrypt */ |
| 240 | __u64 dst_uaddr; /* userspace address of destination */ |
| 241 | __u32 len; /* length of memory region to encrypt */ |
| 242 | }; |
| 243 | |
| 244 | The command returns an error if the guest policy does not allow debugging. |
| 245 | |
| 246 | 9. KVM_SEV_LAUNCH_SECRET |
| 247 | ------------------------ |
| 248 | |
| 249 | The KVM_SEV_LAUNCH_SECRET command can be used by the hypervisor to inject secret |
| 250 | data after the measurement has been validated by the guest owner. |
| 251 | |
| 252 | Parameters (in): struct kvm_sev_launch_secret |
| 253 | |
| 254 | Returns: 0 on success, -negative on error |
| 255 | |
| 256 | :: |
| 257 | |
| 258 | struct kvm_sev_launch_secret { |
| 259 | __u64 hdr_uaddr; /* userspace address containing the packet header */ |
| 260 | __u32 hdr_len; |
| 261 | |
| 262 | __u64 guest_uaddr; /* the guest memory region where the secret should be injected */ |
| 263 | __u32 guest_len; |
| 264 | |
| 265 | __u64 trans_uaddr; /* the hypervisor memory region which contains the secret */ |
| 266 | __u32 trans_len; |
| 267 | }; |
| 268 | |
Brijesh Singh | 2c07ded | 2021-01-04 09:17:49 -0600 | [diff] [blame] | 269 | 10. KVM_SEV_GET_ATTESTATION_REPORT |
| 270 | ---------------------------------- |
| 271 | |
| 272 | The KVM_SEV_GET_ATTESTATION_REPORT command can be used by the hypervisor to query the attestation |
| 273 | report containing the SHA-256 digest of the guest memory and VMSA passed through the KVM_SEV_LAUNCH |
| 274 | commands and signed with the PEK. The digest returned by the command should match the digest |
| 275 | used by the guest owner with the KVM_SEV_LAUNCH_MEASURE. |
| 276 | |
Paolo Bonzini | c265878 | 2021-04-20 04:57:06 -0400 | [diff] [blame] | 277 | If len is zero on entry, the measurement blob length is written to len and |
| 278 | uaddr is unused. |
| 279 | |
Brijesh Singh | 2c07ded | 2021-01-04 09:17:49 -0600 | [diff] [blame] | 280 | Parameters (in): struct kvm_sev_attestation |
| 281 | |
| 282 | Returns: 0 on success, -negative on error |
| 283 | |
| 284 | :: |
| 285 | |
| 286 | struct kvm_sev_attestation_report { |
| 287 | __u8 mnonce[16]; /* A random mnonce that will be placed in the report */ |
| 288 | |
| 289 | __u64 uaddr; /* userspace address where the report should be copied */ |
| 290 | __u32 len; |
| 291 | }; |
| 292 | |
Brijesh Singh | 4cfdd47 | 2021-04-15 15:53:14 +0000 | [diff] [blame] | 293 | 11. KVM_SEV_SEND_START |
| 294 | ---------------------- |
| 295 | |
| 296 | The KVM_SEV_SEND_START command can be used by the hypervisor to create an |
| 297 | outgoing guest encryption context. |
| 298 | |
| 299 | If session_len is zero on entry, the length of the guest session information is |
| 300 | written to session_len and all other fields are not used. |
| 301 | |
| 302 | Parameters (in): struct kvm_sev_send_start |
| 303 | |
| 304 | Returns: 0 on success, -negative on error |
| 305 | |
| 306 | :: |
| 307 | struct kvm_sev_send_start { |
| 308 | __u32 policy; /* guest policy */ |
| 309 | |
| 310 | __u64 pdh_cert_uaddr; /* platform Diffie-Hellman certificate */ |
| 311 | __u32 pdh_cert_len; |
| 312 | |
| 313 | __u64 plat_certs_uaddr; /* platform certificate chain */ |
| 314 | __u32 plat_certs_len; |
| 315 | |
| 316 | __u64 amd_certs_uaddr; /* AMD certificate */ |
| 317 | __u32 amd_certs_len; |
| 318 | |
| 319 | __u64 session_uaddr; /* Guest session information */ |
| 320 | __u32 session_len; |
| 321 | }; |
| 322 | |
Brijesh Singh | d3d1af8 | 2021-04-15 15:53:55 +0000 | [diff] [blame] | 323 | 12. KVM_SEV_SEND_UPDATE_DATA |
| 324 | ---------------------------- |
| 325 | |
| 326 | The KVM_SEV_SEND_UPDATE_DATA command can be used by the hypervisor to encrypt the |
| 327 | outgoing guest memory region with the encryption context creating using |
| 328 | KVM_SEV_SEND_START. |
| 329 | |
| 330 | If hdr_len or trans_len are zero on entry, the length of the packet header and |
| 331 | transport region are written to hdr_len and trans_len respectively, and all |
| 332 | other fields are not used. |
| 333 | |
| 334 | Parameters (in): struct kvm_sev_send_update_data |
| 335 | |
| 336 | Returns: 0 on success, -negative on error |
| 337 | |
| 338 | :: |
| 339 | |
| 340 | struct kvm_sev_launch_send_update_data { |
| 341 | __u64 hdr_uaddr; /* userspace address containing the packet header */ |
| 342 | __u32 hdr_len; |
| 343 | |
| 344 | __u64 guest_uaddr; /* the source memory region to be encrypted */ |
| 345 | __u32 guest_len; |
| 346 | |
| 347 | __u64 trans_uaddr; /* the destination memory region */ |
| 348 | __u32 trans_len; |
| 349 | }; |
| 350 | |
Brijesh Singh | fddecf6 | 2021-04-15 15:54:15 +0000 | [diff] [blame] | 351 | 13. KVM_SEV_SEND_FINISH |
| 352 | ------------------------ |
| 353 | |
| 354 | After completion of the migration flow, the KVM_SEV_SEND_FINISH command can be |
| 355 | issued by the hypervisor to delete the encryption context. |
| 356 | |
| 357 | Returns: 0 on success, -negative on error |
| 358 | |
Steve Rutherford | 5569e2e | 2021-04-20 05:01:20 -0400 | [diff] [blame^] | 359 | 14. KVM_SEV_SEND_CANCEL |
| 360 | ------------------------ |
| 361 | |
| 362 | After completion of SEND_START, but before SEND_FINISH, the source VMM can issue the |
| 363 | SEND_CANCEL command to stop a migration. This is necessary so that a cancelled |
| 364 | migration can restart with a new target later. |
| 365 | |
| 366 | Returns: 0 on success, -negative on error |
| 367 | |
Brijesh Singh | dc48bae | 2017-12-04 10:57:33 -0600 | [diff] [blame] | 368 | References |
| 369 | ========== |
| 370 | |
Mauro Carvalho Chehab | f672feb | 2019-06-07 15:54:23 -0300 | [diff] [blame] | 371 | |
| 372 | See [white-paper]_, [api-spec]_, [amd-apm]_ and [kvm-forum]_ for more info. |
| 373 | |
Brijesh Singh | dc48bae | 2017-12-04 10:57:33 -0600 | [diff] [blame] | 374 | .. [white-paper] http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf |
Alexander A. Klimov | 3c60357 | 2020-07-13 13:47:19 +0200 | [diff] [blame] | 375 | .. [api-spec] https://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf |
| 376 | .. [amd-apm] https://support.amd.com/TechDocs/24593.pdf (section 15.34) |
| 377 | .. [kvm-forum] https://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf |