← Documents Documentation/virt/kvm/x86/amd-memory-encryption.rst GitHub 원문 ↗

Linux 6.18.37 · 가상화 / KVM / x86 / AMD SEV

Secure Encrypted Virtualization (SEV)

AMD SEV·SEV-ES·SEV-SNP VM의 암호화 수명주기, attestation과 migration ioctl ABI입니다.

Source pathDocumentation/virt/kvm/x86/amd-memory-encryption.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

amd-memory-encryption.rst:1-613

AMD SEV·SEV-ES·SEV-SNP VM의 암호화 수명주기, attestation과 migration ioctl ABI입니다.

20개 command의 입력 구조체와 길이 조회, partial processing, policy 제약을 단계별로 정리했습니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ======================================
4 Secure Encrypted Virtualization (SEV)
5 ======================================
6
7 Overview
8 ========
9
10 Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
11
12 SEV is an extension to the AMD-V architecture which supports running
13 virtual machines (VMs) under the control of a hypervisor. When enabled,
14 the memory contents of a VM will be transparently encrypted with a key
15 unique to that VM.
16
17 The hypervisor can determine the SEV support through the CPUID
18 instruction. The CPUID function 0x8000001f reports information related
19 to SEV::
20
21 0x8000001f[eax]:
22 Bit[1] indicates support for SEV
23 ...
24 [ecx]:
25 Bits[31:0] Number of encrypted guests supported simultaneously
26
27 If support for SEV is present, MSR 0xc001_0010 (MSR_AMD64_SYSCFG) and MSR 0xc001_0015
28 (MSR_K7_HWCR) can be used to determine if it can be enabled::
29
30 0xc001_0010:
31 Bit[23] 1 = memory encryption can be enabled
32 0 = memory encryption can not be enabled
33
34 0xc001_0015:
35 Bit[0] 1 = memory encryption can be enabled
36 0 = memory encryption can not be enabled
37
38 When SEV support is available, it can be enabled in a specific VM by
39 setting the SEV bit before executing VMRUN.::
40
41 VMCB[0x90]:
42 Bit[1] 1 = SEV is enabled
43 0 = SEV is disabled
44
45 SEV hardware uses ASIDs to associate a memory encryption key with a VM.
46 Hence, the ASID for the SEV-enabled guests must be from 1 to a maximum value
47 defined in the CPUID 0x8000001f[ecx] field.
48
49 The KVM_MEMORY_ENCRYPT_OP ioctl
50 ===============================
51
52 The main ioctl to access SEV is KVM_MEMORY_ENCRYPT_OP, which operates on
53 the VM file descriptor. If the argument to KVM_MEMORY_ENCRYPT_OP is NULL,
54 the ioctl returns 0 if SEV is enabled and ``ENOTTY`` if it is disabled
55 (on some older versions of Linux, the ioctl tries to run normally even
56 with a NULL argument, and therefore will likely return ``EFAULT`` instead
57 of zero if SEV is enabled). If non-NULL, the argument to
58 KVM_MEMORY_ENCRYPT_OP must be a struct kvm_sev_cmd::
59
60 struct kvm_sev_cmd {
61 __u32 id;
62 __u64 data;
63 __u32 error;
64 __u32 sev_fd;
65 };
66
67
68 The ``id`` field contains the subcommand, and the ``data`` field points to
69 another struct containing arguments specific to command. The ``sev_fd``
70 should point to a file descriptor that is opened on the ``/dev/sev``
71 device, if needed (see individual commands).
72
73 On output, ``error`` is zero on success, or an error code. Error codes
74 are defined in ``<linux/psp-dev.h>``.
75
76 KVM implements the following commands to support common lifecycle events of SEV
77 guests, such as launching, running, snapshotting, migrating and decommissioning.
78
79 1. KVM_SEV_INIT2
80 ----------------
81
82 The KVM_SEV_INIT2 command is used by the hypervisor to initialize the SEV platform
83 context. In a typical workflow, this command should be the first command issued.
84
85 For this command to be accepted, either KVM_X86_SEV_VM or KVM_X86_SEV_ES_VM
86 must have been passed to the KVM_CREATE_VM ioctl. A virtual machine created
87 with those machine types in turn cannot be run until KVM_SEV_INIT2 is invoked.
88
89 Parameters: struct kvm_sev_init (in)
90
91 Returns: 0 on success, -negative on error
92
93 ::
94
95 struct kvm_sev_init {
96 __u64 vmsa_features; /* initial value of features field in VMSA */
97 __u32 flags; /* must be 0 */
98 __u16 ghcb_version; /* maximum guest GHCB version allowed */
99 __u16 pad1;
100 __u32 pad2[8];
101 };
102
103 It is an error if the hypervisor does not support any of the bits that
104 are set in ``flags`` or ``vmsa_features``. ``vmsa_features`` must be
105 0 for SEV virtual machines, as they do not have a VMSA.
106
107 ``ghcb_version`` must be 0 for SEV virtual machines, as they do not issue GHCB
108 requests. If ``ghcb_version`` is 0 for any other guest type, then the maximum
109 allowed guest GHCB protocol will default to version 2.
110
111 This command replaces the deprecated KVM_SEV_INIT and KVM_SEV_ES_INIT commands.
112 The commands did not have any parameters (the ```data``` field was unused) and
113 only work for the KVM_X86_DEFAULT_VM machine type (0).
114
115 They behave as if:
116
117 * the VM type is KVM_X86_SEV_VM for KVM_SEV_INIT, or KVM_X86_SEV_ES_VM for
118 KVM_SEV_ES_INIT
119
120 * the ``flags`` and ``vmsa_features`` fields of ``struct kvm_sev_init`` are
121 set to zero, and ``ghcb_version`` is set to 0 for KVM_SEV_INIT and 1 for
122 KVM_SEV_ES_INIT.
123
124 If the ``KVM_X86_SEV_VMSA_FEATURES`` attribute does not exist, the hypervisor only
125 supports KVM_SEV_INIT and KVM_SEV_ES_INIT. In that case, note that KVM_SEV_ES_INIT
126 might set the debug swap VMSA feature (bit 5) depending on the value of the
127 ``debug_swap`` parameter of ``kvm-amd.ko``.
128
129 2. KVM_SEV_LAUNCH_START
130 -----------------------
131
132 The KVM_SEV_LAUNCH_START command is used for creating the memory encryption
133 context. To create the encryption context, user must provide a guest policy,
134 the owner's public Diffie-Hellman (PDH) key and session information.
135
136 Parameters: struct kvm_sev_launch_start (in/out)
137
138 Returns: 0 on success, -negative on error
139
140 ::
141
142 struct kvm_sev_launch_start {
143 __u32 handle; /* if zero then firmware creates a new handle */
144 __u32 policy; /* guest's policy */
145
146 __u64 dh_uaddr; /* userspace address pointing to the guest owner's PDH key */
147 __u32 dh_len;
148
149 __u64 session_addr; /* userspace address which points to the guest session information */
150 __u32 session_len;
151 };
152
153 On success, the 'handle' field contains a new handle and on error, a negative value.
154
155 KVM_SEV_LAUNCH_START requires the ``sev_fd`` field to be valid.
156
157 For more details, see SEV spec Section 6.2.
158
159 3. KVM_SEV_LAUNCH_UPDATE_DATA
160 -----------------------------
161
162 The KVM_SEV_LAUNCH_UPDATE_DATA is used for encrypting a memory region. It also
163 calculates a measurement of the memory contents. The measurement is a signature
164 of the memory contents that can be sent to the guest owner as an attestation
165 that the memory was encrypted correctly by the firmware.
166
167 Parameters (in): struct kvm_sev_launch_update_data
168
169 Returns: 0 on success, -negative on error
170
171 ::
172
173 struct kvm_sev_launch_update {
174 __u64 uaddr; /* userspace address to be encrypted (must be 16-byte aligned) */
175 __u32 len; /* length of the data to be encrypted (must be 16-byte aligned) */
176 };
177
178 For more details, see SEV spec Section 6.3.
179
180 4. KVM_SEV_LAUNCH_MEASURE
181 -------------------------
182
183 The KVM_SEV_LAUNCH_MEASURE command is used to retrieve the measurement of the
184 data encrypted by the KVM_SEV_LAUNCH_UPDATE_DATA command. The guest owner may
185 wait to provide the guest with confidential information until it can verify the
186 measurement. Since the guest owner knows the initial contents of the guest at
187 boot, the measurement can be verified by comparing it to what the guest owner
188 expects.
189
190 If len is zero on entry, the measurement blob length is written to len and
191 uaddr is unused.
192
193 Parameters (in): struct kvm_sev_launch_measure
194
195 Returns: 0 on success, -negative on error
196
197 ::
198
199 struct kvm_sev_launch_measure {
200 __u64 uaddr; /* where to copy the measurement */
201 __u32 len; /* length of measurement blob */
202 };
203
204 For more details on the measurement verification flow, see SEV spec Section 6.4.
205
206 5. KVM_SEV_LAUNCH_FINISH
207 ------------------------
208
209 After completion of the launch flow, the KVM_SEV_LAUNCH_FINISH command can be
210 issued to make the guest ready for the execution.
211
212 Returns: 0 on success, -negative on error
213
214 6. KVM_SEV_GUEST_STATUS
215 -----------------------
216
217 The KVM_SEV_GUEST_STATUS command is used to retrieve status information about a
218 SEV-enabled guest.
219
220 Parameters (out): struct kvm_sev_guest_status
221
222 Returns: 0 on success, -negative on error
223
224 ::
225
226 struct kvm_sev_guest_status {
227 __u32 handle; /* guest handle */
228 __u32 policy; /* guest policy */
229 __u8 state; /* guest state (see enum below) */
230 };
231
232 SEV guest state:
233
234 ::
235
236 enum {
237 SEV_STATE_INVALID = 0;
238 SEV_STATE_LAUNCHING, /* guest is currently being launched */
239 SEV_STATE_SECRET, /* guest is being launched and ready to accept the ciphertext data */
240 SEV_STATE_RUNNING, /* guest is fully launched and running */
241 SEV_STATE_RECEIVING, /* guest is being migrated in from another SEV machine */
242 SEV_STATE_SENDING /* guest is getting migrated out to another SEV machine */
243 };
244
245 7. KVM_SEV_DBG_DECRYPT
246 ----------------------
247
248 The KVM_SEV_DEBUG_DECRYPT command can be used by the hypervisor to request the
249 firmware to decrypt the data at the given memory region.
250
251 Parameters (in): struct kvm_sev_dbg
252
253 Returns: 0 on success, -negative on error
254
255 ::
256
257 struct kvm_sev_dbg {
258 __u64 src_uaddr; /* userspace address of data to decrypt */
259 __u64 dst_uaddr; /* userspace address of destination */
260 __u32 len; /* length of memory region to decrypt */
261 };
262
263 The command returns an error if the guest policy does not allow debugging.
264
265 8. KVM_SEV_DBG_ENCRYPT
266 ----------------------
267
268 The KVM_SEV_DEBUG_ENCRYPT command can be used by the hypervisor to request the
269 firmware to encrypt the data at the given memory region.
270
271 Parameters (in): struct kvm_sev_dbg
272
273 Returns: 0 on success, -negative on error
274
275 ::
276
277 struct kvm_sev_dbg {
278 __u64 src_uaddr; /* userspace address of data to encrypt */
279 __u64 dst_uaddr; /* userspace address of destination */
280 __u32 len; /* length of memory region to encrypt */
281 };
282
283 The command returns an error if the guest policy does not allow debugging.
284
285 9. KVM_SEV_LAUNCH_SECRET
286 ------------------------
287
288 The KVM_SEV_LAUNCH_SECRET command can be used by the hypervisor to inject secret
289 data after the measurement has been validated by the guest owner.
290
291 Parameters (in): struct kvm_sev_launch_secret
292
293 Returns: 0 on success, -negative on error
294
295 ::
296
297 struct kvm_sev_launch_secret {
298 __u64 hdr_uaddr; /* userspace address containing the packet header */
299 __u32 hdr_len;
300
301 __u64 guest_uaddr; /* the guest memory region where the secret should be injected */
302 __u32 guest_len;
303
304 __u64 trans_uaddr; /* the hypervisor memory region which contains the secret */
305 __u32 trans_len;
306 };
307
308 10. KVM_SEV_GET_ATTESTATION_REPORT
309 ----------------------------------
310
311 The KVM_SEV_GET_ATTESTATION_REPORT command can be used by the hypervisor to query the attestation
312 report containing the SHA-256 digest of the guest memory and VMSA passed through the KVM_SEV_LAUNCH
313 commands and signed with the PEK. The digest returned by the command should match the digest
314 used by the guest owner with the KVM_SEV_LAUNCH_MEASURE.
315
316 If len is zero on entry, the measurement blob length is written to len and
317 uaddr is unused.
318
319 Parameters (in): struct kvm_sev_attestation
320
321 Returns: 0 on success, -negative on error
322
323 ::
324
325 struct kvm_sev_attestation_report {
326 __u8 mnonce[16]; /* A random mnonce that will be placed in the report */
327
328 __u64 uaddr; /* userspace address where the report should be copied */
329 __u32 len;
330 };
331
332 11. KVM_SEV_SEND_START
333 ----------------------
334
335 The KVM_SEV_SEND_START command can be used by the hypervisor to create an
336 outgoing guest encryption context.
337
338 If session_len is zero on entry, the length of the guest session information is
339 written to session_len and all other fields are not used.
340
341 Parameters (in): struct kvm_sev_send_start
342
343 Returns: 0 on success, -negative on error
344
345 ::
346
347 struct kvm_sev_send_start {
348 __u32 policy; /* guest policy */
349
350 __u64 pdh_cert_uaddr; /* platform Diffie-Hellman certificate */
351 __u32 pdh_cert_len;
352
353 __u64 plat_certs_uaddr; /* platform certificate chain */
354 __u32 plat_certs_len;
355
356 __u64 amd_certs_uaddr; /* AMD certificate */
357 __u32 amd_certs_len;
358
359 __u64 session_uaddr; /* Guest session information */
360 __u32 session_len;
361 };
362
363 12. KVM_SEV_SEND_UPDATE_DATA
364 ----------------------------
365
366 The KVM_SEV_SEND_UPDATE_DATA command can be used by the hypervisor to encrypt the
367 outgoing guest memory region with the encryption context creating using
368 KVM_SEV_SEND_START.
369
370 If hdr_len or trans_len are zero on entry, the length of the packet header and
371 transport region are written to hdr_len and trans_len respectively, and all
372 other fields are not used.
373
374 Parameters (in): struct kvm_sev_send_update_data
375
376 Returns: 0 on success, -negative on error
377
378 ::
379
380 struct kvm_sev_launch_send_update_data {
381 __u64 hdr_uaddr; /* userspace address containing the packet header */
382 __u32 hdr_len;
383
384 __u64 guest_uaddr; /* the source memory region to be encrypted */
385 __u32 guest_len;
386
387 __u64 trans_uaddr; /* the destination memory region */
388 __u32 trans_len;
389 };
390
391 13. KVM_SEV_SEND_FINISH
392 ------------------------
393
394 After completion of the migration flow, the KVM_SEV_SEND_FINISH command can be
395 issued by the hypervisor to delete the encryption context.
396
397 Returns: 0 on success, -negative on error
398
399 14. KVM_SEV_SEND_CANCEL
400 ------------------------
401
402 After completion of SEND_START, but before SEND_FINISH, the source VMM can issue the
403 SEND_CANCEL command to stop a migration. This is necessary so that a cancelled
404 migration can restart with a new target later.
405
406 Returns: 0 on success, -negative on error
407
408 15. KVM_SEV_RECEIVE_START
409 -------------------------
410
411 The KVM_SEV_RECEIVE_START command is used for creating the memory encryption
412 context for an incoming SEV guest. To create the encryption context, the user must
413 provide a guest policy, the platform public Diffie-Hellman (PDH) key and session
414 information.
415
416 Parameters: struct kvm_sev_receive_start (in/out)
417
418 Returns: 0 on success, -negative on error
419
420 ::
421
422 struct kvm_sev_receive_start {
423 __u32 handle; /* if zero then firmware creates a new handle */
424 __u32 policy; /* guest's policy */
425
426 __u64 pdh_uaddr; /* userspace address pointing to the PDH key */
427 __u32 pdh_len;
428
429 __u64 session_uaddr; /* userspace address which points to the guest session information */
430 __u32 session_len;
431 };
432
433 On success, the 'handle' field contains a new handle and on error, a negative value.
434
435 For more details, see SEV spec Section 6.12.
436
437 16. KVM_SEV_RECEIVE_UPDATE_DATA
438 -------------------------------
439
440 The KVM_SEV_RECEIVE_UPDATE_DATA command can be used by the hypervisor to copy
441 the incoming buffers into the guest memory region with encryption context
442 created during the KVM_SEV_RECEIVE_START.
443
444 Parameters (in): struct kvm_sev_receive_update_data
445
446 Returns: 0 on success, -negative on error
447
448 ::
449
450 struct kvm_sev_launch_receive_update_data {
451 __u64 hdr_uaddr; /* userspace address containing the packet header */
452 __u32 hdr_len;
453
454 __u64 guest_uaddr; /* the destination guest memory region */
455 __u32 guest_len;
456
457 __u64 trans_uaddr; /* the incoming buffer memory region */
458 __u32 trans_len;
459 };
460
461 17. KVM_SEV_RECEIVE_FINISH
462 --------------------------
463
464 After completion of the migration flow, the KVM_SEV_RECEIVE_FINISH command can be
465 issued by the hypervisor to make the guest ready for execution.
466
467 Returns: 0 on success, -negative on error
468
469 18. KVM_SEV_SNP_LAUNCH_START
470 ----------------------------
471
472 The KVM_SNP_LAUNCH_START command is used for creating the memory encryption
473 context for the SEV-SNP guest. It must be called prior to issuing
474 KVM_SEV_SNP_LAUNCH_UPDATE or KVM_SEV_SNP_LAUNCH_FINISH;
475
476 Parameters (in): struct kvm_sev_snp_launch_start
477
478 Returns: 0 on success, -negative on error
479
480 ::
481
482 struct kvm_sev_snp_launch_start {
483 __u64 policy; /* Guest policy to use. */
484 __u8 gosvw[16]; /* Guest OS visible workarounds. */
485 __u16 flags; /* Must be zero. */
486 __u8 pad0[6];
487 __u64 pad1[4];
488 };
489
490 See SNP_LAUNCH_START in the SEV-SNP specification [snp-fw-abi]_ for further
491 details on the input parameters in ``struct kvm_sev_snp_launch_start``.
492
493 19. KVM_SEV_SNP_LAUNCH_UPDATE
494 -----------------------------
495
496 The KVM_SEV_SNP_LAUNCH_UPDATE command is used for loading userspace-provided
497 data into a guest GPA range, measuring the contents into the SNP guest context
498 created by KVM_SEV_SNP_LAUNCH_START, and then encrypting/validating that GPA
499 range so that it will be immediately readable using the encryption key
500 associated with the guest context once it is booted, after which point it can
501 attest the measurement associated with its context before unlocking any
502 secrets.
503
504 It is required that the GPA ranges initialized by this command have had the
505 KVM_MEMORY_ATTRIBUTE_PRIVATE attribute set in advance. See the documentation
506 for KVM_SET_MEMORY_ATTRIBUTES for more details on this aspect.
507
508 Upon success, this command is not guaranteed to have processed the entire
509 range requested. Instead, the ``gfn_start``, ``uaddr``, and ``len`` fields of
510 ``struct kvm_sev_snp_launch_update`` will be updated to correspond to the
511 remaining range that has yet to be processed. The caller should continue
512 calling this command until those fields indicate the entire range has been
513 processed, e.g. ``len`` is 0, ``gfn_start`` is equal to the last GFN in the
514 range plus 1, and ``uaddr`` is the last byte of the userspace-provided source
515 buffer address plus 1. In the case where ``type`` is KVM_SEV_SNP_PAGE_TYPE_ZERO,
516 ``uaddr`` will be ignored completely.
517
518 Parameters (in): struct kvm_sev_snp_launch_update
519
520 Returns: 0 on success, < 0 on error, -EAGAIN if caller should retry
521
522 ::
523
524 struct kvm_sev_snp_launch_update {
525 __u64 gfn_start; /* Guest page number to load/encrypt data into. */
526 __u64 uaddr; /* Userspace address of data to be loaded/encrypted. */
527 __u64 len; /* 4k-aligned length in bytes to copy into guest memory.*/
528 __u8 type; /* The type of the guest pages being initialized. */
529 __u8 pad0;
530 __u16 flags; /* Must be zero. */
531 __u32 pad1;
532 __u64 pad2[4];
533
534 };
535
536 where the allowed values for page_type are #define'd as::
537
538 KVM_SEV_SNP_PAGE_TYPE_NORMAL
539 KVM_SEV_SNP_PAGE_TYPE_ZERO
540 KVM_SEV_SNP_PAGE_TYPE_UNMEASURED
541 KVM_SEV_SNP_PAGE_TYPE_SECRETS
542 KVM_SEV_SNP_PAGE_TYPE_CPUID
543
544 See the SEV-SNP spec [snp-fw-abi]_ for further details on how each page type is
545 used/measured.
546
547 20. KVM_SEV_SNP_LAUNCH_FINISH
548 -----------------------------
549
550 After completion of the SNP guest launch flow, the KVM_SEV_SNP_LAUNCH_FINISH
551 command can be issued to make the guest ready for execution.
552
553 Parameters (in): struct kvm_sev_snp_launch_finish
554
555 Returns: 0 on success, -negative on error
556
557 ::
558
559 struct kvm_sev_snp_launch_finish {
560 __u64 id_block_uaddr;
561 __u64 id_auth_uaddr;
562 __u8 id_block_en;
563 __u8 auth_key_en;
564 __u8 vcek_disabled;
565 __u8 host_data[32];
566 __u8 pad0[3];
567 __u16 flags; /* Must be zero */
568 __u64 pad1[4];
569 };
570
571
572 See SNP_LAUNCH_FINISH in the SEV-SNP specification [snp-fw-abi]_ for further
573 details on the input parameters in ``struct kvm_sev_snp_launch_finish``.
574
575 Device attribute API
576 ====================
577
578 Attributes of the SEV implementation can be retrieved through the
579 ``KVM_HAS_DEVICE_ATTR`` and ``KVM_GET_DEVICE_ATTR`` ioctls on the ``/dev/kvm``
580 device node, using group ``KVM_X86_GRP_SEV``.
581
582 Currently only one attribute is implemented:
583
584 * ``KVM_X86_SEV_VMSA_FEATURES``: return the set of all bits that
585 are accepted in the ``vmsa_features`` of ``KVM_SEV_INIT2``.
586
587 Firmware Management
588 ===================
589
590 The SEV guest key management is handled by a separate processor called the AMD
591 Secure Processor (AMD-SP). Firmware running inside the AMD-SP provides a secure
592 key management interface to perform common hypervisor activities such as
593 encrypting bootstrap code, snapshot, migrating and debugging the guest. For more
594 information, see the SEV Key Management spec [api-spec]_
595
596 The AMD-SP firmware can be initialized either by using its own non-volatile
597 storage or the OS can manage the NV storage for the firmware using
598 parameter ``init_ex_path`` of the ``ccp`` module. If the file specified
599 by ``init_ex_path`` does not exist or is invalid, the OS will create or
600 override the file with PSP non-volatile storage.
601
602 References
603 ==========
604
605
606 See [white-paper]_, [api-spec]_, [amd-apm]_, [kvm-forum]_, and [snp-fw-abi]_
607 for more info.
608
609 .. [white-paper] https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
610 .. [api-spec] https://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf
611 .. [amd-apm] https://support.amd.com/TechDocs/24593.pdf (section 15.34)
612 .. [kvm-forum] https://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
613 .. [snp-fw-abi] https://www.amd.com/system/files/TechDocs/56860.pdf
614

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

SEV 기능과 하드웨어 조건

1-48

Secure Encrypted Virtualization(SEV)은 AMD-V를 확장해 하이퍼바이저가 VM을 실행하는 동안 해당 VM에 고유한 key로 메모리 내용을 투명하게 암호화하는 AMD 프로세서 기능입니다.

SEV 탐지와 활성화
위치필드의미
`CPUID 0x8000001f[EAX]`bit 1SEV 지원
`CPUID 0x8000001f[ECX]`bit 31:0동시에 지원하는 encrypted guest 수
`MSR_AMD64_SYSCFG (0xc001_0010)`bit 231이면 memory encryption 활성화 가능
`MSR_K7_HWCR (0xc001_0015)`bit 01이면 memory encryption 활성화 가능
`VMCB[0x90]`bit 1VMRUN 전에 1로 설정하면 해당 VM에서 SEV 활성화

CPUID, MSR, VMCB에서 확인하는 비트입니다.

SEV 하드웨어는 ASID로 memory encryption key를 VM과 연결합니다. SEV guest의 ASID는 1부터 `CPUID 0x8000001f[ECX]`가 보고하는 최대값 사이여야 합니다.

.. SPDX-License-Identifier: GPL-2.0

======================================
Secure Encrypted Virtualization (SEV)
======================================

Overview
========

Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.

SEV is an extension to the AMD-V architecture which supports running
virtual machines (VMs) under the control of a hypervisor. When enabled,
the memory contents of a VM will be transparently encrypted with a key
unique to that VM.

The hypervisor can determine the SEV support through the CPUID
instruction. The CPUID function 0x8000001f reports information related
to SEV::

	0x8000001f[eax]:
			Bit[1] 	indicates support for SEV
	    ...
		  [ecx]:
			Bits[31:0]  Number of encrypted guests supported simultaneously

If support for SEV is present, MSR 0xc001_0010 (MSR_AMD64_SYSCFG) and MSR 0xc001_0015
(MSR_K7_HWCR) can be used to determine if it can be enabled::

	0xc001_0010:
		Bit[23]	   1 = memory encryption can be enabled
			   0 = memory encryption can not be enabled

	0xc001_0015:
		Bit[0]	   1 = memory encryption can be enabled
			   0 = memory encryption can not be enabled

When SEV support is available, it can be enabled in a specific VM by
setting the SEV bit before executing VMRUN.::

	VMCB[0x90]:
		Bit[1]	    1 = SEV is enabled
			    0 = SEV is disabled

SEV hardware uses ASIDs to associate a memory encryption key with a VM.
Hence, the ASID for the SEV-enabled guests must be from 1 to a maximum value
defined in the CPUID 0x8000001f[ecx] field.

KVM_MEMORY_ENCRYPT_OP ioctl

49-78

SEV의 주 ioctl은 VM file descriptor에 적용하는 `KVM_MEMORY_ENCRYPT_OP`입니다. 인자가 NULL이면 SEV 활성화 시 0, 비활성화 시 `ENOTTY`를 반환합니다. 오래된 Linux는 NULL도 정상 명령처럼 처리해 활성화 상태에서 0 대신 `EFAULT`를 돌려줄 수 있습니다.

`struct kvm_sev_cmd`
필드역할
`id`SEV subcommand
`data`command별 인자 구조체의 userspace pointer
`error`출력: 성공 시 0, 실패 시 `<linux/psp-dev.h>` 오류 코드
`sev_fd`필요한 command에서 `/dev/sev`로 연 file descriptor

non-NULL ioctl 인자의 공통 command envelope입니다.

KVM은 launch, 실행, snapshot, migration, decommission 등 SEV guest의 공통 수명주기를 아래 subcommand로 제공합니다.

The KVM_MEMORY_ENCRYPT_OP ioctl
===============================

The main ioctl to access SEV is KVM_MEMORY_ENCRYPT_OP, which operates on
the VM file descriptor.  If the argument to KVM_MEMORY_ENCRYPT_OP is NULL,
the ioctl returns 0 if SEV is enabled and ``ENOTTY`` if it is disabled
(on some older versions of Linux, the ioctl tries to run normally even
with a NULL argument, and therefore will likely return ``EFAULT`` instead
of zero if SEV is enabled).  If non-NULL, the argument to
KVM_MEMORY_ENCRYPT_OP must be a struct kvm_sev_cmd::

       struct kvm_sev_cmd {
               __u32 id;
               __u64 data;
               __u32 error;
               __u32 sev_fd;
       };


The ``id`` field contains the subcommand, and the ``data`` field points to
another struct containing arguments specific to command.  The ``sev_fd``
should point to a file descriptor that is opened on the ``/dev/sev``
device, if needed (see individual commands).

On output, ``error`` is zero on success, or an error code.  Error codes
are defined in ``<linux/psp-dev.h>``.

KVM implements the following commands to support common lifecycle events of SEV
guests, such as launching, running, snapshotting, migrating and decommissioning.

KVM_SEV_INIT2

79-128

`KVM_SEV_INIT2`는 SEV platform context를 초기화하며 일반적인 흐름의 첫 command입니다. VM 생성 시 `KVM_X86_SEV_VM` 또는 `KVM_X86_SEV_ES_VM`을 `KVM_CREATE_VM`에 전달해야 하고, 이 machine type의 VM은 INIT2 전에는 실행할 수 없습니다.

`struct kvm_sev_init`
필드의미
`vmsa_features`VMSA features 초기값; VMSA가 없는 SEV VM에서는 0
`flags`지원 비트만 허용, 현재 0
`ghcb_version`허용할 최대 guest GHCB version; SEV VM은 0, 다른 유형에서 0이면 기본 version 2
`pad1`, `pad2[8]`예약 영역

입력 필드와 제약입니다.

하이퍼바이저가 지원하지 않는 `flags`나 `vmsa_features` bit를 설정하면 오류입니다. `KVM_SEV_INIT2`는 deprecated `KVM_SEV_INIT`과 `KVM_SEV_ES_INIT`을 대체합니다.

구형 INIT command는 data가 없고 `KVM_X86_DEFAULT_VM`에만 동작합니다. 각각 VM type을 SEV 또는 SEV-ES로 간주하고 flags·vmsa_features를 0으로, GHCB version을 SEV는 0, SEV-ES는 1로 설정한 것처럼 동작합니다.

`KVM_X86_SEV_VMSA_FEATURES` attribute가 없으면 hypervisor는 구형 INIT 두 개만 지원합니다. 이때 `KVM_SEV_ES_INIT`은 `kvm-amd.ko`의 `debug_swap` 값에 따라 debug swap VMSA feature(bit 5)를 설정할 수 있습니다.

1. KVM_SEV_INIT2
----------------

The KVM_SEV_INIT2 command is used by the hypervisor to initialize the SEV platform
context. In a typical workflow, this command should be the first command issued.

For this command to be accepted, either KVM_X86_SEV_VM or KVM_X86_SEV_ES_VM
must have been passed to the KVM_CREATE_VM ioctl.  A virtual machine created
with those machine types in turn cannot be run until KVM_SEV_INIT2 is invoked.

Parameters: struct kvm_sev_init (in)

Returns: 0 on success, -negative on error

::

        struct kvm_sev_init {
                __u64 vmsa_features;  /* initial value of features field in VMSA */
                __u32 flags;          /* must be 0 */
                __u16 ghcb_version;   /* maximum guest GHCB version allowed */
                __u16 pad1;
                __u32 pad2[8];
        };

It is an error if the hypervisor does not support any of the bits that
are set in ``flags`` or ``vmsa_features``.  ``vmsa_features`` must be
0 for SEV virtual machines, as they do not have a VMSA.

``ghcb_version`` must be 0 for SEV virtual machines, as they do not issue GHCB
requests. If ``ghcb_version`` is 0 for any other guest type, then the maximum
allowed guest GHCB protocol will default to version 2.

This command replaces the deprecated KVM_SEV_INIT and KVM_SEV_ES_INIT commands.
The commands did not have any parameters (the ```data``` field was unused) and
only work for the KVM_X86_DEFAULT_VM machine type (0).

They behave as if:

* the VM type is KVM_X86_SEV_VM for KVM_SEV_INIT, or KVM_X86_SEV_ES_VM for
  KVM_SEV_ES_INIT

* the ``flags`` and ``vmsa_features`` fields of ``struct kvm_sev_init`` are
  set to zero, and ``ghcb_version`` is set to 0 for KVM_SEV_INIT and 1 for
  KVM_SEV_ES_INIT.

If the ``KVM_X86_SEV_VMSA_FEATURES`` attribute does not exist, the hypervisor only
supports KVM_SEV_INIT and KVM_SEV_ES_INIT.  In that case, note that KVM_SEV_ES_INIT
might set the debug swap VMSA feature (bit 5) depending on the value of the
``debug_swap`` parameter of ``kvm-amd.ko``.

KVM_SEV_LAUNCH_START

129-158

이 command는 memory encryption context를 생성합니다. 사용자는 guest policy, 소유자의 public Diffie-Hellman(PDH) key와 session 정보를 제공하며 유효한 `sev_fd`가 필요합니다.

`struct kvm_sev_launch_start`
필드의미
`handle`입력 0이면 firmware가 새 handle 생성; 성공 시 새 handle
`policy`guest policy
`dh_uaddr`, `dh_len`guest owner PDH key 주소와 길이
`session_addr`, `session_len`guest session 정보 주소와 길이

입출력 launch context입니다.

성공 시 0, 실패 시 음수 오류를 반환하며 세부 흐름은 SEV specification section 6.2를 따릅니다.

2. KVM_SEV_LAUNCH_START
-----------------------

The KVM_SEV_LAUNCH_START command is used for creating the memory encryption
context. To create the encryption context, user must provide a guest policy,
the owner's public Diffie-Hellman (PDH) key and session information.

Parameters: struct  kvm_sev_launch_start (in/out)

Returns: 0 on success, -negative on error

::

        struct kvm_sev_launch_start {
                __u32 handle;           /* if zero then firmware creates a new handle */
                __u32 policy;           /* guest's policy */

                __u64 dh_uaddr;         /* userspace address pointing to the guest owner's PDH key */
                __u32 dh_len;

                __u64 session_addr;     /* userspace address which points to the guest session information */
                __u32 session_len;
        };

On success, the 'handle' field contains a new handle and on error, a negative value.

KVM_SEV_LAUNCH_START requires the ``sev_fd`` field to be valid.

For more details, see SEV spec Section 6.2.

KVM_SEV_LAUNCH_UPDATE_DATA

159-179

지정한 guest memory region을 암호화하고 memory content measurement도 계산합니다. measurement는 firmware가 메모리를 올바르게 암호화했다는 attestation으로 guest owner에게 보낼 수 있는 서명입니다.

`struct kvm_sev_launch_update`
필드제약
`uaddr`암호화할 userspace 주소, 16-byte aligned
`len`암호화할 길이, 16-byte aligned

암호화할 userspace 영역입니다.

성공 시 0, 실패 시 음수 오류이며 SEV specification section 6.3에 정의됩니다.

3. KVM_SEV_LAUNCH_UPDATE_DATA
-----------------------------

The KVM_SEV_LAUNCH_UPDATE_DATA is used for encrypting a memory region. It also
calculates a measurement of the memory contents. The measurement is a signature
of the memory contents that can be sent to the guest owner as an attestation
that the memory was encrypted correctly by the firmware.

Parameters (in): struct  kvm_sev_launch_update_data

Returns: 0 on success, -negative on error

::

        struct kvm_sev_launch_update {
                __u64 uaddr;    /* userspace address to be encrypted (must be 16-byte aligned) */
                __u32 len;      /* length of the data to be encrypted (must be 16-byte aligned) */
        };

For more details, see SEV spec Section 6.3.

KVM_SEV_LAUNCH_MEASURE

180-205

`KVM_SEV_LAUNCH_UPDATE_DATA`가 암호화한 데이터의 measurement를 가져옵니다. guest owner는 초기 boot content를 알고 있으므로 예상값과 비교해 검증한 뒤에만 confidential information을 제공할 수 있습니다.

`struct kvm_sev_launch_measure`
필드동작
`uaddr`measurement를 복사할 주소
`len`blob 길이; 입력이 0이면 필요한 길이만 출력하고 uaddr은 사용하지 않음

measurement blob 출력 버퍼입니다.

verification 흐름은 SEV specification section 6.4를 따릅니다.

4. KVM_SEV_LAUNCH_MEASURE
-------------------------

The KVM_SEV_LAUNCH_MEASURE command is used to retrieve the measurement of the
data encrypted by the KVM_SEV_LAUNCH_UPDATE_DATA command. The guest owner may
wait to provide the guest with confidential information until it can verify the
measurement. Since the guest owner knows the initial contents of the guest at
boot, the measurement can be verified by comparing it to what the guest owner
expects.

If len is zero on entry, the measurement blob length is written to len and
uaddr is unused.

Parameters (in): struct  kvm_sev_launch_measure

Returns: 0 on success, -negative on error

::

        struct kvm_sev_launch_measure {
                __u64 uaddr;    /* where to copy the measurement */
                __u32 len;      /* length of measurement blob */
        };

For more details on the measurement verification flow, see SEV spec Section 6.4.

KVM_SEV_LAUNCH_FINISH

206-213

launch flow를 모두 마친 뒤 이 command를 호출하면 guest가 실행 가능한 상태가 됩니다. 성공 시 0, 실패 시 음수 오류를 반환합니다.

5. KVM_SEV_LAUNCH_FINISH
------------------------

After completion of the launch flow, the KVM_SEV_LAUNCH_FINISH command can be
issued to make the guest ready for the execution.

Returns: 0 on success, -negative on error

KVM_SEV_GUEST_STATUS

214-244

SEV-enabled guest의 handle, policy와 현재 수명주기 state를 조회합니다.

SEV guest state
State의미
`SEV_STATE_INVALID`유효하지 않음
`SEV_STATE_LAUNCHING`launch 진행 중
`SEV_STATE_SECRET`launch 중이며 ciphertext data 수락 준비
`SEV_STATE_RUNNING`launch 완료 후 실행 중
`SEV_STATE_RECEIVING`다른 SEV machine에서 migration 수신 중
`SEV_STATE_SENDING`다른 SEV machine으로 migration 송신 중

`struct kvm_sev_guest_status.state` 값입니다.

출력 구조체의 `handle`은 guest handle, `policy`는 guest policy이며 성공 시 0을 반환합니다.

6. KVM_SEV_GUEST_STATUS
-----------------------

The KVM_SEV_GUEST_STATUS command is used to retrieve status information about a
SEV-enabled guest.

Parameters (out): struct kvm_sev_guest_status

Returns: 0 on success, -negative on error

::

        struct kvm_sev_guest_status {
                __u32 handle;   /* guest handle */
                __u32 policy;   /* guest policy */
                __u8 state;     /* guest state (see enum below) */
        };

SEV guest state:

::

        enum {
        SEV_STATE_INVALID = 0;
        SEV_STATE_LAUNCHING,    /* guest is currently being launched */
        SEV_STATE_SECRET,       /* guest is being launched and ready to accept the ciphertext data */
        SEV_STATE_RUNNING,      /* guest is fully launched and running */
        SEV_STATE_RECEIVING,    /* guest is being migrated in from another SEV machine */
        SEV_STATE_SENDING       /* guest is getting migrated out to another SEV machine */
        };

KVM_SEV_DBG_DECRYPT

245-264

하이퍼바이저가 firmware에 지정 memory region의 복호화를 요청합니다. guest policy가 debugging을 허용하지 않으면 오류입니다.

`struct kvm_sev_dbg` 복호화
필드의미
`src_uaddr`복호화할 data 주소
`dst_uaddr`평문 destination 주소
`len`영역 길이

source와 destination userspace 영역입니다.

7. KVM_SEV_DBG_DECRYPT
----------------------

The KVM_SEV_DEBUG_DECRYPT command can be used by the hypervisor to request the
firmware to decrypt the data at the given memory region.

Parameters (in): struct kvm_sev_dbg

Returns: 0 on success, -negative on error

::

        struct kvm_sev_dbg {
                __u64 src_uaddr;        /* userspace address of data to decrypt */
                __u64 dst_uaddr;        /* userspace address of destination */
                __u32 len;              /* length of memory region to decrypt */
        };

The command returns an error if the guest policy does not allow debugging.

KVM_SEV_DBG_ENCRYPT

265-284

하이퍼바이저가 firmware에 지정 memory region의 암호화를 요청합니다. 복호화 command와 같은 `struct kvm_sev_dbg`를 사용하며 guest policy가 debugging을 금지하면 오류입니다.

`struct kvm_sev_dbg` 암호화
필드의미
`src_uaddr`암호화할 data 주소
`dst_uaddr`암호문 destination 주소
`len`영역 길이

평문 source를 암호화 destination으로 변환합니다.

8. KVM_SEV_DBG_ENCRYPT
----------------------

The KVM_SEV_DEBUG_ENCRYPT command can be used by the hypervisor to request the
firmware to encrypt the data at the given memory region.

Parameters (in): struct kvm_sev_dbg

Returns: 0 on success, -negative on error

::

        struct kvm_sev_dbg {
                __u64 src_uaddr;        /* userspace address of data to encrypt */
                __u64 dst_uaddr;        /* userspace address of destination */
                __u32 len;              /* length of memory region to encrypt */
        };

The command returns an error if the guest policy does not allow debugging.

KVM_SEV_LAUNCH_SECRET

285-307

guest owner가 measurement를 검증한 뒤 하이퍼바이저가 secret ciphertext를 guest memory에 주입할 때 사용합니다.

`struct kvm_sev_launch_secret`
필드의미
`hdr_uaddr`, `hdr_len`packet header 주소와 길이
`guest_uaddr`, `guest_len`secret을 주입할 guest memory 영역
`trans_uaddr`, `trans_len`secret을 담은 hypervisor memory 영역

packet header, guest destination, transport secret를 연결합니다.

9. KVM_SEV_LAUNCH_SECRET
------------------------

The KVM_SEV_LAUNCH_SECRET command can be used by the hypervisor to inject secret
data after the measurement has been validated by the guest owner.

Parameters (in): struct kvm_sev_launch_secret

Returns: 0 on success, -negative on error

::

        struct kvm_sev_launch_secret {
                __u64 hdr_uaddr;        /* userspace address containing the packet header */
                __u32 hdr_len;

                __u64 guest_uaddr;      /* the guest memory region where the secret should be injected */
                __u32 guest_len;

                __u64 trans_uaddr;      /* the hypervisor memory region which contains the secret */
                __u32 trans_len;
        };

KVM_SEV_GET_ATTESTATION_REPORT

308-331

KVM_SEV_LAUNCH command로 전달한 guest memory와 VMSA의 SHA-256 digest를 포함하고 PEK로 서명한 attestation report를 조회합니다. digest는 guest owner가 `KVM_SEV_LAUNCH_MEASURE`에서 사용한 값과 일치해야 합니다.

`struct kvm_sev_attestation_report`
필드의미
`mnonce[16]`report에 넣을 random nonce
`uaddr`report 복사 주소
`len`report 길이; 0이면 필요한 길이만 반환

report nonce와 출력 버퍼입니다.

10. KVM_SEV_GET_ATTESTATION_REPORT
----------------------------------

The KVM_SEV_GET_ATTESTATION_REPORT command can be used by the hypervisor to query the attestation
report containing the SHA-256 digest of the guest memory and VMSA passed through the KVM_SEV_LAUNCH
commands and signed with the PEK. The digest returned by the command should match the digest
used by the guest owner with the KVM_SEV_LAUNCH_MEASURE.

If len is zero on entry, the measurement blob length is written to len and
uaddr is unused.

Parameters (in): struct kvm_sev_attestation

Returns: 0 on success, -negative on error

::

        struct kvm_sev_attestation_report {
                __u8 mnonce[16];        /* A random mnonce that will be placed in the report */

                __u64 uaddr;            /* userspace address where the report should be copied */
                __u32 len;
        };

KVM_SEV_SEND_START

332-362

outgoing guest encryption context를 생성해 source 측 migration을 시작합니다. `session_len`이 0이면 필요한 guest session 정보 길이만 반환하고 다른 필드는 사용하지 않습니다.

`struct kvm_sev_send_start`
필드의미
`policy`guest policy
`pdh_cert_uaddr`, `pdh_cert_len`platform Diffie-Hellman certificate
`plat_certs_uaddr`, `plat_certs_len`platform certificate chain
`amd_certs_uaddr`, `amd_certs_len`AMD certificate
`session_uaddr`, `session_len`guest session 정보

source platform 인증 자료와 session 출력입니다.

11. KVM_SEV_SEND_START
----------------------

The KVM_SEV_SEND_START command can be used by the hypervisor to create an
outgoing guest encryption context.

If session_len is zero on entry, the length of the guest session information is
written to session_len and all other fields are not used.

Parameters (in): struct kvm_sev_send_start

Returns: 0 on success, -negative on error

::

        struct kvm_sev_send_start {
                __u32 policy;                 /* guest policy */

                __u64 pdh_cert_uaddr;         /* platform Diffie-Hellman certificate */
                __u32 pdh_cert_len;

                __u64 plat_certs_uaddr;        /* platform certificate chain */
                __u32 plat_certs_len;

                __u64 amd_certs_uaddr;        /* AMD certificate */
                __u32 amd_certs_len;

                __u64 session_uaddr;          /* Guest session information */
                __u32 session_len;
        };

KVM_SEV_SEND_UPDATE_DATA

363-390

`KVM_SEV_SEND_START`가 만든 context로 outgoing guest memory를 암호화해 packet header와 transport region을 생성합니다. `hdr_len` 또는 `trans_len`이 0이면 필요한 두 길이를 반환하고 나머지 필드는 사용하지 않습니다.

`struct kvm_sev_launch_send_update_data`
필드의미
`hdr_uaddr`, `hdr_len`packet header
`guest_uaddr`, `guest_len`암호화할 guest source memory
`trans_uaddr`, `trans_len`암호화 결과 transport destination

migration 송신의 source와 output buffer입니다.

12. KVM_SEV_SEND_UPDATE_DATA
----------------------------

The KVM_SEV_SEND_UPDATE_DATA command can be used by the hypervisor to encrypt the
outgoing guest memory region with the encryption context creating using
KVM_SEV_SEND_START.

If hdr_len or trans_len are zero on entry, the length of the packet header and
transport region are written to hdr_len and trans_len respectively, and all
other fields are not used.

Parameters (in): struct kvm_sev_send_update_data

Returns: 0 on success, -negative on error

::

        struct kvm_sev_launch_send_update_data {
                __u64 hdr_uaddr;        /* userspace address containing the packet header */
                __u32 hdr_len;

                __u64 guest_uaddr;      /* the source memory region to be encrypted */
                __u32 guest_len;

                __u64 trans_uaddr;      /* the destination memory region  */
                __u32 trans_len;
        };

KVM_SEV_SEND_FINISH

391-398

송신 migration flow가 완료되면 source 하이퍼바이저가 이 command로 outgoing encryption context를 삭제합니다.

13. KVM_SEV_SEND_FINISH
------------------------

After completion of the migration flow, the KVM_SEV_SEND_FINISH command can be
issued by the hypervisor to delete the encryption context.

Returns: 0 on success, -negative on error

KVM_SEV_SEND_CANCEL

399-407

`SEND_START` 뒤 `SEND_FINISH` 전 source VMM이 migration을 취소할 때 사용합니다. 취소된 migration이 나중에 새 target으로 다시 시작할 수 있도록 기존 context를 정리합니다.

14. KVM_SEV_SEND_CANCEL
------------------------

After completion of SEND_START, but before SEND_FINISH, the source VMM can issue the
SEND_CANCEL command to stop a migration. This is necessary so that a cancelled
migration can restart with a new target later.

Returns: 0 on success, -negative on error

KVM_SEV_RECEIVE_START

408-436

incoming SEV guest를 위한 memory encryption context를 생성합니다. 사용자는 guest policy, platform PDH key와 session 정보를 제공합니다.

`struct kvm_sev_receive_start`
필드의미
`handle`0이면 firmware가 새 handle 생성; 성공 시 handle 출력
`policy`guest policy
`pdh_uaddr`, `pdh_len`PDH key 주소와 길이
`session_uaddr`, `session_len`guest session 정보

수신 context 생성 인자입니다.

성공 시 0이며 세부 흐름은 SEV specification section 6.12를 따릅니다.

15. KVM_SEV_RECEIVE_START
-------------------------

The KVM_SEV_RECEIVE_START command is used for creating the memory encryption
context for an incoming SEV guest. To create the encryption context, the user must
provide a guest policy, the platform public Diffie-Hellman (PDH) key and session
information.

Parameters: struct  kvm_sev_receive_start (in/out)

Returns: 0 on success, -negative on error

::

        struct kvm_sev_receive_start {
                __u32 handle;           /* if zero then firmware creates a new handle */
                __u32 policy;           /* guest's policy */

                __u64 pdh_uaddr;        /* userspace address pointing to the PDH key */
                __u32 pdh_len;

                __u64 session_uaddr;    /* userspace address which points to the guest session information */
                __u32 session_len;
        };

On success, the 'handle' field contains a new handle and on error, a negative value.

For more details, see SEV spec Section 6.12.

KVM_SEV_RECEIVE_UPDATE_DATA

437-460

`KVM_SEV_RECEIVE_START`가 만든 context를 사용해 incoming header와 transport buffer를 guest memory destination에 복사·복호화합니다.

`struct kvm_sev_launch_receive_update_data`
필드의미
`hdr_uaddr`, `hdr_len`incoming packet header
`guest_uaddr`, `guest_len`destination guest memory
`trans_uaddr`, `trans_len`incoming transport buffer

migration 수신 buffer입니다.

16. KVM_SEV_RECEIVE_UPDATE_DATA
-------------------------------

The KVM_SEV_RECEIVE_UPDATE_DATA command can be used by the hypervisor to copy
the incoming buffers into the guest memory region with encryption context
created during the KVM_SEV_RECEIVE_START.

Parameters (in): struct kvm_sev_receive_update_data

Returns: 0 on success, -negative on error

::

        struct kvm_sev_launch_receive_update_data {
                __u64 hdr_uaddr;        /* userspace address containing the packet header */
                __u32 hdr_len;

                __u64 guest_uaddr;      /* the destination guest memory region */
                __u32 guest_len;

                __u64 trans_uaddr;      /* the incoming buffer memory region  */
                __u32 trans_len;
        };

KVM_SEV_RECEIVE_FINISH

461-468

수신 migration flow 완료 뒤 이 command를 호출하면 incoming guest가 실행 준비 상태가 됩니다.

17. KVM_SEV_RECEIVE_FINISH
--------------------------

After completion of the migration flow, the KVM_SEV_RECEIVE_FINISH command can be
issued by the hypervisor to make the guest ready for execution.

Returns: 0 on success, -negative on error

KVM_SEV_SNP_LAUNCH_START

469-492

SEV-SNP guest의 memory encryption context를 만들며 `KVM_SEV_SNP_LAUNCH_UPDATE`와 `KVM_SEV_SNP_LAUNCH_FINISH`보다 먼저 호출해야 합니다.

`struct kvm_sev_snp_launch_start`
필드의미
`policy`guest policy
`gosvw[16]`Guest OS visible workarounds
`flags`0이어야 함
`pad0`, `pad1[4]`예약 영역

SNP guest 초기 policy와 workaround입니다.

세부 입력 의미는 SEV-SNP firmware ABI의 `SNP_LAUNCH_START`를 따릅니다.

18. KVM_SEV_SNP_LAUNCH_START
----------------------------

The KVM_SNP_LAUNCH_START command is used for creating the memory encryption
context for the SEV-SNP guest. It must be called prior to issuing
KVM_SEV_SNP_LAUNCH_UPDATE or KVM_SEV_SNP_LAUNCH_FINISH;

Parameters (in): struct  kvm_sev_snp_launch_start

Returns: 0 on success, -negative on error

::

        struct kvm_sev_snp_launch_start {
                __u64 policy;           /* Guest policy to use. */
                __u8 gosvw[16];         /* Guest OS visible workarounds. */
                __u16 flags;            /* Must be zero. */
                __u8 pad0[6];
                __u64 pad1[4];
        };

See SNP_LAUNCH_START in the SEV-SNP specification [snp-fw-abi]_ for further
details on the input parameters in ``struct kvm_sev_snp_launch_start``.

KVM_SEV_SNP_LAUNCH_UPDATE

493-546

userspace data를 guest GPA range에 적재하고 SNP context measurement에 포함한 뒤 해당 range를 암호화·검증합니다. guest boot 뒤에는 context key로 즉시 읽을 수 있고 guest는 secret을 열기 전에 measurement를 attest할 수 있습니다.

대상 GPA range에는 미리 `KVM_MEMORY_ATTRIBUTE_PRIVATE`가 설정되어 있어야 합니다. 세부 설정은 `KVM_SET_MEMORY_ATTRIBUTES` 문서를 따릅니다.

성공해도 요청 range 전체를 처리했다는 보장은 없습니다. 남은 range에 맞춰 `gfn_start`, `uaddr`, `len`을 갱신하므로 호출자는 `len == 0`이고 주소들이 마지막 범위 다음을 가리킬 때까지 반복 호출해야 합니다. 처리 재시도가 필요하면 `-EAGAIN`을 반환합니다.

`struct kvm_sev_snp_launch_update`
필드의미
`gfn_start`data를 적재·암호화할 시작 guest page
`uaddr`userspace source; ZERO type에서는 무시
`len`4K-aligned byte 길이
`type`초기화할 guest page type
`flags`0이어야 함
padding`pad0`, `pad1`, `pad2[4]` 예약

부분 처리 가능한 SNP page 초기화 인자입니다.

SNP page type
상수분류
`KVM_SEV_SNP_PAGE_TYPE_NORMAL`일반 측정 page
`KVM_SEV_SNP_PAGE_TYPE_ZERO`zero page, uaddr 무시
`KVM_SEV_SNP_PAGE_TYPE_UNMEASURED`measurement 제외 page
`KVM_SEV_SNP_PAGE_TYPE_SECRETS`secrets page
`KVM_SEV_SNP_PAGE_TYPE_CPUID`CPUID page

허용되는 `type` 값입니다.

19. KVM_SEV_SNP_LAUNCH_UPDATE
-----------------------------

The KVM_SEV_SNP_LAUNCH_UPDATE command is used for loading userspace-provided
data into a guest GPA range, measuring the contents into the SNP guest context
created by KVM_SEV_SNP_LAUNCH_START, and then encrypting/validating that GPA
range so that it will be immediately readable using the encryption key
associated with the guest context once it is booted, after which point it can
attest the measurement associated with its context before unlocking any
secrets.

It is required that the GPA ranges initialized by this command have had the
KVM_MEMORY_ATTRIBUTE_PRIVATE attribute set in advance. See the documentation
for KVM_SET_MEMORY_ATTRIBUTES for more details on this aspect.

Upon success, this command is not guaranteed to have processed the entire
range requested. Instead, the ``gfn_start``, ``uaddr``, and ``len`` fields of
``struct kvm_sev_snp_launch_update`` will be updated to correspond to the
remaining range that has yet to be processed. The caller should continue
calling this command until those fields indicate the entire range has been
processed, e.g. ``len`` is 0, ``gfn_start`` is equal to the last GFN in the
range plus 1, and ``uaddr`` is the last byte of the userspace-provided source
buffer address plus 1. In the case where ``type`` is KVM_SEV_SNP_PAGE_TYPE_ZERO,
``uaddr`` will be ignored completely.

Parameters (in): struct  kvm_sev_snp_launch_update

Returns: 0 on success, < 0 on error, -EAGAIN if caller should retry

::

        struct kvm_sev_snp_launch_update {
                __u64 gfn_start;        /* Guest page number to load/encrypt data into. */
                __u64 uaddr;            /* Userspace address of data to be loaded/encrypted. */
                __u64 len;              /* 4k-aligned length in bytes to copy into guest memory.*/
                __u8 type;              /* The type of the guest pages being initialized. */
                __u8 pad0;
                __u16 flags;            /* Must be zero. */
                __u32 pad1;
                __u64 pad2[4];

        };

where the allowed values for page_type are #define'd as::

        KVM_SEV_SNP_PAGE_TYPE_NORMAL
        KVM_SEV_SNP_PAGE_TYPE_ZERO
        KVM_SEV_SNP_PAGE_TYPE_UNMEASURED
        KVM_SEV_SNP_PAGE_TYPE_SECRETS
        KVM_SEV_SNP_PAGE_TYPE_CPUID

See the SEV-SNP spec [snp-fw-abi]_ for further details on how each page type is
used/measured.

KVM_SEV_SNP_LAUNCH_FINISH

547-574

SNP launch flow를 완료하고 guest를 실행 준비 상태로 만듭니다. ID block과 authorization 자료, VCEK 정책 및 host data를 firmware에 전달합니다.

`struct kvm_sev_snp_launch_finish`
필드의미
`id_block_uaddr`ID block 주소
`id_auth_uaddr`ID authorization 주소
`id_block_en`ID block 사용 여부
`auth_key_en`authorization key 사용 여부
`vcek_disabled`VCEK 비활성 여부
`host_data[32]`host 제공 data
`flags`0이어야 함
`pad0`, `pad1[4]`예약 영역

SNP identity와 host-provided data입니다.

세부 의미는 SEV-SNP firmware ABI의 `SNP_LAUNCH_FINISH`를 따릅니다.

20. KVM_SEV_SNP_LAUNCH_FINISH
-----------------------------

After completion of the SNP guest launch flow, the KVM_SEV_SNP_LAUNCH_FINISH
command can be issued to make the guest ready for execution.

Parameters (in): struct kvm_sev_snp_launch_finish

Returns: 0 on success, -negative on error

::

        struct kvm_sev_snp_launch_finish {
                __u64 id_block_uaddr;
                __u64 id_auth_uaddr;
                __u8 id_block_en;
                __u8 auth_key_en;
                __u8 vcek_disabled;
                __u8 host_data[32];
                __u8 pad0[3];
                __u16 flags;                    /* Must be zero */
                __u64 pad1[4];
        };


See SNP_LAUNCH_FINISH in the SEV-SNP specification [snp-fw-abi]_ for further
details on the input parameters in ``struct kvm_sev_snp_launch_finish``.

SEV device attribute API

575-586

`/dev/kvm` device node에 `KVM_X86_GRP_SEV` group을 지정해 `KVM_HAS_DEVICE_ATTR`과 `KVM_GET_DEVICE_ATTR`로 SEV 구현 속성을 조회합니다.

현재 구현된 `KVM_X86_SEV_VMSA_FEATURES`는 `KVM_SEV_INIT2.vmsa_features`가 허용하는 모든 bit의 집합을 반환합니다.

Device attribute API
====================

Attributes of the SEV implementation can be retrieved through the
``KVM_HAS_DEVICE_ATTR`` and ``KVM_GET_DEVICE_ATTR`` ioctls on the ``/dev/kvm``
device node, using group ``KVM_X86_GRP_SEV``.

Currently only one attribute is implemented:

* ``KVM_X86_SEV_VMSA_FEATURES``: return the set of all bits that
  are accepted in the ``vmsa_features`` of ``KVM_SEV_INIT2``.

AMD Secure Processor 펌웨어 관리

587-601

SEV guest key 관리는 별도 AMD Secure Processor(AMD-SP)가 담당합니다. AMD-SP firmware는 bootstrap code 암호화, snapshot, migration, debugging 같은 하이퍼바이저 작업을 위한 secure key management interface를 제공합니다.

AMD-SP firmware는 자체 non-volatile storage로 초기화하거나 OS가 `ccp` module의 `init_ex_path` 매개변수로 NV storage를 관리할 수 있습니다. 지정 파일이 없거나 유효하지 않으면 OS가 PSP non-volatile storage 내용으로 파일을 만들거나 덮어씁니다.

Firmware Management
===================

The SEV guest key management is handled by a separate processor called the AMD
Secure Processor (AMD-SP). Firmware running inside the AMD-SP provides a secure
key management interface to perform common hypervisor activities such as
encrypting bootstrap code, snapshot, migrating and debugging the guest. For more
information, see the SEV Key Management spec [api-spec]_

The AMD-SP firmware can be initialized either by using its own non-volatile
storage or the OS can manage the NV storage for the firmware using
parameter ``init_ex_path`` of the ``ccp`` module. If the file specified
by ``init_ex_path`` does not exist or is invalid, the OS will create or
override the file with PSP non-volatile storage.

참고 문서

602-613
SEV 참고 자료
표기내용
`white-paper`AMD Memory Encryption whitepaper
`api-spec`SEV Key Management API specification
`amd-apm`AMD Architecture Programmer's Manual section 15.34
`kvm-forum`AMD virtualization memory encryption 발표
`snp-fw-abi`SEV-SNP firmware ABI

하드웨어, key management, SNP firmware ABI 자료입니다.

References
==========


See [white-paper]_, [api-spec]_, [amd-apm]_, [kvm-forum]_, and [snp-fw-abi]_
for more info.

.. [white-paper] https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
.. [api-spec] https://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf
.. [amd-apm] https://support.amd.com/TechDocs/24593.pdf (section 15.34)
.. [kvm-forum]  https://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
.. [snp-fw-abi] https://www.amd.com/system/files/TechDocs/56860.pdf