All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support
@ 2024-03-20  8:38 Michael Roth
  2024-03-20  8:38 ` [PATCH v3 01/49] Revert "linux-headers hack" from sevinit2 base tree Michael Roth
                   ` (51 more replies)
  0 siblings, 52 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

These patches implement SEV-SNP base support along with CPUID enforcement
support for QEMU, and are also available at:

  https://github.com/amdese/qemu/commits/snp-v3-rfc

they are based on top of the following patchset from Paolo:

  "[PATCH 0/7] target/i386: VM type infrastructure and KVM_SEV_INIT2 support"
  https://lists.gnu.org/archive/html/qemu-devel/2024-03/msg04663.html


Patch Layout
------------

01-05: Various changes needed to handle new header files in kvm-next tree
       and some hacks to get a functional header sync in place for building
       this series.
06-18: These are patches directly plucked from Xiaoyao's TDX v5 patchset[1]
       that implement common dependencies between SNP/TDX like base
       guest_memfd, KVM_EXIT_MEMORY_FAULT handling (with a small FIXUP), and
       mechanisms to disable SMM. We would've also needed some of the basic
       infrastructure for handling specifying VM types for KVM_CREATE, but
       much of that is now part of the sevinit2 series this patchset is based
       on. Ideally all these patches, once stable, could be maintained in a
       common tree so that future SNP/TDX patchsets can be more easily
       iterated on/reviewed.
19-20: Patches introduced by this series that are  possible candidate for a
       common tree.
       shared/private pages when things like VFIO are in use.
21-32: Introduction of sev-snp-guest object and various configuration
       requirements for SNP.
33-36: Handling for various KVM_EXIT_VMGEXIT events that are handled in
       userspace.
37-49: Support for creating a cryptographic "launch" context and populating
       various OVMF metadata pages, BIOS regions, and vCPU/VMSA pages with
       the initial encrypted/measured/validated launch data prior to
       launching the SNP guest.


Testing
-------

This series has been tested against the following host kernel tree, which
is a snapshot of the latest WIP SNP hypervisor tree at the time of this
posting. It will likely not be kept up to date afterward, so please keep an
eye upstream or official AMDESE github if you are looking for the latest
some time after this posting:

  https://github.com/mdroth/linux/commits/snp-host-v12-wip40/

A patched OVMF is also needed due to upstream KVM no longer supporting MMIO
ranges that are mapped as private. It is recommended you build the AmdSevX64
variant as it provides the kernel-hashing support present in this series:

  https://github.com/mdroth/edk2/commits/apic-mmio-fix1c/

A basic command-line invocation for SNP would be:

 qemu-system-x86_64 -smp 32,maxcpus=255 -cpu EPYC-Milan-v2
  -machine q35,confidential-guest-support=sev0,memory-backend=ram1
  -object memory-backend-memfd,id=ram1,size=4G,share=true,reserve=false
  -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,id-auth=
  -bios /home/mroth/ovmf/OVMF_CODE-upstream-20240228-apicfix-1c-AmdSevX64.fd

With kernel-hashing and certificate data supplied:

 qemu-system-x86_64 -smp 32,maxcpus=255 -cpu EPYC-Milan-v2
  -machine q35,confidential-guest-support=sev0,memory-backend=ram1
  -object memory-backend-memfd,id=ram1,size=4G,share=true,reserve=false
  -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,id-auth=,certs-path=/home/mroth/cert.blob,kernel-hashes=on
  -bios /home/mroth/ovmf/OVMF_CODE-upstream-20240228-apicfix-1c-AmdSevX64.fd
  -kernel /boot/vmlinuz-6.8.0-snp-host-v12-wip40+
  -initrd /boot/initrd.img-6.8.0-snp-host-v12-wip40+
  -append "root=UUID=d72a6d1c-06cf-4b79-af43-f1bac4f620f9 ro console=ttyS0,115200n8"

Any comments/feedback would be very much appreciated.

[1] https://github.com/amdese/linux
    https://github.com/amdese/amdsev/tree/snp-latest

Changes since rfc2:

- reworked on top of guest_memfd support
- added handling for various KVM_EXIT_VMGEXIT events
- various changes/considerations for PCI passthrough support
- general bugfixes/hardening/cleanups
- qapi cmdline doc fixes/rework (Dov, Markus)
- switch to qbase64_decode, more error-checking for cmdline opts (Dov)
- unset id_block_en for 0 input (Dov)
- use error_setg in snp init (Dov)
- report more info in trace_kvm_sev_init (Dov)
- rework bounds-checking for kvm_cpuid_info, rework existing checks for readability, add additional checks (Dov)
- fixups for validated_ranges handling (Dov)
- rename 'policy' field to 'snp-policy' in query-sev when sev-type is SNP

Changes since rfc1:

 - rebased onto latest master
 - drop SNP config file in favor of a new 'sev-snp-guest' object where all
   SNP-related params are passed as strings/integers via command-line
 - report specific error if BIOS reports invalid address/len for
   reserved/pre-validated regions (Connor)
 - use Range helpers for handling validated region overlaps (Dave)
 - simplify error handling in sev_snp_launch_start, and report the correct
   return code when handling LAUNCH_START failures (Dov)
 - add SEV-SNP bit to CPUID 0x8000001f when SNP enabled
 - updated query-sev to handle differences between SEV and SEV-SNP
 - updated to work against v5 of SEV-SNP host kernel / hypervisor patches

----------------------------------------------------------------
Brijesh Singh (5):
      i386/sev: Introduce 'sev-snp-guest' object
      i386/sev: Add the SNP launch start context
      i386/sev: Add handling to encrypt/finalize guest launch data
      hw/i386/sev: Add function to get SEV metadata from OVMF header
      i386/sev: Add support for populating OVMF metadata pages

Chao Peng (2):
      kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot
      kvm: handle KVM_EXIT_MEMORY_FAULT

Dov Murik (4):
      qapi, i386: Move kernel-hashes to SevCommonProperties
      i386/sev: Extract build_kernel_loader_hashes
      i386/sev: Reorder struct declarations
      i386/sev: Allow measured direct kernel boot on SNP

Isaku Yamahata (2):
      pci-host/q35: Move PAM initialization above SMRAM initialization
      q35: Introduce smm_ranges property for q35-pci-host

Michael Roth (30):
      Revert "linux-headers hack" from sevinit2 base tree
      scripts/update-linux-headers: Add setup_data.h to import list
      scripts/update-linux-headers: Add bits.h to file imports
      [HACK] linux-headers: Update headers for 6.8 + kvm-coco-queue + SNP
      [TEMP] hw/i386: Remove redeclaration of struct setup_data
      RAMBlock: Add support of KVM private guest memfd
      [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size
      trace/kvm: Add trace for page convertion between shared and private
      kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled()
      trace/kvm: Add trace for KVM_EXIT_MEMORY_FAULT
      i386/sev: Introduce "sev-common" type to encapsulate common SEV state
      i386/sev: Add a sev_snp_enabled() helper
      target/i386: Add handling for KVM_X86_SNP_VM VM type
      i386/sev: Skip RAMBlock notifiers for SNP
      i386/sev: Skip machine-init-done notifiers for SNP
      i386/sev: Set ms->require_guest_memfd for SNP
      i386/sev: Disable SMM for SNP
      i386/sev: Don't disable block discarding for SNP
      i386/cpu: Set SEV-SNP CPUID bit when SNP enabled
      i386/sev: Update query-sev QAPI format to handle SEV-SNP
      i386/sev: Don't return launch measurements for SEV-SNP guests
      kvm: Make kvm_convert_memory() non-static
      i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes
      i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based)
      i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests
      i386/sev: Set CPU state to protected once SNP guest payload is finalized
      i386/sev: Add support for SNP CPUID validation
      hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
      hw/i386/sev: Use guest_memfd for legacy ROMs
      hw/i386: Add support for loading BIOS using guest_memfd

Xiaoyao Li (6):
      HostMem: Add mechanism to opt in kvm guest memfd via MachineState
      trace/kvm: Split address space and slot id in trace_kvm_set_user_memory()
      kvm: Introduce support for memory_attributes
      physmem: Introduce ram_block_discard_guest_memfd_range()
      kvm/memory: Make memory type private by default if it has guest memfd backend
      memory: Introduce memory_region_init_ram_guest_memfd()

 accel/kvm/kvm-all.c                                |  241 ++-
 accel/kvm/trace-events                             |    4 +-
 accel/stubs/kvm-stub.c                             |    5 +
 backends/hostmem-file.c                            |    1 +
 backends/hostmem-memfd.c                           |    1 +
 backends/hostmem-ram.c                             |    1 +
 backends/hostmem.c                                 |    1 +
 docs/system/i386/amd-memory-encryption.rst         |   78 +-
 hw/core/machine.c                                  |    5 +
 hw/i386/pc.c                                       |   13 +-
 hw/i386/pc_q35.c                                   |    2 +
 hw/i386/pc_sysfw.c                                 |   25 +-
 hw/i386/pc_sysfw_ovmf.c                            |   33 +
 hw/i386/x86.c                                      |   46 +-
 hw/pci-host/q35.c                                  |   61 +-
 include/exec/cpu-common.h                          |    2 +
 include/exec/memory.h                              |   26 +-
 include/exec/ram_addr.h                            |    2 +-
 include/exec/ramblock.h                            |    1 +
 include/hw/boards.h                                |    2 +
 include/hw/i386/pc.h                               |   31 +-
 include/hw/i386/x86.h                              |    2 +-
 include/hw/pci-host/q35.h                          |    1 +
 include/standard-headers/asm-x86/bootparam.h       |   17 +-
 include/standard-headers/asm-x86/kvm_para.h        |    3 +-
 include/standard-headers/linux/ethtool.h           |   48 +
 include/standard-headers/linux/fuse.h              |   39 +-
 include/standard-headers/linux/input-event-codes.h |    1 +
 include/standard-headers/linux/virtio_gpu.h        |    2 +
 include/standard-headers/linux/virtio_snd.h        |  154 ++
 include/sysemu/hostmem.h                           |    1 +
 include/sysemu/kvm.h                               |    7 +
 include/sysemu/kvm_int.h                           |    2 +
 linux-headers/asm-arm64/kvm.h                      |   15 +-
 linux-headers/asm-arm64/sve_context.h              |   11 +
 linux-headers/asm-generic/bitsperlong.h            |    4 +
 linux-headers/asm-loongarch/kvm.h                  |    2 -
 linux-headers/asm-mips/kvm.h                       |    2 -
 linux-headers/asm-powerpc/kvm.h                    |   45 +-
 linux-headers/asm-riscv/kvm.h                      |    3 +-
 linux-headers/asm-s390/kvm.h                       |  315 +++-
 linux-headers/asm-x86/kvm.h                        |  372 ++++-
 linux-headers/asm-x86/setup_data.h                 |   83 +
 linux-headers/linux/bits.h                         |   15 +
 linux-headers/linux/kvm.h                          |  719 +--------
 linux-headers/linux/psp-sev.h                      |   71 +
 qapi/misc-target.json                              |   71 +-
 qapi/qom.json                                      |   96 +-
 scripts/update-linux-headers.sh                    |    5 +-
 system/memory.c                                    |   30 +
 system/physmem.c                                   |   47 +-
 target/i386/cpu.c                                  |    1 +
 target/i386/kvm/kvm.c                              |    4 +
 target/i386/sev-sysemu-stub.c                      |    2 +-
 target/i386/sev.c                                  | 1631 ++++++++++++++++----
 target/i386/sev.h                                  |   13 +-
 target/i386/trace-events                           |    3 +
 57 files changed, 3272 insertions(+), 1146 deletions(-)
 create mode 100644 linux-headers/asm-x86/setup_data.h
 create mode 100644 linux-headers/linux/bits.h



^ permalink raw reply	[flat|nested] 110+ messages in thread

* [PATCH v3 01/49] Revert "linux-headers hack" from sevinit2 base tree
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
@ 2024-03-20  8:38 ` Michael Roth
  2024-03-20  8:38 ` [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list Michael Roth
                   ` (50 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

TODO: Either apply this in advance of sevinit2 patches, or drop this in
favor of a separate preceeding sync of 6.8 kvm-next.

A separate standalone linux-headers sync will be used instead.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 linux-headers/asm-x86/kvm.h | 8 --------
 linux-headers/linux/kvm.h   | 2 --
 2 files changed, 10 deletions(-)

diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 8f58c32d37..003fb74534 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -562,13 +562,5 @@ struct kvm_pmu_event_filter {
 
 #define KVM_X86_DEFAULT_VM	0
 #define KVM_X86_SW_PROTECTED_VM	1
-#define KVM_X86_SEV_VM          2
-#define KVM_X86_SEV_ES_VM       3
-
-struct kvm_sev_init {
-        __u64 vmsa_features;
-        __u32 flags;
-        __u32 pad[9];
-};
 
 #endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 5fd84fd7d0..17839229b2 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1865,8 +1865,6 @@ enum sev_cmd_id {
 	/* Guest Migration Extension */
 	KVM_SEV_SEND_CANCEL,
 
-	KVM_SEV_INIT2,
-
 	KVM_SEV_NR_MAX,
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
  2024-03-20  8:38 ` [PATCH v3 01/49] Revert "linux-headers hack" from sevinit2 base tree Michael Roth
@ 2024-03-20  8:38 ` Michael Roth
  2024-03-20  9:19   ` Paolo Bonzini
  2024-03-20  8:38 ` [PATCH v3 03/49] scripts/update-linux-headers: Add bits.h to file imports Michael Roth
                   ` (49 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Data structures like struct setup_data have been moved to a separate
setup_data.h header which bootparam.h relies on. Add setup_data.h to
the cp_portable() list and sync it along with the other header files.

Note that currently struct setup_data is stripped away as part of
generating bootparam.h, but that handling is no currently needed for
setup_data.h since it doesn't pull in many external
headers/dependencies. However, QEMU currently redefines struct
setup_data in hw/i386/x86.c, so that will need to be removed as part of
any header update that pulls in the new setup_data.h to avoid build
bisect breakage.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 scripts/update-linux-headers.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index a0006eec6f..579b03dc82 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -62,6 +62,7 @@ cp_portable() {
                                      -e 'linux/kernel' \
                                      -e 'linux/sysinfo' \
                                      -e 'asm-generic/kvm_para' \
+                                     -e 'asm/setup_data.h' \
                                      > /dev/null
     then
         echo "Unexpected #include in input file $f".
@@ -155,6 +156,8 @@ for arch in $ARCHLIST; do
                "$tmpdir/include/asm/bootparam.h" > "$tmpdir/bootparam.h"
         cp_portable "$tmpdir/bootparam.h" \
                     "$output/include/standard-headers/asm-$arch"
+        cp_portable "$tmpdir/include/asm/setup_data.h" \
+                    "$output/linux-headers/asm-x86"
     fi
     if [ $arch = riscv ]; then
         cp "$tmpdir/include/asm/ptrace.h" "$output/linux-headers/asm-riscv/"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 03/49] scripts/update-linux-headers: Add bits.h to file imports
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
  2024-03-20  8:38 ` [PATCH v3 01/49] Revert "linux-headers hack" from sevinit2 base tree Michael Roth
  2024-03-20  8:38 ` [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list Michael Roth
@ 2024-03-20  8:38 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 04/49] [HACK] linux-headers: Update headers for 6.8 + kvm-coco-queue + SNP Michael Roth
                   ` (48 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 scripts/update-linux-headers.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 579b03dc82..b992ed7b15 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -168,7 +168,7 @@ rm -rf "$output/linux-headers/linux"
 mkdir -p "$output/linux-headers/linux"
 for header in const.h stddef.h kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \
               psci.h psp-sev.h userfaultfd.h memfd.h mman.h nvme_ioctl.h \
-              vduse.h iommufd.h; do
+              vduse.h iommufd.h bits.h; do
     cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
 done
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 04/49] [HACK] linux-headers: Update headers for 6.8 + kvm-coco-queue + SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (2 preceding siblings ...)
  2024-03-20  8:38 ` [PATCH v3 03/49] scripts/update-linux-headers: Add bits.h to file imports Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 05/49] [TEMP] hw/i386: Remove redeclaration of struct setup_data Michael Roth
                   ` (47 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Pull in 6.8 kvm-next + kvm-coco-queue + SNP headers.

Be careful to omit removing the following virtio_pci.h definitions which
are no longer present upstream, since QEMU still relies on them:

  #define LM_LOGGING_CTRL                 0
  #define LM_BASE_ADDR_LOW                4
  #define LM_BASE_ADDR_HIGH               8
  #define LM_END_ADDR_LOW                 12
  #define LM_END_ADDR_HIGH                16
  #define LM_VRING_STATE_OFFSET           0x20

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 include/standard-headers/asm-x86/bootparam.h  |  17 +-
 include/standard-headers/asm-x86/kvm_para.h   |   3 +-
 include/standard-headers/linux/ethtool.h      |  48 ++
 include/standard-headers/linux/fuse.h         |  39 +-
 .../linux/input-event-codes.h                 |   1 +
 include/standard-headers/linux/virtio_gpu.h   |   2 +
 include/standard-headers/linux/virtio_snd.h   | 154 ++++
 linux-headers/asm-arm64/kvm.h                 |  15 +-
 linux-headers/asm-arm64/sve_context.h         |  11 +
 linux-headers/asm-generic/bitsperlong.h       |   4 +
 linux-headers/asm-loongarch/kvm.h             |   2 -
 linux-headers/asm-mips/kvm.h                  |   2 -
 linux-headers/asm-powerpc/kvm.h               |  45 +-
 linux-headers/asm-riscv/kvm.h                 |   3 +-
 linux-headers/asm-s390/kvm.h                  | 315 +++++++-
 linux-headers/asm-x86/kvm.h                   | 364 ++++++++-
 linux-headers/asm-x86/setup_data.h            |  83 ++
 linux-headers/linux/bits.h                    |  15 +
 linux-headers/linux/kvm.h                     | 717 +-----------------
 linux-headers/linux/psp-sev.h                 |  71 ++
 20 files changed, 1186 insertions(+), 725 deletions(-)
 create mode 100644 linux-headers/asm-x86/setup_data.h
 create mode 100644 linux-headers/linux/bits.h

diff --git a/include/standard-headers/asm-x86/bootparam.h b/include/standard-headers/asm-x86/bootparam.h
index 0b06d2bff1..62e4cd5390 100644
--- a/include/standard-headers/asm-x86/bootparam.h
+++ b/include/standard-headers/asm-x86/bootparam.h
@@ -2,21 +2,7 @@
 #ifndef _ASM_X86_BOOTPARAM_H
 #define _ASM_X86_BOOTPARAM_H
 
-/* setup_data/setup_indirect types */
-#define SETUP_NONE			0
-#define SETUP_E820_EXT			1
-#define SETUP_DTB			2
-#define SETUP_PCI			3
-#define SETUP_EFI			4
-#define SETUP_APPLE_PROPERTIES		5
-#define SETUP_JAILHOUSE			6
-#define SETUP_CC_BLOB			7
-#define SETUP_IMA			8
-#define SETUP_RNG_SEED			9
-#define SETUP_ENUM_MAX			SETUP_RNG_SEED
-
-#define SETUP_INDIRECT			(1<<31)
-#define SETUP_TYPE_MAX			(SETUP_ENUM_MAX | SETUP_INDIRECT)
+#include <asm/setup_data.h>
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
@@ -38,6 +24,7 @@
 #define XLF_EFI_KEXEC			(1<<4)
 #define XLF_5LEVEL			(1<<5)
 #define XLF_5LEVEL_ENABLED		(1<<6)
+#define XLF_MEM_ENCRYPTION		(1<<7)
 
 
 #endif /* _ASM_X86_BOOTPARAM_H */
diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h
index f0235e58a1..9a011d20f0 100644
--- a/include/standard-headers/asm-x86/kvm_para.h
+++ b/include/standard-headers/asm-x86/kvm_para.h
@@ -92,7 +92,7 @@ struct kvm_clock_pairing {
 #define KVM_ASYNC_PF_DELIVERY_AS_INT		(1 << 3)
 
 /* MSR_KVM_ASYNC_PF_INT */
-#define KVM_ASYNC_PF_VEC_MASK			GENMASK(7, 0)
+#define KVM_ASYNC_PF_VEC_MASK			__GENMASK(7, 0)
 
 /* MSR_KVM_MIGRATION_CONTROL */
 #define KVM_MIGRATION_READY		(1 << 0)
@@ -142,7 +142,6 @@ struct kvm_vcpu_pv_apf_data {
 	uint32_t token;
 
 	uint8_t pad[56];
-	uint32_t enabled;
 };
 
 #define KVM_PV_EOI_BIT 0
diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h
index dfb54eff6f..01503784d2 100644
--- a/include/standard-headers/linux/ethtool.h
+++ b/include/standard-headers/linux/ethtool.h
@@ -2023,6 +2023,53 @@ static inline int ethtool_validate_duplex(uint8_t duplex)
 #define	IPV4_FLOW	0x10	/* hash only */
 #define	IPV6_FLOW	0x11	/* hash only */
 #define	ETHER_FLOW	0x12	/* spec only (ether_spec) */
+
+/* Used for GTP-U IPv4 and IPv6.
+ * The format of GTP packets only includes
+ * elements such as TEID and GTP version.
+ * It is primarily intended for data communication of the UE.
+ */
+#define GTPU_V4_FLOW 0x13	/* hash only */
+#define GTPU_V6_FLOW 0x14	/* hash only */
+
+/* Use for GTP-C IPv4 and v6.
+ * The format of these GTP packets does not include TEID.
+ * Primarily expected to be used for communication
+ * to create sessions for UE data communication,
+ * commonly referred to as CSR (Create Session Request).
+ */
+#define GTPC_V4_FLOW 0x15	/* hash only */
+#define GTPC_V6_FLOW 0x16	/* hash only */
+
+/* Use for GTP-C IPv4 and v6.
+ * Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID.
+ * After session creation, it becomes this packet.
+ * This is mainly used for requests to realize UE handover.
+ */
+#define GTPC_TEID_V4_FLOW 0x17	/* hash only */
+#define GTPC_TEID_V6_FLOW 0x18	/* hash only */
+
+/* Use for GTP-U and extended headers for the PSC (PDU Session Container).
+ * The format of these GTP packets includes TEID and QFI.
+ * In 5G communication using UPF (User Plane Function),
+ * data communication with this extended header is performed.
+ */
+#define GTPU_EH_V4_FLOW 0x19	/* hash only */
+#define GTPU_EH_V6_FLOW 0x1a	/* hash only */
+
+/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers.
+ * This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by
+ * UL/DL included in the PSC.
+ * There are differences in the data included based on Downlink/Uplink,
+ * and can be used to distinguish packets.
+ * The functions described so far are useful when you want to
+ * handle communication from the mobile network in UPF, PGW, etc.
+ */
+#define GTPU_UL_V4_FLOW 0x1b	/* hash only */
+#define GTPU_UL_V6_FLOW 0x1c	/* hash only */
+#define GTPU_DL_V4_FLOW 0x1d	/* hash only */
+#define GTPU_DL_V6_FLOW 0x1e	/* hash only */
+
 /* Flag to enable additional fields in struct ethtool_rx_flow_spec */
 #define	FLOW_EXT	0x80000000
 #define	FLOW_MAC_EXT	0x40000000
@@ -2037,6 +2084,7 @@ static inline int ethtool_validate_duplex(uint8_t duplex)
 #define	RXH_IP_DST	(1 << 5)
 #define	RXH_L4_B_0_1	(1 << 6) /* src port in case of TCP/UDP/SCTP */
 #define	RXH_L4_B_2_3	(1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define	RXH_GTP_TEID	(1 << 8) /* teid in case of GTP */
 #define	RXH_DISCARD	(1 << 31)
 
 #define	RX_CLS_FLOW_DISC	0xffffffffffffffffULL
diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h
index fc0dcd10ae..bac9dbc49f 100644
--- a/include/standard-headers/linux/fuse.h
+++ b/include/standard-headers/linux/fuse.h
@@ -211,6 +211,12 @@
  *  7.39
  *  - add FUSE_DIRECT_IO_ALLOW_MMAP
  *  - add FUSE_STATX and related structures
+ *
+ *  7.40
+ *  - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag
+ *  - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag
+ *  - add FUSE_NO_EXPORT_SUPPORT init flag
+ *  - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag
  */
 
 #ifndef _LINUX_FUSE_H
@@ -242,7 +248,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 39
+#define FUSE_KERNEL_MINOR_VERSION 40
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -349,6 +355,7 @@ struct fuse_file_lock {
  * FOPEN_STREAM: the file is stream-like (no file position at all)
  * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
  * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode
+ * FOPEN_PASSTHROUGH: passthrough read/write io for this open file
  */
 #define FOPEN_DIRECT_IO		(1 << 0)
 #define FOPEN_KEEP_CACHE	(1 << 1)
@@ -357,6 +364,7 @@ struct fuse_file_lock {
 #define FOPEN_STREAM		(1 << 4)
 #define FOPEN_NOFLUSH		(1 << 5)
 #define FOPEN_PARALLEL_DIRECT_WRITES	(1 << 6)
+#define FOPEN_PASSTHROUGH	(1 << 7)
 
 /**
  * INIT request/reply flags
@@ -406,6 +414,9 @@ struct fuse_file_lock {
  *			symlink and mknod (single group that matches parent)
  * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
  * FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode.
+ * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support
+ * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit
+ *		    of the request ID indicates resend requests
  */
 #define FUSE_ASYNC_READ		(1 << 0)
 #define FUSE_POSIX_LOCKS	(1 << 1)
@@ -445,6 +456,9 @@ struct fuse_file_lock {
 #define FUSE_CREATE_SUPP_GROUP	(1ULL << 34)
 #define FUSE_HAS_EXPIRE_ONLY	(1ULL << 35)
 #define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36)
+#define FUSE_PASSTHROUGH	(1ULL << 37)
+#define FUSE_NO_EXPORT_SUPPORT	(1ULL << 38)
+#define FUSE_HAS_RESEND		(1ULL << 39)
 
 /* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
 #define FUSE_DIRECT_IO_RELAX	FUSE_DIRECT_IO_ALLOW_MMAP
@@ -631,6 +645,7 @@ enum fuse_notify_code {
 	FUSE_NOTIFY_STORE = 4,
 	FUSE_NOTIFY_RETRIEVE = 5,
 	FUSE_NOTIFY_DELETE = 6,
+	FUSE_NOTIFY_RESEND = 7,
 	FUSE_NOTIFY_CODE_MAX,
 };
 
@@ -757,7 +772,7 @@ struct fuse_create_in {
 struct fuse_open_out {
 	uint64_t	fh;
 	uint32_t	open_flags;
-	uint32_t	padding;
+	int32_t		backing_id;
 };
 
 struct fuse_release_in {
@@ -873,7 +888,8 @@ struct fuse_init_out {
 	uint16_t	max_pages;
 	uint16_t	map_alignment;
 	uint32_t	flags2;
-	uint32_t	unused[7];
+	uint32_t	max_stack_depth;
+	uint32_t	unused[6];
 };
 
 #define CUSE_INIT_INFO_MAX 4096
@@ -956,6 +972,14 @@ struct fuse_fallocate_in {
 	uint32_t	padding;
 };
 
+/**
+ * FUSE request unique ID flag
+ *
+ * Indicates whether this is a resend request. The receiver should handle this
+ * request accordingly.
+ */
+#define FUSE_UNIQUE_RESEND (1ULL << 63)
+
 struct fuse_in_header {
 	uint32_t	len;
 	uint32_t	opcode;
@@ -1045,9 +1069,18 @@ struct fuse_notify_retrieve_in {
 	uint64_t	dummy4;
 };
 
+struct fuse_backing_map {
+	int32_t		fd;
+	uint32_t	flags;
+	uint64_t	padding;
+};
+
 /* Device ioctls: */
 #define FUSE_DEV_IOC_MAGIC		229
 #define FUSE_DEV_IOC_CLONE		_IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
+#define FUSE_DEV_IOC_BACKING_OPEN	_IOW(FUSE_DEV_IOC_MAGIC, 1, \
+					     struct fuse_backing_map)
+#define FUSE_DEV_IOC_BACKING_CLOSE	_IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
 
 struct fuse_lseek_in {
 	uint64_t	fh;
diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h
index f6bab08540..2221b0c383 100644
--- a/include/standard-headers/linux/input-event-codes.h
+++ b/include/standard-headers/linux/input-event-codes.h
@@ -602,6 +602,7 @@
 
 #define KEY_ALS_TOGGLE		0x230	/* Ambient light sensor */
 #define KEY_ROTATE_LOCK_TOGGLE	0x231	/* Display rotation lock */
+#define KEY_REFRESH_RATE_TOGGLE	0x232	/* Display refresh rate toggle */
 
 #define KEY_BUTTONCONFIG		0x240	/* AL Button Configuration */
 #define KEY_TASKMANAGER		0x241	/* AL Task/Project Manager */
diff --git a/include/standard-headers/linux/virtio_gpu.h b/include/standard-headers/linux/virtio_gpu.h
index 2da48d3d4c..2db643ed8f 100644
--- a/include/standard-headers/linux/virtio_gpu.h
+++ b/include/standard-headers/linux/virtio_gpu.h
@@ -309,6 +309,8 @@ struct virtio_gpu_cmd_submit {
 
 #define VIRTIO_GPU_CAPSET_VIRGL 1
 #define VIRTIO_GPU_CAPSET_VIRGL2 2
+/* 3 is reserved for gfxstream */
+#define VIRTIO_GPU_CAPSET_VENUS 4
 
 /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
 struct virtio_gpu_get_capset_info {
diff --git a/include/standard-headers/linux/virtio_snd.h b/include/standard-headers/linux/virtio_snd.h
index 1af96b9fc6..860f12e0a4 100644
--- a/include/standard-headers/linux/virtio_snd.h
+++ b/include/standard-headers/linux/virtio_snd.h
@@ -7,6 +7,14 @@
 
 #include "standard-headers/linux/virtio_types.h"
 
+/*******************************************************************************
+ * FEATURE BITS
+ */
+enum {
+	/* device supports control elements */
+	VIRTIO_SND_F_CTLS = 0
+};
+
 /*******************************************************************************
  * CONFIGURATION SPACE
  */
@@ -17,6 +25,8 @@ struct virtio_snd_config {
 	uint32_t streams;
 	/* # of available channel maps */
 	uint32_t chmaps;
+	/* # of available control elements */
+	uint32_t controls;
 };
 
 enum {
@@ -55,6 +65,15 @@ enum {
 	/* channel map control request types */
 	VIRTIO_SND_R_CHMAP_INFO = 0x0200,
 
+	/* control element request types */
+	VIRTIO_SND_R_CTL_INFO = 0x0300,
+	VIRTIO_SND_R_CTL_ENUM_ITEMS,
+	VIRTIO_SND_R_CTL_READ,
+	VIRTIO_SND_R_CTL_WRITE,
+	VIRTIO_SND_R_CTL_TLV_READ,
+	VIRTIO_SND_R_CTL_TLV_WRITE,
+	VIRTIO_SND_R_CTL_TLV_COMMAND,
+
 	/* jack event types */
 	VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
 	VIRTIO_SND_EVT_JACK_DISCONNECTED,
@@ -63,6 +82,9 @@ enum {
 	VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
 	VIRTIO_SND_EVT_PCM_XRUN,
 
+	/* control element event types */
+	VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
+
 	/* common status codes */
 	VIRTIO_SND_S_OK = 0x8000,
 	VIRTIO_SND_S_BAD_MSG,
@@ -331,4 +353,136 @@ struct virtio_snd_chmap_info {
 	uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
 };
 
+/*******************************************************************************
+ * CONTROL ELEMENTS MESSAGES
+ */
+struct virtio_snd_ctl_hdr {
+	/* VIRTIO_SND_R_CTL_XXX */
+	struct virtio_snd_hdr hdr;
+	/* 0 ... virtio_snd_config::controls - 1 */
+	uint32_t control_id;
+};
+
+/* supported roles for control elements */
+enum {
+	VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
+	VIRTIO_SND_CTL_ROLE_VOLUME,
+	VIRTIO_SND_CTL_ROLE_MUTE,
+	VIRTIO_SND_CTL_ROLE_GAIN
+};
+
+/* supported value types for control elements */
+enum {
+	VIRTIO_SND_CTL_TYPE_BOOLEAN = 0,
+	VIRTIO_SND_CTL_TYPE_INTEGER,
+	VIRTIO_SND_CTL_TYPE_INTEGER64,
+	VIRTIO_SND_CTL_TYPE_ENUMERATED,
+	VIRTIO_SND_CTL_TYPE_BYTES,
+	VIRTIO_SND_CTL_TYPE_IEC958
+};
+
+/* supported access rights for control elements */
+enum {
+	VIRTIO_SND_CTL_ACCESS_READ = 0,
+	VIRTIO_SND_CTL_ACCESS_WRITE,
+	VIRTIO_SND_CTL_ACCESS_VOLATILE,
+	VIRTIO_SND_CTL_ACCESS_INACTIVE,
+	VIRTIO_SND_CTL_ACCESS_TLV_READ,
+	VIRTIO_SND_CTL_ACCESS_TLV_WRITE,
+	VIRTIO_SND_CTL_ACCESS_TLV_COMMAND
+};
+
+struct virtio_snd_ctl_info {
+	/* common header */
+	struct virtio_snd_info hdr;
+	/* element role (VIRTIO_SND_CTL_ROLE_XXX) */
+	uint32_t role;
+	/* element value type (VIRTIO_SND_CTL_TYPE_XXX) */
+	uint32_t type;
+	/* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */
+	uint32_t access;
+	/* # of members in the element value */
+	uint32_t count;
+	/* index for an element with a non-unique name */
+	uint32_t index;
+	/* name identifier string for the element */
+	uint8_t name[44];
+	/* additional information about the element's value */
+	union {
+		/* VIRTIO_SND_CTL_TYPE_INTEGER */
+		struct {
+			/* minimum supported value */
+			uint32_t min;
+			/* maximum supported value */
+			uint32_t max;
+			/* fixed step size for value (0 = variable size) */
+			uint32_t step;
+		} integer;
+		/* VIRTIO_SND_CTL_TYPE_INTEGER64 */
+		struct {
+			/* minimum supported value */
+			uint64_t min;
+			/* maximum supported value */
+			uint64_t max;
+			/* fixed step size for value (0 = variable size) */
+			uint64_t step;
+		} integer64;
+		/* VIRTIO_SND_CTL_TYPE_ENUMERATED */
+		struct {
+			/* # of options supported for value */
+			uint32_t items;
+		} enumerated;
+	} value;
+};
+
+struct virtio_snd_ctl_enum_item {
+	/* option name */
+	uint8_t item[64];
+};
+
+struct virtio_snd_ctl_iec958 {
+	/* AES/IEC958 channel status bits */
+	uint8_t status[24];
+	/* AES/IEC958 subcode bits */
+	uint8_t subcode[147];
+	/* nothing */
+	uint8_t pad;
+	/* AES/IEC958 subframe bits */
+	uint8_t dig_subframe[4];
+};
+
+struct virtio_snd_ctl_value {
+	union {
+		/* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */
+		uint32_t integer[128];
+		/* VIRTIO_SND_CTL_TYPE_INTEGER64 value */
+		uint64_t integer64[64];
+		/* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */
+		uint32_t enumerated[128];
+		/* VIRTIO_SND_CTL_TYPE_BYTES value */
+		uint8_t bytes[512];
+		/* VIRTIO_SND_CTL_TYPE_IEC958 value */
+		struct virtio_snd_ctl_iec958 iec958;
+	} value;
+};
+
+/* supported event reason types */
+enum {
+	/* element's value has changed */
+	VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
+	/* element's information has changed */
+	VIRTIO_SND_CTL_EVT_MASK_INFO,
+	/* element's metadata has changed */
+	VIRTIO_SND_CTL_EVT_MASK_TLV
+};
+
+struct virtio_snd_ctl_event {
+	/* VIRTIO_SND_EVT_CTL_NOTIFY */
+	struct virtio_snd_hdr hdr;
+	/* 0 ... virtio_snd_config::controls - 1 */
+	uint16_t control_id;
+	/* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */
+	uint16_t mask;
+};
+
 #endif /* VIRTIO_SND_IF_H */
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index c59ea55cd8..2af9931ae9 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -37,9 +37,7 @@
 #include <asm/ptrace.h>
 #include <asm/sve_context.h>
 
-#define __KVM_HAVE_GUEST_DEBUG
 #define __KVM_HAVE_IRQ_LINE
-#define __KVM_HAVE_READONLY_MEM
 #define __KVM_HAVE_VCPU_EVENTS
 
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -76,11 +74,11 @@ struct kvm_regs {
 
 /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
 #define KVM_ARM_DEVICE_TYPE_SHIFT	0
-#define KVM_ARM_DEVICE_TYPE_MASK	GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \
-						KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_TYPE_MASK	__GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \
+						  KVM_ARM_DEVICE_TYPE_SHIFT)
 #define KVM_ARM_DEVICE_ID_SHIFT		16
-#define KVM_ARM_DEVICE_ID_MASK		GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \
-						KVM_ARM_DEVICE_ID_SHIFT)
+#define KVM_ARM_DEVICE_ID_MASK		__GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \
+						  KVM_ARM_DEVICE_ID_SHIFT)
 
 /* Supported device IDs */
 #define KVM_ARM_DEVICE_VGIC_V2		0
@@ -162,6 +160,11 @@ struct kvm_sync_regs {
 	__u64 device_irq_level;
 };
 
+/* Bits for run->s.regs.device_irq_level */
+#define KVM_ARM_DEV_EL1_VTIMER		(1 << 0)
+#define KVM_ARM_DEV_EL1_PTIMER		(1 << 1)
+#define KVM_ARM_DEV_PMU			(1 << 2)
+
 /*
  * PMU filter structure. Describe a range of events with a particular
  * action. To be used with KVM_ARM_VCPU_PMU_V3_FILTER.
diff --git a/linux-headers/asm-arm64/sve_context.h b/linux-headers/asm-arm64/sve_context.h
index 1d0e3e1d09..d1b1ec8cb1 100644
--- a/linux-headers/asm-arm64/sve_context.h
+++ b/linux-headers/asm-arm64/sve_context.h
@@ -13,6 +13,17 @@
 
 #define __SVE_VQ_BYTES		16	/* number of bytes per quadword */
 
+/*
+ * Yes, __SVE_VQ_MAX is 512 QUADWORDS.
+ *
+ * To help ensure forward portability, this is much larger than the
+ * current maximum value defined by the SVE architecture.  While arrays
+ * or static allocations can be sized based on this value, watch out!
+ * It will waste a surprisingly large amount of memory.
+ *
+ * Dynamic sizing based on the actual runtime vector length is likely to
+ * be preferable for most purposes.
+ */
 #define __SVE_VQ_MIN		1
 #define __SVE_VQ_MAX		512
 
diff --git a/linux-headers/asm-generic/bitsperlong.h b/linux-headers/asm-generic/bitsperlong.h
index 75f320fa91..1fb4f0c9f2 100644
--- a/linux-headers/asm-generic/bitsperlong.h
+++ b/linux-headers/asm-generic/bitsperlong.h
@@ -24,4 +24,8 @@
 #endif
 #endif
 
+#ifndef __BITS_PER_LONG_LONG
+#define __BITS_PER_LONG_LONG 64
+#endif
+
 #endif /* __ASM_GENERIC_BITS_PER_LONG */
diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h
index 923d0bd382..109785922c 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -14,8 +14,6 @@
  * Some parts derived from the x86 version of this file.
  */
 
-#define __KVM_HAVE_READONLY_MEM
-
 #define KVM_COALESCED_MMIO_PAGE_OFFSET	1
 #define KVM_DIRTY_LOG_PAGE_OFFSET	64
 
diff --git a/linux-headers/asm-mips/kvm.h b/linux-headers/asm-mips/kvm.h
index edcf717c43..9673dc9cb3 100644
--- a/linux-headers/asm-mips/kvm.h
+++ b/linux-headers/asm-mips/kvm.h
@@ -20,8 +20,6 @@
  * Some parts derived from the x86 version of this file.
  */
 
-#define __KVM_HAVE_READONLY_MEM
-
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 
 /*
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 9f18fa090f..1691297a76 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -28,7 +28,6 @@
 #define __KVM_HAVE_PPC_SMT
 #define __KVM_HAVE_IRQCHIP
 #define __KVM_HAVE_IRQ_LINE
-#define __KVM_HAVE_GUEST_DEBUG
 
 /* Not always available, but if it is, this is the correct offset.  */
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -733,4 +732,48 @@ struct kvm_ppc_xive_eq {
 #define KVM_XIVE_TIMA_PAGE_OFFSET	0
 #define KVM_XIVE_ESB_PAGE_OFFSET	4
 
+/* for KVM_PPC_GET_PVINFO */
+
+#define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
+
+struct kvm_ppc_pvinfo {
+	/* out */
+	__u32 flags;
+	__u32 hcall[4];
+	__u8  pad[108];
+};
+
+/* for KVM_PPC_GET_SMMU_INFO */
+#define KVM_PPC_PAGE_SIZES_MAX_SZ	8
+
+struct kvm_ppc_one_page_size {
+	__u32 page_shift;	/* Page shift (or 0) */
+	__u32 pte_enc;		/* Encoding in the HPTE (>>12) */
+};
+
+struct kvm_ppc_one_seg_page_size {
+	__u32 page_shift;	/* Base page shift of segment (or 0) */
+	__u32 slb_enc;		/* SLB encoding for BookS */
+	struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
+};
+
+#define KVM_PPC_PAGE_SIZES_REAL		0x00000001
+#define KVM_PPC_1T_SEGMENTS		0x00000002
+#define KVM_PPC_NO_HASH			0x00000004
+
+struct kvm_ppc_smmu_info {
+	__u64 flags;
+	__u32 slb_size;
+	__u16 data_keys;	/* # storage keys supported for data */
+	__u16 instr_keys;	/* # storage keys supported for instructions */
+	struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
+};
+
+/* for KVM_PPC_RESIZE_HPT_{PREPARE,COMMIT} */
+struct kvm_ppc_resize_hpt {
+	__u64 flags;
+	__u32 shift;
+	__u32 pad;
+};
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h
index 7499e88a94..b1c503c295 100644
--- a/linux-headers/asm-riscv/kvm.h
+++ b/linux-headers/asm-riscv/kvm.h
@@ -16,7 +16,6 @@
 #include <asm/ptrace.h>
 
 #define __KVM_HAVE_IRQ_LINE
-#define __KVM_HAVE_READONLY_MEM
 
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 
@@ -166,6 +165,8 @@ enum KVM_RISCV_ISA_EXT_ID {
 	KVM_RISCV_ISA_EXT_ZVFH,
 	KVM_RISCV_ISA_EXT_ZVFHMIN,
 	KVM_RISCV_ISA_EXT_ZFA,
+	KVM_RISCV_ISA_EXT_ZTSO,
+	KVM_RISCV_ISA_EXT_ZACAS,
 	KVM_RISCV_ISA_EXT_MAX,
 };
 
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 023a2763a9..684c4e1205 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -12,7 +12,320 @@
 #include <linux/types.h>
 
 #define __KVM_S390
-#define __KVM_HAVE_GUEST_DEBUG
+
+struct kvm_s390_skeys {
+	__u64 start_gfn;
+	__u64 count;
+	__u64 skeydata_addr;
+	__u32 flags;
+	__u32 reserved[9];
+};
+
+#define KVM_S390_CMMA_PEEK (1 << 0)
+
+/**
+ * kvm_s390_cmma_log - Used for CMMA migration.
+ *
+ * Used both for input and output.
+ *
+ * @start_gfn: Guest page number to start from.
+ * @count: Size of the result buffer.
+ * @flags: Control operation mode via KVM_S390_CMMA_* flags
+ * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty
+ *             pages are still remaining.
+ * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set
+ *        in the PGSTE.
+ * @values: Pointer to the values buffer.
+ *
+ * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls.
+ */
+struct kvm_s390_cmma_log {
+	__u64 start_gfn;
+	__u32 count;
+	__u32 flags;
+	union {
+		__u64 remaining;
+		__u64 mask;
+	};
+	__u64 values;
+};
+
+#define KVM_S390_RESET_POR       1
+#define KVM_S390_RESET_CLEAR     2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT  8
+#define KVM_S390_RESET_IPL       16
+
+/* for KVM_S390_MEM_OP */
+struct kvm_s390_mem_op {
+	/* in */
+	__u64 gaddr;		/* the guest address */
+	__u64 flags;		/* flags */
+	__u32 size;		/* amount of bytes */
+	__u32 op;		/* type of operation */
+	__u64 buf;		/* buffer in userspace */
+	union {
+		struct {
+			__u8 ar;	/* the access register number */
+			__u8 key;	/* access key, ignored if flag unset */
+			__u8 pad1[6];	/* ignored */
+			__u64 old_addr;	/* ignored if cmpxchg flag unset */
+		};
+		__u32 sida_offset; /* offset into the sida */
+		__u8 reserved[32]; /* ignored */
+	};
+};
+/* types for kvm_s390_mem_op->op */
+#define KVM_S390_MEMOP_LOGICAL_READ	0
+#define KVM_S390_MEMOP_LOGICAL_WRITE	1
+#define KVM_S390_MEMOP_SIDA_READ	2
+#define KVM_S390_MEMOP_SIDA_WRITE	3
+#define KVM_S390_MEMOP_ABSOLUTE_READ	4
+#define KVM_S390_MEMOP_ABSOLUTE_WRITE	5
+#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG	6
+
+/* flags for kvm_s390_mem_op->flags */
+#define KVM_S390_MEMOP_F_CHECK_ONLY		(1ULL << 0)
+#define KVM_S390_MEMOP_F_INJECT_EXCEPTION	(1ULL << 1)
+#define KVM_S390_MEMOP_F_SKEY_PROTECTION	(1ULL << 2)
+
+/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */
+#define KVM_S390_MEMOP_EXTENSION_CAP_BASE	(1 << 0)
+#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG	(1 << 1)
+
+struct kvm_s390_psw {
+	__u64 mask;
+	__u64 addr;
+};
+
+/* valid values for type in kvm_s390_interrupt */
+#define KVM_S390_SIGP_STOP		0xfffe0000u
+#define KVM_S390_PROGRAM_INT		0xfffe0001u
+#define KVM_S390_SIGP_SET_PREFIX	0xfffe0002u
+#define KVM_S390_RESTART		0xfffe0003u
+#define KVM_S390_INT_PFAULT_INIT	0xfffe0004u
+#define KVM_S390_INT_PFAULT_DONE	0xfffe0005u
+#define KVM_S390_MCHK			0xfffe1000u
+#define KVM_S390_INT_CLOCK_COMP		0xffff1004u
+#define KVM_S390_INT_CPU_TIMER		0xffff1005u
+#define KVM_S390_INT_VIRTIO		0xffff2603u
+#define KVM_S390_INT_SERVICE		0xffff2401u
+#define KVM_S390_INT_EMERGENCY		0xffff1201u
+#define KVM_S390_INT_EXTERNAL_CALL	0xffff1202u
+/* Anything below 0xfffe0000u is taken by INT_IO */
+#define KVM_S390_INT_IO(ai,cssid,ssid,schid)   \
+	(((schid)) |			       \
+	 ((ssid) << 16) |		       \
+	 ((cssid) << 18) |		       \
+	 ((ai) << 26))
+#define KVM_S390_INT_IO_MIN		0x00000000u
+#define KVM_S390_INT_IO_MAX		0xfffdffffu
+#define KVM_S390_INT_IO_AI_MASK		0x04000000u
+
+
+struct kvm_s390_interrupt {
+	__u32 type;
+	__u32 parm;
+	__u64 parm64;
+};
+
+struct kvm_s390_io_info {
+	__u16 subchannel_id;
+	__u16 subchannel_nr;
+	__u32 io_int_parm;
+	__u32 io_int_word;
+};
+
+struct kvm_s390_ext_info {
+	__u32 ext_params;
+	__u32 pad;
+	__u64 ext_params2;
+};
+
+struct kvm_s390_pgm_info {
+	__u64 trans_exc_code;
+	__u64 mon_code;
+	__u64 per_address;
+	__u32 data_exc_code;
+	__u16 code;
+	__u16 mon_class_nr;
+	__u8 per_code;
+	__u8 per_atmid;
+	__u8 exc_access_id;
+	__u8 per_access_id;
+	__u8 op_access_id;
+#define KVM_S390_PGM_FLAGS_ILC_VALID	0x01
+#define KVM_S390_PGM_FLAGS_ILC_0	0x02
+#define KVM_S390_PGM_FLAGS_ILC_1	0x04
+#define KVM_S390_PGM_FLAGS_ILC_MASK	0x06
+#define KVM_S390_PGM_FLAGS_NO_REWIND	0x08
+	__u8 flags;
+	__u8 pad[2];
+};
+
+struct kvm_s390_prefix_info {
+	__u32 address;
+};
+
+struct kvm_s390_extcall_info {
+	__u16 code;
+};
+
+struct kvm_s390_emerg_info {
+	__u16 code;
+};
+
+#define KVM_S390_STOP_FLAG_STORE_STATUS	0x01
+struct kvm_s390_stop_info {
+	__u32 flags;
+};
+
+struct kvm_s390_mchk_info {
+	__u64 cr14;
+	__u64 mcic;
+	__u64 failing_storage_address;
+	__u32 ext_damage_code;
+	__u32 pad;
+	__u8 fixed_logout[16];
+};
+
+struct kvm_s390_irq {
+	__u64 type;
+	union {
+		struct kvm_s390_io_info io;
+		struct kvm_s390_ext_info ext;
+		struct kvm_s390_pgm_info pgm;
+		struct kvm_s390_emerg_info emerg;
+		struct kvm_s390_extcall_info extcall;
+		struct kvm_s390_prefix_info prefix;
+		struct kvm_s390_stop_info stop;
+		struct kvm_s390_mchk_info mchk;
+		char reserved[64];
+	} u;
+};
+
+struct kvm_s390_irq_state {
+	__u64 buf;
+	__u32 flags;        /* will stay unused for compatibility reasons */
+	__u32 len;
+	__u32 reserved[4];  /* will stay unused for compatibility reasons */
+};
+
+struct kvm_s390_ucas_mapping {
+	__u64 user_addr;
+	__u64 vcpu_addr;
+	__u64 length;
+};
+
+struct kvm_s390_pv_sec_parm {
+	__u64 origin;
+	__u64 length;
+};
+
+struct kvm_s390_pv_unp {
+	__u64 addr;
+	__u64 size;
+	__u64 tweak;
+};
+
+enum pv_cmd_dmp_id {
+	KVM_PV_DUMP_INIT,
+	KVM_PV_DUMP_CONFIG_STOR_STATE,
+	KVM_PV_DUMP_COMPLETE,
+	KVM_PV_DUMP_CPU,
+};
+
+struct kvm_s390_pv_dmp {
+	__u64 subcmd;
+	__u64 buff_addr;
+	__u64 buff_len;
+	__u64 gaddr;		/* For dump storage state */
+	__u64 reserved[4];
+};
+
+enum pv_cmd_info_id {
+	KVM_PV_INFO_VM,
+	KVM_PV_INFO_DUMP,
+};
+
+struct kvm_s390_pv_info_dump {
+	__u64 dump_cpu_buffer_len;
+	__u64 dump_config_mem_buffer_per_1m;
+	__u64 dump_config_finalize_len;
+};
+
+struct kvm_s390_pv_info_vm {
+	__u64 inst_calls_list[4];
+	__u64 max_cpus;
+	__u64 max_guests;
+	__u64 max_guest_addr;
+	__u64 feature_indication;
+};
+
+struct kvm_s390_pv_info_header {
+	__u32 id;
+	__u32 len_max;
+	__u32 len_written;
+	__u32 reserved;
+};
+
+struct kvm_s390_pv_info {
+	struct kvm_s390_pv_info_header header;
+	union {
+		struct kvm_s390_pv_info_dump dump;
+		struct kvm_s390_pv_info_vm vm;
+	};
+};
+
+enum pv_cmd_id {
+	KVM_PV_ENABLE,
+	KVM_PV_DISABLE,
+	KVM_PV_SET_SEC_PARMS,
+	KVM_PV_UNPACK,
+	KVM_PV_VERIFY,
+	KVM_PV_PREP_RESET,
+	KVM_PV_UNSHARE_ALL,
+	KVM_PV_INFO,
+	KVM_PV_DUMP,
+	KVM_PV_ASYNC_CLEANUP_PREPARE,
+	KVM_PV_ASYNC_CLEANUP_PERFORM,
+};
+
+struct kvm_pv_cmd {
+	__u32 cmd;	/* Command to be executed */
+	__u16 rc;	/* Ultravisor return code */
+	__u16 rrc;	/* Ultravisor return reason code */
+	__u64 data;	/* Data or address */
+	__u32 flags;    /* flags for future extensions. Must be 0 for now */
+	__u32 reserved[3];
+};
+
+struct kvm_s390_zpci_op {
+	/* in */
+	__u32 fh;               /* target device */
+	__u8  op;               /* operation to perform */
+	__u8  pad[3];
+	union {
+		/* for KVM_S390_ZPCIOP_REG_AEN */
+		struct {
+			__u64 ibv;      /* Guest addr of interrupt bit vector */
+			__u64 sb;       /* Guest addr of summary bit */
+			__u32 flags;
+			__u32 noi;      /* Number of interrupts */
+			__u8 isc;       /* Guest interrupt subclass */
+			__u8 sbo;       /* Offset of guest summary bit vector */
+			__u16 pad;
+		} reg_aen;
+		__u64 reserved[8];
+	} u;
+};
+
+/* types for kvm_s390_zpci_op->op */
+#define KVM_S390_ZPCIOP_REG_AEN                0
+#define KVM_S390_ZPCIOP_DEREG_AEN      1
+
+/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
+#define KVM_S390_ZPCIOP_REGAEN_HOST    (1 << 0)
 
 /* Device control API: s390-specific devices */
 #define KVM_DEV_FLIC_GET_ALL_IRQS	1
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 003fb74534..a551e44b1c 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -7,6 +7,8 @@
  *
  */
 
+#include <linux/const.h>
+#include <linux/bits.h>
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/stddef.h>
@@ -40,7 +42,6 @@
 #define __KVM_HAVE_IRQ_LINE
 #define __KVM_HAVE_MSI
 #define __KVM_HAVE_USER_NMI
-#define __KVM_HAVE_GUEST_DEBUG
 #define __KVM_HAVE_MSIX
 #define __KVM_HAVE_MCE
 #define __KVM_HAVE_PIT_STATE2
@@ -49,7 +50,6 @@
 #define __KVM_HAVE_DEBUGREGS
 #define __KVM_HAVE_XSAVE
 #define __KVM_HAVE_XCRS
-#define __KVM_HAVE_READONLY_MEM
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -457,6 +457,7 @@ struct kvm_sync_regs {
 
 /* attributes for system fd (group 0) */
 #define KVM_X86_XCOMP_GUEST_SUPP	0
+#define KVM_X86_SEV_VMSA_FEATURES	1
 
 struct kvm_vmx_nested_state_data {
 	__u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
@@ -524,9 +525,353 @@ struct kvm_pmu_event_filter {
 #define KVM_PMU_EVENT_ALLOW 0
 #define KVM_PMU_EVENT_DENY 1
 
-#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS BIT(0)
+#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS _BITUL(0)
 #define KVM_PMU_EVENT_FLAGS_VALID_MASK (KVM_PMU_EVENT_FLAG_MASKED_EVENTS)
 
+/* for KVM_CAP_MCE */
+struct kvm_x86_mce {
+	__u64 status;
+	__u64 addr;
+	__u64 misc;
+	__u64 mcg_status;
+	__u8 bank;
+	__u8 pad1[7];
+	__u64 pad2[3];
+};
+
+/* for KVM_CAP_XEN_HVM */
+#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR	(1 << 0)
+#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL	(1 << 1)
+#define KVM_XEN_HVM_CONFIG_SHARED_INFO		(1 << 2)
+#define KVM_XEN_HVM_CONFIG_RUNSTATE		(1 << 3)
+#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL	(1 << 4)
+#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND		(1 << 5)
+#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG	(1 << 6)
+#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE	(1 << 7)
+#define KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA	(1 << 8)
+
+struct kvm_xen_hvm_config {
+	__u32 flags;
+	__u32 msr;
+	__u64 blob_addr_32;
+	__u64 blob_addr_64;
+	__u8 blob_size_32;
+	__u8 blob_size_64;
+	__u8 pad2[30];
+};
+
+struct kvm_xen_hvm_attr {
+	__u16 type;
+	__u16 pad[3];
+	union {
+		__u8 long_mode;
+		__u8 vector;
+		__u8 runstate_update_flag;
+		union {
+			__u64 gfn;
+#define KVM_XEN_INVALID_GFN ((__u64)-1)
+			__u64 hva;
+		} shared_info;
+		struct {
+			__u32 send_port;
+			__u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */
+			__u32 flags;
+#define KVM_XEN_EVTCHN_DEASSIGN		(1 << 0)
+#define KVM_XEN_EVTCHN_UPDATE		(1 << 1)
+#define KVM_XEN_EVTCHN_RESET		(1 << 2)
+			/*
+			 * Events sent by the guest are either looped back to
+			 * the guest itself (potentially on a different port#)
+			 * or signalled via an eventfd.
+			 */
+			union {
+				struct {
+					__u32 port;
+					__u32 vcpu;
+					__u32 priority;
+				} port;
+				struct {
+					__u32 port; /* Zero for eventfd */
+					__s32 fd;
+				} eventfd;
+				__u32 padding[4];
+			} deliver;
+		} evtchn;
+		__u32 xen_version;
+		__u64 pad[8];
+	} u;
+};
+
+
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
+#define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
+#define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
+#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR		0x2
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_ATTR_TYPE_EVTCHN		0x3
+#define KVM_XEN_ATTR_TYPE_XEN_VERSION		0x4
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */
+#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG	0x5
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */
+#define KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA	0x6
+
+struct kvm_xen_vcpu_attr {
+	__u16 type;
+	__u16 pad[3];
+	union {
+		__u64 gpa;
+#define KVM_XEN_INVALID_GPA ((__u64)-1)
+		__u64 hva;
+		__u64 pad[8];
+		struct {
+			__u64 state;
+			__u64 state_entry_time;
+			__u64 time_running;
+			__u64 time_runnable;
+			__u64 time_blocked;
+			__u64 time_offline;
+		} runstate;
+		__u32 vcpu_id;
+		struct {
+			__u32 port;
+			__u32 priority;
+			__u64 expires_ns;
+		} timer;
+		__u8 vector;
+	} u;
+};
+
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO	0x0
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO	0x1
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR	0x2
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT	0x3
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA	0x4
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST	0x5
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID		0x6
+#define KVM_XEN_VCPU_ATTR_TYPE_TIMER		0x7
+#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR	0x8
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA	0x9
+
+/* Secure Encrypted Virtualization command */
+enum sev_cmd_id {
+	/* Guest initialization commands */
+	KVM_SEV_INIT = 0,
+	KVM_SEV_ES_INIT,
+	/* Guest launch commands */
+	KVM_SEV_LAUNCH_START,
+	KVM_SEV_LAUNCH_UPDATE_DATA,
+	KVM_SEV_LAUNCH_UPDATE_VMSA,
+	KVM_SEV_LAUNCH_SECRET,
+	KVM_SEV_LAUNCH_MEASURE,
+	KVM_SEV_LAUNCH_FINISH,
+	/* Guest migration commands (outgoing) */
+	KVM_SEV_SEND_START,
+	KVM_SEV_SEND_UPDATE_DATA,
+	KVM_SEV_SEND_UPDATE_VMSA,
+	KVM_SEV_SEND_FINISH,
+	/* Guest migration commands (incoming) */
+	KVM_SEV_RECEIVE_START,
+	KVM_SEV_RECEIVE_UPDATE_DATA,
+	KVM_SEV_RECEIVE_UPDATE_VMSA,
+	KVM_SEV_RECEIVE_FINISH,
+	/* Guest status and debug commands */
+	KVM_SEV_GUEST_STATUS,
+	KVM_SEV_DBG_DECRYPT,
+	KVM_SEV_DBG_ENCRYPT,
+	/* Guest certificates commands */
+	KVM_SEV_CERT_EXPORT,
+	/* Attestation report */
+	KVM_SEV_GET_ATTESTATION_REPORT,
+	/* Guest Migration Extension */
+	KVM_SEV_SEND_CANCEL,
+
+	/* Second time is the charm; improved versions of the above ioctls.  */
+	KVM_SEV_INIT2,
+
+	/* SNP-specific commands */
+	KVM_SEV_SNP_INIT,
+	KVM_SEV_SNP_LAUNCH_START,
+	KVM_SEV_SNP_LAUNCH_UPDATE,
+	KVM_SEV_SNP_LAUNCH_FINISH,
+
+	KVM_SEV_NR_MAX,
+};
+
+struct kvm_sev_cmd {
+	__u32 id;
+	__u32 pad0;
+	__u64 data;
+	__u32 error;
+	__u32 sev_fd;
+};
+
+struct kvm_sev_init {
+	__u64 vmsa_features;
+	__u32 flags;
+	__u32 pad[9];
+};
+
+struct kvm_sev_launch_start {
+	__u32 handle;
+	__u32 policy;
+	__u64 dh_uaddr;
+	__u32 dh_len;
+	__u32 pad0;
+	__u64 session_uaddr;
+	__u32 session_len;
+	__u32 pad1;
+};
+
+struct kvm_sev_launch_update_data {
+	__u64 uaddr;
+	__u32 len;
+	__u32 pad0;
+};
+
+
+struct kvm_sev_launch_secret {
+	__u64 hdr_uaddr;
+	__u32 hdr_len;
+	__u32 pad0;
+	__u64 guest_uaddr;
+	__u32 guest_len;
+	__u32 pad1;
+	__u64 trans_uaddr;
+	__u32 trans_len;
+	__u32 pad2;
+};
+
+struct kvm_sev_launch_measure {
+	__u64 uaddr;
+	__u32 len;
+	__u32 pad0;
+};
+
+struct kvm_sev_guest_status {
+	__u32 handle;
+	__u32 policy;
+	__u32 state;
+};
+
+struct kvm_sev_dbg {
+	__u64 src_uaddr;
+	__u64 dst_uaddr;
+	__u32 len;
+	__u32 pad0;
+};
+
+struct kvm_sev_attestation_report {
+	__u8 mnonce[16];
+	__u64 uaddr;
+	__u32 len;
+	__u32 pad0;
+};
+
+struct kvm_sev_send_start {
+	__u32 policy;
+	__u32 pad0;
+	__u64 pdh_cert_uaddr;
+	__u32 pdh_cert_len;
+	__u32 pad1;
+	__u64 plat_certs_uaddr;
+	__u32 plat_certs_len;
+	__u32 pad2;
+	__u64 amd_certs_uaddr;
+	__u32 amd_certs_len;
+	__u32 pad3;
+	__u64 session_uaddr;
+	__u32 session_len;
+	__u32 pad4;
+};
+
+struct kvm_sev_send_update_data {
+	__u64 hdr_uaddr;
+	__u32 hdr_len;
+	__u32 pad0;
+	__u64 guest_uaddr;
+	__u32 guest_len;
+	__u32 pad1;
+	__u64 trans_uaddr;
+	__u32 trans_len;
+	__u32 pad2;
+};
+
+struct kvm_sev_receive_start {
+	__u32 handle;
+	__u32 policy;
+	__u64 pdh_uaddr;
+	__u32 pdh_len;
+	__u32 pad0;
+	__u64 session_uaddr;
+	__u32 session_len;
+	__u32 pad1;
+};
+
+struct kvm_sev_receive_update_data {
+	__u64 hdr_uaddr;
+	__u32 hdr_len;
+	__u32 pad0;
+	__u64 guest_uaddr;
+	__u32 guest_len;
+	__u32 pad1;
+	__u64 trans_uaddr;
+	__u32 trans_len;
+	__u32 pad2;
+};
+
+/* TODO: use a common struct via KVM_SEV_INIT2 */
+struct kvm_snp_init {
+	__u64 flags;
+};
+
+struct kvm_sev_snp_launch_start {
+	__u64 policy;
+	__u8 gosvw[16];
+};
+
+/* Kept in sync with firmware values for simplicity. */
+#define KVM_SEV_SNP_PAGE_TYPE_NORMAL		0x1
+#define KVM_SEV_SNP_PAGE_TYPE_ZERO		0x3
+#define KVM_SEV_SNP_PAGE_TYPE_UNMEASURED	0x4
+#define KVM_SEV_SNP_PAGE_TYPE_SECRETS		0x5
+#define KVM_SEV_SNP_PAGE_TYPE_CPUID		0x6
+
+struct kvm_sev_snp_launch_update {
+	__u64 gfn_start;
+	__u64 uaddr;
+	__u32 len;
+	__u8 type;
+};
+
+#define KVM_SEV_SNP_ID_BLOCK_SIZE	96
+#define KVM_SEV_SNP_ID_AUTH_SIZE	4096
+#define KVM_SEV_SNP_FINISH_DATA_SIZE	32
+
+struct kvm_sev_snp_launch_finish {
+	__u64 id_block_uaddr;
+	__u64 id_auth_uaddr;
+	__u8 id_block_en;
+	__u8 auth_key_en;
+	__u8 host_data[KVM_SEV_SNP_FINISH_DATA_SIZE];
+	__u8 pad[6];
+};
+
+#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
+
+struct kvm_hyperv_eventfd {
+	__u32 conn_id;
+	__s32 fd;
+	__u32 flags;
+	__u32 padding[3];
+};
+
+#define KVM_HYPERV_CONN_ID_MASK		0x00ffffff
+#define KVM_HYPERV_EVENTFD_DEASSIGN	(1 << 0)
+
 /*
  * Masked event layout.
  * Bits   Description
@@ -547,10 +892,10 @@ struct kvm_pmu_event_filter {
 	((__u64)(!!(exclude)) << 55))
 
 #define KVM_PMU_MASKED_ENTRY_EVENT_SELECT \
-	(GENMASK_ULL(7, 0) | GENMASK_ULL(35, 32))
-#define KVM_PMU_MASKED_ENTRY_UMASK_MASK		(GENMASK_ULL(63, 56))
-#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH	(GENMASK_ULL(15, 8))
-#define KVM_PMU_MASKED_ENTRY_EXCLUDE		(BIT_ULL(55))
+	(__GENMASK_ULL(7, 0) | __GENMASK_ULL(35, 32))
+#define KVM_PMU_MASKED_ENTRY_UMASK_MASK		(__GENMASK_ULL(63, 56))
+#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH	(__GENMASK_ULL(15, 8))
+#define KVM_PMU_MASKED_ENTRY_EXCLUDE		(_BITULL(55))
 #define KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT	(56)
 
 /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
@@ -558,9 +903,12 @@ struct kvm_pmu_event_filter {
 #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
 
 /* x86-specific KVM_EXIT_HYPERCALL flags. */
-#define KVM_EXIT_HYPERCALL_LONG_MODE	BIT(0)
+#define KVM_EXIT_HYPERCALL_LONG_MODE	_BITULL(0)
 
 #define KVM_X86_DEFAULT_VM	0
 #define KVM_X86_SW_PROTECTED_VM	1
+#define KVM_X86_SEV_VM		2
+#define KVM_X86_SEV_ES_VM	3
+#define KVM_X86_SNP_VM		4
 
 #endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/asm-x86/setup_data.h b/linux-headers/asm-x86/setup_data.h
new file mode 100644
index 0000000000..09355f54c5
--- /dev/null
+++ b/linux-headers/asm-x86/setup_data.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASM_X86_SETUP_DATA_H
+#define _ASM_X86_SETUP_DATA_H
+
+/* setup_data/setup_indirect types */
+#define SETUP_NONE			0
+#define SETUP_E820_EXT			1
+#define SETUP_DTB			2
+#define SETUP_PCI			3
+#define SETUP_EFI			4
+#define SETUP_APPLE_PROPERTIES		5
+#define SETUP_JAILHOUSE			6
+#define SETUP_CC_BLOB			7
+#define SETUP_IMA			8
+#define SETUP_RNG_SEED			9
+#define SETUP_ENUM_MAX			SETUP_RNG_SEED
+
+#define SETUP_INDIRECT			(1<<31)
+#define SETUP_TYPE_MAX			(SETUP_ENUM_MAX | SETUP_INDIRECT)
+
+#ifndef __ASSEMBLY__
+
+#include "standard-headers/linux/types.h"
+
+/* extensible setup data list node */
+struct setup_data {
+	uint64_t next;
+	uint32_t type;
+	uint32_t len;
+	uint8_t data[];
+};
+
+/* extensible setup indirect data node */
+struct setup_indirect {
+	uint32_t type;
+	uint32_t reserved;  /* Reserved, must be set to zero. */
+	uint64_t len;
+	uint64_t addr;
+};
+
+/*
+ * The E820 memory region entry of the boot protocol ABI:
+ */
+struct boot_e820_entry {
+	uint64_t addr;
+	uint64_t size;
+	uint32_t type;
+} QEMU_PACKED;
+
+/*
+ * The boot loader is passing platform information via this Jailhouse-specific
+ * setup data structure.
+ */
+struct jailhouse_setup_data {
+	struct {
+		uint16_t	version;
+		uint16_t	compatible_version;
+	} QEMU_PACKED hdr;
+	struct {
+		uint16_t	pm_timer_address;
+		uint16_t	num_cpus;
+		uint64_t	pci_mmconfig_base;
+		uint32_t	tsc_khz;
+		uint32_t	apic_khz;
+		uint8_t	standard_ioapic;
+		uint8_t	cpu_ids[255];
+	} QEMU_PACKED v1;
+	struct {
+		uint32_t	flags;
+	} QEMU_PACKED v2;
+} QEMU_PACKED;
+
+/*
+ * IMA buffer setup data information from the previous kernel during kexec
+ */
+struct ima_setup_data {
+	uint64_t addr;
+	uint64_t size;
+} QEMU_PACKED;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_SETUP_DATA_H */
diff --git a/linux-headers/linux/bits.h b/linux-headers/linux/bits.h
new file mode 100644
index 0000000000..d9897771be
--- /dev/null
+++ b/linux-headers/linux/bits.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* bits.h: Macros for dealing with bitmasks.  */
+
+#ifndef _LINUX_BITS_H
+#define _LINUX_BITS_H
+
+#define __GENMASK(h, l) \
+        (((~_UL(0)) - (_UL(1) << (l)) + 1) & \
+         (~_UL(0) >> (__BITS_PER_LONG - 1 - (h))))
+
+#define __GENMASK_ULL(h, l) \
+        (((~_ULL(0)) - (_ULL(1) << (l)) + 1) & \
+         (~_ULL(0) >> (__BITS_PER_LONG_LONG - 1 - (h))))
+
+#endif /* _LINUX_BITS_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 17839229b2..629a015e4e 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -16,6 +16,11 @@
 
 #define KVM_API_VERSION 12
 
+/*
+ * Backwards-compatible definitions.
+ */
+#define __KVM_HAVE_GUEST_DEBUG
+
 /* for KVM_SET_USER_MEMORY_REGION */
 struct kvm_userspace_memory_region {
 	__u32 slot;
@@ -85,43 +90,6 @@ struct kvm_pit_config {
 
 #define KVM_PIT_SPEAKER_DUMMY     1
 
-struct kvm_s390_skeys {
-	__u64 start_gfn;
-	__u64 count;
-	__u64 skeydata_addr;
-	__u32 flags;
-	__u32 reserved[9];
-};
-
-#define KVM_S390_CMMA_PEEK (1 << 0)
-
-/**
- * kvm_s390_cmma_log - Used for CMMA migration.
- *
- * Used both for input and output.
- *
- * @start_gfn: Guest page number to start from.
- * @count: Size of the result buffer.
- * @flags: Control operation mode via KVM_S390_CMMA_* flags
- * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty
- *             pages are still remaining.
- * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set
- *        in the PGSTE.
- * @values: Pointer to the values buffer.
- *
- * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls.
- */
-struct kvm_s390_cmma_log {
-	__u64 start_gfn;
-	__u32 count;
-	__u32 flags;
-	union {
-		__u64 remaining;
-		__u64 mask;
-	};
-	__u64 values;
-};
-
 struct kvm_hyperv_exit {
 #define KVM_EXIT_HYPERV_SYNIC          1
 #define KVM_EXIT_HYPERV_HCALL          2
@@ -167,6 +135,31 @@ struct kvm_xen_exit {
 	} u;
 };
 
+struct kvm_user_vmgexit {
+#define KVM_USER_VMGEXIT_PSC_MSR	1
+#define KVM_USER_VMGEXIT_PSC		2
+#define KVM_USER_VMGEXIT_EXT_GUEST_REQ	3
+	__u32 type; /* KVM_USER_VMGEXIT_* type */
+	union {
+		struct {
+			__u64 gpa;
+#define KVM_USER_VMGEXIT_PSC_MSR_OP_PRIVATE	1
+#define KVM_USER_VMGEXIT_PSC_MSR_OP_SHARED	2
+			__u8 op;
+			__u32 ret;
+		} psc_msr;
+		struct {
+			__u64 shared_gpa;
+			__u64 ret;
+		} psc;
+		struct {
+			__u64 data_gpa;
+			__u64 data_npages;
+			__u32 ret;
+		} ext_guest_req;
+	};
+};
+
 #define KVM_S390_GET_SKEYS_NONE   1
 #define KVM_S390_SKEYS_MAX        1048576
 
@@ -210,6 +203,7 @@ struct kvm_xen_exit {
 #define KVM_EXIT_NOTIFY           37
 #define KVM_EXIT_LOONGARCH_IOCSR  38
 #define KVM_EXIT_MEMORY_FAULT     39
+#define KVM_EXIT_VMGEXIT          40
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -313,11 +307,6 @@ struct kvm_run {
 			__u32 ipb;
 		} s390_sieic;
 		/* KVM_EXIT_S390_RESET */
-#define KVM_S390_RESET_POR       1
-#define KVM_S390_RESET_CLEAR     2
-#define KVM_S390_RESET_SUBSYSTEM 4
-#define KVM_S390_RESET_CPU_INIT  8
-#define KVM_S390_RESET_IPL       16
 		__u64 s390_reset_flags;
 		/* KVM_EXIT_S390_UCONTROL */
 		struct {
@@ -466,6 +455,8 @@ struct kvm_run {
 			__u64 gpa;
 			__u64 size;
 		} memory_fault;
+		/* KVM_EXIT_VMGEXIT */
+		struct kvm_user_vmgexit vmgexit;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -532,43 +523,6 @@ struct kvm_translation {
 	__u8  pad[5];
 };
 
-/* for KVM_S390_MEM_OP */
-struct kvm_s390_mem_op {
-	/* in */
-	__u64 gaddr;		/* the guest address */
-	__u64 flags;		/* flags */
-	__u32 size;		/* amount of bytes */
-	__u32 op;		/* type of operation */
-	__u64 buf;		/* buffer in userspace */
-	union {
-		struct {
-			__u8 ar;	/* the access register number */
-			__u8 key;	/* access key, ignored if flag unset */
-			__u8 pad1[6];	/* ignored */
-			__u64 old_addr;	/* ignored if cmpxchg flag unset */
-		};
-		__u32 sida_offset; /* offset into the sida */
-		__u8 reserved[32]; /* ignored */
-	};
-};
-/* types for kvm_s390_mem_op->op */
-#define KVM_S390_MEMOP_LOGICAL_READ	0
-#define KVM_S390_MEMOP_LOGICAL_WRITE	1
-#define KVM_S390_MEMOP_SIDA_READ	2
-#define KVM_S390_MEMOP_SIDA_WRITE	3
-#define KVM_S390_MEMOP_ABSOLUTE_READ	4
-#define KVM_S390_MEMOP_ABSOLUTE_WRITE	5
-#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG	6
-
-/* flags for kvm_s390_mem_op->flags */
-#define KVM_S390_MEMOP_F_CHECK_ONLY		(1ULL << 0)
-#define KVM_S390_MEMOP_F_INJECT_EXCEPTION	(1ULL << 1)
-#define KVM_S390_MEMOP_F_SKEY_PROTECTION	(1ULL << 2)
-
-/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */
-#define KVM_S390_MEMOP_EXTENSION_CAP_BASE	(1 << 0)
-#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG	(1 << 1)
-
 /* for KVM_INTERRUPT */
 struct kvm_interrupt {
 	/* in */
@@ -633,124 +587,6 @@ struct kvm_mp_state {
 	__u32 mp_state;
 };
 
-struct kvm_s390_psw {
-	__u64 mask;
-	__u64 addr;
-};
-
-/* valid values for type in kvm_s390_interrupt */
-#define KVM_S390_SIGP_STOP		0xfffe0000u
-#define KVM_S390_PROGRAM_INT		0xfffe0001u
-#define KVM_S390_SIGP_SET_PREFIX	0xfffe0002u
-#define KVM_S390_RESTART		0xfffe0003u
-#define KVM_S390_INT_PFAULT_INIT	0xfffe0004u
-#define KVM_S390_INT_PFAULT_DONE	0xfffe0005u
-#define KVM_S390_MCHK			0xfffe1000u
-#define KVM_S390_INT_CLOCK_COMP		0xffff1004u
-#define KVM_S390_INT_CPU_TIMER		0xffff1005u
-#define KVM_S390_INT_VIRTIO		0xffff2603u
-#define KVM_S390_INT_SERVICE		0xffff2401u
-#define KVM_S390_INT_EMERGENCY		0xffff1201u
-#define KVM_S390_INT_EXTERNAL_CALL	0xffff1202u
-/* Anything below 0xfffe0000u is taken by INT_IO */
-#define KVM_S390_INT_IO(ai,cssid,ssid,schid)   \
-	(((schid)) |			       \
-	 ((ssid) << 16) |		       \
-	 ((cssid) << 18) |		       \
-	 ((ai) << 26))
-#define KVM_S390_INT_IO_MIN		0x00000000u
-#define KVM_S390_INT_IO_MAX		0xfffdffffu
-#define KVM_S390_INT_IO_AI_MASK		0x04000000u
-
-
-struct kvm_s390_interrupt {
-	__u32 type;
-	__u32 parm;
-	__u64 parm64;
-};
-
-struct kvm_s390_io_info {
-	__u16 subchannel_id;
-	__u16 subchannel_nr;
-	__u32 io_int_parm;
-	__u32 io_int_word;
-};
-
-struct kvm_s390_ext_info {
-	__u32 ext_params;
-	__u32 pad;
-	__u64 ext_params2;
-};
-
-struct kvm_s390_pgm_info {
-	__u64 trans_exc_code;
-	__u64 mon_code;
-	__u64 per_address;
-	__u32 data_exc_code;
-	__u16 code;
-	__u16 mon_class_nr;
-	__u8 per_code;
-	__u8 per_atmid;
-	__u8 exc_access_id;
-	__u8 per_access_id;
-	__u8 op_access_id;
-#define KVM_S390_PGM_FLAGS_ILC_VALID	0x01
-#define KVM_S390_PGM_FLAGS_ILC_0	0x02
-#define KVM_S390_PGM_FLAGS_ILC_1	0x04
-#define KVM_S390_PGM_FLAGS_ILC_MASK	0x06
-#define KVM_S390_PGM_FLAGS_NO_REWIND	0x08
-	__u8 flags;
-	__u8 pad[2];
-};
-
-struct kvm_s390_prefix_info {
-	__u32 address;
-};
-
-struct kvm_s390_extcall_info {
-	__u16 code;
-};
-
-struct kvm_s390_emerg_info {
-	__u16 code;
-};
-
-#define KVM_S390_STOP_FLAG_STORE_STATUS	0x01
-struct kvm_s390_stop_info {
-	__u32 flags;
-};
-
-struct kvm_s390_mchk_info {
-	__u64 cr14;
-	__u64 mcic;
-	__u64 failing_storage_address;
-	__u32 ext_damage_code;
-	__u32 pad;
-	__u8 fixed_logout[16];
-};
-
-struct kvm_s390_irq {
-	__u64 type;
-	union {
-		struct kvm_s390_io_info io;
-		struct kvm_s390_ext_info ext;
-		struct kvm_s390_pgm_info pgm;
-		struct kvm_s390_emerg_info emerg;
-		struct kvm_s390_extcall_info extcall;
-		struct kvm_s390_prefix_info prefix;
-		struct kvm_s390_stop_info stop;
-		struct kvm_s390_mchk_info mchk;
-		char reserved[64];
-	} u;
-};
-
-struct kvm_s390_irq_state {
-	__u64 buf;
-	__u32 flags;        /* will stay unused for compatibility reasons */
-	__u32 len;
-	__u32 reserved[4];  /* will stay unused for compatibility reasons */
-};
-
 /* for KVM_SET_GUEST_DEBUG */
 
 #define KVM_GUESTDBG_ENABLE		0x00000001
@@ -806,50 +642,6 @@ struct kvm_enable_cap {
 	__u8  pad[64];
 };
 
-/* for KVM_PPC_GET_PVINFO */
-
-#define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
-
-struct kvm_ppc_pvinfo {
-	/* out */
-	__u32 flags;
-	__u32 hcall[4];
-	__u8  pad[108];
-};
-
-/* for KVM_PPC_GET_SMMU_INFO */
-#define KVM_PPC_PAGE_SIZES_MAX_SZ	8
-
-struct kvm_ppc_one_page_size {
-	__u32 page_shift;	/* Page shift (or 0) */
-	__u32 pte_enc;		/* Encoding in the HPTE (>>12) */
-};
-
-struct kvm_ppc_one_seg_page_size {
-	__u32 page_shift;	/* Base page shift of segment (or 0) */
-	__u32 slb_enc;		/* SLB encoding for BookS */
-	struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
-};
-
-#define KVM_PPC_PAGE_SIZES_REAL		0x00000001
-#define KVM_PPC_1T_SEGMENTS		0x00000002
-#define KVM_PPC_NO_HASH			0x00000004
-
-struct kvm_ppc_smmu_info {
-	__u64 flags;
-	__u32 slb_size;
-	__u16 data_keys;	/* # storage keys supported for data */
-	__u16 instr_keys;	/* # storage keys supported for instructions */
-	struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
-};
-
-/* for KVM_PPC_RESIZE_HPT_{PREPARE,COMMIT} */
-struct kvm_ppc_resize_hpt {
-	__u64 flags;
-	__u32 shift;
-	__u32 pad;
-};
-
 #define KVMIO 0xAE
 
 /* machine type bits, to be used as argument to KVM_CREATE_VM */
@@ -919,9 +711,7 @@ struct kvm_ppc_resize_hpt {
 /* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
 #define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
 #define KVM_CAP_USER_NMI 22
-#ifdef __KVM_HAVE_GUEST_DEBUG
 #define KVM_CAP_SET_GUEST_DEBUG 23
-#endif
 #ifdef __KVM_HAVE_PIT
 #define KVM_CAP_REINJECT_CONTROL 24
 #endif
@@ -1152,8 +942,6 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_GUEST_MEMFD 234
 #define KVM_CAP_VM_TYPES 235
 
-#ifdef KVM_CAP_IRQ_ROUTING
-
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
 	__u32 pin;
@@ -1218,42 +1006,6 @@ struct kvm_irq_routing {
 	struct kvm_irq_routing_entry entries[];
 };
 
-#endif
-
-#ifdef KVM_CAP_MCE
-/* x86 MCE */
-struct kvm_x86_mce {
-	__u64 status;
-	__u64 addr;
-	__u64 misc;
-	__u64 mcg_status;
-	__u8 bank;
-	__u8 pad1[7];
-	__u64 pad2[3];
-};
-#endif
-
-#ifdef KVM_CAP_XEN_HVM
-#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR	(1 << 0)
-#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL	(1 << 1)
-#define KVM_XEN_HVM_CONFIG_SHARED_INFO		(1 << 2)
-#define KVM_XEN_HVM_CONFIG_RUNSTATE		(1 << 3)
-#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL	(1 << 4)
-#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND		(1 << 5)
-#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG	(1 << 6)
-#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE	(1 << 7)
-
-struct kvm_xen_hvm_config {
-	__u32 flags;
-	__u32 msr;
-	__u64 blob_addr_32;
-	__u64 blob_addr_64;
-	__u8 blob_size_32;
-	__u8 blob_size_64;
-	__u8 pad2[30];
-};
-#endif
-
 #define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
 /*
  * Available with KVM_CAP_IRQFD_RESAMPLE
@@ -1438,11 +1190,6 @@ struct kvm_vfio_spapr_tce {
 					 struct kvm_userspace_memory_region2)
 
 /* enable ucontrol for s390 */
-struct kvm_s390_ucas_mapping {
-	__u64 user_addr;
-	__u64 vcpu_addr;
-	__u64 length;
-};
 #define KVM_S390_UCAS_MAP        _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
 #define KVM_S390_UCAS_UNMAP      _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
 #define KVM_S390_VCPU_FAULT	 _IOW(KVMIO, 0x52, unsigned long)
@@ -1637,89 +1384,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET	_IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET	_IO(KVMIO,   0xc4)
 
-struct kvm_s390_pv_sec_parm {
-	__u64 origin;
-	__u64 length;
-};
-
-struct kvm_s390_pv_unp {
-	__u64 addr;
-	__u64 size;
-	__u64 tweak;
-};
-
-enum pv_cmd_dmp_id {
-	KVM_PV_DUMP_INIT,
-	KVM_PV_DUMP_CONFIG_STOR_STATE,
-	KVM_PV_DUMP_COMPLETE,
-	KVM_PV_DUMP_CPU,
-};
-
-struct kvm_s390_pv_dmp {
-	__u64 subcmd;
-	__u64 buff_addr;
-	__u64 buff_len;
-	__u64 gaddr;		/* For dump storage state */
-	__u64 reserved[4];
-};
-
-enum pv_cmd_info_id {
-	KVM_PV_INFO_VM,
-	KVM_PV_INFO_DUMP,
-};
-
-struct kvm_s390_pv_info_dump {
-	__u64 dump_cpu_buffer_len;
-	__u64 dump_config_mem_buffer_per_1m;
-	__u64 dump_config_finalize_len;
-};
-
-struct kvm_s390_pv_info_vm {
-	__u64 inst_calls_list[4];
-	__u64 max_cpus;
-	__u64 max_guests;
-	__u64 max_guest_addr;
-	__u64 feature_indication;
-};
-
-struct kvm_s390_pv_info_header {
-	__u32 id;
-	__u32 len_max;
-	__u32 len_written;
-	__u32 reserved;
-};
-
-struct kvm_s390_pv_info {
-	struct kvm_s390_pv_info_header header;
-	union {
-		struct kvm_s390_pv_info_dump dump;
-		struct kvm_s390_pv_info_vm vm;
-	};
-};
-
-enum pv_cmd_id {
-	KVM_PV_ENABLE,
-	KVM_PV_DISABLE,
-	KVM_PV_SET_SEC_PARMS,
-	KVM_PV_UNPACK,
-	KVM_PV_VERIFY,
-	KVM_PV_PREP_RESET,
-	KVM_PV_UNSHARE_ALL,
-	KVM_PV_INFO,
-	KVM_PV_DUMP,
-	KVM_PV_ASYNC_CLEANUP_PREPARE,
-	KVM_PV_ASYNC_CLEANUP_PERFORM,
-};
-
-struct kvm_pv_cmd {
-	__u32 cmd;	/* Command to be executed */
-	__u16 rc;	/* Ultravisor return code */
-	__u16 rrc;	/* Ultravisor return reason code */
-	__u64 data;	/* Data or address */
-	__u32 flags;    /* flags for future extensions. Must be 0 for now */
-	__u32 reserved[3];
-};
-
 /* Available with KVM_CAP_S390_PROTECTED */
 #define KVM_S390_PV_COMMAND		_IOWR(KVMIO, 0xc5, struct kvm_pv_cmd)
 
@@ -1733,58 +1397,6 @@ struct kvm_pv_cmd {
 #define KVM_XEN_HVM_GET_ATTR	_IOWR(KVMIO, 0xc8, struct kvm_xen_hvm_attr)
 #define KVM_XEN_HVM_SET_ATTR	_IOW(KVMIO,  0xc9, struct kvm_xen_hvm_attr)
 
-struct kvm_xen_hvm_attr {
-	__u16 type;
-	__u16 pad[3];
-	union {
-		__u8 long_mode;
-		__u8 vector;
-		__u8 runstate_update_flag;
-		struct {
-			__u64 gfn;
-#define KVM_XEN_INVALID_GFN ((__u64)-1)
-		} shared_info;
-		struct {
-			__u32 send_port;
-			__u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */
-			__u32 flags;
-#define KVM_XEN_EVTCHN_DEASSIGN		(1 << 0)
-#define KVM_XEN_EVTCHN_UPDATE		(1 << 1)
-#define KVM_XEN_EVTCHN_RESET		(1 << 2)
-			/*
-			 * Events sent by the guest are either looped back to
-			 * the guest itself (potentially on a different port#)
-			 * or signalled via an eventfd.
-			 */
-			union {
-				struct {
-					__u32 port;
-					__u32 vcpu;
-					__u32 priority;
-				} port;
-				struct {
-					__u32 port; /* Zero for eventfd */
-					__s32 fd;
-				} eventfd;
-				__u32 padding[4];
-			} deliver;
-		} evtchn;
-		__u32 xen_version;
-		__u64 pad[8];
-	} u;
-};
-
-
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
-#define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
-#define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
-#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR		0x2
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
-#define KVM_XEN_ATTR_TYPE_EVTCHN		0x3
-#define KVM_XEN_ATTR_TYPE_XEN_VERSION		0x4
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */
-#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG	0x5
-
 /* Per-vCPU Xen attributes */
 #define KVM_XEN_VCPU_GET_ATTR	_IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
 #define KVM_XEN_VCPU_SET_ATTR	_IOW(KVMIO,  0xcb, struct kvm_xen_vcpu_attr)
@@ -1795,242 +1407,6 @@ struct kvm_xen_hvm_attr {
 #define KVM_GET_SREGS2             _IOR(KVMIO,  0xcc, struct kvm_sregs2)
 #define KVM_SET_SREGS2             _IOW(KVMIO,  0xcd, struct kvm_sregs2)
 
-struct kvm_xen_vcpu_attr {
-	__u16 type;
-	__u16 pad[3];
-	union {
-		__u64 gpa;
-#define KVM_XEN_INVALID_GPA ((__u64)-1)
-		__u64 pad[8];
-		struct {
-			__u64 state;
-			__u64 state_entry_time;
-			__u64 time_running;
-			__u64 time_runnable;
-			__u64 time_blocked;
-			__u64 time_offline;
-		} runstate;
-		__u32 vcpu_id;
-		struct {
-			__u32 port;
-			__u32 priority;
-			__u64 expires_ns;
-		} timer;
-		__u8 vector;
-	} u;
-};
-
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
-#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO	0x0
-#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO	0x1
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR	0x2
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT	0x3
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA	0x4
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST	0x5
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
-#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID		0x6
-#define KVM_XEN_VCPU_ATTR_TYPE_TIMER		0x7
-#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR	0x8
-
-/* Secure Encrypted Virtualization command */
-enum sev_cmd_id {
-	/* Guest initialization commands */
-	KVM_SEV_INIT = 0,
-	KVM_SEV_ES_INIT,
-	/* Guest launch commands */
-	KVM_SEV_LAUNCH_START,
-	KVM_SEV_LAUNCH_UPDATE_DATA,
-	KVM_SEV_LAUNCH_UPDATE_VMSA,
-	KVM_SEV_LAUNCH_SECRET,
-	KVM_SEV_LAUNCH_MEASURE,
-	KVM_SEV_LAUNCH_FINISH,
-	/* Guest migration commands (outgoing) */
-	KVM_SEV_SEND_START,
-	KVM_SEV_SEND_UPDATE_DATA,
-	KVM_SEV_SEND_UPDATE_VMSA,
-	KVM_SEV_SEND_FINISH,
-	/* Guest migration commands (incoming) */
-	KVM_SEV_RECEIVE_START,
-	KVM_SEV_RECEIVE_UPDATE_DATA,
-	KVM_SEV_RECEIVE_UPDATE_VMSA,
-	KVM_SEV_RECEIVE_FINISH,
-	/* Guest status and debug commands */
-	KVM_SEV_GUEST_STATUS,
-	KVM_SEV_DBG_DECRYPT,
-	KVM_SEV_DBG_ENCRYPT,
-	/* Guest certificates commands */
-	KVM_SEV_CERT_EXPORT,
-	/* Attestation report */
-	KVM_SEV_GET_ATTESTATION_REPORT,
-	/* Guest Migration Extension */
-	KVM_SEV_SEND_CANCEL,
-
-	KVM_SEV_NR_MAX,
-};
-
-struct kvm_sev_cmd {
-	__u32 id;
-	__u64 data;
-	__u32 error;
-	__u32 sev_fd;
-};
-
-struct kvm_sev_launch_start {
-	__u32 handle;
-	__u32 policy;
-	__u64 dh_uaddr;
-	__u32 dh_len;
-	__u64 session_uaddr;
-	__u32 session_len;
-};
-
-struct kvm_sev_launch_update_data {
-	__u64 uaddr;
-	__u32 len;
-};
-
-
-struct kvm_sev_launch_secret {
-	__u64 hdr_uaddr;
-	__u32 hdr_len;
-	__u64 guest_uaddr;
-	__u32 guest_len;
-	__u64 trans_uaddr;
-	__u32 trans_len;
-};
-
-struct kvm_sev_launch_measure {
-	__u64 uaddr;
-	__u32 len;
-};
-
-struct kvm_sev_guest_status {
-	__u32 handle;
-	__u32 policy;
-	__u32 state;
-};
-
-struct kvm_sev_dbg {
-	__u64 src_uaddr;
-	__u64 dst_uaddr;
-	__u32 len;
-};
-
-struct kvm_sev_attestation_report {
-	__u8 mnonce[16];
-	__u64 uaddr;
-	__u32 len;
-};
-
-struct kvm_sev_send_start {
-	__u32 policy;
-	__u64 pdh_cert_uaddr;
-	__u32 pdh_cert_len;
-	__u64 plat_certs_uaddr;
-	__u32 plat_certs_len;
-	__u64 amd_certs_uaddr;
-	__u32 amd_certs_len;
-	__u64 session_uaddr;
-	__u32 session_len;
-};
-
-struct kvm_sev_send_update_data {
-	__u64 hdr_uaddr;
-	__u32 hdr_len;
-	__u64 guest_uaddr;
-	__u32 guest_len;
-	__u64 trans_uaddr;
-	__u32 trans_len;
-};
-
-struct kvm_sev_receive_start {
-	__u32 handle;
-	__u32 policy;
-	__u64 pdh_uaddr;
-	__u32 pdh_len;
-	__u64 session_uaddr;
-	__u32 session_len;
-};
-
-struct kvm_sev_receive_update_data {
-	__u64 hdr_uaddr;
-	__u32 hdr_len;
-	__u64 guest_uaddr;
-	__u32 guest_len;
-	__u64 trans_uaddr;
-	__u32 trans_len;
-};
-
-#define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
-#define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
-#define KVM_DEV_ASSIGN_MASK_INTX	(1 << 2)
-
-struct kvm_assigned_pci_dev {
-	__u32 assigned_dev_id;
-	__u32 busnr;
-	__u32 devfn;
-	__u32 flags;
-	__u32 segnr;
-	union {
-		__u32 reserved[11];
-	};
-};
-
-#define KVM_DEV_IRQ_HOST_INTX    (1 << 0)
-#define KVM_DEV_IRQ_HOST_MSI     (1 << 1)
-#define KVM_DEV_IRQ_HOST_MSIX    (1 << 2)
-
-#define KVM_DEV_IRQ_GUEST_INTX   (1 << 8)
-#define KVM_DEV_IRQ_GUEST_MSI    (1 << 9)
-#define KVM_DEV_IRQ_GUEST_MSIX   (1 << 10)
-
-#define KVM_DEV_IRQ_HOST_MASK	 0x00ff
-#define KVM_DEV_IRQ_GUEST_MASK   0xff00
-
-struct kvm_assigned_irq {
-	__u32 assigned_dev_id;
-	__u32 host_irq; /* ignored (legacy field) */
-	__u32 guest_irq;
-	__u32 flags;
-	union {
-		__u32 reserved[12];
-	};
-};
-
-struct kvm_assigned_msix_nr {
-	__u32 assigned_dev_id;
-	__u16 entry_nr;
-	__u16 padding;
-};
-
-#define KVM_MAX_MSIX_PER_DEV		256
-struct kvm_assigned_msix_entry {
-	__u32 assigned_dev_id;
-	__u32 gsi;
-	__u16 entry; /* The index of entry in the MSI-X table */
-	__u16 padding[3];
-};
-
-#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
-#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
-
-/* Available with KVM_CAP_ARM_USER_IRQ */
-
-/* Bits for run->s.regs.device_irq_level */
-#define KVM_ARM_DEV_EL1_VTIMER		(1 << 0)
-#define KVM_ARM_DEV_EL1_PTIMER		(1 << 1)
-#define KVM_ARM_DEV_PMU			(1 << 2)
-
-struct kvm_hyperv_eventfd {
-	__u32 conn_id;
-	__s32 fd;
-	__u32 flags;
-	__u32 padding[3];
-};
-
-#define KVM_HYPERV_CONN_ID_MASK		0x00ffffff
-#define KVM_HYPERV_EVENTFD_DEASSIGN	(1 << 0)
-
 #define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE    (1 << 0)
 #define KVM_DIRTY_LOG_INITIALLY_SET            (1 << 1)
 
@@ -2176,33 +1552,6 @@ struct kvm_stats_desc {
 /* Available with KVM_CAP_S390_ZPCI_OP */
 #define KVM_S390_ZPCI_OP         _IOW(KVMIO,  0xd1, struct kvm_s390_zpci_op)
 
-struct kvm_s390_zpci_op {
-	/* in */
-	__u32 fh;               /* target device */
-	__u8  op;               /* operation to perform */
-	__u8  pad[3];
-	union {
-		/* for KVM_S390_ZPCIOP_REG_AEN */
-		struct {
-			__u64 ibv;      /* Guest addr of interrupt bit vector */
-			__u64 sb;       /* Guest addr of summary bit */
-			__u32 flags;
-			__u32 noi;      /* Number of interrupts */
-			__u8 isc;       /* Guest interrupt subclass */
-			__u8 sbo;       /* Offset of guest summary bit vector */
-			__u16 pad;
-		} reg_aen;
-		__u64 reserved[8];
-	} u;
-};
-
-/* types for kvm_s390_zpci_op->op */
-#define KVM_S390_ZPCIOP_REG_AEN                0
-#define KVM_S390_ZPCIOP_DEREG_AEN      1
-
-/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
-#define KVM_S390_ZPCIOP_REGAEN_HOST    (1 << 0)
-
 /* Available with KVM_CAP_MEMORY_ATTRIBUTES */
 #define KVM_SET_MEMORY_ATTRIBUTES              _IOW(KVMIO,  0xd2, struct kvm_memory_attributes)
 
diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h
index bcb21339ee..3095af51e5 100644
--- a/linux-headers/linux/psp-sev.h
+++ b/linux-headers/linux/psp-sev.h
@@ -28,6 +28,11 @@ enum {
 	SEV_PEK_CERT_IMPORT,
 	SEV_GET_ID,	/* This command is deprecated, use SEV_GET_ID2 */
 	SEV_GET_ID2,
+	SNP_PLATFORM_STATUS,
+	SNP_COMMIT,
+	SNP_SET_CONFIG,
+	SNP_SET_CONFIG_START,
+	SNP_SET_CONFIG_END,
 
 	SEV_MAX,
 };
@@ -69,6 +74,12 @@ typedef enum {
 	SEV_RET_RESOURCE_LIMIT,
 	SEV_RET_SECURE_DATA_INVALID,
 	SEV_RET_INVALID_KEY = 0x27,
+	SEV_RET_INVALID_PAGE_SIZE,
+	SEV_RET_INVALID_PAGE_STATE,
+	SEV_RET_INVALID_MDATA_ENTRY,
+	SEV_RET_INVALID_PAGE_OWNER,
+	SEV_RET_INVALID_PAGE_AEAD_OFLOW,
+	SEV_RET_RMP_INIT_REQUIRED,
 	SEV_RET_MAX,
 } sev_ret_code;
 
@@ -155,6 +166,66 @@ struct sev_user_data_get_id2 {
 	__u32 length;				/* In/Out */
 } __attribute__((packed));
 
+/**
+ * struct sev_user_data_snp_status - SNP status
+ *
+ * @api_major: API major version
+ * @api_minor: API minor version
+ * @state: current platform state
+ * @is_rmp_initialized: whether RMP is initialized or not
+ * @rsvd: reserved
+ * @build_id: firmware build id for the API version
+ * @mask_chip_id: whether chip id is present in attestation reports or not
+ * @mask_chip_key: whether attestation reports are signed or not
+ * @vlek_en: VLEK (Version Loaded Endorsement Key) hashstick is loaded
+ * @rsvd1: reserved
+ * @guest_count: the number of guest currently managed by the firmware
+ * @current_tcb_version: current TCB version
+ * @reported_tcb_version: reported TCB version
+ */
+struct sev_user_data_snp_status {
+	__u8 api_major;			/* Out */
+	__u8 api_minor;			/* Out */
+	__u8 state;			/* Out */
+	__u8 is_rmp_initialized:1;	/* Out */
+	__u8 rsvd:7;
+	__u32 build_id;			/* Out */
+	__u32 mask_chip_id:1;		/* Out */
+	__u32 mask_chip_key:1;		/* Out */
+	__u32 vlek_en:1;		/* Out */
+	__u32 rsvd1:29;
+	__u32 guest_count;		/* Out */
+	__u64 current_tcb_version;	/* Out */
+	__u64 reported_tcb_version;	/* Out */
+} __attribute__((packed));
+
+/**
+ * struct sev_user_data_snp_config - system wide configuration value for SNP.
+ *
+ * @reported_tcb: the TCB version to report in the guest attestation report.
+ * @mask_chip_id: whether chip id is present in attestation reports or not
+ * @mask_chip_key: whether attestation reports are signed or not
+ * @rsvd: reserved
+ * @rsvd1: reserved
+ */
+struct sev_user_data_snp_config {
+	__u64 reported_tcb  ;   /* In */
+	__u32 mask_chip_id:1;   /* In */
+	__u32 mask_chip_key:1;  /* In */
+	__u32 rsvd:30;          /* In */
+	__u8 rsvd1[52];
+} __attribute__((packed));
+
+/**
+ * struct sev_user_data_snp_config_transaction - metadata for config transactions
+ *
+ * @id: the ID of the transaction started/ended by a call to SNP_SET_CONFIG_START
+ *	or SNP_SET_CONFIG_END, respectively.
+ */
+struct sev_user_data_snp_config_transaction {
+	__u64 id;		/* Out */
+} __attribute__((packed));
+
 /**
  * struct sev_issue_cmd - SEV ioctl parameters
  *
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 05/49] [TEMP] hw/i386: Remove redeclaration of struct setup_data
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (3 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 04/49] [HACK] linux-headers: Update headers for 6.8 + kvm-coco-queue + SNP Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 06/49] RAMBlock: Add support of KVM private guest memfd Michael Roth
                   ` (46 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

TODO: this needs to be done as part of header update to avoid temporary
build bisect breakage. Keeping it separate for reference.

It is now provided by kernel headers.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/i386/x86.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 2d4b148cd2..825dc4c735 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -679,14 +679,6 @@ DeviceState *ioapic_init_secondary(GSIState *gsi_state)
     return dev;
 }
 
-struct setup_data {
-    uint64_t next;
-    uint32_t type;
-    uint32_t len;
-    uint8_t data[];
-} __attribute__((packed));
-
-
 /*
  * The entry point into the kernel for PVH boot is different from
  * the native entry point.  The PVH entry is defined by the x86/HVM
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 06/49] RAMBlock: Add support of KVM private guest memfd
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (4 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 05/49] [TEMP] hw/i386: Remove redeclaration of struct setup_data Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 16:38   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 07/49] HostMem: Add mechanism to opt in kvm guest memfd via MachineState Michael Roth
                   ` (45 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	David Hildenbrand

Add KVM guest_memfd support to RAMBlock so both normal hva based memory
and kvm guest memfd based private memory can be associated in one RAMBlock.

Introduce new flag RAM_GUEST_MEMFD. When it's set, it calls KVM ioctl to
create private guest_memfd during RAMBlock setup.

Allocating a new RAM_GUEST_MEMFD flag to instruct the setup of guest memfd
is more flexible and extensible than simply relying on the VM type because
in the future we may have the case that not all the memory of a VM need
guest memfd. As a benefit, it also avoid getting MachineState in memory
subsystem.

Note, RAM_GUEST_MEMFD is supposed to be set for memory backends of
confidential guests, such as TDX VM. How and when to set it for memory
backends will be implemented in the following patches.

Introduce memory_region_has_guest_memfd() to query if the MemoryRegion has
KVM guest_memfd allocated.

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
---
Changes in v5:
- Use assert(new_block->guest_memfd < 0) instead of condition check;
- Collect Reviewed-by tag from David;

Changes in v4:
- Add clarification of RAM_GUEST_MEMFD in commit message; (David Hildenbrand)
- refine the return value and error message; (Daniel P. Berrangé)
- remove flags in ram_block_add(); (David Hildenbrand)

Changes in v3:
- rename gmem to guest_memfd;
- close(guest_memfd) when RAMBlock is released; (Daniel P. Berrangé)
- Suqash the patch that introduces memory_region_has_guest_memfd().

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c     | 25 +++++++++++++++++++++++++
 accel/stubs/kvm-stub.c  |  5 +++++
 include/exec/memory.h   | 20 +++++++++++++++++---
 include/exec/ram_addr.h |  2 +-
 include/exec/ramblock.h |  1 +
 include/sysemu/kvm.h    |  2 ++
 system/memory.c         |  5 +++++
 system/physmem.c        | 24 +++++++++++++++++++++---
 8 files changed, 77 insertions(+), 7 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index a05dea2313..132ab65df5 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -91,6 +91,7 @@ bool kvm_msi_use_devid;
 static bool kvm_has_guest_debug;
 static int kvm_sstep_flags;
 static bool kvm_immediate_exit;
+static bool kvm_guest_memfd_supported;
 static hwaddr kvm_max_slot_size = ~0;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
@@ -2395,6 +2396,8 @@ static int kvm_init(MachineState *ms)
     }
     s->as = g_new0(struct KVMAs, s->nr_as);
 
+    kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);
+
     if (object_property_find(OBJECT(current_machine), "kvm-type")) {
         g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
                                                             "kvm-type",
@@ -4099,3 +4102,25 @@ void kvm_mark_guest_state_protected(void)
 {
     kvm_state->guest_state_protected = true;
 }
+
+int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
+{
+    int fd;
+    struct kvm_create_guest_memfd guest_memfd = {
+        .size = size,
+        .flags = flags,
+    };
+
+    if (!kvm_guest_memfd_supported) {
+        error_setg(errp, "KVM doesn't support guest memfd\n");
+        return -1;
+    }
+
+    fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
+    if (fd < 0) {
+        error_setg_errno(errp, errno, "Error creating kvm guest memfd");
+        return -1;
+    }
+
+    return fd;
+}
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index ca38172884..8e0eb22e61 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -129,3 +129,8 @@ bool kvm_hwpoisoned_mem(void)
 {
     return false;
 }
+
+int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
+{
+    return -ENOSYS;
+}
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 8626a355b3..679a847685 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -243,6 +243,9 @@ typedef struct IOMMUTLBEvent {
 /* RAM FD is opened read-only */
 #define RAM_READONLY_FD (1 << 11)
 
+/* RAM can be private that has kvm guest memfd backend */
+#define RAM_GUEST_MEMFD   (1 << 12)
+
 static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
                                        IOMMUNotifierFlag flags,
                                        hwaddr start, hwaddr end,
@@ -1307,7 +1310,8 @@ bool memory_region_init_ram_nomigrate(MemoryRegion *mr,
  * @name: Region name, becomes part of RAMBlock name used in migration stream
  *        must be unique within any device
  * @size: size of the region.
- * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_NORESERVE.
+ * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_NORESERVE,
+ *             RAM_GUEST_MEMFD.
  * @errp: pointer to Error*, to store an error if it happens.
  *
  * Note that this function does not do anything to cause the data in the
@@ -1369,7 +1373,7 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
  *         (getpagesize()) will be used.
  * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
  *             RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- *             RAM_READONLY_FD
+ *             RAM_READONLY_FD, RAM_GUEST_MEMFD
  * @path: the path in which to allocate the RAM.
  * @offset: offset within the file referenced by path
  * @errp: pointer to Error*, to store an error if it happens.
@@ -1399,7 +1403,7 @@ bool memory_region_init_ram_from_file(MemoryRegion *mr,
  * @size: size of the region.
  * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
  *             RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- *             RAM_READONLY_FD
+ *             RAM_READONLY_FD, RAM_GUEST_MEMFD
  * @fd: the fd to mmap.
  * @offset: offset within the file referenced by fd
  * @errp: pointer to Error*, to store an error if it happens.
@@ -1722,6 +1726,16 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
  */
 bool memory_region_is_protected(MemoryRegion *mr);
 
+/**
+ * memory_region_has_guest_memfd: check whether a memory region has guest_memfd
+ *     associated
+ *
+ * Returns %true if a memory region's ram_block has valid guest_memfd assigned.
+ *
+ * @mr: the memory region being queried
+ */
+bool memory_region_has_guest_memfd(MemoryRegion *mr);
+
 /**
  * memory_region_get_iommu: check whether a memory region is an iommu
  *
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 90676093f5..4ebd9ded5e 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -109,7 +109,7 @@ long qemu_maxrampagesize(void);
  *  @mr: the memory region where the ram block is
  *  @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
  *              RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- *              RAM_READONLY_FD
+ *              RAM_READONLY_FD, RAM_GUEST_MEMFD
  *  @mem_path or @fd: specify the backing file or device
  *  @offset: Offset into target file
  *  @errp: pointer to Error*, to store an error if it happens
diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h
index 848915ea5b..459c8917de 100644
--- a/include/exec/ramblock.h
+++ b/include/exec/ramblock.h
@@ -41,6 +41,7 @@ struct RAMBlock {
     QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
     int fd;
     uint64_t fd_offset;
+    int guest_memfd;
     size_t page_size;
     /* dirty bitmap used during migration */
     unsigned long *bmap;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 54f4d83a37..b4913281e2 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -536,4 +536,6 @@ void kvm_mark_guest_state_protected(void);
  * reported for the VM.
  */
 bool kvm_hwpoisoned_mem(void);
+
+int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp);
 #endif
diff --git a/system/memory.c b/system/memory.c
index a229a79988..c756950c0c 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1850,6 +1850,11 @@ bool memory_region_is_protected(MemoryRegion *mr)
     return mr->ram && (mr->ram_block->flags & RAM_PROTECTED);
 }
 
+bool memory_region_has_guest_memfd(MemoryRegion *mr)
+{
+    return mr->ram_block && mr->ram_block->guest_memfd >= 0;
+}
+
 uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
 {
     uint8_t mask = mr->dirty_log_mask;
diff --git a/system/physmem.c b/system/physmem.c
index 6cfb7a80ab..3a4a3f10d5 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -1842,6 +1842,17 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
         }
     }
 
+    if (kvm_enabled() && (new_block->flags & RAM_GUEST_MEMFD)) {
+        assert(new_block->guest_memfd < 0);
+
+        new_block->guest_memfd = kvm_create_guest_memfd(new_block->max_length,
+                                                        0, errp);
+        if (new_block->guest_memfd < 0) {
+            qemu_mutex_unlock_ramlist();
+            return;
+        }
+    }
+
     new_ram_size = MAX(old_ram_size,
               (new_block->offset + new_block->max_length) >> TARGET_PAGE_BITS);
     if (new_ram_size > old_ram_size) {
@@ -1904,7 +1915,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
     /* Just support these ram flags by now. */
     assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
                           RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY |
-                          RAM_READONLY_FD)) == 0);
+                          RAM_READONLY_FD | RAM_GUEST_MEMFD)) == 0);
 
     if (xen_enabled()) {
         error_setg(errp, "-mem-path not supported with Xen");
@@ -1941,6 +1952,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
     new_block->used_length = size;
     new_block->max_length = size;
     new_block->flags = ram_flags;
+    new_block->guest_memfd = -1;
     new_block->host = file_ram_alloc(new_block, size, fd, !file_size, offset,
                                      errp);
     if (!new_block->host) {
@@ -2020,7 +2032,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
     int align;
 
     assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC |
-                          RAM_NORESERVE)) == 0);
+                          RAM_NORESERVE| RAM_GUEST_MEMFD)) == 0);
     assert(!host ^ (ram_flags & RAM_PREALLOC));
 
     align = qemu_real_host_page_size();
@@ -2035,6 +2047,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
     new_block->max_length = max_size;
     assert(max_size >= size);
     new_block->fd = -1;
+    new_block->guest_memfd = -1;
     new_block->page_size = qemu_real_host_page_size();
     new_block->host = host;
     new_block->flags = ram_flags;
@@ -2057,7 +2070,7 @@ RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
 RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags,
                          MemoryRegion *mr, Error **errp)
 {
-    assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE)) == 0);
+    assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE | RAM_GUEST_MEMFD)) == 0);
     return qemu_ram_alloc_internal(size, size, NULL, NULL, ram_flags, mr, errp);
 }
 
@@ -2085,6 +2098,11 @@ static void reclaim_ramblock(RAMBlock *block)
     } else {
         qemu_anon_ram_free(block->host, block->max_length);
     }
+
+    if (block->guest_memfd >= 0) {
+        close(block->guest_memfd);
+    }
+
     g_free(block);
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 07/49] HostMem: Add mechanism to opt in kvm guest memfd via MachineState
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (5 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 06/49] RAMBlock: Add support of KVM private guest memfd Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 08/49] trace/kvm: Split address space and slot id in trace_kvm_set_user_memory() Michael Roth
                   ` (44 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	David Hildenbrand

From: Xiaoyao Li <xiaoyao.li@intel.com>

Add a new member "guest_memfd" to memory backends. When it's set
to true, it enables RAM_GUEST_MEMFD in ram_flags, thus private kvm
guest_memfd will be allocated during RAMBlock allocation.

Memory backend's @guest_memfd is wired with @require_guest_memfd
field of MachineState. It avoid looking up the machine in phymem.c.

MachineState::require_guest_memfd is supposed to be set by any VMs
that requires KVM guest memfd as private memory, e.g., TDX VM.

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
---
Changes in v4:
 - rename "require_guest_memfd" to "guest_memfd" in struct
   HostMemoryBackend;	(David Hildenbrand)
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 backends/hostmem-file.c  | 1 +
 backends/hostmem-memfd.c | 1 +
 backends/hostmem-ram.c   | 1 +
 backends/hostmem.c       | 1 +
 hw/core/machine.c        | 5 +++++
 include/hw/boards.h      | 2 ++
 include/sysemu/hostmem.h | 1 +
 7 files changed, 12 insertions(+)

diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index ac3e433cbd..3c69db7946 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -85,6 +85,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
     ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
     ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
     ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+    ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
     ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
     ram_flags |= RAM_NAMED_FILE;
     return memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 3923ea9364..745ead0034 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -55,6 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
     name = host_memory_backend_get_name(backend);
     ram_flags = backend->share ? RAM_SHARED : 0;
     ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+    ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
     return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
                                           backend->size, ram_flags, fd, 0, errp);
 }
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index d121249f0f..f7d81af783 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -30,6 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
     name = host_memory_backend_get_name(backend);
     ram_flags = backend->share ? RAM_SHARED : 0;
     ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+    ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
     return memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend),
                                                   name, backend->size,
                                                   ram_flags, errp);
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 81a72ce40b..eb9682b4a8 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -277,6 +277,7 @@ static void host_memory_backend_init(Object *obj)
     /* TODO: convert access to globals to compat properties */
     backend->merge = machine_mem_merge(machine);
     backend->dump = machine_dump_guest_core(machine);
+    backend->guest_memfd = machine_require_guest_memfd(machine);
     backend->reserve = true;
     backend->prealloc_threads = machine->smp.cpus;
 }
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 37ede0e7d4..73ce9da835 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1198,6 +1198,11 @@ bool machine_mem_merge(MachineState *machine)
     return machine->mem_merge;
 }
 
+bool machine_require_guest_memfd(MachineState *machine)
+{
+    return machine->require_guest_memfd;
+}
+
 static char *cpu_slot_to_string(const CPUArchId *cpu)
 {
     GString *s = g_string_new(NULL);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 8b8f6d5c00..44c2a4e1ec 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine);
 int machine_phandle_start(MachineState *machine);
 bool machine_dump_guest_core(MachineState *machine);
 bool machine_mem_merge(MachineState *machine);
+bool machine_require_guest_memfd(MachineState *machine);
 HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine);
 void machine_set_cpu_numa_node(MachineState *machine,
                                const CpuInstanceProperties *props,
@@ -370,6 +371,7 @@ struct MachineState {
     char *dt_compatible;
     bool dump_guest_core;
     bool mem_merge;
+    bool require_guest_memfd;
     bool usb;
     bool usb_disabled;
     char *firmware;
diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h
index 0e411aaa29..04b884bf42 100644
--- a/include/sysemu/hostmem.h
+++ b/include/sysemu/hostmem.h
@@ -74,6 +74,7 @@ struct HostMemoryBackend {
     uint64_t size;
     bool merge, dump, use_canonical_path;
     bool prealloc, is_mapped, share, reserve;
+    bool guest_memfd;
     uint32_t prealloc_threads;
     ThreadContext *prealloc_context;
     DECLARE_BITMAP(host_nodes, MAX_NODES + 1);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 08/49] trace/kvm: Split address space and slot id in trace_kvm_set_user_memory()
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (6 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 07/49] HostMem: Add mechanism to opt in kvm guest memfd via MachineState Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 09/49] kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot Michael Roth
                   ` (43 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

From: Xiaoyao Li <xiaoyao.li@intel.com>

The upper 16 bits of kvm_userspace_memory_region::slot are
address space id. Parse it separately in trace_kvm_set_user_memory().

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c    | 5 +++--
 accel/kvm/trace-events | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 132ab65df5..d2856dd736 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -304,8 +304,9 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, boo
     ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
     slot->old_flags = mem.flags;
 err:
-    trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
-                              mem.memory_size, mem.userspace_addr, ret);
+    trace_kvm_set_user_memory(mem.slot >> 16, (uint16_t)mem.slot, mem.flags,
+                              mem.guest_phys_addr, mem.memory_size,
+                              mem.userspace_addr, ret);
     if (ret < 0) {
         error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
                      " start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index a25902597b..9f599abc17 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -15,7 +15,7 @@ kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
 kvm_irqchip_release_virq(int virq) "virq %d"
 kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
 kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
-kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
+kvm_set_user_memory(uint16_t as, uint16_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "AddrSpace#%d Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
 kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
 kvm_resample_fd_notify(int gsi) "gsi %d"
 kvm_dirty_ring_full(int id) "vcpu %d"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 09/49] kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (7 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 08/49] trace/kvm: Split address space and slot id in trace_kvm_set_user_memory() Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 15:56   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 10/49] kvm: Introduce support for memory_attributes Michael Roth
                   ` (42 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Chao Peng

From: Chao Peng <chao.p.peng@linux.intel.com>

Switch to KVM_SET_USER_MEMORY_REGION2 when supported by KVM.

With KVM_SET_USER_MEMORY_REGION2, QEMU can set up memory region that
backend'ed both by hva-based shared memory and guest memfd based private
memory.

Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
Changes in v4:
- update KVM_MEM_PRIVATE to KVM_MEM_GUEST_MEMFD; (Isaku)
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c      | 56 ++++++++++++++++++++++++++++++++++------
 accel/kvm/trace-events   |  2 +-
 include/sysemu/kvm_int.h |  2 ++
 3 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index d2856dd736..e83429b31e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -283,35 +283,69 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
 static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new)
 {
     KVMState *s = kvm_state;
-    struct kvm_userspace_memory_region mem;
+    struct kvm_userspace_memory_region2 mem;
+    static int cap_user_memory2 = -1;
     int ret;
 
+    if (cap_user_memory2 == -1) {
+        cap_user_memory2 = kvm_check_extension(s, KVM_CAP_USER_MEMORY2);
+    }
+
+    if (!cap_user_memory2 && slot->guest_memfd >= 0) {
+        error_report("%s, KVM doesn't support KVM_CAP_USER_MEMORY2,"
+                     " which is required by guest memfd!", __func__);
+        exit(1);
+    }
+
     mem.slot = slot->slot | (kml->as_id << 16);
     mem.guest_phys_addr = slot->start_addr;
     mem.userspace_addr = (unsigned long)slot->ram;
     mem.flags = slot->flags;
+    mem.guest_memfd = slot->guest_memfd;
+    mem.guest_memfd_offset = slot->guest_memfd_offset;
 
     if (slot->memory_size && !new && (mem.flags ^ slot->old_flags) & KVM_MEM_READONLY) {
         /* Set the slot size to 0 before setting the slot to the desired
          * value. This is needed based on KVM commit 75d61fbc. */
         mem.memory_size = 0;
-        ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+
+        if (cap_user_memory2) {
+            ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
+        } else {
+            ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+        }
         if (ret < 0) {
             goto err;
         }
     }
     mem.memory_size = slot->memory_size;
-    ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+    if (cap_user_memory2) {
+        ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
+    } else {
+        ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+    }
     slot->old_flags = mem.flags;
 err:
     trace_kvm_set_user_memory(mem.slot >> 16, (uint16_t)mem.slot, mem.flags,
                               mem.guest_phys_addr, mem.memory_size,
-                              mem.userspace_addr, ret);
+                              mem.userspace_addr, mem.guest_memfd,
+                              mem.guest_memfd_offset, ret);
     if (ret < 0) {
-        error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
-                     " start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
-                     __func__, mem.slot, slot->start_addr,
-                     (uint64_t)mem.memory_size, strerror(errno));
+        if (cap_user_memory2) {
+                error_report("%s: KVM_SET_USER_MEMORY_REGION2 failed, slot=%d,"
+                        " start=0x%" PRIx64 ", size=0x%" PRIx64 ","
+                        " flags=0x%" PRIx32 ", guest_memfd=%" PRId32 ","
+                        " guest_memfd_offset=0x%" PRIx64 ": %s",
+                        __func__, mem.slot, slot->start_addr,
+                        (uint64_t)mem.memory_size, mem.flags,
+                        mem.guest_memfd, (uint64_t)mem.guest_memfd_offset,
+                        strerror(errno));
+        } else {
+                error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
+                            " start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
+                            __func__, mem.slot, slot->start_addr,
+                            (uint64_t)mem.memory_size, strerror(errno));
+        }
     }
     return ret;
 }
@@ -466,6 +500,9 @@ static int kvm_mem_flags(MemoryRegion *mr)
     if (readonly && kvm_readonly_mem_allowed) {
         flags |= KVM_MEM_READONLY;
     }
+    if (memory_region_has_guest_memfd(mr)) {
+        flags |= KVM_MEM_GUEST_MEMFD;
+    }
     return flags;
 }
 
@@ -1363,6 +1400,9 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
         mem->ram_start_offset = ram_start_offset;
         mem->ram = ram;
         mem->flags = kvm_mem_flags(mr);
+        mem->guest_memfd = mr->ram_block->guest_memfd;
+        mem->guest_memfd_offset = (uint8_t*)ram - mr->ram_block->host;
+
         kvm_slot_init_dirty_bitmap(mem);
         err = kvm_set_user_memory_region(kml, mem, true);
         if (err) {
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index 9f599abc17..e8c52cb9e7 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -15,7 +15,7 @@ kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
 kvm_irqchip_release_virq(int virq) "virq %d"
 kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
 kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
-kvm_set_user_memory(uint16_t as, uint16_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "AddrSpace#%d Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
+kvm_set_user_memory(uint16_t as, uint16_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, uint32_t fd, uint64_t fd_offset, int ret) "AddrSpace#%d Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " guest_memfd=%d" " guest_memfd_offset=0x%" PRIx64 " ret=%d"
 kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
 kvm_resample_fd_notify(int gsi) "gsi %d"
 kvm_dirty_ring_full(int id) "vcpu %d"
diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h
index 3496be7997..a5a3fee411 100644
--- a/include/sysemu/kvm_int.h
+++ b/include/sysemu/kvm_int.h
@@ -30,6 +30,8 @@ typedef struct KVMSlot
     int as_id;
     /* Cache of the offset in ram address space */
     ram_addr_t ram_start_offset;
+    int guest_memfd;
+    hwaddr guest_memfd_offset;
 } KVMSlot;
 
 typedef struct KVMMemoryUpdate {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 10/49] kvm: Introduce support for memory_attributes
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (8 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 09/49] kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 16:00   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range() Michael Roth
                   ` (41 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

From: Xiaoyao Li <xiaoyao.li@intel.com>

Introduce the helper functions to set the attributes of a range of
memory to private or shared.

This is necessary to notify KVM the private/shared attribute of each gpa
range. KVM needs the information to decide the GPA needs to be mapped at
hva-based shared memory or guest_memfd based private memory.

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
Changes in v4:
- move the check of kvm_supported_memory_attributes to the common
  kvm_set_memory_attributes(); (Wang Wei)
- change warn_report() to error_report() in kvm_set_memory_attributes()
  and drop the __func__; (Daniel)

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c  | 44 ++++++++++++++++++++++++++++++++++++++++++++
 include/sysemu/kvm.h |  3 +++
 2 files changed, 47 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index e83429b31e..df7a32735a 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -92,6 +92,7 @@ static bool kvm_has_guest_debug;
 static int kvm_sstep_flags;
 static bool kvm_immediate_exit;
 static bool kvm_guest_memfd_supported;
+static uint64_t kvm_supported_memory_attributes;
 static hwaddr kvm_max_slot_size = ~0;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
@@ -1304,6 +1305,46 @@ void kvm_set_max_memslot_size(hwaddr max_slot_size)
     kvm_max_slot_size = max_slot_size;
 }
 
+static int kvm_set_memory_attributes(hwaddr start, hwaddr size, uint64_t attr)
+{
+    struct kvm_memory_attributes attrs;
+    int r;
+
+    if (kvm_supported_memory_attributes == 0) {
+        error_report("No memory attribute supported by KVM\n");
+        return -EINVAL;
+    }
+
+    if ((attr & kvm_supported_memory_attributes) != attr) {
+        error_report("memory attribute 0x%lx not supported by KVM,"
+                     " supported bits are 0x%lx\n",
+                     attr, kvm_supported_memory_attributes);
+        return -EINVAL;
+    }
+
+    attrs.attributes = attr;
+    attrs.address = start;
+    attrs.size = size;
+    attrs.flags = 0;
+
+    r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ATTRIBUTES, &attrs);
+    if (r) {
+        error_report("failed to set memory (0x%lx+%#zx) with attr 0x%lx error '%s'",
+                     start, size, attr, strerror(errno));
+    }
+    return r;
+}
+
+int kvm_set_memory_attributes_private(hwaddr start, hwaddr size)
+{
+    return kvm_set_memory_attributes(start, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
+}
+
+int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size)
+{
+    return kvm_set_memory_attributes(start, size, 0);
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static void kvm_set_phys_mem(KVMMemoryListener *kml,
                              MemoryRegionSection *section, bool add)
@@ -2439,6 +2480,9 @@ static int kvm_init(MachineState *ms)
 
     kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);
 
+    ret = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
+    kvm_supported_memory_attributes = ret > 0 ? ret : 0;
+
     if (object_property_find(OBJECT(current_machine), "kvm-type")) {
         g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
                                                             "kvm-type",
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index b4913281e2..2cb3192509 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -538,4 +538,7 @@ void kvm_mark_guest_state_protected(void);
 bool kvm_hwpoisoned_mem(void);
 
 int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp);
+
+int kvm_set_memory_attributes_private(hwaddr start, hwaddr size);
+int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size);
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (9 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 10/49] kvm: Introduce support for memory_attributes Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  9:37   ` David Hildenbrand
  2024-03-20  8:39 ` [PATCH v3 12/49] kvm: handle KVM_EXIT_MEMORY_FAULT Michael Roth
                   ` (40 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	David Hildenbrand

From: Xiaoyao Li <xiaoyao.li@intel.com>

When memory page is converted from private to shared, the original
private memory is back'ed by guest_memfd. Introduce
ram_block_discard_guest_memfd_range() for discarding memory in
guest_memfd.

Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
---
Changes in v5:
- Collect Reviewed-by from David;

Changes in in v4:
- Drop ram_block_convert_range() and open code its implementation in the
  next Patch.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 include/exec/cpu-common.h |  2 ++
 system/physmem.c          | 23 +++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 6346df17ce..6d5318895a 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -159,6 +159,8 @@ typedef int (RAMBlockIterFunc)(RAMBlock *rb, void *opaque);
 
 int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
 int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length);
+int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
+                                        size_t length);
 
 #endif
 
diff --git a/system/physmem.c b/system/physmem.c
index 3a4a3f10d5..8be8053cf7 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -3705,6 +3705,29 @@ err:
     return ret;
 }
 
+int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
+                                        size_t length)
+{
+    int ret = -1;
+
+#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
+    ret = fallocate(rb->guest_memfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+                    start, length);
+
+    if (ret) {
+        ret = -errno;
+        error_report("%s: Failed to fallocate %s:%" PRIx64 " +%zx (%d)",
+                     __func__, rb->idstr, start, length, ret);
+    }
+#else
+    ret = -ENOSYS;
+    error_report("%s: fallocate not available %s:%" PRIx64 " +%zx (%d)",
+                 __func__, rb->idstr, start, length, ret);
+#endif
+
+    return ret;
+}
+
 bool ramblock_is_pmem(RAMBlock *rb)
 {
     return rb->flags & RAM_PMEM;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 12/49] kvm: handle KVM_EXIT_MEMORY_FAULT
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (10 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range() Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 13/49] [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size Michael Roth
                   ` (39 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Chao Peng

From: Chao Peng <chao.p.peng@linux.intel.com>

When geeting KVM_EXIT_MEMORY_FAULT exit, it indicates userspace needs to
do the memory conversion on the RAMBlock to turn the memory into desired
attribute, i.e., private/shared.

Currently only KVM_MEMORY_EXIT_FLAG_PRIVATE in flags is valid when
KVM_EXIT_MEMORY_FAULT happens.

Note, KVM_EXIT_MEMORY_FAULT makes sense only when the RAMBlock has
guest_memfd memory backend.

Note, KVM_EXIT_MEMORY_FAULT returns with -EFAULT, so special handling is
added.

When page is converted from shared to private, the original shared
memory can be discarded via ram_block_discard_range(). Note, shared
memory can be discarded only when it's not back'ed by hugetlb because
hugetlb is supposed to be pre-allocated and no need for discarding.

Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>

---
Changes in v4:
- open-coded ram_block_discard logic;
- change warn_report() to error_report(); (Daniel)

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c | 94 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 84 insertions(+), 10 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index df7a32735a..2fdc07a472 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2903,6 +2903,68 @@ static void kvm_eat_signals(CPUState *cpu)
     } while (sigismember(&chkset, SIG_IPI));
 }
 
+static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
+{
+    MemoryRegionSection section;
+    ram_addr_t offset;
+    MemoryRegion *mr;
+    RAMBlock *rb;
+    void *addr;
+    int ret = -1;
+
+    if (!QEMU_PTR_IS_ALIGNED(start, qemu_host_page_size) ||
+        !QEMU_PTR_IS_ALIGNED(size, qemu_host_page_size)) {
+        return -1;
+    }
+
+    if (!size) {
+        return -1;
+    }
+
+    section = memory_region_find(get_system_memory(), start, size);
+    mr = section.mr;
+    if (!mr) {
+        return -1;
+    }
+
+    if (memory_region_has_guest_memfd(mr)) {
+        if (to_private) {
+            ret = kvm_set_memory_attributes_private(start, size);
+        } else {
+            ret = kvm_set_memory_attributes_shared(start, size);
+        }
+
+        if (ret) {
+            memory_region_unref(section.mr);
+            return ret;
+        }
+
+        addr = memory_region_get_ram_ptr(mr) + section.offset_within_region;
+        rb = qemu_ram_block_from_host(addr, false, &offset);
+
+        if (to_private) {
+            if (rb->page_size != qemu_host_page_size) {
+                /*
+                * shared memory is back'ed by  hugetlb, which is supposed to be
+                * pre-allocated and doesn't need to be discarded
+                */
+                return 0;
+            } else {
+                ret = ram_block_discard_range(rb, offset, size);
+            }
+        } else {
+            ret = ram_block_discard_guest_memfd_range(rb, offset, size);
+        }
+    } else {
+        error_report("Convert non guest_memfd backed memory region "
+                    "(0x%"HWADDR_PRIx" ,+ 0x%"HWADDR_PRIx") to %s",
+                    start, size, to_private ? "private" : "shared");
+    }
+
+    memory_region_unref(section.mr);
+    return ret;
+}
+
 int kvm_cpu_exec(CPUState *cpu)
 {
     struct kvm_run *run = cpu->kvm_run;
@@ -2970,18 +3032,20 @@ int kvm_cpu_exec(CPUState *cpu)
                 ret = EXCP_INTERRUPT;
                 break;
             }
-            fprintf(stderr, "error: kvm run failed %s\n",
-                    strerror(-run_ret));
+            if (!(run_ret == -EFAULT && run->exit_reason == KVM_EXIT_MEMORY_FAULT)) {
+                fprintf(stderr, "error: kvm run failed %s\n",
+                        strerror(-run_ret));
 #ifdef TARGET_PPC
-            if (run_ret == -EBUSY) {
-                fprintf(stderr,
-                        "This is probably because your SMT is enabled.\n"
-                        "VCPU can only run on primary threads with all "
-                        "secondary threads offline.\n");
-            }
+                if (run_ret == -EBUSY) {
+                    fprintf(stderr,
+                            "This is probably because your SMT is enabled.\n"
+                            "VCPU can only run on primary threads with all "
+                            "secondary threads offline.\n");
+                }
 #endif
-            ret = -1;
-            break;
+                ret = -1;
+                break;
+            }
         }
 
         trace_kvm_run_exit(cpu->cpu_index, run->exit_reason);
@@ -3064,6 +3128,16 @@ int kvm_cpu_exec(CPUState *cpu)
                 break;
             }
             break;
+        case KVM_EXIT_MEMORY_FAULT:
+            if (run->memory_fault.flags & ~KVM_MEMORY_EXIT_FLAG_PRIVATE) {
+                error_report("KVM_EXIT_MEMORY_FAULT: Unknown flag 0x%" PRIx64,
+                             (uint64_t)run->memory_fault.flags);
+                ret = -1;
+                break;
+            }
+            ret = kvm_convert_memory(run->memory_fault.gpa, run->memory_fault.size,
+                                     run->memory_fault.flags & KVM_MEMORY_EXIT_FLAG_PRIVATE);
+            break;
         default:
             ret = kvm_arch_handle_exit(cpu, run);
             break;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 13/49] [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (11 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 12/49] kvm: handle KVM_EXIT_MEMORY_FAULT Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:46   ` Xiaoyao Li
  2024-03-20  8:39 ` [PATCH v3 14/49] trace/kvm: Add trace for page convertion between shared and private Michael Roth
                   ` (38 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

TODO: squash into "kvm: handle KVM_EXIT_MEMORY_FAULT"

qemu_host_page_size has been superseded by qemu_real_host_page_size()
in newer QEMU, so update the patch accordingly.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 2fdc07a472..a9c19ab9a1 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2912,8 +2912,8 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
     void *addr;
     int ret = -1;
 
-    if (!QEMU_PTR_IS_ALIGNED(start, qemu_host_page_size) ||
-        !QEMU_PTR_IS_ALIGNED(size, qemu_host_page_size)) {
+    if (!QEMU_PTR_IS_ALIGNED(start, qemu_real_host_page_size()) ||
+        !QEMU_PTR_IS_ALIGNED(size, qemu_real_host_page_size())) {
         return -1;
     }
 
@@ -2943,7 +2943,7 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
         rb = qemu_ram_block_from_host(addr, false, &offset);
 
         if (to_private) {
-            if (rb->page_size != qemu_host_page_size) {
+            if (rb->page_size != qemu_real_host_page_size()) {
                 /*
                 * shared memory is back'ed by  hugetlb, which is supposed to be
                 * pre-allocated and doesn't need to be discarded
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 14/49] trace/kvm: Add trace for page convertion between shared and private
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (12 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 13/49] [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 15/49] kvm/memory: Make memory type private by default if it has guest memfd backend Michael Roth
                   ` (37 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Isaku Yamahata

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c    | 2 ++
 accel/kvm/trace-events | 1 +
 2 files changed, 3 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index a9c19ab9a1..9a8b365a69 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2912,6 +2912,8 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
     void *addr;
     int ret = -1;
 
+    trace_kvm_convert_memory(start, size, to_private ? "shared_to_private" : "private_to_shared");
+
     if (!QEMU_PTR_IS_ALIGNED(start, qemu_real_host_page_size()) ||
         !QEMU_PTR_IS_ALIGNED(size, qemu_real_host_page_size())) {
         return -1;
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index e8c52cb9e7..31175fed97 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -31,3 +31,4 @@ kvm_cpu_exec(void) ""
 kvm_interrupt_exit_request(void) ""
 kvm_io_window_exit(void) ""
 kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32
+kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 15/49] kvm/memory: Make memory type private by default if it has guest memfd backend
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (13 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 14/49] trace/kvm: Add trace for page convertion between shared and private Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 16/49] memory: Introduce memory_region_init_ram_guest_memfd() Michael Roth
                   ` (36 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

From: Xiaoyao Li <xiaoyao.li@intel.com>

KVM side leaves the memory to shared by default, while may incur the
overhead of paging conversion on the first visit of each page. Because
the expectation is that page is likely to private for the VMs that
require private memory (has guest memfd).

Explicitly set the memory to private when memory region has valid
guest memfd backend.

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 9a8b365a69..53ce4f091e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1451,6 +1451,16 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
                     strerror(-err));
             abort();
         }
+
+        if (memory_region_has_guest_memfd(mr)) {
+            err = kvm_set_memory_attributes_private(start_addr, slot_size);
+            if (err) {
+                error_report("%s: failed to set memory attribute private: %s\n",
+                             __func__, strerror(-err));
+                exit(1);
+            }
+        }
+
         start_addr += slot_size;
         ram_start_offset += slot_size;
         ram += slot_size;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 16/49] memory: Introduce memory_region_init_ram_guest_memfd()
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (14 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 15/49] kvm/memory: Make memory type private by default if it has guest memfd backend Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 17/49] pci-host/q35: Move PAM initialization above SMRAM initialization Michael Roth
                   ` (35 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

From: Xiaoyao Li <xiaoyao.li@intel.com>

Introduce memory_region_init_ram_guest_memfd() to allocate private
guset memfd on the MemoryRegion initialization. It's for the use case of
TDVF, which must be private on TDX case.

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
Changes in v5:
- drop memory_region_set_default_private() because this function is
  dropped in this v5 series;

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 include/exec/memory.h |  6 ++++++
 system/memory.c       | 25 +++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 679a847685..1e351f6fc8 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1603,6 +1603,12 @@ bool memory_region_init_ram(MemoryRegion *mr,
                             uint64_t size,
                             Error **errp);
 
+bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
+                                        Object *owner,
+                                        const char *name,
+                                        uint64_t size,
+                                        Error **errp);
+
 /**
  * memory_region_init_rom: Initialize a ROM memory region.
  *
diff --git a/system/memory.c b/system/memory.c
index c756950c0c..85a22408e9 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -3606,6 +3606,31 @@ bool memory_region_init_ram(MemoryRegion *mr,
     return true;
 }
 
+bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
+                                        Object *owner,
+                                        const char *name,
+                                        uint64_t size,
+                                        Error **errp)
+{
+    DeviceState *owner_dev;
+
+    if (!memory_region_init_ram_flags_nomigrate(mr, owner, name, size,
+                                                RAM_GUEST_MEMFD, errp)) {
+        return false;
+    }
+
+    /* This will assert if owner is neither NULL nor a DeviceState.
+     * We only want the owner here for the purposes of defining a
+     * unique name for migration. TODO: Ideally we should implement
+     * a naming scheme for Objects which are not DeviceStates, in
+     * which case we can relax this restriction.
+     */
+    owner_dev = DEVICE(owner);
+    vmstate_register_ram(mr, owner_dev);
+
+    return true;
+}
+
 bool memory_region_init_rom(MemoryRegion *mr,
                             Object *owner,
                             const char *name,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 17/49] pci-host/q35: Move PAM initialization above SMRAM initialization
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (15 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 16/49] memory: Introduce memory_region_init_ram_guest_memfd() Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 18/49] q35: Introduce smm_ranges property for q35-pci-host Michael Roth
                   ` (34 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Isaku Yamahata

From: Isaku Yamahata <isaku.yamahata@intel.com>

In mch_realize(), process PAM initialization before SMRAM initialization so
that later patch can skill all the SMRAM related with a single check.

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/pci-host/q35.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 0d7d4e3f08..98d4a7c253 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -568,6 +568,16 @@ static void mch_realize(PCIDevice *d, Error **errp)
     /* setup pci memory mapping */
     pc_pci_as_mapping_init(mch->system_memory, mch->pci_address_space);
 
+    /* PAM */
+    init_pam(&mch->pam_regions[0], OBJECT(mch), mch->ram_memory,
+             mch->system_memory, mch->pci_address_space,
+             PAM_BIOS_BASE, PAM_BIOS_SIZE);
+    for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
+        init_pam(&mch->pam_regions[i + 1], OBJECT(mch), mch->ram_memory,
+                 mch->system_memory, mch->pci_address_space,
+                 PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
+    }
+
     /* if *disabled* show SMRAM to all CPUs */
     memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
                              mch->pci_address_space, MCH_HOST_BRIDGE_SMRAM_C_BASE,
@@ -634,15 +644,6 @@ static void mch_realize(PCIDevice *d, Error **errp)
 
     object_property_add_const_link(qdev_get_machine(), "smram",
                                    OBJECT(&mch->smram));
-
-    init_pam(&mch->pam_regions[0], OBJECT(mch), mch->ram_memory,
-             mch->system_memory, mch->pci_address_space,
-             PAM_BIOS_BASE, PAM_BIOS_SIZE);
-    for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
-        init_pam(&mch->pam_regions[i + 1], OBJECT(mch), mch->ram_memory,
-                 mch->system_memory, mch->pci_address_space,
-                 PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
-    }
 }
 
 uint64_t mch_mcfg_base(void)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 18/49] q35: Introduce smm_ranges property for q35-pci-host
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (16 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 17/49] pci-host/q35: Move PAM initialization above SMRAM initialization Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled() Michael Roth
                   ` (33 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Sean Christopherson

From: Isaku Yamahata <isaku.yamahata@linux.intel.com>

Add a q35 property to check whether or not SMM ranges, e.g. SMRAM, TSEG,
etc... exist for the target platform.  TDX doesn't support SMM and doesn't
play nice with QEMU modifying related guest memory ranges.

Signed-off-by: Isaku Yamahata <isaku.yamahata@linux.intel.com>
Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/i386/pc_q35.c          |  2 ++
 hw/pci-host/q35.c         | 42 +++++++++++++++++++++++++++------------
 include/hw/i386/pc.h      |  1 +
 include/hw/pci-host/q35.h |  1 +
 4 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 8a427c4647..42324448d7 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -219,6 +219,8 @@ static void pc_q35_init(MachineState *machine)
                             x86ms->above_4g_mem_size, NULL);
     object_property_set_bool(phb, PCI_HOST_BYPASS_IOMMU,
                              pcms->default_bus_bypass_iommu, NULL);
+    object_property_set_bool(phb, PCI_HOST_PROP_SMM_RANGES,
+                             x86_machine_is_smm_enabled(x86ms), NULL);
     sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal);
 
     /* pci */
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 98d4a7c253..0b6cbaed7e 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -179,6 +179,8 @@ static Property q35_host_props[] = {
                      mch.below_4g_mem_size, 0),
     DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, Q35PCIHost,
                      mch.above_4g_mem_size, 0),
+    DEFINE_PROP_BOOL(PCI_HOST_PROP_SMM_RANGES, Q35PCIHost,
+                     mch.has_smm_ranges, true),
     DEFINE_PROP_BOOL("x-pci-hole64-fix", Q35PCIHost, pci_hole64_fix, true),
     DEFINE_PROP_END_OF_LIST(),
 };
@@ -214,6 +216,7 @@ static void q35_host_initfn(Object *obj)
     /* mch's object_initialize resets the default value, set it again */
     qdev_prop_set_uint64(DEVICE(s), PCI_HOST_PROP_PCI_HOLE64_SIZE,
                          Q35_PCI_HOST_HOLE64_SIZE_DEFAULT);
+
     object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32",
                         q35_host_get_pci_hole_start,
                         NULL, NULL, NULL);
@@ -476,6 +479,10 @@ static void mch_write_config(PCIDevice *d,
         mch_update_pciexbar(mch);
     }
 
+    if (!mch->has_smm_ranges) {
+        return;
+    }
+
     if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM,
                        MCH_HOST_BRIDGE_SMRAM_SIZE)) {
         mch_update_smram(mch);
@@ -494,10 +501,13 @@ static void mch_write_config(PCIDevice *d,
 static void mch_update(MCHPCIState *mch)
 {
     mch_update_pciexbar(mch);
+
     mch_update_pam(mch);
-    mch_update_smram(mch);
-    mch_update_ext_tseg_mbytes(mch);
-    mch_update_smbase_smram(mch);
+    if (mch->has_smm_ranges) {
+        mch_update_smram(mch);
+        mch_update_ext_tseg_mbytes(mch);
+        mch_update_smbase_smram(mch);
+    }
 
     /*
      * pci hole goes from end-of-low-ram to io-apic.
@@ -538,18 +548,20 @@ static void mch_reset(DeviceState *qdev)
     pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
                  MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
 
-    d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
-    d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT;
-    d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
-    d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
+    if (mch->has_smm_ranges) {
+        d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
+        d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT;
+        d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
+        d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
 
-    if (mch->ext_tseg_mbytes > 0) {
-        pci_set_word(d->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
-                     MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
-    }
+        if (mch->ext_tseg_mbytes > 0) {
+            pci_set_word(d->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
+                        MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
+        }
 
-    d->config[MCH_HOST_BRIDGE_F_SMBASE] = 0;
-    d->wmask[MCH_HOST_BRIDGE_F_SMBASE] = 0xff;
+        d->config[MCH_HOST_BRIDGE_F_SMBASE] = 0;
+        d->wmask[MCH_HOST_BRIDGE_F_SMBASE] = 0xff;
+    }
 
     mch_update(mch);
 }
@@ -578,6 +590,10 @@ static void mch_realize(PCIDevice *d, Error **errp)
                  PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
     }
 
+    if (!mch->has_smm_ranges) {
+        return;
+    }
+
     /* if *disabled* show SMRAM to all CPUs */
     memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
                              mch->pci_address_space, MCH_HOST_BRIDGE_SMRAM_C_BASE,
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 27a68071d7..fb1d4106e5 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -161,6 +161,7 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
 #define PCI_HOST_PROP_PCI_HOLE64_SIZE  "pci-hole64-size"
 #define PCI_HOST_BELOW_4G_MEM_SIZE     "below-4g-mem-size"
 #define PCI_HOST_ABOVE_4G_MEM_SIZE     "above-4g-mem-size"
+#define PCI_HOST_PROP_SMM_RANGES       "smm-ranges"
 
 
 void pc_pci_as_mapping_init(MemoryRegion *system_memory,
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index bafcbe6752..22fadfa3ed 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -50,6 +50,7 @@ struct MCHPCIState {
     MemoryRegion tseg_blackhole, tseg_window;
     MemoryRegion smbase_blackhole, smbase_window;
     bool has_smram_at_smbase;
+    bool has_smm_ranges;
     Range pci_hole;
     uint64_t below_4g_mem_size;
     uint64_t above_4g_mem_size;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled()
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (17 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 18/49] q35: Introduce smm_ranges property for q35-pci-host Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 16:26   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 20/49] trace/kvm: Add trace for KVM_EXIT_MEMORY_FAULT Michael Roth
                   ` (32 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Some subsystems like VFIO might disable ram block discard for
uncoordinated cases. Since kvm_convert_memory()/guest_memfd don't
implement a RamDiscardManager handler to convey discard operations to
various listeners like VFIO. Because of this, sequences like the
following can result due to stale IOMMU mappings:

  - convert page shared->private
  - discard shared page
  - convert page private->shared
  - new page is allocated
  - issue DMA operations against that shared page

Address this by taking ram_block_discard_is_enabled() into account when
deciding whether or not to discard pages.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 53ce4f091e..6ae03c880f 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2962,10 +2962,14 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
                 */
                 return 0;
             } else {
-                ret = ram_block_discard_range(rb, offset, size);
+                ret = ram_block_discard_is_disabled()
+                      ? ram_block_discard_range(rb, offset, size)
+                      : 0;
             }
         } else {
-            ret = ram_block_discard_guest_memfd_range(rb, offset, size);
+            ret = ram_block_discard_is_disabled()
+                  ? ram_block_discard_guest_memfd_range(rb, offset, size)
+                  : 0;
         }
     } else {
         error_report("Convert non guest_memfd backed memory region "
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 20/49] trace/kvm: Add trace for KVM_EXIT_MEMORY_FAULT
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (18 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled() Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state Michael Roth
                   ` (31 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c    | 3 +++
 accel/kvm/trace-events | 1 +
 2 files changed, 4 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 6ae03c880f..b5872fdc07 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3145,6 +3145,9 @@ int kvm_cpu_exec(CPUState *cpu)
             }
             break;
         case KVM_EXIT_MEMORY_FAULT:
+            trace_kvm_memory_fault(run->memory_fault.gpa,
+                                   run->memory_fault.size,
+                                   run->memory_fault.flags);
             if (run->memory_fault.flags & ~KVM_MEMORY_EXIT_FLAG_PRIVATE) {
                 error_report("KVM_EXIT_MEMORY_FAULT: Unknown flag 0x%" PRIx64,
                              (uint64_t)run->memory_fault.flags);
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index 31175fed97..681ccb667d 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -32,3 +32,4 @@ kvm_interrupt_exit_request(void) ""
 kvm_io_window_exit(void) ""
 kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32
 kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
+kvm_memory_fault(uint64_t start, uint64_t size, uint64_t flags) "start 0x%" PRIx64 " size 0x%" PRIx64 " flags 0x%" PRIx64
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (19 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 20/49] trace/kvm: Add trace for KVM_EXIT_MEMORY_FAULT Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 11:44   ` Daniel P. Berrangé
                     ` (2 more replies)
  2024-03-20  8:39 ` [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object Michael Roth
                   ` (30 subsequent siblings)
  51 siblings, 3 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Currently all SEV/SEV-ES functionality is managed through a single
'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
same approach won't work well since some of the properties/state
managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
rely on a new QOM type with its own set of properties/state.

To prepare for this, this patch moves common state into an abstract
'sev-common' parent type to encapsulate properties/state that are
common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
properties/state in the current 'sev-guest' type. This should not
affect current behavior or command-line options.

As part of this patch, some related changes are also made:

  - a static 'sev_guest' variable is currently used to keep track of
    the 'sev-guest' instance. SEV-SNP would similarly introduce an
    'sev_snp_guest' static variable. But these instances are now
    available via qdev_get_machine()->cgs, so switch to using that
    instead and drop the static variable.

  - 'sev_guest' is currently used as the name for the static variable
    holding a pointer to the 'sev-guest' instance. Re-purpose the name
    as a local variable referring the 'sev-guest' instance, and use
    that consistently throughout the code so it can be easily
    distinguished from sev-common/sev-snp-guest instances.

  - 'sev' is generally used as the name for local variables holding a
    pointer to the 'sev-guest' instance. In cases where that now points
    to common state, use the name 'sev_common'; in cases where that now
    points to state specific to 'sev-guest' instance, use the name
    'sev_guest'

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 qapi/qom.json     |  32 ++--
 target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
 target/i386/sev.h |   3 +
 3 files changed, 281 insertions(+), 211 deletions(-)

diff --git a/qapi/qom.json b/qapi/qom.json
index baae3a183f..66b5781ca6 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -875,12 +875,29 @@
   'data': { '*filename': 'str' } }
 
 ##
-# @SevGuestProperties:
+# @SevCommonProperties:
 #
-# Properties for sev-guest objects.
+# Properties common to objects that are derivatives of sev-common.
 #
 # @sev-device: SEV device to use (default: "/dev/sev")
 #
+# @cbitpos: C-bit location in page table entry (default: 0)
+#
+# @reduced-phys-bits: number of bits in physical addresses that become
+#     unavailable when SEV is enabled
+#
+# Since: 2.12
+##
+{ 'struct': 'SevCommonProperties',
+  'data': { '*sev-device': 'str',
+            '*cbitpos': 'uint32',
+            'reduced-phys-bits': 'uint32' } }
+
+##
+# @SevGuestProperties:
+#
+# Properties for sev-guest objects.
+#
 # @dh-cert-file: guest owners DH certificate (encoded with base64)
 #
 # @session-file: guest owners session parameters (encoded with base64)
@@ -889,11 +906,6 @@
 #
 # @handle: SEV firmware handle (default: 0)
 #
-# @cbitpos: C-bit location in page table entry (default: 0)
-#
-# @reduced-phys-bits: number of bits in physical addresses that become
-#     unavailable when SEV is enabled
-#
 # @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
 #     designated guest firmware page for measured boot with -kernel
 #     (default: false) (since 6.2)
@@ -901,13 +913,11 @@
 # Since: 2.12
 ##
 { 'struct': 'SevGuestProperties',
-  'data': { '*sev-device': 'str',
-            '*dh-cert-file': 'str',
+  'base': 'SevCommonProperties',
+  'data': { '*dh-cert-file': 'str',
             '*session-file': 'str',
             '*policy': 'uint32',
             '*handle': 'uint32',
-            '*cbitpos': 'uint32',
-            'reduced-phys-bits': 'uint32',
             '*kernel-hashes': 'bool' } }
 
 ##
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 9dab4060b8..63a220de5e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -40,48 +40,53 @@
 #include "hw/i386/pc.h"
 #include "exec/address-spaces.h"
 
-#define TYPE_SEV_GUEST "sev-guest"
+OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
 OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
 
-
-/**
- * SevGuestState:
- *
- * The SevGuestState object is used for creating and managing a SEV
- * guest.
- *
- * # $QEMU \
- *         -object sev-guest,id=sev0 \
- *         -machine ...,memory-encryption=sev0
- */
-struct SevGuestState {
+struct SevCommonState {
     X86ConfidentialGuest parent_obj;
 
     int kvm_type;
 
     /* configuration parameters */
     char *sev_device;
-    uint32_t policy;
-    char *dh_cert_file;
-    char *session_file;
     uint32_t cbitpos;
     uint32_t reduced_phys_bits;
-    bool kernel_hashes;
 
     /* runtime state */
-    uint32_t handle;
     uint8_t api_major;
     uint8_t api_minor;
     uint8_t build_id;
     int sev_fd;
     SevState state;
-    gchar *measurement;
 
     uint32_t reset_cs;
     uint32_t reset_ip;
     bool reset_data_valid;
 };
 
+/**
+ * SevGuestState:
+ *
+ * The SevGuestState object is used for creating and managing a SEV
+ * guest.
+ *
+ * # $QEMU \
+ *         -object sev-guest,id=sev0 \
+ *         -machine ...,memory-encryption=sev0
+ */
+struct SevGuestState {
+    SevCommonState sev_common;
+    gchar *measurement;
+
+    /* configuration parameters */
+    uint32_t handle;
+    uint32_t policy;
+    char *dh_cert_file;
+    char *session_file;
+    bool kernel_hashes;
+};
+
 #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
 #define DEFAULT_SEV_DEVICE      "/dev/sev"
 
@@ -127,7 +132,6 @@ typedef struct QEMU_PACKED PaddedSevHashTable {
 
 QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
 
-static SevGuestState *sev_guest;
 static Error *sev_mig_blocker;
 
 static const char *const sev_fw_errlist[] = {
@@ -208,21 +212,21 @@ fw_error_to_str(int code)
 }
 
 static bool
-sev_check_state(const SevGuestState *sev, SevState state)
+sev_check_state(const SevCommonState *sev_common, SevState state)
 {
-    assert(sev);
-    return sev->state == state ? true : false;
+    assert(sev_common);
+    return sev_common->state == state ? true : false;
 }
 
 static void
-sev_set_guest_state(SevGuestState *sev, SevState new_state)
+sev_set_guest_state(SevCommonState *sev_common, SevState new_state)
 {
     assert(new_state < SEV_STATE__MAX);
-    assert(sev);
+    assert(sev_common);
 
-    trace_kvm_sev_change_state(SevState_str(sev->state),
+    trace_kvm_sev_change_state(SevState_str(sev_common->state),
                                SevState_str(new_state));
-    sev->state = new_state;
+    sev_common->state = new_state;
 }
 
 static void
@@ -289,111 +293,61 @@ static struct RAMBlockNotifier sev_ram_notifier = {
     .ram_block_removed = sev_ram_block_removed,
 };
 
-static void
-sev_guest_finalize(Object *obj)
-{
-}
-
-static char *
-sev_guest_get_session_file(Object *obj, Error **errp)
-{
-    SevGuestState *s = SEV_GUEST(obj);
-
-    return s->session_file ? g_strdup(s->session_file) : NULL;
-}
-
-static void
-sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
-{
-    SevGuestState *s = SEV_GUEST(obj);
-
-    s->session_file = g_strdup(value);
-}
-
-static char *
-sev_guest_get_dh_cert_file(Object *obj, Error **errp)
-{
-    SevGuestState *s = SEV_GUEST(obj);
-
-    return g_strdup(s->dh_cert_file);
-}
-
-static void
-sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
-{
-    SevGuestState *s = SEV_GUEST(obj);
-
-    s->dh_cert_file = g_strdup(value);
-}
-
-static char *
-sev_guest_get_sev_device(Object *obj, Error **errp)
-{
-    SevGuestState *sev = SEV_GUEST(obj);
-
-    return g_strdup(sev->sev_device);
-}
-
-static void
-sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
-{
-    SevGuestState *sev = SEV_GUEST(obj);
-
-    sev->sev_device = g_strdup(value);
-}
-
-static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
-{
-    SevGuestState *sev = SEV_GUEST(obj);
-
-    return sev->kernel_hashes;
-}
-
-static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
-{
-    SevGuestState *sev = SEV_GUEST(obj);
-
-    sev->kernel_hashes = value;
-}
-
 bool
 sev_enabled(void)
 {
-    return !!sev_guest;
+    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+
+    return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
 }
 
 bool
 sev_es_enabled(void)
 {
-    return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
+    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+
+    return sev_enabled() && (SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
 }
 
 uint32_t
 sev_get_cbit_position(void)
 {
-    return sev_guest ? sev_guest->cbitpos : 0;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
+    return sev_common ? sev_common->cbitpos : 0;
 }
 
 uint32_t
 sev_get_reduced_phys_bits(void)
 {
-    return sev_guest ? sev_guest->reduced_phys_bits : 0;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
+    return sev_common ? sev_common->reduced_phys_bits : 0;
 }
 
 static SevInfo *sev_get_info(void)
 {
     SevInfo *info;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+    SevGuestState *sev_guest =
+        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
+                                             TYPE_SEV_GUEST);
 
     info = g_new0(SevInfo, 1);
     info->enabled = sev_enabled();
 
     if (info->enabled) {
-        info->api_major = sev_guest->api_major;
-        info->api_minor = sev_guest->api_minor;
-        info->build_id = sev_guest->build_id;
-        info->policy = sev_guest->policy;
-        info->state = sev_guest->state;
-        info->handle = sev_guest->handle;
+        if (sev_guest) {
+            info->handle = sev_guest->handle;
+        }
+        info->api_major = sev_common->api_major;
+        info->api_minor = sev_common->api_minor;
+        info->build_id = sev_common->build_id;
+        info->state = sev_common->state;
+        /* we only report the lower 32-bits of policy for SNP, ok for now... */
+        info->policy =
+            (uint32_t)object_property_get_uint(OBJECT(sev_common),
+                                               "policy", NULL);
     }
 
     return info;
@@ -519,6 +473,8 @@ static SevCapability *sev_get_capabilities(Error **errp)
     size_t pdh_len = 0, cert_chain_len = 0, cpu0_id_len = 0;
     uint32_t ebx;
     int fd;
+    SevCommonState *sev_common;
+    char *sev_device;
 
     if (!kvm_enabled()) {
         error_setg(errp, "KVM not enabled");
@@ -529,12 +485,21 @@ static SevCapability *sev_get_capabilities(Error **errp)
         return NULL;
     }
 
-    fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
+    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+    if (!sev_common) {
+        error_setg(errp, "SEV is not configured");
+    }
+
+    sev_device = object_property_get_str(OBJECT(sev_common), "sev-device",
+                                         &error_abort);
+    fd = open(sev_device, O_RDWR);
     if (fd < 0) {
         error_setg_errno(errp, errno, "SEV: Failed to open %s",
                          DEFAULT_SEV_DEVICE);
+        g_free(sev_device);
         return NULL;
     }
+    g_free(sev_device);
 
     if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
                          &cert_chain_data, &cert_chain_len, errp)) {
@@ -577,7 +542,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
 {
     struct kvm_sev_attestation_report input = {};
     SevAttestationReport *report = NULL;
-    SevGuestState *sev = sev_guest;
+    SevCommonState *sev_common;
     g_autofree guchar *data = NULL;
     g_autofree guchar *buf = NULL;
     gsize len;
@@ -602,8 +567,10 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
         return NULL;
     }
 
+    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
     /* Query the report length */
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
+    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
             &input, &err);
     if (ret < 0) {
         if (err != SEV_RET_INVALID_LEN) {
@@ -619,7 +586,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
     memcpy(input.mnonce, buf, sizeof(input.mnonce));
 
     /* Query the report */
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
+    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
             &input, &err);
     if (ret) {
         error_setg_errno(errp, errno, "SEV: Failed to get attestation report"
@@ -659,26 +626,27 @@ sev_read_file_base64(const char *filename, guchar **data, gsize *len)
 }
 
 static int
-sev_launch_start(SevGuestState *sev)
+sev_launch_start(SevGuestState *sev_guest)
 {
     gsize sz;
     int ret = 1;
     int fw_error, rc;
     struct kvm_sev_launch_start start = {
-        .handle = sev->handle, .policy = sev->policy
+        .handle = sev_guest->handle, .policy = sev_guest->policy
     };
     guchar *session = NULL, *dh_cert = NULL;
+    SevCommonState *sev_common = SEV_COMMON(sev_guest);
 
-    if (sev->session_file) {
-        if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
+    if (sev_guest->session_file) {
+        if (sev_read_file_base64(sev_guest->session_file, &session, &sz) < 0) {
             goto out;
         }
         start.session_uaddr = (unsigned long)session;
         start.session_len = sz;
     }
 
-    if (sev->dh_cert_file) {
-        if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
+    if (sev_guest->dh_cert_file) {
+        if (sev_read_file_base64(sev_guest->dh_cert_file, &dh_cert, &sz) < 0) {
             goto out;
         }
         start.dh_uaddr = (unsigned long)dh_cert;
@@ -686,15 +654,15 @@ sev_launch_start(SevGuestState *sev)
     }
 
     trace_kvm_sev_launch_start(start.policy, session, dh_cert);
-    rc = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_START, &start, &fw_error);
+    rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_START, &start, &fw_error);
     if (rc < 0) {
         error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
                 __func__, ret, fw_error, fw_error_to_str(fw_error));
         goto out;
     }
 
-    sev_set_guest_state(sev, SEV_STATE_LAUNCH_UPDATE);
-    sev->handle = start.handle;
+    sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
+    sev_guest->handle = start.handle;
     ret = 0;
 
 out:
@@ -704,7 +672,7 @@ out:
 }
 
 static int
-sev_launch_update_data(SevGuestState *sev, uint8_t *addr, uint64_t len)
+sev_launch_update_data(SevGuestState *sev_guest, uint8_t *addr, uint64_t len)
 {
     int ret, fw_error;
     struct kvm_sev_launch_update_data update;
@@ -716,7 +684,7 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, uint64_t len)
     update.uaddr = (uintptr_t)addr;
     update.len = len;
     trace_kvm_sev_launch_update_data(addr, len);
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
+    ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
                     &update, &fw_error);
     if (ret) {
         error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
@@ -727,11 +695,12 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, uint64_t len)
 }
 
 static int
-sev_launch_update_vmsa(SevGuestState *sev)
+sev_launch_update_vmsa(SevGuestState *sev_guest)
 {
     int ret, fw_error;
 
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, &fw_error);
+    ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA,
+                    NULL, &fw_error);
     if (ret) {
         error_report("%s: LAUNCH_UPDATE_VMSA ret=%d fw_error=%d '%s'",
                 __func__, ret, fw_error, fw_error_to_str(fw_error));
@@ -743,18 +712,19 @@ sev_launch_update_vmsa(SevGuestState *sev)
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
-    SevGuestState *sev = sev_guest;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+    SevGuestState *sev_guest = SEV_GUEST(sev_common);
     int ret, error;
     g_autofree guchar *data = NULL;
     struct kvm_sev_launch_measure measurement = {};
 
-    if (!sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) {
+    if (!sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
         return;
     }
 
     if (sev_es_enabled()) {
         /* measure all the VM save areas before getting launch_measure */
-        ret = sev_launch_update_vmsa(sev);
+        ret = sev_launch_update_vmsa(sev_guest);
         if (ret) {
             exit(1);
         }
@@ -762,7 +732,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
     }
 
     /* query the measurement blob length */
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_MEASURE,
+    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_MEASURE,
                     &measurement, &error);
     if (!measurement.len) {
         error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
@@ -774,7 +744,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
     measurement.uaddr = (unsigned long)data;
 
     /* get the measurement blob */
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_MEASURE,
+    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_MEASURE,
                     &measurement, &error);
     if (ret) {
         error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
@@ -782,17 +752,19 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
         return;
     }
 
-    sev_set_guest_state(sev, SEV_STATE_LAUNCH_SECRET);
+    sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_SECRET);
 
     /* encode the measurement value and emit the event */
-    sev->measurement = g_base64_encode(data, measurement.len);
-    trace_kvm_sev_launch_measurement(sev->measurement);
+    sev_guest->measurement = g_base64_encode(data, measurement.len);
+    trace_kvm_sev_launch_measurement(sev_guest->measurement);
 }
 
 static char *sev_get_launch_measurement(void)
 {
+    SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
+
     if (sev_guest &&
-        sev_guest->state >= SEV_STATE_LAUNCH_SECRET) {
+        SEV_COMMON(sev_guest)->state >= SEV_STATE_LAUNCH_SECRET) {
         return g_strdup(sev_guest->measurement);
     }
 
@@ -821,19 +793,20 @@ static Notifier sev_machine_done_notify = {
 };
 
 static void
-sev_launch_finish(SevGuestState *sev)
+sev_launch_finish(SevGuestState *sev_guest)
 {
     int ret, error;
 
     trace_kvm_sev_launch_finish();
-    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
+    ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_FINISH, 0,
+                    &error);
     if (ret) {
         error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
                      __func__, ret, error, fw_error_to_str(error));
         exit(1);
     }
 
-    sev_set_guest_state(sev, SEV_STATE_RUNNING);
+    sev_set_guest_state(SEV_COMMON(sev_guest), SEV_STATE_RUNNING);
 
     /* add migration blocker */
     error_setg(&sev_mig_blocker,
@@ -844,38 +817,39 @@ sev_launch_finish(SevGuestState *sev)
 static void
 sev_vm_state_change(void *opaque, bool running, RunState state)
 {
-    SevGuestState *sev = opaque;
+    SevCommonState *sev_common = opaque;
 
     if (running) {
-        if (!sev_check_state(sev, SEV_STATE_RUNNING)) {
-            sev_launch_finish(sev);
+        if (!sev_check_state(sev_common, SEV_STATE_RUNNING)) {
+            sev_launch_finish(SEV_GUEST(sev_common));
         }
     }
 }
 
 static int sev_kvm_type(X86ConfidentialGuest *cg)
 {
-    SevGuestState *sev = SEV_GUEST(cg);
+    SevCommonState *sev_common = SEV_COMMON(cg);
+    SevGuestState *sev_guest = SEV_GUEST(sev_common);
     int kvm_type;
 
-    if (sev->kvm_type != -1) {
+    if (sev_common->kvm_type != -1) {
         goto out;
     }
 
-    kvm_type = (sev->policy & SEV_POLICY_ES) ? KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
+    kvm_type = (sev_guest->policy & SEV_POLICY_ES) ? KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
     if (kvm_is_vm_type_supported(kvm_type)) {
-        sev->kvm_type = kvm_type;
+        sev_common->kvm_type = kvm_type;
     } else {
-        sev->kvm_type = KVM_X86_DEFAULT_VM;
+        sev_common->kvm_type = KVM_X86_DEFAULT_VM;
     }
 
 out:
-    return sev->kvm_type;
+    return sev_common->kvm_type;
 }
 
 static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
-    SevGuestState *sev = SEV_GUEST(cgs);
+    SevCommonState *sev_common = SEV_COMMON(cgs);
     char *devname;
     int ret, fw_error, cmd;
     uint32_t ebx;
@@ -888,8 +862,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
         return -1;
     }
 
-    sev_guest = sev;
-    sev->state = SEV_STATE_UNINIT;
+    sev_common->state = SEV_STATE_UNINIT;
 
     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
     host_cbitpos = ebx & 0x3f;
@@ -899,9 +872,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
      * register of CPUID 0x8000001F. No need to verify the range as the
      * comparison against the host value accomplishes that.
      */
-    if (host_cbitpos != sev->cbitpos) {
+    if (host_cbitpos != sev_common->cbitpos) {
         error_setg(errp, "%s: cbitpos check failed, host '%d' requested '%d'",
-                   __func__, host_cbitpos, sev->cbitpos);
+                   __func__, host_cbitpos, sev_common->cbitpos);
         goto err;
     }
 
@@ -910,16 +883,16 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
      * the EBX register of CPUID 0x8000001F, so verify the supplied value
      * is in the range of 1 to 63.
      */
-    if (sev->reduced_phys_bits < 1 || sev->reduced_phys_bits > 63) {
+    if (sev_common->reduced_phys_bits < 1 || sev_common->reduced_phys_bits > 63) {
         error_setg(errp, "%s: reduced_phys_bits check failed,"
                    " it should be in the range of 1 to 63, requested '%d'",
-                   __func__, sev->reduced_phys_bits);
+                   __func__, sev_common->reduced_phys_bits);
         goto err;
     }
 
-    devname = object_property_get_str(OBJECT(sev), "sev-device", NULL);
-    sev->sev_fd = open(devname, O_RDWR);
-    if (sev->sev_fd < 0) {
+    devname = object_property_get_str(OBJECT(sev_common), "sev-device", NULL);
+    sev_common->sev_fd = open(devname, O_RDWR);
+    if (sev_common->sev_fd < 0) {
         error_setg(errp, "%s: Failed to open %s '%s'", __func__,
                    devname, strerror(errno));
         g_free(devname);
@@ -927,7 +900,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
     }
     g_free(devname);
 
-    ret = sev_platform_ioctl(sev->sev_fd, SEV_PLATFORM_STATUS, &status,
+    ret = sev_platform_ioctl(sev_common->sev_fd, SEV_PLATFORM_STATUS, &status,
                              &fw_error);
     if (ret) {
         error_setg(errp, "%s: failed to get platform status ret=%d "
@@ -935,9 +908,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
                    fw_error_to_str(fw_error));
         goto err;
     }
-    sev->build_id = status.build;
-    sev->api_major = status.api_major;
-    sev->api_minor = status.api_minor;
+    sev_common->build_id = status.build;
+    sev_common->api_major = status.api_major;
+    sev_common->api_minor = status.api_minor;
 
     if (sev_es_enabled()) {
         if (!kvm_kernel_irqchip_allowed()) {
@@ -955,14 +928,14 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
     }
 
     trace_kvm_sev_init();
-    if (sev_kvm_type(X86_CONFIDENTIAL_GUEST(sev)) == KVM_X86_DEFAULT_VM) {
+    if (sev_kvm_type(X86_CONFIDENTIAL_GUEST(sev_common)) == KVM_X86_DEFAULT_VM) {
         cmd = sev_es_enabled() ? KVM_SEV_ES_INIT : KVM_SEV_INIT;
 
-        ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error);
+        ret = sev_ioctl(sev_common->sev_fd, cmd, NULL, &fw_error);
     } else {
         struct kvm_sev_init args = { 0 };
 
-        ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT2, &args, &fw_error);
+        ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_INIT2, &args, &fw_error);
     }
 
     if (ret) {
@@ -971,7 +944,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
         goto err;
     }
 
-    ret = sev_launch_start(sev);
+    ret = sev_launch_start(SEV_GUEST(sev_common));
     if (ret) {
         error_setg(errp, "%s: failed to create encryption context", __func__);
         goto err;
@@ -979,13 +952,12 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 
     ram_block_notifier_add(&sev_ram_notifier);
     qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
-    qemu_add_vm_change_state_handler(sev_vm_state_change, sev);
+    qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
 
     cgs->ready = true;
 
     return 0;
 err:
-    sev_guest = NULL;
     ram_block_discard_disable(false);
     return -1;
 }
@@ -993,13 +965,15 @@ err:
 int
 sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
 {
-    if (!sev_guest) {
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
+    if (!sev_common) {
         return 0;
     }
 
     /* if SEV is in update state then encrypt the data else do nothing */
-    if (sev_check_state(sev_guest, SEV_STATE_LAUNCH_UPDATE)) {
-        int ret = sev_launch_update_data(sev_guest, ptr, len);
+    if (sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
+        int ret = sev_launch_update_data(SEV_GUEST(sev_common), ptr, len);
         if (ret < 0) {
             error_setg(errp, "SEV: Failed to encrypt pflash rom");
             return ret;
@@ -1019,16 +993,17 @@ int sev_inject_launch_secret(const char *packet_hdr, const char *secret,
     void *hva;
     gsize hdr_sz = 0, data_sz = 0;
     MemoryRegion *mr = NULL;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
 
-    if (!sev_guest) {
+    if (!sev_common) {
         error_setg(errp, "SEV not enabled for guest");
         return 1;
     }
 
     /* secret can be injected only in this state */
-    if (!sev_check_state(sev_guest, SEV_STATE_LAUNCH_SECRET)) {
+    if (!sev_check_state(sev_common, SEV_STATE_LAUNCH_SECRET)) {
         error_setg(errp, "SEV: Not in correct state. (LSECRET) %x",
-                     sev_guest->state);
+                   sev_common->state);
         return 1;
     }
 
@@ -1062,7 +1037,7 @@ int sev_inject_launch_secret(const char *packet_hdr, const char *secret,
     trace_kvm_sev_launch_secret(gpa, input.guest_uaddr,
                                 input.trans_uaddr, input.trans_len);
 
-    ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_LAUNCH_SECRET,
+    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_SECRET,
                     &input, &error);
     if (ret) {
         error_setg(errp, "SEV: failed to inject secret ret=%d fw_error=%d '%s'",
@@ -1169,9 +1144,10 @@ void sev_es_set_reset_vector(CPUState *cpu)
 {
     X86CPU *x86;
     CPUX86State *env;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
 
     /* Only update if we have valid reset information */
-    if (!sev_guest || !sev_guest->reset_data_valid) {
+    if (!sev_common || !sev_common->reset_data_valid) {
         return;
     }
 
@@ -1183,11 +1159,11 @@ void sev_es_set_reset_vector(CPUState *cpu)
     x86 = X86_CPU(cpu);
     env = &x86->env;
 
-    cpu_x86_load_seg_cache(env, R_CS, 0xf000, sev_guest->reset_cs, 0xffff,
+    cpu_x86_load_seg_cache(env, R_CS, 0xf000, sev_common->reset_cs, 0xffff,
                            DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
                            DESC_R_MASK | DESC_A_MASK);
 
-    env->eip = sev_guest->reset_ip;
+    env->eip = sev_common->reset_ip;
 }
 
 int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
@@ -1195,6 +1171,7 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
     CPUState *cpu;
     uint32_t addr;
     int ret;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
 
     if (!sev_es_enabled()) {
         return 0;
@@ -1208,9 +1185,9 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
     }
 
     if (addr) {
-        sev_guest->reset_cs = addr & 0xffff0000;
-        sev_guest->reset_ip = addr & 0x0000ffff;
-        sev_guest->reset_data_valid = true;
+        sev_common->reset_cs = addr & 0xffff0000;
+        sev_common->reset_ip = addr & 0x0000ffff;
+        sev_common->reset_data_valid = true;
 
         CPU_FOREACH(cpu) {
             sev_es_set_reset_vector(cpu);
@@ -1256,12 +1233,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     hwaddr mapped_len = sizeof(*padded_ht);
     MemTxAttrs attrs = { 0 };
     bool ret = true;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+    SevGuestState *sev_guest =
+        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
+                                             TYPE_SEV_GUEST);
 
     /*
      * Only add the kernel hashes if the sev-guest configuration explicitly
-     * stated kernel-hashes=on.
+     * stated kernel-hashes=on. Currently only enabled for SEV/SEV-ES guests,
+     * so check for TYPE_SEV_GUEST as well.
      */
-    if (!sev_guest->kernel_hashes) {
+    if (sev_guest && !sev_guest->kernel_hashes) {
         return false;
     }
 
@@ -1352,8 +1334,20 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     return ret;
 }
 
+static char *
+sev_common_get_sev_device(Object *obj, Error **errp)
+{
+    return g_strdup(SEV_COMMON(obj)->sev_device);
+}
+
 static void
-sev_guest_class_init(ObjectClass *oc, void *data)
+sev_common_set_sev_device(Object *obj, const char *value, Error **errp)
+{
+    SEV_COMMON(obj)->sev_device = g_strdup(value);
+}
+
+static void
+sev_common_class_init(ObjectClass *oc, void *data)
 {
     ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
     X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
@@ -1362,10 +1356,85 @@ sev_guest_class_init(ObjectClass *oc, void *data)
     x86_klass->kvm_type = sev_kvm_type;
 
     object_class_property_add_str(oc, "sev-device",
-                                  sev_guest_get_sev_device,
-                                  sev_guest_set_sev_device);
+                                  sev_common_get_sev_device,
+                                  sev_common_set_sev_device);
     object_class_property_set_description(oc, "sev-device",
             "SEV device to use");
+}
+
+static void
+sev_common_instance_init(Object *obj)
+{
+    SevCommonState *sev_common = SEV_COMMON(obj);
+
+    sev_common->kvm_type = -1;
+
+    sev_common->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
+
+    object_property_add_uint32_ptr(obj, "cbitpos", &sev_common->cbitpos,
+                                   OBJ_PROP_FLAG_READWRITE);
+    object_property_add_uint32_ptr(obj, "reduced-phys-bits",
+                                   &sev_common->reduced_phys_bits,
+                                   OBJ_PROP_FLAG_READWRITE);
+}
+
+/* sev guest info common to sev/sev-es/sev-snp */
+static const TypeInfo sev_common_info = {
+    .parent = TYPE_X86_CONFIDENTIAL_GUEST,
+    .name = TYPE_SEV_COMMON,
+    .instance_size = sizeof(SevCommonState),
+    .class_init = sev_common_class_init,
+    .instance_init = sev_common_instance_init,
+    .abstract = true,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_USER_CREATABLE },
+        { }
+    }
+};
+
+static char *
+sev_guest_get_dh_cert_file(Object *obj, Error **errp)
+{
+    return g_strdup(SEV_GUEST(obj)->dh_cert_file);
+}
+
+static void
+sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
+{
+    SEV_GUEST(obj)->dh_cert_file = g_strdup(value);
+}
+
+static char *
+sev_guest_get_session_file(Object *obj, Error **errp)
+{
+    SevGuestState *sev_guest = SEV_GUEST(obj);
+
+    return sev_guest->session_file ? g_strdup(sev_guest->session_file) : NULL;
+}
+
+static void
+sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
+{
+    SEV_GUEST(obj)->session_file = g_strdup(value);
+}
+
+static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
+{
+    SevGuestState *sev_guest = SEV_GUEST(obj);
+
+    return sev_guest->kernel_hashes;
+}
+
+static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
+{
+    SevGuestState *sev = SEV_GUEST(obj);
+
+    sev->kernel_hashes = value;
+}
+
+static void
+sev_guest_class_init(ObjectClass *oc, void *data)
+{
     object_class_property_add_str(oc, "dh-cert-file",
                                   sev_guest_get_dh_cert_file,
                                   sev_guest_set_dh_cert_file);
@@ -1386,40 +1455,28 @@ sev_guest_class_init(ObjectClass *oc, void *data)
 static void
 sev_guest_instance_init(Object *obj)
 {
-    SevGuestState *sev = SEV_GUEST(obj);
+    SevGuestState *sev_guest = SEV_GUEST(obj);
 
-    sev->kvm_type = -1;
-
-    sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
-    sev->policy = DEFAULT_GUEST_POLICY;
-    object_property_add_uint32_ptr(obj, "policy", &sev->policy,
-                                   OBJ_PROP_FLAG_READWRITE);
-    object_property_add_uint32_ptr(obj, "handle", &sev->handle,
-                                   OBJ_PROP_FLAG_READWRITE);
-    object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
+    sev_guest->policy = DEFAULT_GUEST_POLICY;
+    object_property_add_uint32_ptr(obj, "handle", &sev_guest->handle,
                                    OBJ_PROP_FLAG_READWRITE);
-    object_property_add_uint32_ptr(obj, "reduced-phys-bits",
-                                   &sev->reduced_phys_bits,
+    object_property_add_uint32_ptr(obj, "policy", &sev_guest->policy,
                                    OBJ_PROP_FLAG_READWRITE);
 }
 
-/* sev guest info */
+/* guest info specific sev/sev-es */
 static const TypeInfo sev_guest_info = {
-    .parent = TYPE_X86_CONFIDENTIAL_GUEST,
+    .parent = TYPE_SEV_COMMON,
     .name = TYPE_SEV_GUEST,
     .instance_size = sizeof(SevGuestState),
-    .instance_finalize = sev_guest_finalize,
-    .class_init = sev_guest_class_init,
     .instance_init = sev_guest_instance_init,
-    .interfaces = (InterfaceInfo[]) {
-        { TYPE_USER_CREATABLE },
-        { }
-    }
+    .class_init = sev_guest_class_init,
 };
 
 static void
 sev_register_types(void)
 {
+    type_register_static(&sev_common_info);
     type_register_static(&sev_guest_info);
 }
 
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 9e10d09539..668374eef3 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -20,6 +20,9 @@
 
 #include "exec/confidential-guest-support.h"
 
+#define TYPE_SEV_COMMON "sev-common"
+#define TYPE_SEV_GUEST "sev-guest"
+
 #define SEV_POLICY_NODBG        0x1
 #define SEV_POLICY_NOKS         0x2
 #define SEV_POLICY_ES           0x4
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (20 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 11:58   ` Daniel P. Berrangé
  2024-04-22 13:52   ` Markus Armbruster
  2024-03-20  8:39 ` [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper Michael Roth
                   ` (29 subsequent siblings)
  51 siblings, 2 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

From: Brijesh Singh <brijesh.singh@amd.com>

SEV-SNP support relies on a different set of properties/state than the
existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
object, which can be used to configure an SEV-SNP guest. For example,
a default-configured SEV-SNP guest with no additional information
passed in for use with attestation:

  -object sev-snp-guest,id=sev0

or a fully-specified SEV-SNP guest where all spec-defined binary
blobs are passed in as base64-encoded strings:

  -object sev-snp-guest,id=sev0, \
    policy=0x30000, \
    init-flags=0, \
    id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
    id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
    auth-key-enabled=on, \
    host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
    guest-visible-workarounds=AA==, \

See the QAPI schema updates included in this patch for more usage
details.

In some cases these blobs may be up to 4096 characters, but this is
generally well below the default limit for linux hosts where
command-line sizes are defined by the sysconf-configurable ARG_MAX
value, which defaults to 2097152 characters for Ubuntu hosts, for
example.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Co-developed-by: Michael Roth <michael.roth@amd.com>
Acked-by: Markus Armbruster <armbru@redhat.com> (for QAPI schema)
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 docs/system/i386/amd-memory-encryption.rst |  78 ++++++-
 qapi/qom.json                              |  51 +++++
 target/i386/sev.c                          | 241 +++++++++++++++++++++
 target/i386/sev.h                          |   1 +
 4 files changed, 369 insertions(+), 2 deletions(-)

diff --git a/docs/system/i386/amd-memory-encryption.rst b/docs/system/i386/amd-memory-encryption.rst
index e9bc142bc1..9d6b63acd9 100644
--- a/docs/system/i386/amd-memory-encryption.rst
+++ b/docs/system/i386/amd-memory-encryption.rst
@@ -25,8 +25,8 @@ support for notifying a guest's operating system when certain types of VMEXITs
 are about to occur. This allows the guest to selectively share information with
 the hypervisor to satisfy the requested function.
 
-Launching
----------
+Launching (SEV and SEV-ES)
+--------------------------
 
 Boot images (such as bios) must be encrypted before a guest can be booted. The
 ``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images: ``LAUNCH_START``,
@@ -161,6 +161,80 @@ The value of GCTX.LD is
 If kernel hashes are not used, or SEV-ES is disabled, use empty blobs for
 ``kernel_hashes_blob`` and ``vmsas_blob`` as needed.
 
+Launching (SEV-SNP)
+-------------------
+Boot images (such as bios) must be encrypted before a guest can be booted. The
+``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images:
+``KVM_SNP_INIT``, ``SNP_LAUNCH_START``, ``SNP_LAUNCH_UPDATE``, and
+``SNP_LAUNCH_FINISH``. These four commands together generate a fresh memory
+encryption key for the VM, encrypt the boot images for a successful launch.
+
+KVM_SNP_INIT is called first to initialize the SEV-SNP firmware and SNP
+features in the KVM. The feature flags value can be provided through the
+init-flags property of the sev-snp-guest object.
+
++------------+-------+----------+---------------------------------+
+| key        | type  | default  | meaning                         |
++------------+-------+----------+---------------------------------+
+| init_flags | hex   | 0        | SNP feature flags               |
++-----------------------------------------------------------------+
+
+Note: currently the init_flags must be zero.
+
+``SNP_LAUNCH_START`` is called first to create a cryptographic launch context
+within the firmware. To create this context, guest owner must provide a guest
+policy and other parameters as described in the SEV-SNP firmware
+specification. The launch parameters should be specified as described in the
+QAPI schema for the sev-snp-guest object.
+
+The ``SNP_LAUNCH_START`` uses the following parameters (see the SEV-SNP
+specification for more details):
+
++--------+-------+----------+----------------------------------------------+
+| key    | type  | default  | meaning                                      |
++--------+-------+----------+----------------------------------------------+
+| policy | hex   | 0x30000  | a 64-bit guest policy                        |
+| imi_en | bool  | 0        | 1 when IMI is enabled                        |
+| ma_end | bool  | 0        | 1 when migration agent is used               |
+| gosvw  | string| 0        | 16-byte base64 encoded string for the guest  |
+|        |       |          | OS visible workaround.                       |
++--------+-------+----------+----------------------------------------------+
+
+``SNP_LAUNCH_UPDATE`` encrypts the memory region using the cryptographic context
+created via the ``SNP_LAUNCH_START`` command. If required, this command can be
+called multiple times to encrypt different memory regions. The command also
+calculates the measurement of the memory contents as it encrypts.
+
+``SNP_LAUNCH_FINISH`` finalizes the guest launch flow. Optionally, while
+finalizing the launch the firmware can perform checks on the launch digest
+computing through the ``SNP_LAUNCH_UPDATE``. To perform the check the user must
+supply the id block, authentication blob and host data that should be included
+in the attestation report. See the SEV-SNP spec for further details.
+
+The ``SNP_LAUNCH_FINISH`` uses the following parameters, which can be configured
+by the corresponding parameters documented in the QAPI schema for the
+'sev-snp-guest' object.
+
++------------+-------+----------+----------------------------------------------+
+| key        | type  | default  | meaning                                      |
++------------+-------+----------+----------------------------------------------+
+| id_block   | string| none     | base64 encoded ID block                      |
++------------+-------+----------+----------------------------------------------+
+| id_auth    | string| none     | base64 encoded authentication information    |
++------------+-------+----------+----------------------------------------------+
+| auth_key_en| bool  | 0        | auth block contains author key               |
++------------+-------+----------+----------------------------------------------+
+| host_data  | string| none     | host provided data                           |
++------------+-------+----------+----------------------------------------------+
+
+To launch a SEV-SNP guest (additional parameters are documented in the QAPI
+schema for the 'sev-snp-guest' object)::
+
+  # ${QEMU} \
+    -machine ...,confidential-guest-support=sev0 \
+    -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1
+
+
 Debugging
 ---------
 
diff --git a/qapi/qom.json b/qapi/qom.json
index 66b5781ca6..b25a3043da 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -920,6 +920,55 @@
             '*handle': 'uint32',
             '*kernel-hashes': 'bool' } }
 
+##
+# @SevSnpGuestProperties:
+#
+# Properties for sev-snp-guest objects. Most of these are direct arguments
+# for the KVM_SNP_* interfaces documented in the linux kernel source
+# under Documentation/virt/kvm/amd-memory-encryption.rst, which are in
+# turn closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
+# documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).
+#
+# More usage information is also available in the QEMU source tree under
+# docs/amd-memory-encryption.
+#
+# @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
+#          defined in the SEV-SNP firmware ABI (default: 0x30000)
+#
+# @guest-visible-workarounds: 16-byte, base64-encoded blob to report
+#                             hypervisor-defined workarounds, corresponding
+#                             to the 'GOSVW' parameter of the
+#                             SNP_LAUNCH_START command defined in the
+#                             SEV-SNP firmware ABI (default: all-zero)
+#
+# @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
+#            structure for the SNP_LAUNCH_FINISH command defined in the
+#            SEV-SNP firmware ABI (default: all-zero)
+#
+# @id-auth: 4096-byte, base64-encoded blob to provide the 'ID Authentication
+#           Information Structure' for the SNP_LAUNCH_FINISH command defined
+#           in the SEV-SNP firmware ABI (default: all-zero)
+#
+# @auth-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY' field
+#                    defined SEV-SNP firmware ABI (default: false)
+#
+# @host-data: 32-byte, base64-encoded, user-defined blob to provide to the
+#             guest, as documented for the 'HOST_DATA' parameter of the
+#             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
+#             (default: all-zero)
+#
+# Since: 7.2
+##
+{ 'struct': 'SevSnpGuestProperties',
+  'base': 'SevCommonProperties',
+  'data': {
+            '*policy': 'uint64',
+            '*guest-visible-workarounds': 'str',
+            '*id-block': 'str',
+            '*id-auth': 'str',
+            '*auth-key-enabled': 'bool',
+            '*host-data': 'str' } }
+
 ##
 # @ThreadContextProperties:
 #
@@ -998,6 +1047,7 @@
     { 'name': 'secret_keyring',
       'if': 'CONFIG_SECRET_KEYRING' },
     'sev-guest',
+    'sev-snp-guest',
     'thread-context',
     's390-pv-guest',
     'throttle-group',
@@ -1068,6 +1118,7 @@
       'secret_keyring':             { 'type': 'SecretKeyringProperties',
                                       'if': 'CONFIG_SECRET_KEYRING' },
       'sev-guest':                  'SevGuestProperties',
+      'sev-snp-guest':              'SevSnpGuestProperties',
       'thread-context':             'ThreadContextProperties',
       'throttle-group':             'ThrottleGroupProperties',
       'tls-creds-anon':             'TlsCredsAnonProperties',
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 63a220de5e..7e6dab642a 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -42,6 +42,7 @@
 
 OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
 OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
+OBJECT_DECLARE_SIMPLE_TYPE(SevSnpGuestState, SEV_SNP_GUEST)
 
 struct SevCommonState {
     X86ConfidentialGuest parent_obj;
@@ -87,8 +88,22 @@ struct SevGuestState {
     bool kernel_hashes;
 };
 
+struct SevSnpGuestState {
+    SevCommonState sev_common;
+
+    /* configuration parameters */
+    char *guest_visible_workarounds;
+    char *id_block;
+    char *id_auth;
+    char *host_data;
+
+    struct kvm_sev_snp_launch_start kvm_start_conf;
+    struct kvm_sev_snp_launch_finish kvm_finish_conf;
+};
+
 #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
 #define DEFAULT_SEV_DEVICE      "/dev/sev"
+#define DEFAULT_SEV_SNP_POLICY  0x30000
 
 #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
 typedef struct __attribute__((__packed__)) SevInfoBlock {
@@ -1473,11 +1488,237 @@ static const TypeInfo sev_guest_info = {
     .class_init = sev_guest_class_init,
 };
 
+static void
+sev_snp_guest_get_policy(Object *obj, Visitor *v, const char *name,
+                         void *opaque, Error **errp)
+{
+    visit_type_uint64(v, name,
+                      (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
+                      errp);
+}
+
+static void
+sev_snp_guest_set_policy(Object *obj, Visitor *v, const char *name,
+                         void *opaque, Error **errp)
+{
+    visit_type_uint64(v, name,
+                      (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
+                      errp);
+}
+
+static char *
+sev_snp_guest_get_guest_visible_workarounds(Object *obj, Error **errp)
+{
+    return g_strdup(SEV_SNP_GUEST(obj)->guest_visible_workarounds);
+}
+
+static void
+sev_snp_guest_set_guest_visible_workarounds(Object *obj, const char *value,
+                                            Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
+    g_autofree guchar *blob;
+    gsize len;
+
+    if (sev_snp_guest->guest_visible_workarounds) {
+        g_free(sev_snp_guest->guest_visible_workarounds);
+    }
+
+    /* store the base64 str so we don't need to re-encode in getter */
+    sev_snp_guest->guest_visible_workarounds = g_strdup(value);
+
+    blob = qbase64_decode(sev_snp_guest->guest_visible_workarounds, -1, &len, errp);
+    if (!blob) {
+        return;
+    }
+
+    if (len > sizeof(start->gosvw)) {
+        error_setg(errp, "parameter length of %lu exceeds max of %lu",
+                   len, sizeof(start->gosvw));
+        return;
+    }
+
+    memcpy(start->gosvw, blob, len);
+}
+
+static char *
+sev_snp_guest_get_id_block(Object *obj, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    return g_strdup(sev_snp_guest->id_block);
+}
+
+static void
+sev_snp_guest_set_id_block(Object *obj, const char *value, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
+    gsize len;
+
+    if (sev_snp_guest->id_block) {
+        g_free(sev_snp_guest->id_block);
+        g_free((guchar *)finish->id_block_uaddr);
+    }
+
+    /* store the base64 str so we don't need to re-encode in getter */
+    sev_snp_guest->id_block = g_strdup(value);
+
+    finish->id_block_uaddr =
+        (uint64_t)qbase64_decode(sev_snp_guest->id_block, -1, &len, errp);
+
+    if (!finish->id_block_uaddr) {
+        return;
+    }
+
+    if (len > KVM_SEV_SNP_ID_BLOCK_SIZE) {
+        error_setg(errp, "parameter length of %lu exceeds max of %u",
+                   len, KVM_SEV_SNP_ID_BLOCK_SIZE);
+        return;
+    }
+
+    finish->id_block_en = (len) ? 1 : 0;
+}
+
+static char *
+sev_snp_guest_get_id_auth(Object *obj, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    return g_strdup(sev_snp_guest->id_auth);
+}
+
+static void
+sev_snp_guest_set_id_auth(Object *obj, const char *value, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
+    gsize len;
+
+    if (sev_snp_guest->id_auth) {
+        g_free(sev_snp_guest->id_auth);
+        g_free((guchar *)finish->id_auth_uaddr);
+    }
+
+    /* store the base64 str so we don't need to re-encode in getter */
+    sev_snp_guest->id_auth = g_strdup(value);
+
+    finish->id_auth_uaddr =
+        (uint64_t)qbase64_decode(sev_snp_guest->id_auth, -1, &len, errp);
+
+    if (!finish->id_auth_uaddr) {
+        return;
+    }
+
+    if (len > KVM_SEV_SNP_ID_AUTH_SIZE) {
+        error_setg(errp, "parameter length of %lu exceeds max of %u",
+                   len, KVM_SEV_SNP_ID_AUTH_SIZE);
+        return;
+    }
+}
+
+static bool
+sev_snp_guest_get_auth_key_en(Object *obj, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    return !!sev_snp_guest->kvm_finish_conf.auth_key_en;
+}
+
+static void
+sev_snp_guest_set_auth_key_en(Object *obj, bool value, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    sev_snp_guest->kvm_finish_conf.auth_key_en = value;
+}
+
+static char *
+sev_snp_guest_get_host_data(Object *obj, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    return g_strdup(sev_snp_guest->host_data);
+}
+
+static void
+sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
+    g_autofree guchar *blob;
+    gsize len;
+
+    if (sev_snp_guest->host_data) {
+        g_free(sev_snp_guest->host_data);
+    }
+
+    /* store the base64 str so we don't need to re-encode in getter */
+    sev_snp_guest->host_data = g_strdup(value);
+
+    blob = qbase64_decode(sev_snp_guest->host_data, -1, &len, errp);
+
+    if (!blob) {
+        return;
+    }
+
+    if (len > sizeof(finish->host_data)) {
+        error_setg(errp, "parameter length of %lu exceeds max of %lu",
+                   len, sizeof(finish->host_data));
+        return;
+    }
+
+    memcpy(finish->host_data, blob, len);
+}
+
+static void
+sev_snp_guest_class_init(ObjectClass *oc, void *data)
+{
+    object_class_property_add(oc, "policy", "uint64",
+                              sev_snp_guest_get_policy,
+                              sev_snp_guest_set_policy, NULL, NULL);
+    object_class_property_add_str(oc, "guest-visible-workarounds",
+                                  sev_snp_guest_get_guest_visible_workarounds,
+                                  sev_snp_guest_set_guest_visible_workarounds);
+    object_class_property_add_str(oc, "id-block",
+                                  sev_snp_guest_get_id_block,
+                                  sev_snp_guest_set_id_block);
+    object_class_property_add_str(oc, "id-auth",
+                                  sev_snp_guest_get_id_auth,
+                                  sev_snp_guest_set_id_auth);
+    object_class_property_add_bool(oc, "auth-key-enabled",
+                                   sev_snp_guest_get_auth_key_en,
+                                   sev_snp_guest_set_auth_key_en);
+    object_class_property_add_str(oc, "host-data",
+                                  sev_snp_guest_get_host_data,
+                                  sev_snp_guest_set_host_data);
+}
+
+static void
+sev_snp_guest_instance_init(Object *obj)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    /* default init/start/finish params for kvm */
+    sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
+}
+
+/* guest info specific to sev-snp */
+static const TypeInfo sev_snp_guest_info = {
+    .parent = TYPE_SEV_COMMON,
+    .name = TYPE_SEV_SNP_GUEST,
+    .instance_size = sizeof(SevSnpGuestState),
+    .class_init = sev_snp_guest_class_init,
+    .instance_init = sev_snp_guest_instance_init,
+};
+
 static void
 sev_register_types(void)
 {
     type_register_static(&sev_common_info);
     type_register_static(&sev_guest_info);
+    type_register_static(&sev_snp_guest_info);
 }
 
 type_init(sev_register_types);
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 668374eef3..bedc667eeb 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -22,6 +22,7 @@
 
 #define TYPE_SEV_COMMON "sev-common"
 #define TYPE_SEV_GUEST "sev-guest"
+#define TYPE_SEV_SNP_GUEST "sev-snp-guest"
 
 #define SEV_POLICY_NODBG        0x1
 #define SEV_POLICY_NOKS         0x2
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (21 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:35   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 24/49] target/i386: Add handling for KVM_X86_SNP_VM VM type Michael Roth
                   ` (28 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Add a simple helper to check if the current guest type is SNP. Also have
SNP-enabled imply that SEV-ES is enabled as well, and fix up any places
where the sev_es_enabled() check is expecting a pure/non-SNP guest.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 13 ++++++++++++-
 target/i386/sev.h |  2 ++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 7e6dab642a..2eb13ba639 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -316,12 +316,21 @@ sev_enabled(void)
     return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
 }
 
+bool
+sev_snp_enabled(void)
+{
+    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+
+    return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_SNP_GUEST);
+}
+
 bool
 sev_es_enabled(void)
 {
     ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
 
-    return sev_enabled() && (SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
+    return sev_snp_enabled() ||
+            (sev_enabled() && SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
 }
 
 uint32_t
@@ -933,7 +942,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
                          __func__);
             goto err;
         }
+    }
 
+    if (sev_es_enabled() && !sev_snp_enabled()) {
         if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
             error_report("%s: guest policy requires SEV-ES, but "
                          "host SEV-ES support unavailable",
diff --git a/target/i386/sev.h b/target/i386/sev.h
index bedc667eeb..94295ee74f 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -45,9 +45,11 @@ typedef struct SevKernelLoaderContext {
 #ifdef CONFIG_SEV
 bool sev_enabled(void);
 bool sev_es_enabled(void);
+bool sev_snp_enabled(void);
 #else
 #define sev_enabled() 0
 #define sev_es_enabled() 0
+#define sev_snp_enabled() 0
 #endif
 
 uint32_t sev_get_cbit_position(void);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 24/49] target/i386: Add handling for KVM_X86_SNP_VM VM type
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (22 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  9:33   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP Michael Roth
                   ` (27 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

An SNP VM requires VM type KVM_X86_SNP_VM to be passed to
kvm_ioctl(KVM_CREATE_VM). Add it to the list of supported VM types, and
return it appropriately via X86ConfidentialGuestClass->kvm_type().

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/kvm/kvm.c |  1 +
 target/i386/sev.c     | 10 ++++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index e109648f26..59e9048e61 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -164,6 +164,7 @@ static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value);
 
 static const char *vm_type_name[] = {
     [KVM_X86_DEFAULT_VM] = "default",
+    [KVM_X86_SNP_VM] = "snp"
 };
 
 bool kvm_is_vm_type_supported(int type)
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 2eb13ba639..61af312a11 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -853,14 +853,20 @@ sev_vm_state_change(void *opaque, bool running, RunState state)
 static int sev_kvm_type(X86ConfidentialGuest *cg)
 {
     SevCommonState *sev_common = SEV_COMMON(cg);
-    SevGuestState *sev_guest = SEV_GUEST(sev_common);
     int kvm_type;
 
     if (sev_common->kvm_type != -1) {
         goto out;
     }
 
-    kvm_type = (sev_guest->policy & SEV_POLICY_ES) ? KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
+    if (sev_snp_enabled()) {
+        kvm_type = KVM_X86_SNP_VM;
+    } else if (sev_es_enabled()) {
+        kvm_type = KVM_X86_SEV_ES_VM;
+    } else {
+        kvm_type = KVM_X86_SEV_VM;
+    }
+
     if (kvm_is_vm_type_supported(kvm_type)) {
         sev_common->kvm_type = kvm_type;
     } else {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (23 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 24/49] target/i386: Add handling for KVM_X86_SNP_VM VM type Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  9:46   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 26/49] i386/sev: Skip machine-init-done " Michael Roth
                   ` (26 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SEV uses these notifiers to register/pin pages prior to guest use, since
they could potentially be used for private memory where page migration
is not supported. But SNP only uses guest_memfd-provided pages for
private memory, which has its own kernel-internal mechanisms for
registering/pinning memory.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 61af312a11..774262d834 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -982,7 +982,15 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
         goto err;
     }
 
-    ram_block_notifier_add(&sev_ram_notifier);
+    if (!sev_snp_enabled()) {
+        /*
+         * SEV uses these notifiers to register/pin pages prior to guest use,
+         * but SNP relies on guest_memfd for private pages, which has it's
+         * own internal mechanisms for registering/pinning private memory.
+         */
+        ram_block_notifier_add(&sev_ram_notifier);
+    }
+
     qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
     qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 26/49] i386/sev: Skip machine-init-done notifiers for SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (24 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 27/49] i386/sev: Set ms->require_guest_memfd " Michael Roth
                   ` (25 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

The machine done notify event is used for SEV guests to get the
measurement of the encrypted images. When SEV-SNP is enabled, the
measurement is part of the guest attestation process where it can be
collected without any reliance on the VMM. So skip registering the
notifier for SNP in favor of using guest attestation instead.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 774262d834..e4deb7b41e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -989,9 +989,17 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
          * own internal mechanisms for registering/pinning private memory.
          */
         ram_block_notifier_add(&sev_ram_notifier);
+
+        /*
+         * The machine done notify event is used for SEV guests to get the
+         * measurement of the encrypted images. When SEV-SNP is enabled, the
+         * measurement is part of the guest attestation process where it can
+         * be collected without any reliance on the VMM. So skip registering
+         * the notifier for SNP in favor of using guest attestation instead.
+         */
+        qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
     }
 
-    qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
     qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
 
     cgs->ready = true;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 27/49] i386/sev: Set ms->require_guest_memfd for SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (25 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 26/49] i386/sev: Skip machine-init-done " Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  9:48   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 28/49] i386/sev: Disable SMM " Michael Roth
                   ` (24 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SNP requires guest_memfd for private guest memory, so enable it so that
the appropriate guest_memfd backend will be available for normal RAM
regions.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index e4deb7b41e..b06c796aae 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -880,6 +880,7 @@ out:
 static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
     SevCommonState *sev_common = SEV_COMMON(cgs);
+    MachineState *ms = MACHINE(qdev_get_machine());
     char *devname;
     int ret, fw_error, cmd;
     uint32_t ebx;
@@ -1000,6 +1001,10 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
         qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
     }
 
+    if (sev_snp_enabled()) {
+        ms->require_guest_memfd = true;
+    }
+
     qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
 
     cgs->ready = true;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 28/49] i386/sev: Disable SMM for SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (26 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 27/49] i386/sev: Set ms->require_guest_memfd " Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:32   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 29/49] i386/sev: Don't disable block discarding " Michael Roth
                   ` (23 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SNP does not support SMM.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index b06c796aae..134e8f7c22 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -881,6 +881,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
     SevCommonState *sev_common = SEV_COMMON(cgs);
     MachineState *ms = MACHINE(qdev_get_machine());
+    X86MachineState *x86ms = X86_MACHINE(ms);
     char *devname;
     int ret, fw_error, cmd;
     uint32_t ebx;
@@ -1003,6 +1004,13 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 
     if (sev_snp_enabled()) {
         ms->require_guest_memfd = true;
+
+        if (x86ms->smm == ON_OFF_AUTO_AUTO) {
+            x86ms->smm = ON_OFF_AUTO_OFF;
+        } else if (x86ms->smm == ON_OFF_AUTO_ON) {
+            error_report("SEV-SNP does not support SMM.");
+            goto err;
+        }
     }
 
     qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 29/49] i386/sev: Don't disable block discarding for SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (27 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 28/49] i386/sev: Disable SMM " Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:33   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 30/49] i386/cpu: Set SEV-SNP CPUID bit when SNP enabled Michael Roth
                   ` (22 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SEV/SEV-ES rely on pinned memory to back guest RAM so discarding
isn't actually possible. With SNP, only guest_memfd pages are used
for private guest memory, so discarding of shared memory is still
possible, so only disable discard for SEV/SEV-ES.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 134e8f7c22..43e6c0172f 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -888,10 +888,18 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
     uint32_t host_cbitpos;
     struct sev_user_data_status status = {};
 
-    ret = ram_block_discard_disable(true);
-    if (ret) {
-        error_report("%s: cannot disable RAM discard", __func__);
-        return -1;
+    /*
+     * SEV/SEV-ES rely on pinned memory to back guest RAM so discarding
+     * isn't actually possible. With SNP, only guest_memfd pages are used
+     * for private guest memory, so discarding of shared memory is still
+     * possible..
+     */
+    if (!sev_snp_enabled()) {
+        ret = ram_block_discard_disable(true);
+        if (ret) {
+            error_report("%s: cannot disable RAM discard", __func__);
+            return -1;
+        }
     }
 
     sev_common->state = SEV_STATE_UNINIT;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 30/49] i386/cpu: Set SEV-SNP CPUID bit when SNP enabled
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (28 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 29/49] i386/sev: Don't disable block discarding " Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP Michael Roth
                   ` (21 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SNP guests will rely on this bit to determine certain feature support.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/cpu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 33760a2ee1..3fdaac3472 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6664,6 +6664,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         if (sev_enabled()) {
             *eax = 0x2;
             *eax |= sev_es_enabled() ? 0x8 : 0;
+            *eax |= sev_snp_enabled() ? 0x10 : 0;
             *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
             *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */
         }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (29 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 30/49] i386/cpu: Set SEV-SNP CPUID bit when SNP enabled Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:10   ` Daniel P. Berrangé
  2024-04-22 15:01   ` Markus Armbruster
  2024-03-20  8:39 ` [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests Michael Roth
                   ` (20 subsequent siblings)
  51 siblings, 2 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Most of the current 'query-sev' command is relevant to both legacy
SEV/SEV-ES guests and SEV-SNP guests, with 2 exceptions:

  - 'policy' is a 64-bit field for SEV-SNP, not 32-bit, and
    the meaning of the bit positions has changed
  - 'handle' is not relevant to SEV-SNP

To address this, this patch adds a new 'sev-type' field that can be
used as a discriminator to select between SEV and SEV-SNP-specific
fields/formats without breaking compatibility for existing management
tools (so long as management tools that add support for launching
SEV-SNP guest update their handling of query-sev appropriately).

The corresponding HMP command has also been fixed up similarly.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 qapi/misc-target.json | 71 ++++++++++++++++++++++++++++++++++---------
 target/i386/sev.c     | 50 ++++++++++++++++++++----------
 target/i386/sev.h     |  3 ++
 3 files changed, 94 insertions(+), 30 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4e0a6492a9..daceb85d95 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -47,6 +47,49 @@
            'send-update', 'receive-update' ],
   'if': 'TARGET_I386' }
 
+##
+# @SevGuestType:
+#
+# An enumeration indicating the type of SEV guest being run.
+#
+# @sev:     The guest is a legacy SEV or SEV-ES guest.
+# @sev-snp: The guest is an SEV-SNP guest.
+#
+# Since: 6.2
+##
+{ 'enum': 'SevGuestType',
+  'data': [ 'sev', 'sev-snp' ],
+  'if': 'TARGET_I386' }
+
+##
+# @SevGuestInfo:
+#
+# Information specific to legacy SEV/SEV-ES guests.
+#
+# @policy: SEV policy value
+#
+# @handle: SEV firmware handle
+#
+# Since: 2.12
+##
+{ 'struct': 'SevGuestInfo',
+  'data': { 'policy': 'uint32',
+            'handle': 'uint32' },
+  'if': 'TARGET_I386' }
+
+##
+# @SevSnpGuestInfo:
+#
+# Information specific to SEV-SNP guests.
+#
+# @snp-policy: SEV-SNP policy value
+#
+# Since: 6.2
+##
+{ 'struct': 'SevSnpGuestInfo',
+  'data': { 'snp-policy': 'uint64' },
+  'if': 'TARGET_I386' }
+
 ##
 # @SevInfo:
 #
@@ -60,25 +103,25 @@
 #
 # @build-id: SEV FW build id
 #
-# @policy: SEV policy value
-#
 # @state: SEV guest state
 #
-# @handle: SEV firmware handle
+# @sev-type: Type of SEV guest being run
 #
 # Since: 2.12
 ##
-{ 'struct': 'SevInfo',
-    'data': { 'enabled': 'bool',
-              'api-major': 'uint8',
-              'api-minor' : 'uint8',
-              'build-id' : 'uint8',
-              'policy' : 'uint32',
-              'state' : 'SevState',
-              'handle' : 'uint32'
-            },
-  'if': 'TARGET_I386'
-}
+{ 'union': 'SevInfo',
+  'base': { 'enabled': 'bool',
+            'api-major': 'uint8',
+            'api-minor' : 'uint8',
+            'build-id' : 'uint8',
+            'state' : 'SevState',
+            'sev-type' : 'SevGuestType' },
+  'discriminator': 'sev-type',
+  'data': {
+      'sev': 'SevGuestInfo',
+      'sev-snp': 'SevSnpGuestInfo' },
+  'if': 'TARGET_I386' }
+
 
 ##
 # @query-sev:
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 43e6c0172f..b03d70a3d1 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -353,25 +353,27 @@ static SevInfo *sev_get_info(void)
 {
     SevInfo *info;
     SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
-    SevGuestState *sev_guest =
-        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
-                                             TYPE_SEV_GUEST);
 
     info = g_new0(SevInfo, 1);
     info->enabled = sev_enabled();
 
     if (info->enabled) {
-        if (sev_guest) {
-            info->handle = sev_guest->handle;
-        }
         info->api_major = sev_common->api_major;
         info->api_minor = sev_common->api_minor;
         info->build_id = sev_common->build_id;
         info->state = sev_common->state;
-        /* we only report the lower 32-bits of policy for SNP, ok for now... */
-        info->policy =
-            (uint32_t)object_property_get_uint(OBJECT(sev_common),
-                                               "policy", NULL);
+
+        if (sev_snp_enabled()) {
+            info->sev_type = SEV_GUEST_TYPE_SEV_SNP;
+            info->u.sev_snp.snp_policy =
+                object_property_get_uint(OBJECT(sev_common), "policy", NULL);
+        } else {
+            info->sev_type = SEV_GUEST_TYPE_SEV;
+            info->u.sev.handle = SEV_GUEST(sev_common)->handle;
+            info->u.sev.policy =
+                (uint32_t)object_property_get_uint(OBJECT(sev_common),
+                                                   "policy", NULL);
+        }
     }
 
     return info;
@@ -394,20 +396,36 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict)
 {
     SevInfo *info = sev_get_info();
 
-    if (info && info->enabled) {
-        monitor_printf(mon, "handle: %d\n", info->handle);
+    if (!info || !info->enabled) {
+        monitor_printf(mon, "SEV is not enabled\n");
+        goto out;
+    }
+
+    if (sev_snp_enabled()) {
         monitor_printf(mon, "state: %s\n", SevState_str(info->state));
         monitor_printf(mon, "build: %d\n", info->build_id);
         monitor_printf(mon, "api version: %d.%d\n",
                        info->api_major, info->api_minor);
         monitor_printf(mon, "debug: %s\n",
-                       info->policy & SEV_POLICY_NODBG ? "off" : "on");
-        monitor_printf(mon, "key-sharing: %s\n",
-                       info->policy & SEV_POLICY_NOKS ? "off" : "on");
+                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_DBG ? "on"
+                                                                       : "off");
+        monitor_printf(mon, "SMT allowed: %s\n",
+                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_SMT ? "on"
+                                                                       : "off");
     } else {
-        monitor_printf(mon, "SEV is not enabled\n");
+        monitor_printf(mon, "handle: %d\n", info->u.sev.handle);
+        monitor_printf(mon, "state: %s\n", SevState_str(info->state));
+        monitor_printf(mon, "build: %d\n", info->build_id);
+        monitor_printf(mon, "api version: %d.%d\n",
+                       info->api_major, info->api_minor);
+        monitor_printf(mon, "debug: %s\n",
+                       info->u.sev.policy & SEV_POLICY_NODBG ? "off" : "on");
+        monitor_printf(mon, "key-sharing: %s\n",
+                       info->u.sev.policy & SEV_POLICY_NOKS ? "off" : "on");
     }
+    monitor_printf(mon, "SEV type: %s\n", SevGuestType_str(info->sev_type));
 
+out:
     qapi_free_SevInfo(info);
 }
 
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 94295ee74f..5dc4767b1e 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -31,6 +31,9 @@
 #define SEV_POLICY_DOMAIN       0x10
 #define SEV_POLICY_SEV          0x20
 
+#define SEV_SNP_POLICY_SMT      0x10000
+#define SEV_SNP_POLICY_DBG      0x80000
+
 typedef struct SevKernelLoaderContext {
     char *setup_data;
     size_t setup_size;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (30 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:15   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 33/49] kvm: Make kvm_convert_memory() non-static Michael Roth
                   ` (19 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

For SEV-SNP guests, launch measurement is queried from within the guest
during attestation, so don't attempt to return it as part of
query-sev-launch-measure.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index b03d70a3d1..0c8e4bdb4c 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -803,7 +803,9 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 
 static char *sev_get_launch_measurement(void)
 {
-    SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
+    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+    SevGuestState *sev_guest =
+        (SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
 
     if (sev_guest &&
         SEV_COMMON(sev_guest)->state >= SEV_STATE_LAUNCH_SECRET) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 33/49] kvm: Make kvm_convert_memory() non-static
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (31 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 34/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes Michael Roth
                   ` (18 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 accel/kvm/kvm-all.c  | 2 +-
 include/sysemu/kvm.h | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index b5872fdc07..bf0ae0c8ad 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2913,7 +2913,7 @@ static void kvm_eat_signals(CPUState *cpu)
     } while (sigismember(&chkset, SIG_IPI));
 }
 
-static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
+int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
 {
     MemoryRegionSection section;
     ram_addr_t offset;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 2cb3192509..698f1640fe 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -541,4 +541,6 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp);
 
 int kvm_set_memory_attributes_private(hwaddr start, hwaddr size);
 int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size);
+
+int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private);
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 34/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (32 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 33/49] kvm: Make kvm_convert_memory() non-static Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 35/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based) Michael Roth
                   ` (17 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

When running SEV-SNP guests, the kernel may forward some subset of
VMGEXIT-based guest hypercalls to userspace. One of these is for Page
State Change requests, as documented by the GHCB specification[1].

Userspace does not directly have control over the SNP RMP table to
actually satisfy these requests, but will instead make use of the
kvm_convert_memory() interface, which makes use of the
KVM_SET_MEMORY_ATTRIBUTES ioctl to instruct KVM to map these these
GPAs using private/shared memory and make the appropriate RMP changes
via the associated kernel hooks.

Add the basic infrastructure for handling KVM_EXIT_VMGEXIT events, and
then implement handling for Page State Change requests on top of that.

[1] https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/kvm/kvm.c |   3 +
 target/i386/sev.c     | 152 ++++++++++++++++++++++++++++++++++++++++++
 target/i386/sev.h     |   2 +
 3 files changed, 157 insertions(+)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 59e9048e61..22eb21a2f3 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5409,6 +5409,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
         ret = kvm_xen_handle_exit(cpu, &run->xen);
         break;
 #endif
+    case KVM_EXIT_VMGEXIT:
+        ret = kvm_handle_vmgexit(run);
+        break;
     default:
         fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
         ret = -1;
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0c8e4bdb4c..0c6a253138 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1423,6 +1423,158 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     return ret;
 }
 
+typedef struct __attribute__((__packed__)) PscHdr {
+    uint16_t cur_entry;
+    uint16_t end_entry;
+    uint32_t reserved;
+} PscHdr;
+
+typedef struct __attribute__((__packed__)) PscEntry {
+    uint64_t cur_page    : 12,
+             gfn         : 40,
+             operation   : 4,
+             pagesize    : 1,
+             reserved    : 7;
+} PscEntry;
+
+#define VMGEXIT_PSC_MAX_ENTRY 253
+
+typedef struct __attribute__((__packed__)) SnpPscDesc {
+    PscHdr hdr;
+    PscEntry entries[VMGEXIT_PSC_MAX_ENTRY];
+} SnpPscDesc;
+
+static int next_contig_gpa_range(SnpPscDesc *desc, uint16_t *entries_processed,
+                                 hwaddr *gfn_base, int *gfn_count,
+                                 bool *range_to_private)
+{
+    int i;
+
+    *entries_processed = 0;
+    *gfn_base = 0;
+    *gfn_count = 0;
+    *range_to_private = false;
+
+    for (i = desc->hdr.cur_entry; i <= desc->hdr.end_entry; i++) {
+        PscEntry *entry = &desc->entries[i];
+        bool to_private = entry->operation == 1;
+        int page_count = entry->pagesize ? 512 : 1;
+
+        if (!*gfn_count) {
+            *range_to_private = to_private;
+            *gfn_base = entry->gfn;
+        }
+
+        /* When first non-adjacent entry is seen, report the previous range */
+        if (entry->gfn != *gfn_base + *gfn_count || (to_private != *range_to_private)) {
+            return 0;
+        }
+
+        *gfn_count += page_count;
+
+        /*
+         * Currently entry-specific PSC_ERROR_INVALID_ENTRY errors are not
+         * returned. Instead only the more general GENERIC/INVALID_HDR
+         * errors are returned. If support for PSC_ERROR_INVALID_ENTRY errors
+         * are added, this logic will need to be re-worked to either not
+         * increment entries_processed until the request is issued
+         * successfully, or to rewind it after failure. Guests don't
+         * currently do anything useful with entry-specific errors so vs.
+         * the other errors types so this is unlikely to be an issue in the
+         * meantime.
+         */
+        entry->cur_page = page_count;
+        *entries_processed += 1;
+    }
+
+    return *gfn_count ? 0 : -ENOENT;
+}
+
+#define GHCB_SHARED_BUF_SIZE    0x7f0
+#define PSC_ERROR_GENERIC       (0x100UL << 32)
+#define PSC_ERROR_INVALID_HDR   ((0x1UL << 32) | 1)
+#define PSC_ERROR_INVALID_ENTRY ((0x1UL << 32) | 2)
+#define PSC_ENTRY_COUNT_MAX     253
+
+static int kvm_handle_vmgexit_psc(__u64 shared_gpa, __u64 *psc_ret)
+{
+    hwaddr len = GHCB_SHARED_BUF_SIZE;
+    MemTxAttrs attrs = { 0 };
+    SnpPscDesc *desc;
+    void *ghcb_shared_buf;
+    uint8_t shared_buf[GHCB_SHARED_BUF_SIZE];
+    uint16_t entries_processed;
+    hwaddr gfn_base = 0;
+    int gfn_count = 0;
+    bool range_to_private;
+
+    *psc_ret = 0;
+    ghcb_shared_buf = address_space_map(&address_space_memory, shared_gpa,
+                                        &len, true, attrs);
+    if (len < GHCB_SHARED_BUF_SIZE) {
+        g_warning("unable to map entire shared GHCB buffer, mapped size %ld (expected %d)",
+                  len, GHCB_SHARED_BUF_SIZE);
+        *psc_ret = PSC_ERROR_GENERIC;
+        goto out_unmap;
+    }
+    memcpy(shared_buf, ghcb_shared_buf, GHCB_SHARED_BUF_SIZE);
+    address_space_unmap(&address_space_memory, ghcb_shared_buf, len, true, len);
+
+    desc = (SnpPscDesc *)shared_buf;
+
+    if (desc->hdr.end_entry >= PSC_ENTRY_COUNT_MAX) {
+        *psc_ret = PSC_ERROR_INVALID_HDR;
+        goto out_unmap;
+    }
+
+    /* No more entries left to process. */
+    if (desc->hdr.cur_entry > desc->hdr.end_entry) {
+        goto out_unmap;
+    }
+
+    while (!next_contig_gpa_range(desc, &entries_processed,
+                                  &gfn_base, &gfn_count, &range_to_private)) {
+        int ret = kvm_convert_memory(gfn_base * 0x1000, gfn_count * 0x1000,
+                                     range_to_private);
+        if (ret) {
+            *psc_ret = 0x100ULL << 32; /* Indicate interrupted processing */
+            g_warning("error doing memory conversion: %d", ret);
+            break;
+        }
+
+        desc->hdr.cur_entry += entries_processed;
+    }
+
+    ghcb_shared_buf = address_space_map(&address_space_memory, shared_gpa,
+                                        &len, true, attrs);
+    if (len < GHCB_SHARED_BUF_SIZE) {
+        g_warning("unable to map entire shared GHCB buffer, mapped size %ld (expected %d)",
+                  len, GHCB_SHARED_BUF_SIZE);
+        *psc_ret = PSC_ERROR_GENERIC;
+        goto out_unmap;
+    }
+    memcpy(ghcb_shared_buf, shared_buf, GHCB_SHARED_BUF_SIZE);
+out_unmap:
+    address_space_unmap(&address_space_memory, ghcb_shared_buf, len, true, len);
+
+    return 0;
+}
+
+int kvm_handle_vmgexit(struct kvm_run *run)
+{
+    int ret;
+
+    if (run->vmgexit.type == KVM_USER_VMGEXIT_PSC) {
+        ret = kvm_handle_vmgexit_psc(run->vmgexit.psc.shared_gpa,
+                                     &run->vmgexit.psc.ret);
+    } else {
+        warn_report("KVM: unknown vmgexit type: %d", run->vmgexit.type);
+        ret = -1;
+    }
+
+    return ret;
+}
+
 static char *
 sev_common_get_sev_device(Object *obj, Error **errp)
 {
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 5dc4767b1e..5cbfc3365b 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -66,4 +66,6 @@ int sev_inject_launch_secret(const char *hdr, const char *secret,
 int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size);
 void sev_es_set_reset_vector(CPUState *cpu);
 
+int kvm_handle_vmgexit(struct kvm_run *run);
+
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 35/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based)
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (33 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 34/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests Michael Roth
                   ` (16 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SEV-SNP guests might issue MSR-based Page State Changes for situations
like early boot where it might not be easily able to make use of a GHCB
page to issue the request. Just as with GHCB-based Page State Changes,
these are forwarded to userspace as KVM_EXIT_VMGEXITs. Add handling for
these.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0c6a253138..b54422b28e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1560,6 +1560,18 @@ out_unmap:
     return 0;
 }
 
+static int kvm_handle_vmgexit_psc_msr_protocol(__u64 gpa, __u8 op, __u32 *psc_ret)
+{
+    int ret;
+
+    ret = kvm_convert_memory(gpa, TARGET_PAGE_SIZE,
+                             op == KVM_USER_VMGEXIT_PSC_MSR_OP_PRIVATE);
+
+    *psc_ret = ret;
+
+    return ret;
+}
+
 int kvm_handle_vmgexit(struct kvm_run *run)
 {
     int ret;
@@ -1567,6 +1579,10 @@ int kvm_handle_vmgexit(struct kvm_run *run)
     if (run->vmgexit.type == KVM_USER_VMGEXIT_PSC) {
         ret = kvm_handle_vmgexit_psc(run->vmgexit.psc.shared_gpa,
                                      &run->vmgexit.psc.ret);
+    } else if (run->vmgexit.type == KVM_USER_VMGEXIT_PSC_MSR) {
+        ret = kvm_handle_vmgexit_psc_msr_protocol(run->vmgexit.psc_msr.gpa,
+                                                  run->vmgexit.psc_msr.op,
+                                                  &run->vmgexit.psc_msr.ret);
     } else {
         warn_report("KVM: unknown vmgexit type: %d", run->vmgexit.type);
         ret = -1;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (34 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 35/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based) Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-04-22 15:02   ` Markus Armbruster
  2024-03-20  8:39 ` [PATCH v3 37/49] i386/sev: Add the SNP launch start context Michael Roth
                   ` (15 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

The GHCB specification[1] defines a VMGEXIT-based Guest Request
hypercall to allow an SNP guest to issue encrypted requests directly to
SNP firmware to do things like query the attestation report for the
guest. These are generally handled purely in the kernel.

In some some cases, it's useful for the host to be able to additionally
supply the certificate chain for the signing key that SNP firmware uses
to sign these attestation reports. To allow for, the GHCB specification
defines an Extended Guest Request where this certificate data can be
provided in a special format described in the GHCB spec. This
certificate data may be global or guest-specific depending on how the
guest was configured. Rather than providing interfaces to manage these
within the kernel, KVM handles this by forward the Extended Guest
Requests on to userspace so the certificate data can be provided in the
expected format.

Add a certs-path parameter to the sev-snp-guest object so that it can
be used to inject any certificate data into these Extended Guest
Requests.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 qapi/qom.json     |  7 +++-
 target/i386/sev.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/qapi/qom.json b/qapi/qom.json
index b25a3043da..7ba778af91 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -957,6 +957,10 @@
 #             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
 #             (default: all-zero)
 #
+# @certs-path: path to certificate data that can be passed to guests via
+#              SNP Extended Guest Requests. File should be in the format
+#              described in the GHCB specification. (default: none)
+#
 # Since: 7.2
 ##
 { 'struct': 'SevSnpGuestProperties',
@@ -967,7 +971,8 @@
             '*id-block': 'str',
             '*id-auth': 'str',
             '*auth-key-enabled': 'bool',
-            '*host-data': 'str' } }
+            '*host-data': 'str',
+            '*certs-path': 'str' } }
 
 ##
 # @ThreadContextProperties:
diff --git a/target/i386/sev.c b/target/i386/sev.c
index b54422b28e..3b4dbc63b1 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -96,6 +96,7 @@ struct SevSnpGuestState {
     char *id_block;
     char *id_auth;
     char *host_data;
+    char *certs_path;
 
     struct kvm_sev_snp_launch_start kvm_start_conf;
     struct kvm_sev_snp_launch_finish kvm_finish_conf;
@@ -1572,6 +1573,63 @@ static int kvm_handle_vmgexit_psc_msr_protocol(__u64 gpa, __u8 op, __u32 *psc_re
     return ret;
 }
 
+#define SNP_EXT_REQ_ERROR_INVALID_LEN   1
+#define SNP_EXT_REQ_ERROR_BUSY          2
+#define SNP_EXT_REQ_ERROR_GENERIC       (1 << 31)
+
+static int kvm_handle_vmgexit_ext_req(__u64 gpa, __u64 *npages, __u32 *vmm_ret)
+{
+    SevSnpGuestState *sev_snp_guest;
+    MemTxAttrs attrs = { 0 };
+    void *guest_buf;
+    hwaddr buf_sz;
+    gsize sz;
+    g_autofree gchar *contents = NULL;
+    GError *error = NULL;
+
+    *vmm_ret = SNP_EXT_REQ_ERROR_GENERIC;
+
+    if (!sev_snp_enabled()) {
+        return 0;
+    }
+
+    sev_snp_guest = SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
+
+    if (!sev_snp_guest->certs_path) {
+        *vmm_ret = 0;
+        return 0;
+    }
+
+    if (!g_file_get_contents(sev_snp_guest->certs_path, &contents, &sz, &error)) {
+        error_report("SEV: Failed to read '%s' (%s)", sev_snp_guest->certs_path, error->message);
+        g_error_free(error);
+        return 0;
+    }
+
+    buf_sz = *npages * TARGET_PAGE_SIZE;
+
+    if (buf_sz < sz) {
+        *vmm_ret = SNP_EXT_REQ_ERROR_INVALID_LEN;
+        *npages = (sz + TARGET_PAGE_SIZE) / TARGET_PAGE_SIZE;
+        return 0;
+    }
+
+    guest_buf = address_space_map(&address_space_memory, gpa, &buf_sz, true, attrs);
+    if (buf_sz < sz) {
+        g_warning("unable to map entire shared buffer, mapped size %ld (expected %d)",
+                  buf_sz, GHCB_SHARED_BUF_SIZE);
+        goto out_unmap;
+    }
+
+    memcpy(guest_buf, contents, buf_sz);
+    *vmm_ret = 0;
+
+out_unmap:
+    address_space_unmap(&address_space_memory, guest_buf, buf_sz, true, buf_sz);
+
+    return 0;
+}
+
 int kvm_handle_vmgexit(struct kvm_run *run)
 {
     int ret;
@@ -1583,6 +1641,10 @@ int kvm_handle_vmgexit(struct kvm_run *run)
         ret = kvm_handle_vmgexit_psc_msr_protocol(run->vmgexit.psc_msr.gpa,
                                                   run->vmgexit.psc_msr.op,
                                                   &run->vmgexit.psc_msr.ret);
+    } else if (run->vmgexit.type == KVM_USER_VMGEXIT_EXT_GUEST_REQ) {
+        ret = kvm_handle_vmgexit_ext_req(run->vmgexit.ext_guest_req.data_gpa,
+                                         &run->vmgexit.ext_guest_req.data_npages,
+                                         &run->vmgexit.ext_guest_req.ret);
     } else {
         warn_report("KVM: unknown vmgexit type: %d", run->vmgexit.type);
         ret = -1;
@@ -1914,6 +1976,26 @@ sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
     memcpy(finish->host_data, blob, len);
 }
 
+static char *
+sev_snp_guest_get_certs_path(Object *obj, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    return g_strdup(sev_snp_guest->certs_path);
+}
+
+static void
+sev_snp_guest_set_certs_path(Object *obj, const char *value, Error **errp)
+{
+    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+    if (sev_snp_guest->host_data) {
+        g_free(sev_snp_guest->host_data);
+    }
+
+    sev_snp_guest->certs_path = value ? g_strdup(value) : NULL;
+}
+
 static void
 sev_snp_guest_class_init(ObjectClass *oc, void *data)
 {
@@ -1935,6 +2017,9 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
     object_class_property_add_str(oc, "host-data",
                                   sev_snp_guest_get_host_data,
                                   sev_snp_guest_set_host_data);
+    object_class_property_add_str(oc, "certs-path",
+                                  sev_snp_guest_get_certs_path,
+                                  sev_snp_guest_set_certs_path);
 }
 
 static void
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 37/49] i386/sev: Add the SNP launch start context
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (35 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  9:58   ` Paolo Bonzini
  2024-03-20  8:39 ` [PATCH v3 38/49] i386/sev: Add handling to encrypt/finalize guest launch data Michael Roth
                   ` (14 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

From: Brijesh Singh <brijesh.singh@amd.com>

The SNP_LAUNCH_START is called first to create a cryptographic launch
context within the firmware.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c        | 42 +++++++++++++++++++++++++++++++++++++++-
 target/i386/trace-events |  1 +
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 3b4dbc63b1..9f63a41f08 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -39,6 +39,7 @@
 #include "confidential-guest.h"
 #include "hw/i386/pc.h"
 #include "exec/address-spaces.h"
+#include "qemu/queue.h"
 
 OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
 OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
@@ -106,6 +107,16 @@ struct SevSnpGuestState {
 #define DEFAULT_SEV_DEVICE      "/dev/sev"
 #define DEFAULT_SEV_SNP_POLICY  0x30000
 
+typedef struct SevLaunchUpdateData {
+    QTAILQ_ENTRY(SevLaunchUpdateData) next;
+    hwaddr gpa;
+    void *hva;
+    uint64_t len;
+    int type;
+} SevLaunchUpdateData;
+
+static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
+
 #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
 typedef struct __attribute__((__packed__)) SevInfoBlock {
     /* SEV-ES Reset Vector Address */
@@ -668,6 +679,30 @@ sev_read_file_base64(const char *filename, guchar **data, gsize *len)
     return 0;
 }
 
+static int
+sev_snp_launch_start(SevSnpGuestState *sev_snp_guest)
+{
+    int fw_error, rc;
+    SevCommonState *sev_common = SEV_COMMON(sev_snp_guest);
+    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
+
+    trace_kvm_sev_snp_launch_start(start->policy, sev_snp_guest->guest_visible_workarounds);
+
+    rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
+                   start, &fw_error);
+    if (rc < 0) {
+        error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'",
+                __func__, rc, fw_error, fw_error_to_str(fw_error));
+        return 1;
+    }
+
+    QTAILQ_INIT(&launch_update);
+
+    sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
+
+    return 0;
+}
+
 static int
 sev_launch_start(SevGuestState *sev_guest)
 {
@@ -1007,7 +1042,12 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
         goto err;
     }
 
-    ret = sev_launch_start(SEV_GUEST(sev_common));
+    if (sev_snp_enabled()) {
+        ret = sev_snp_launch_start(SEV_SNP_GUEST(sev_common));
+    } else {
+        ret = sev_launch_start(SEV_GUEST(sev_common));
+    }
+
     if (ret) {
         error_setg(errp, "%s: failed to create encryption context", __func__);
         goto err;
diff --git a/target/i386/trace-events b/target/i386/trace-events
index 2cd8726eeb..cb26d8a925 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -11,3 +11,4 @@ kvm_sev_launch_measurement(const char *value) "data %s"
 kvm_sev_launch_finish(void) ""
 kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
 kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
+kvm_sev_snp_launch_start(uint64_t policy, char *gosvw) "policy 0x%" PRIx64 " gosvw %s"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 38/49] i386/sev: Add handling to encrypt/finalize guest launch data
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (36 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 37/49] i386/sev: Add the SNP launch start context Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 39/49] i386/sev: Set CPU state to protected once SNP guest payload is finalized Michael Roth
                   ` (13 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

From: Brijesh Singh <brijesh.singh@amd.com>

Process any queued up launch data and encrypt/measure it into the SNP
guest instance prior to initial guest launch.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Co-authored-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c        | 101 ++++++++++++++++++++++++++++++++++++++-
 target/i386/trace-events |   2 +
 2 files changed, 102 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 9f63a41f08..4155342e72 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -749,6 +749,61 @@ out:
     return ret;
 }
 
+static const char *
+snp_page_type_to_str(int type)
+{
+    switch (type) {
+    case KVM_SEV_SNP_PAGE_TYPE_NORMAL: return "Normal";
+    case KVM_SEV_SNP_PAGE_TYPE_ZERO: return "Zero";
+    case KVM_SEV_SNP_PAGE_TYPE_UNMEASURED: return "Unmeasured";
+    case KVM_SEV_SNP_PAGE_TYPE_SECRETS: return "Secrets";
+    case KVM_SEV_SNP_PAGE_TYPE_CPUID: return "Cpuid";
+    default: return "unknown";
+    }
+}
+
+static int
+sev_snp_launch_update(SevSnpGuestState *sev_snp_guest, SevLaunchUpdateData *data)
+{
+    int ret, fw_error;
+    struct kvm_sev_snp_launch_update update = {0};
+
+    if (!data->hva || !data->len) {
+        error_report("SNP_LAUNCH_UPDATE called with invalid address / length: %p / %lx",
+                     data->hva, data->len);
+        return 1;
+    }
+
+    update.uaddr = (__u64)(unsigned long)data->hva;
+    update.gfn_start = data->gpa >> TARGET_PAGE_BITS;
+    update.len = data->len;
+    update.type = data->type;
+
+    trace_kvm_sev_snp_launch_update(data->hva, data->gpa, data->len,
+                                    snp_page_type_to_str(data->type));
+
+    /*
+     * KVM_SEV_SNP_LAUNCH_UPDATE requires that GPA ranges have the private
+     * memory attribute set in advance.
+     */
+    ret = kvm_set_memory_attributes_private(data->gpa, data->len);
+    if (ret) {
+        error_report("SEV-SNP: failed to configure initial private guest memory");
+        goto out;
+    }
+
+    ret = sev_ioctl(SEV_COMMON(sev_snp_guest)->sev_fd,
+                    KVM_SEV_SNP_LAUNCH_UPDATE,
+                    &update, &fw_error);
+    if (ret) {
+        error_report("SNP_LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
+                     ret, fw_error, fw_error_to_str(fw_error));
+    }
+
+out:
+    return ret;
+}
+
 static int
 sev_launch_update_data(SevGuestState *sev_guest, uint8_t *addr, uint64_t len)
 {
@@ -894,6 +949,46 @@ sev_launch_finish(SevGuestState *sev_guest)
     migrate_add_blocker(&sev_mig_blocker, &error_fatal);
 }
 
+static void
+sev_snp_launch_finish(SevSnpGuestState *sev_snp)
+{
+    int ret, error;
+    Error *local_err = NULL;
+    OvmfSevMetadata *metadata;
+    SevLaunchUpdateData *data;
+    struct kvm_sev_snp_launch_finish *finish = &sev_snp->kvm_finish_conf;
+
+    QTAILQ_FOREACH(data, &launch_update, next) {
+        ret = sev_snp_launch_update(sev_snp, data);
+        if (ret) {
+            exit(1);
+        }
+    }
+
+    trace_kvm_sev_snp_launch_finish(sev_snp->id_block, sev_snp->id_auth,
+                                    sev_snp->host_data);
+    ret = sev_ioctl(SEV_COMMON(sev_snp)->sev_fd, KVM_SEV_SNP_LAUNCH_FINISH,
+                    finish, &error);
+    if (ret) {
+        error_report("SNP_LAUNCH_FINISH ret=%d fw_error=%d '%s'",
+                     ret, error, fw_error_to_str(error));
+        exit(1);
+    }
+
+    sev_set_guest_state(SEV_COMMON(sev_snp), SEV_STATE_RUNNING);
+
+    /* add migration blocker */
+    error_setg(&sev_mig_blocker,
+               "SEV-SNP: Migration is not implemented");
+    ret = migrate_add_blocker(&sev_mig_blocker, &local_err);
+    if (local_err) {
+        error_report_err(local_err);
+        error_free(sev_mig_blocker);
+        exit(1);
+    }
+}
+
+
 static void
 sev_vm_state_change(void *opaque, bool running, RunState state)
 {
@@ -901,7 +996,11 @@ sev_vm_state_change(void *opaque, bool running, RunState state)
 
     if (running) {
         if (!sev_check_state(sev_common, SEV_STATE_RUNNING)) {
-            sev_launch_finish(SEV_GUEST(sev_common));
+            if (sev_snp_enabled()) {
+                sev_snp_launch_finish(SEV_SNP_GUEST(sev_common));
+            } else {
+                sev_launch_finish(SEV_GUEST(sev_common));
+            }
         }
     }
 }
diff --git a/target/i386/trace-events b/target/i386/trace-events
index cb26d8a925..873a7e424e 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -12,3 +12,5 @@ kvm_sev_launch_finish(void) ""
 kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
 kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
 kvm_sev_snp_launch_start(uint64_t policy, char *gosvw) "policy 0x%" PRIx64 " gosvw %s"
+kvm_sev_snp_launch_update(void *addr, uint32_t gpa, uint64_t len, const char *type) "addr %p gpa 0x%x len 0x%" PRIx64 " (%s page)"
+kvm_sev_snp_launch_finish(char *id_block, char *id_auth, char *host_data) "id_block %s id_auth %s host_data %s"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 39/49] i386/sev: Set CPU state to protected once SNP guest payload is finalized
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (37 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 38/49] i386/sev: Add handling to encrypt/finalize guest launch data Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header Michael Roth
                   ` (12 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Once KVM_SNP_LAUNCH_FINISH is called the vCPU state is copied into the
vCPU's VMSA page and measured/encrypted. Any attempt to read/write CPU
state afterward will only be acting on the initial data and so are
effectively no-ops.

Set the vCPU state to protected at this point so that QEMU don't
continue trying to re-sync vCPU data during guest runtime.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 4155342e72..4d862eef78 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -975,6 +975,7 @@ sev_snp_launch_finish(SevSnpGuestState *sev_snp)
         exit(1);
     }
 
+    kvm_mark_guest_state_protected();
     sev_set_guest_state(SEV_COMMON(sev_snp), SEV_STATE_RUNNING);
 
     /* add migration blocker */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (38 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 39/49] i386/sev: Set CPU state to protected once SNP guest payload is finalized Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 17:55   ` Isaku Yamahata
  2024-03-20  8:39 ` [PATCH v3 41/49] i386/sev: Add support for populating OVMF metadata pages Michael Roth
                   ` (11 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

From: Brijesh Singh <brijesh.singh@amd.com>

A recent version of OVMF expanded the reset vector GUID list to add
SEV-specific metadata GUID. The SEV metadata describes the reserved
memory regions such as the secrets and CPUID page used during the SEV-SNP
guest launch.

The pc_system_get_ovmf_sev_metadata_ptr() is used to retieve the SEV
metadata pointer from the OVMF GUID list.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/i386/pc_sysfw_ovmf.c | 33 +++++++++++++++++++++++++++++++++
 include/hw/i386/pc.h    | 26 ++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c
index 07a4c267fa..32efa34614 100644
--- a/hw/i386/pc_sysfw_ovmf.c
+++ b/hw/i386/pc_sysfw_ovmf.c
@@ -35,6 +35,31 @@ static const int bytes_after_table_footer = 32;
 static bool ovmf_flash_parsed;
 static uint8_t *ovmf_table;
 static int ovmf_table_len;
+static OvmfSevMetadata *ovmf_sev_metadata_table;
+
+#define OVMF_SEV_META_DATA_GUID "dc886566-984a-4798-A75e-5585a7bf67cc"
+typedef struct __attribute__((__packed__)) OvmfSevMetadataOffset {
+    uint32_t offset;
+} OvmfSevMetadataOffset;
+
+static void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
+{
+    OvmfSevMetadata     *metadata;
+    OvmfSevMetadataOffset  *data;
+
+    if (!pc_system_ovmf_table_find(OVMF_SEV_META_DATA_GUID, (uint8_t **)&data,
+                                   NULL)) {
+        return;
+    }
+
+    metadata = (OvmfSevMetadata *)(flash_ptr + flash_size - data->offset);
+    if (memcmp(metadata->signature, "ASEV", 4) != 0) {
+        return;
+    }
+
+    ovmf_sev_metadata_table = g_malloc(metadata->len);
+    memcpy(ovmf_sev_metadata_table, metadata, metadata->len);
+}
 
 void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
 {
@@ -90,6 +115,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
      */
     memcpy(ovmf_table, ptr - tot_len, tot_len);
     ovmf_table += tot_len;
+
+    /* Copy the SEV metadata table (if exist) */
+    pc_system_parse_sev_metadata(flash_ptr, flash_size);
 }
 
 /**
@@ -159,3 +187,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
     }
     return false;
 }
+
+OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void)
+{
+    return ovmf_sev_metadata_table;
+}
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index fb1d4106e5..df9a61540d 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -163,6 +163,32 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
 #define PCI_HOST_ABOVE_4G_MEM_SIZE     "above-4g-mem-size"
 #define PCI_HOST_PROP_SMM_RANGES       "smm-ranges"
 
+typedef enum {
+    SEV_DESC_TYPE_UNDEF,
+    /* The section contains the region that must be validated by the VMM. */
+    SEV_DESC_TYPE_SNP_SEC_MEM,
+    /* The section contains the SNP secrets page */
+    SEV_DESC_TYPE_SNP_SECRETS,
+    /* The section contains address that can be used as a CPUID page */
+    SEV_DESC_TYPE_CPUID,
+
+} ovmf_sev_metadata_desc_type;
+
+typedef struct __attribute__((__packed__)) OvmfSevMetadataDesc {
+    uint32_t base;
+    uint32_t len;
+    ovmf_sev_metadata_desc_type type;
+} OvmfSevMetadataDesc;
+
+typedef struct __attribute__((__packed__)) OvmfSevMetadata {
+    uint8_t signature[4];
+    uint32_t len;
+    uint32_t version;
+    uint32_t num_desc;
+    OvmfSevMetadataDesc descs[];
+} OvmfSevMetadata;
+
+OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void);
 
 void pc_pci_as_mapping_init(MemoryRegion *system_memory,
                             MemoryRegion *pci_address_space);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 41/49] i386/sev: Add support for populating OVMF metadata pages
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (39 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 42/49] i386/sev: Add support for SNP CPUID validation Michael Roth
                   ` (10 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

From: Brijesh Singh <brijesh.singh@amd.com>

OVMF reserves various pages so they can be pre-initialized/validated
prior to launching the guest. Add support for populating these pages
with the expected content.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 4d862eef78..6c5166c729 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -949,6 +949,67 @@ sev_launch_finish(SevGuestState *sev_guest)
     migrate_add_blocker(&sev_mig_blocker, &error_fatal);
 }
 
+static int
+snp_launch_update_data(uint64_t gpa, void *hva, uint32_t len, int type)
+{
+    SevLaunchUpdateData *data;
+
+    data = g_new0(SevLaunchUpdateData, 1);
+    data->gpa = gpa;
+    data->hva = hva;
+    data->len = len;
+    data->type = type;
+
+    QTAILQ_INSERT_TAIL(&launch_update, data, next);
+
+    return 0;
+}
+
+static int
+snp_metadata_desc_to_page_type(int desc_type)
+{
+    switch(desc_type) {
+    /* Add the umeasured prevalidated pages as a zero page */
+    case SEV_DESC_TYPE_SNP_SEC_MEM: return KVM_SEV_SNP_PAGE_TYPE_ZERO;
+    case SEV_DESC_TYPE_SNP_SECRETS: return KVM_SEV_SNP_PAGE_TYPE_SECRETS;
+    case SEV_DESC_TYPE_CPUID: return KVM_SEV_SNP_PAGE_TYPE_CPUID;
+    default: return -1;
+    }
+}
+
+static void
+snp_populate_metadata_pages(SevSnpGuestState *sev_snp, OvmfSevMetadata *metadata)
+{
+    OvmfSevMetadataDesc *desc;
+    int type, ret, i;
+    void *hva;
+    MemoryRegion *mr = NULL;
+
+    for (i = 0; i < metadata->num_desc; i++) {
+        desc = &metadata->descs[i];
+
+        type = snp_metadata_desc_to_page_type(desc->type);
+        if (type < 0) {
+            error_report("%s: Invalid memory type '%d'\n", __func__, desc->type);
+            exit(1);
+        }
+
+        hva = gpa2hva(&mr, desc->base, desc->len, NULL);
+        if (!hva) {
+            error_report("%s: Failed to get HVA for GPA 0x%x sz 0x%x\n",
+                         __func__, desc->base, desc->len);
+            exit(1);
+        }
+
+        ret = snp_launch_update_data(desc->base, hva, desc->len, type);
+        if (ret) {
+            error_report("%s: Failed to add metadata page gpa 0x%x+%x type %d\n",
+                         __func__, desc->base, desc->len, desc->type);
+            exit(1);
+        }
+    }
+}
+
 static void
 sev_snp_launch_finish(SevSnpGuestState *sev_snp)
 {
@@ -958,6 +1019,20 @@ sev_snp_launch_finish(SevSnpGuestState *sev_snp)
     SevLaunchUpdateData *data;
     struct kvm_sev_snp_launch_finish *finish = &sev_snp->kvm_finish_conf;
 
+    /*
+     * To boot the SNP guest, the hypervisor is required to populate the CPUID
+     * and Secrets page before finalizing the launch flow. The location of
+     * the secrets and CPUID page is available through the OVMF metadata GUID.
+     */
+    metadata = pc_system_get_ovmf_sev_metadata_ptr();
+    if (metadata == NULL) {
+        error_report("%s: Failed to locate SEV metadata header\n", __func__);
+        exit(1);
+    }
+
+    /* Populate all the metadata pages */
+    snp_populate_metadata_pages(sev_snp, metadata);
+
     QTAILQ_FOREACH(data, &launch_update, next) {
         ret = sev_snp_launch_update(sev_snp, data);
         if (ret) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 42/49] i386/sev: Add support for SNP CPUID validation
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (40 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 41/49] i386/sev: Add support for populating OVMF metadata pages Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:18   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties Michael Roth
                   ` (9 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

SEV-SNP firmware allows a special guest page to be populated with a
table of guest CPUID values so that they can be validated through
firmware before being loaded into encrypted guest memory where they can
be used in place of hypervisor-provided values[1].

As part of SEV-SNP guest initialization, use this interface to validate
the CPUID entries reported by KVM_GET_CPUID2 prior to initial guest
start and populate the CPUID page reserved by OVMF with the resulting
encrypted data.

[1] SEV SNP Firmware ABI Specification, Rev. 0.8, 8.13.2.6

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 159 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 158 insertions(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 6c5166c729..db888afb53 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -191,6 +191,36 @@ static const char *const sev_fw_errlist[] = {
 
 #define SEV_FW_MAX_ERROR      ARRAY_SIZE(sev_fw_errlist)
 
+/* <linux/kvm.h> doesn't expose this, so re-use the max from kvm.c */
+#define KVM_MAX_CPUID_ENTRIES 100
+
+typedef struct KvmCpuidInfo {
+    struct kvm_cpuid2 cpuid;
+    struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
+} KvmCpuidInfo;
+
+#define SNP_CPUID_FUNCTION_MAXCOUNT 64
+#define SNP_CPUID_FUNCTION_UNKNOWN 0xFFFFFFFF
+
+typedef struct {
+    uint32_t eax_in;
+    uint32_t ecx_in;
+    uint64_t xcr0_in;
+    uint64_t xss_in;
+    uint32_t eax;
+    uint32_t ebx;
+    uint32_t ecx;
+    uint32_t edx;
+    uint64_t reserved;
+} __attribute__((packed)) SnpCpuidFunc;
+
+typedef struct {
+    uint32_t count;
+    uint32_t reserved1;
+    uint64_t reserved2;
+    SnpCpuidFunc entries[SNP_CPUID_FUNCTION_MAXCOUNT];
+} __attribute__((packed)) SnpCpuidInfo;
+
 static int
 sev_ioctl(int fd, int cmd, void *data, int *error)
 {
@@ -749,6 +779,34 @@ out:
     return ret;
 }
 
+static void
+sev_snp_cpuid_report_mismatches(SnpCpuidInfo *old,
+                                SnpCpuidInfo *new)
+{
+    size_t i;
+
+    if (old->count != new->count) {
+        error_report("SEV-SNP: CPUID validation failed due to count mismatch, provided: %d, expected: %d",
+                     old->count, new->count);
+    }
+
+    for (i = 0; i < old->count; i++) {
+        SnpCpuidFunc *old_func, *new_func;
+
+        old_func = &old->entries[i];
+        new_func = &new->entries[i];
+
+        if (memcmp(old_func, new_func, sizeof(SnpCpuidFunc))) {
+            error_report("SEV-SNP: CPUID validation failed for function 0x%x, index: 0x%x.\n"
+                         "provided: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n"
+                         "expected: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x",
+                         old_func->eax_in, old_func->ecx_in,
+                         old_func->eax, old_func->ebx, old_func->ecx, old_func->edx,
+                         new_func->eax, new_func->ebx, new_func->ecx, new_func->edx);
+        }
+    }
+}
+
 static const char *
 snp_page_type_to_str(int type)
 {
@@ -766,6 +824,7 @@ static int
 sev_snp_launch_update(SevSnpGuestState *sev_snp_guest, SevLaunchUpdateData *data)
 {
     int ret, fw_error;
+    SnpCpuidInfo snp_cpuid_info;
     struct kvm_sev_snp_launch_update update = {0};
 
     if (!data->hva || !data->len) {
@@ -774,6 +833,11 @@ sev_snp_launch_update(SevSnpGuestState *sev_snp_guest, SevLaunchUpdateData *data
         return 1;
     }
 
+    if (data->type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
+        /* Save a copy for comparison in case the LAUNCH_UPDATE fails */
+        memcpy(&snp_cpuid_info, data->hva, sizeof(snp_cpuid_info));
+    }
+
     update.uaddr = (__u64)(unsigned long)data->hva;
     update.gfn_start = data->gpa >> TARGET_PAGE_BITS;
     update.len = data->len;
@@ -798,6 +862,11 @@ sev_snp_launch_update(SevSnpGuestState *sev_snp_guest, SevLaunchUpdateData *data
     if (ret) {
         error_report("SNP_LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
                      ret, fw_error, fw_error_to_str(fw_error));
+
+        if (data->type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
+            sev_snp_cpuid_report_mismatches(&snp_cpuid_info, data->hva);
+            error_report("SEV-SNP: failed update CPUID page");
+        }
     }
 
 out:
@@ -965,6 +1034,89 @@ snp_launch_update_data(uint64_t gpa, void *hva, uint32_t len, int type)
     return 0;
 }
 
+static int
+sev_snp_cpuid_info_fill(SnpCpuidInfo *snp_cpuid_info,
+                        const KvmCpuidInfo *kvm_cpuid_info)
+{
+    size_t i;
+
+    if (kvm_cpuid_info->cpuid.nent > SNP_CPUID_FUNCTION_MAXCOUNT) {
+        error_report("SEV-SNP: CPUID entry count (%d) exceeds max (%d)",
+                     kvm_cpuid_info->cpuid.nent, SNP_CPUID_FUNCTION_MAXCOUNT);
+        return -1;
+    }
+
+    memset(snp_cpuid_info, 0, sizeof(*snp_cpuid_info));
+
+    for (i = 0; i < kvm_cpuid_info->cpuid.nent; i++) {
+        const struct kvm_cpuid_entry2 *kvm_cpuid_entry;
+        SnpCpuidFunc *snp_cpuid_entry;
+
+        kvm_cpuid_entry = &kvm_cpuid_info->entries[i];
+        snp_cpuid_entry = &snp_cpuid_info->entries[i];
+
+        snp_cpuid_entry->eax_in = kvm_cpuid_entry->function;
+        if (kvm_cpuid_entry->flags == KVM_CPUID_FLAG_SIGNIFCANT_INDEX) {
+            snp_cpuid_entry->ecx_in = kvm_cpuid_entry->index;
+        }
+        snp_cpuid_entry->eax = kvm_cpuid_entry->eax;
+        snp_cpuid_entry->ebx = kvm_cpuid_entry->ebx;
+        snp_cpuid_entry->ecx = kvm_cpuid_entry->ecx;
+        snp_cpuid_entry->edx = kvm_cpuid_entry->edx;
+
+        /*
+         * Guest kernels will calculate EBX themselves using the 0xD
+         * subfunctions corresponding to the individual XSAVE areas, so only
+         * encode the base XSAVE size in the initial leaves, corresponding
+         * to the initial XCR0=1 state.
+         */
+        if (snp_cpuid_entry->eax_in == 0xD &&
+            (snp_cpuid_entry->ecx_in == 0x0 || snp_cpuid_entry->ecx_in == 0x1)) {
+            snp_cpuid_entry->ebx = 0x240;
+            snp_cpuid_entry->xcr0_in = 1;
+            snp_cpuid_entry->xss_in = 0;
+        }
+    }
+
+    snp_cpuid_info->count = i;
+
+    return 0;
+}
+
+static int
+snp_launch_update_cpuid(uint32_t cpuid_addr, void *hva, uint32_t cpuid_len)
+{
+    KvmCpuidInfo kvm_cpuid_info = {0};
+    SnpCpuidInfo snp_cpuid_info;
+    CPUState *cs = first_cpu;
+    int ret;
+    uint32_t i = 0;
+
+    assert(sizeof(snp_cpuid_info) <= cpuid_len);
+
+    /* get the cpuid list from KVM */
+    do {
+        kvm_cpuid_info.cpuid.nent = ++i;
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_CPUID2, &kvm_cpuid_info);
+    } while (ret == -E2BIG);
+
+    if (ret) {
+        error_report("SEV-SNP: unable to query CPUID values for CPU: '%s'",
+                     strerror(-ret));
+        return 1;
+    }
+
+    ret = sev_snp_cpuid_info_fill(&snp_cpuid_info, &kvm_cpuid_info);
+    if (ret) {
+        error_report("SEV-SNP: failed to generate CPUID table information");
+        return 1;
+    }
+
+    memcpy(hva, &snp_cpuid_info, sizeof(snp_cpuid_info));
+
+    return snp_launch_update_data(cpuid_addr, hva, cpuid_len, KVM_SEV_SNP_PAGE_TYPE_CPUID);
+}
+
 static int
 snp_metadata_desc_to_page_type(int desc_type)
 {
@@ -1001,7 +1153,12 @@ snp_populate_metadata_pages(SevSnpGuestState *sev_snp, OvmfSevMetadata *metadata
             exit(1);
         }
 
-        ret = snp_launch_update_data(desc->base, hva, desc->len, type);
+        if (type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
+            ret = snp_launch_update_cpuid(desc->base, hva, desc->len);
+        } else {
+            ret = snp_launch_update_data(desc->base, hva, desc->len, type);
+        }
+
         if (ret) {
             error_report("%s: Failed to add metadata page gpa 0x%x+%x type %d\n",
                          __func__, desc->base, desc->len, desc->type);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (41 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 42/49] i386/sev: Add support for SNP CPUID validation Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:20   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 44/49] i386/sev: Extract build_kernel_loader_hashes Michael Roth
                   ` (8 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Dov Murik

From: Dov Murik <dovmurik@linux.ibm.com>

In order to enable kernel-hashes for SNP, pull it from
SevGuestProperties to its parent SevCommonProperties so
it will be available for both SEV and SNP.

Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 qapi/qom.json     | 14 +++++++-------
 target/i386/sev.c | 44 ++++++++++++++++++--------------------------
 2 files changed, 25 insertions(+), 33 deletions(-)

diff --git a/qapi/qom.json b/qapi/qom.json
index 7ba778af91..ea8832a8c3 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -886,12 +886,17 @@
 # @reduced-phys-bits: number of bits in physical addresses that become
 #     unavailable when SEV is enabled
 #
+# @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
+#     designated guest firmware page for measured boot with -kernel
+#     (default: false) (since 6.2)
+#
 # Since: 2.12
 ##
 { 'struct': 'SevCommonProperties',
   'data': { '*sev-device': 'str',
             '*cbitpos': 'uint32',
-            'reduced-phys-bits': 'uint32' } }
+            'reduced-phys-bits': 'uint32',
+            '*kernel-hashes': 'bool' } }
 
 ##
 # @SevGuestProperties:
@@ -906,10 +911,6 @@
 #
 # @handle: SEV firmware handle (default: 0)
 #
-# @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
-#     designated guest firmware page for measured boot with -kernel
-#     (default: false) (since 6.2)
-#
 # Since: 2.12
 ##
 { 'struct': 'SevGuestProperties',
@@ -917,8 +918,7 @@
   'data': { '*dh-cert-file': 'str',
             '*session-file': 'str',
             '*policy': 'uint32',
-            '*handle': 'uint32',
-            '*kernel-hashes': 'bool' } }
+            '*handle': 'uint32' } }
 
 ##
 # @SevSnpGuestProperties:
diff --git a/target/i386/sev.c b/target/i386/sev.c
index db888afb53..3187b3dee8 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -54,6 +54,7 @@ struct SevCommonState {
     char *sev_device;
     uint32_t cbitpos;
     uint32_t reduced_phys_bits;
+    bool kernel_hashes;
 
     /* runtime state */
     uint8_t api_major;
@@ -86,7 +87,6 @@ struct SevGuestState {
     uint32_t policy;
     char *dh_cert_file;
     char *session_file;
-    bool kernel_hashes;
 };
 
 struct SevSnpGuestState {
@@ -1696,16 +1696,12 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     MemTxAttrs attrs = { 0 };
     bool ret = true;
     SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
-    SevGuestState *sev_guest =
-        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
-                                             TYPE_SEV_GUEST);
 
     /*
      * Only add the kernel hashes if the sev-guest configuration explicitly
-     * stated kernel-hashes=on. Currently only enabled for SEV/SEV-ES guests,
-     * so check for TYPE_SEV_GUEST as well.
+     * stated kernel-hashes=on.
      */
-    if (sev_guest && !sev_guest->kernel_hashes) {
+    if (!sev_common->kernel_hashes) {
         return false;
     }
 
@@ -2037,6 +2033,16 @@ sev_common_set_sev_device(Object *obj, const char *value, Error **errp)
     SEV_COMMON(obj)->sev_device = g_strdup(value);
 }
 
+static bool sev_common_get_kernel_hashes(Object *obj, Error **errp)
+{
+    return SEV_COMMON(obj)->kernel_hashes;
+}
+
+static void sev_common_set_kernel_hashes(Object *obj, bool value, Error **errp)
+{
+    SEV_COMMON(obj)->kernel_hashes = value;
+}
+
 static void
 sev_common_class_init(ObjectClass *oc, void *data)
 {
@@ -2051,6 +2057,11 @@ sev_common_class_init(ObjectClass *oc, void *data)
                                   sev_common_set_sev_device);
     object_class_property_set_description(oc, "sev-device",
             "SEV device to use");
+    object_class_property_add_bool(oc, "kernel-hashes",
+                                   sev_common_get_kernel_hashes,
+                                   sev_common_set_kernel_hashes);
+    object_class_property_set_description(oc, "kernel-hashes",
+            "add kernel hashes to guest firmware for measured Linux boot");
 }
 
 static void
@@ -2109,20 +2120,6 @@ sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
     SEV_GUEST(obj)->session_file = g_strdup(value);
 }
 
-static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
-{
-    SevGuestState *sev_guest = SEV_GUEST(obj);
-
-    return sev_guest->kernel_hashes;
-}
-
-static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
-{
-    SevGuestState *sev = SEV_GUEST(obj);
-
-    sev->kernel_hashes = value;
-}
-
 static void
 sev_guest_class_init(ObjectClass *oc, void *data)
 {
@@ -2136,11 +2133,6 @@ sev_guest_class_init(ObjectClass *oc, void *data)
                                   sev_guest_set_session_file);
     object_class_property_set_description(oc, "session-file",
             "guest owners session parameters (encoded with base64)");
-    object_class_property_add_bool(oc, "kernel-hashes",
-                                   sev_guest_get_kernel_hashes,
-                                   sev_guest_set_kernel_hashes);
-    object_class_property_set_description(oc, "kernel-hashes",
-            "add kernel hashes to guest firmware for measured Linux boot");
 }
 
 static void
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 44/49] i386/sev: Extract build_kernel_loader_hashes
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (42 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 45/49] i386/sev: Reorder struct declarations Michael Roth
                   ` (7 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Dov Murik

From: Dov Murik <dovmurik@linux.ibm.com>

Extract the building of the kernel hashes table out from
sev_add_kernel_loader_hashes() to allow building it in
other memory areas (for SNP support).

No functional change intended.

Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 101 ++++++++++++++++++++++++++--------------------
 1 file changed, 58 insertions(+), 43 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 3187b3dee8..0913cb7fed 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1677,45 +1677,16 @@ static const QemuUUID sev_cmdline_entry_guid = {
                     0x4d, 0x36, 0xab, 0x2a)
 };
 
-/*
- * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
- * which is included in SEV's initial memory measurement.
- */
-bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+static bool build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
+                                       SevKernelLoaderContext *ctx,
+                                       Error **errp)
 {
-    uint8_t *data;
-    SevHashTableDescriptor *area;
     SevHashTable *ht;
-    PaddedSevHashTable *padded_ht;
     uint8_t cmdline_hash[HASH_SIZE];
     uint8_t initrd_hash[HASH_SIZE];
     uint8_t kernel_hash[HASH_SIZE];
     uint8_t *hashp;
     size_t hash_len = HASH_SIZE;
-    hwaddr mapped_len = sizeof(*padded_ht);
-    MemTxAttrs attrs = { 0 };
-    bool ret = true;
-    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
-
-    /*
-     * Only add the kernel hashes if the sev-guest configuration explicitly
-     * stated kernel-hashes=on.
-     */
-    if (!sev_common->kernel_hashes) {
-        return false;
-    }
-
-    if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
-        error_setg(errp, "SEV: kernel specified but guest firmware "
-                         "has no hashes table GUID");
-        return false;
-    }
-    area = (SevHashTableDescriptor *)data;
-    if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
-        error_setg(errp, "SEV: guest firmware hashes table area is invalid "
-                         "(base=0x%x size=0x%x)", area->base, area->size);
-        return false;
-    }
 
     /*
      * Calculate hash of kernel command-line with the terminating null byte. If
@@ -1752,16 +1723,6 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     }
     assert(hash_len == HASH_SIZE);
 
-    /*
-     * Populate the hashes table in the guest's memory at the OVMF-designated
-     * area for the SEV hashes table
-     */
-    padded_ht = address_space_map(&address_space_memory, area->base,
-                                  &mapped_len, true, attrs);
-    if (!padded_ht || mapped_len != sizeof(*padded_ht)) {
-        error_setg(errp, "SEV: cannot map hashes table guest memory area");
-        return false;
-    }
     ht = &padded_ht->ht;
 
     ht->guid = sev_hash_table_header_guid;
@@ -1782,7 +1743,61 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     /* zero the excess data so the measurement can be reliably calculated */
     memset(padded_ht->padding, 0, sizeof(padded_ht->padding));
 
-    if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht), errp) < 0) {
+    return true;
+}
+
+/*
+ * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
+ * which is included in SEV's initial memory measurement.
+ */
+bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+{
+    uint8_t *data;
+    SevHashTableDescriptor *area;
+    PaddedSevHashTable *padded_ht;
+    hwaddr mapped_len = sizeof(*padded_ht);
+    MemTxAttrs attrs = { 0 };
+    bool ret = true;
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
+    /*
+     * Only add the kernel hashes if the sev-guest configuration explicitly
+     * stated kernel-hashes=on.
+     */
+    if (!sev_common->kernel_hashes) {
+        return false;
+    }
+
+    if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
+        error_setg(errp, "SEV: kernel specified but guest firmware "
+                         "has no hashes table GUID");
+        return false;
+    }
+
+    area = (SevHashTableDescriptor *)data;
+    if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
+        error_setg(errp, "SEV: guest firmware hashes table area is invalid "
+                         "(base=0x%x size=0x%x)", area->base, area->size);
+        return false;
+    }
+
+    /*
+     * Populate the hashes table in the guest's memory at the OVMF-designated
+     * area for the SEV hashes table
+     */
+    padded_ht = address_space_map(&address_space_memory, area->base,
+                                  &mapped_len, true, attrs);
+    if (!padded_ht || mapped_len != sizeof(*padded_ht)) {
+        error_setg(errp, "SEV: cannot map hashes table guest memory area");
+        return false;
+    }
+
+    if (build_kernel_loader_hashes(padded_ht, ctx, errp)) {
+        if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht),
+                              errp) < 0) {
+            ret = false;
+        }
+    } else {
         ret = false;
     }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 45/49] i386/sev: Reorder struct declarations
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (43 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 44/49] i386/sev: Extract build_kernel_loader_hashes Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 46/49] i386/sev: Allow measured direct kernel boot on SNP Michael Roth
                   ` (6 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Dov Murik

From: Dov Murik <dovmurik@linux.ibm.com>

Move the declaration of PaddedSevHashTable before SevSnpGuest so
we can add a new such field to the latter.

No functional change intended.

Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 target/i386/sev.c | 56 +++++++++++++++++++++++------------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0913cb7fed..4bc6004037 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -41,6 +41,34 @@
 #include "exec/address-spaces.h"
 #include "qemu/queue.h"
 
+/* hard code sha256 digest size */
+#define HASH_SIZE 32
+
+typedef struct QEMU_PACKED SevHashTableEntry {
+    QemuUUID guid;
+    uint16_t len;
+    uint8_t hash[HASH_SIZE];
+} SevHashTableEntry;
+
+typedef struct QEMU_PACKED SevHashTable {
+    QemuUUID guid;
+    uint16_t len;
+    SevHashTableEntry cmdline;
+    SevHashTableEntry initrd;
+    SevHashTableEntry kernel;
+} SevHashTable;
+
+/*
+ * Data encrypted by sev_encrypt_flash() must be padded to a multiple of
+ * 16 bytes.
+ */
+typedef struct QEMU_PACKED PaddedSevHashTable {
+    SevHashTable ht;
+    uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
+} PaddedSevHashTable;
+
+QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
+
 OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
 OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
 OBJECT_DECLARE_SIMPLE_TYPE(SevSnpGuestState, SEV_SNP_GUEST)
@@ -131,34 +159,6 @@ typedef struct QEMU_PACKED SevHashTableDescriptor {
     uint32_t size;
 } SevHashTableDescriptor;
 
-/* hard code sha256 digest size */
-#define HASH_SIZE 32
-
-typedef struct QEMU_PACKED SevHashTableEntry {
-    QemuUUID guid;
-    uint16_t len;
-    uint8_t hash[HASH_SIZE];
-} SevHashTableEntry;
-
-typedef struct QEMU_PACKED SevHashTable {
-    QemuUUID guid;
-    uint16_t len;
-    SevHashTableEntry cmdline;
-    SevHashTableEntry initrd;
-    SevHashTableEntry kernel;
-} SevHashTable;
-
-/*
- * Data encrypted by sev_encrypt_flash() must be padded to a multiple of
- * 16 bytes.
- */
-typedef struct QEMU_PACKED PaddedSevHashTable {
-    SevHashTable ht;
-    uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
-} PaddedSevHashTable;
-
-QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
-
 static Error *sev_mig_blocker;
 
 static const char *const sev_fw_errlist[] = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 46/49] i386/sev: Allow measured direct kernel boot on SNP
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (44 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 45/49] i386/sev: Reorder struct declarations Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  8:39 ` [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled Michael Roth
                   ` (5 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Dov Murik

From: Dov Murik <dovmurik@linux.ibm.com>

In SNP, the hashes page designated with a specific metadata entry
published in AmdSev OVMF.

Therefore, if the user enabled kernel hashes (for measured direct boot),
QEMU should prepare the content of hashes table, and during the
processing of the metadata entry it copy the content into the designated
page and encrypt it.

Note that in SNP (unlike SEV and SEV-ES) the measurements is done in
whole 4KB pages.  Therefore QEMU zeros the whole page that includes the
hashes table, and fills in the kernel hashes area in that page, and then
encrypts the whole page.  The rest of the page is reserved for SEV
launch secrets which are not usable anyway on SNP.

If the user disabled kernel hashes, QEMU pre-validates the kernel hashes
page as a zero page.

Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 include/hw/i386/pc.h |  2 ++
 target/i386/sev.c    | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index df9a61540d..d9d3a5b5b8 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -171,6 +171,8 @@ typedef enum {
     SEV_DESC_TYPE_SNP_SECRETS,
     /* The section contains address that can be used as a CPUID page */
     SEV_DESC_TYPE_CPUID,
+    /* The section contains the region for kernel hashes for measured direct boot */
+    SEV_DESC_TYPE_SNP_KERNEL_HASHES = 0x10,
 
 } ovmf_sev_metadata_desc_type;
 
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 4bc6004037..e2506f74da 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -129,6 +129,9 @@ struct SevSnpGuestState {
 
     struct kvm_sev_snp_launch_start kvm_start_conf;
     struct kvm_sev_snp_launch_finish kvm_finish_conf;
+
+    uint32_t kernel_hashes_offset;
+    PaddedSevHashTable *kernel_hashes_data;
 };
 
 #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
@@ -1117,6 +1120,23 @@ snp_launch_update_cpuid(uint32_t cpuid_addr, void *hva, uint32_t cpuid_len)
     return snp_launch_update_data(cpuid_addr, hva, cpuid_len, KVM_SEV_SNP_PAGE_TYPE_CPUID);
 }
 
+static int
+snp_launch_update_kernel_hashes(SevSnpGuestState *sev_snp, uint32_t addr,
+                                void *hva, uint32_t len)
+{
+    int type = KVM_SEV_SNP_PAGE_TYPE_ZERO;
+    if (sev_snp->sev_common.kernel_hashes) {
+        assert(sev_snp->kernel_hashes_data);
+        assert((sev_snp->kernel_hashes_offset +
+                sizeof(*sev_snp->kernel_hashes_data)) <= len);
+        memset(hva, 0, len);
+        memcpy(hva + sev_snp->kernel_hashes_offset, sev_snp->kernel_hashes_data,
+               sizeof(*sev_snp->kernel_hashes_data));
+        type = KVM_SEV_SNP_PAGE_TYPE_NORMAL;
+    }
+    return snp_launch_update_data(addr, hva, len, type);
+}
+
 static int
 snp_metadata_desc_to_page_type(int desc_type)
 {
@@ -1125,6 +1145,7 @@ snp_metadata_desc_to_page_type(int desc_type)
     case SEV_DESC_TYPE_SNP_SEC_MEM: return KVM_SEV_SNP_PAGE_TYPE_ZERO;
     case SEV_DESC_TYPE_SNP_SECRETS: return KVM_SEV_SNP_PAGE_TYPE_SECRETS;
     case SEV_DESC_TYPE_CPUID: return KVM_SEV_SNP_PAGE_TYPE_CPUID;
+    case SEV_DESC_TYPE_SNP_KERNEL_HASHES: return KVM_SEV_SNP_PAGE_TYPE_NORMAL;
     default: return -1;
     }
 }
@@ -1155,6 +1176,9 @@ snp_populate_metadata_pages(SevSnpGuestState *sev_snp, OvmfSevMetadata *metadata
 
         if (type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
             ret = snp_launch_update_cpuid(desc->base, hva, desc->len);
+        } else if (desc->type == SEV_DESC_TYPE_SNP_KERNEL_HASHES) {
+            ret = snp_launch_update_kernel_hashes(sev_snp, desc->base, hva,
+                                                  desc->len);
         } else {
             ret = snp_launch_update_data(desc->base, hva, desc->len, type);
         }
@@ -1781,6 +1805,18 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
         return false;
     }
 
+    if (sev_snp_enabled()) {
+        /*
+         * SNP: Populate the hashes table in an area that later in
+         * snp_launch_update_kernel_hashes() will be copied to the guest memory
+         * and encrypted.
+         */
+        SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
+        sev_snp_guest->kernel_hashes_offset = area->base & ~TARGET_PAGE_MASK;
+        sev_snp_guest->kernel_hashes_data = g_new0(PaddedSevHashTable, 1);
+        return build_kernel_loader_hashes(sev_snp_guest->kernel_hashes_data, ctx, errp);
+    }
+
     /*
      * Populate the hashes table in the guest's memory at the OVMF-designated
      * area for the SEV hashes table
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (45 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 46/49] i386/sev: Allow measured direct kernel boot on SNP Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 12:22   ` Daniel P. Berrangé
  2024-03-20  8:39 ` [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs Michael Roth
                   ` (4 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

TODO: Brijesh as author, me as co-author (vice-versa depending)
      drop flash handling? we only support BIOS now

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/i386/pc_sysfw.c            | 12 +++++++-----
 hw/i386/x86.c                 |  2 +-
 include/hw/i386/x86.h         |  2 +-
 target/i386/sev-sysemu-stub.c |  2 +-
 target/i386/sev.c             | 15 +++++++++++----
 target/i386/sev.h             |  2 +-
 6 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 3efabbbab2..9dbb3f7337 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -149,6 +149,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
     assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
     for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
+        hwaddr gpa;
+
         system_flash = pcms->flash[i];
         blk = pflash_cfi01_get_blk(system_flash);
         if (!blk) {
@@ -178,11 +180,11 @@ static void pc_system_flash_map(PCMachineState *pcms,
         }
 
         total_size += size;
+        gpa = 0x100000000ULL - total_size; /* where the flash is mapped */
         qdev_prop_set_uint32(DEVICE(system_flash), "num-blocks",
                              size / FLASH_SECTOR_SIZE);
         sysbus_realize_and_unref(SYS_BUS_DEVICE(system_flash), &error_fatal);
-        sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0,
-                        0x100000000ULL - total_size);
+        sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0, gpa);
 
         if (i == 0) {
             flash_mem = pflash_cfi01_get_memory(system_flash);
@@ -192,7 +194,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
             if (sev_enabled()) {
                 flash_ptr = memory_region_get_ram_ptr(flash_mem);
                 flash_size = memory_region_size(flash_mem);
-                x86_firmware_configure(flash_ptr, flash_size);
+                x86_firmware_configure(gpa, flash_ptr, flash_size);
             }
         }
     }
@@ -245,7 +247,7 @@ void pc_system_firmware_init(PCMachineState *pcms,
     pc_system_flash_cleanup_unused(pcms);
 }
 
-void x86_firmware_configure(void *ptr, int size)
+void x86_firmware_configure(hwaddr gpa, void *ptr, int size)
 {
     int ret;
 
@@ -262,6 +264,6 @@ void x86_firmware_configure(void *ptr, int size)
             exit(1);
         }
 
-        sev_encrypt_flash(ptr, size, &error_fatal);
+        sev_encrypt_flash(gpa, ptr, size, &error_fatal);
     }
 }
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 825dc4c735..e3ddc39133 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -1161,7 +1161,7 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware,
          */
         void *ptr = memory_region_get_ram_ptr(bios);
         load_image_size(filename, ptr, bios_size);
-        x86_firmware_configure(ptr, bios_size);
+        x86_firmware_configure(0x100000000ULL - bios_size, ptr, bios_size);
     } else {
         if (!isapc_ram_fw) {
             memory_region_set_readonly(bios, true);
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index 4dc30dcb4d..53dfd95cb2 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -143,6 +143,6 @@ void ioapic_init_gsi(GSIState *gsi_state, Object *parent);
 DeviceState *ioapic_init_secondary(GSIState *gsi_state);
 
 /* pc_sysfw.c */
-void x86_firmware_configure(void *ptr, int size);
+void x86_firmware_configure(hwaddr gpa, void *ptr, int size);
 
 #endif
diff --git a/target/i386/sev-sysemu-stub.c b/target/i386/sev-sysemu-stub.c
index 96e1c15cc3..6af643e3a1 100644
--- a/target/i386/sev-sysemu-stub.c
+++ b/target/i386/sev-sysemu-stub.c
@@ -42,7 +42,7 @@ void qmp_sev_inject_launch_secret(const char *packet_header, const char *secret,
     error_setg(errp, "SEV is not available in this QEMU");
 }
 
-int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
+int sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp)
 {
     g_assert_not_reached();
 }
diff --git a/target/i386/sev.c b/target/i386/sev.c
index e2506f74da..d8e6aba67c 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1449,7 +1449,7 @@ err:
 }
 
 int
-sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
+sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp)
 {
     SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
 
@@ -1459,7 +1459,14 @@ sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
 
     /* if SEV is in update state then encrypt the data else do nothing */
     if (sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
-        int ret = sev_launch_update_data(SEV_GUEST(sev_common), ptr, len);
+        int ret;
+
+        if (sev_snp_enabled()) {
+            ret = snp_launch_update_data(gpa, ptr, len,
+                                         KVM_SEV_SNP_PAGE_TYPE_NORMAL);
+        } else {
+            ret = sev_launch_update_data(SEV_GUEST(sev_common), ptr, len);
+        }
         if (ret < 0) {
             error_setg(errp, "SEV: Failed to encrypt pflash rom");
             return ret;
@@ -1829,8 +1836,8 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
     }
 
     if (build_kernel_loader_hashes(padded_ht, ctx, errp)) {
-        if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht),
-                              errp) < 0) {
+        if (sev_encrypt_flash(area->base, (uint8_t *)padded_ht,
+                              sizeof(*padded_ht), errp) < 0) {
             ret = false;
         }
     } else {
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 5cbfc3365b..d570777769 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -59,7 +59,7 @@ uint32_t sev_get_cbit_position(void);
 uint32_t sev_get_reduced_phys_bits(void);
 bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp);
 
-int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp);
+int sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp);
 int sev_inject_launch_secret(const char *hdr, const char *secret,
                              uint64_t gpa, Error **errp);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (46 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20 18:12   ` Isaku Yamahata
  2024-03-20  8:39 ` [PATCH v3 49/49] hw/i386: Add support for loading BIOS using guest_memfd Michael Roth
                   ` (3 subsequent siblings)
  51 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

TODO: make this SNP-specific if TDX disables legacy ROMs in general

Current SNP guest kernels will attempt to access these regions with
with C-bit set, so guest_memfd is needed to handle that. Otherwise,
kvm_convert_memory() will fail when the guest kernel tries to access it
and QEMU attempts to call KVM_SET_MEMORY_ATTRIBUTES to set these ranges
to private.

Whether guests should actually try to access ROM regions in this way (or
need to deal with legacy ROM regions at all), is a separate issue to be
addressed on kernel side, but current SNP guest kernels will exhibit
this behavior and so this handling is needed to allow QEMU to continue
running existing SNP guest kernels.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/i386/pc.c       | 13 +++++++++----
 hw/i386/pc_sysfw.c | 13 ++++++++++---
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index feb7a93083..5feaeb43ee 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1011,10 +1011,15 @@ void pc_memory_init(PCMachineState *pcms,
     pc_system_firmware_init(pcms, rom_memory);
 
     option_rom_mr = g_malloc(sizeof(*option_rom_mr));
-    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
-                           &error_fatal);
-    if (pcmc->pci_enabled) {
-        memory_region_set_readonly(option_rom_mr, true);
+    if (machine_require_guest_memfd(machine)) {
+        memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
+                                           PC_ROM_SIZE, &error_fatal);
+    } else {
+        memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
+                               &error_fatal);
+        if (pcmc->pci_enabled) {
+            memory_region_set_readonly(option_rom_mr, true);
+        }
     }
     memory_region_add_subregion_overlap(rom_memory,
                                         PC_ROM_MIN_VGA,
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 9dbb3f7337..850f86edd4 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -54,8 +54,13 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
     /* map the last 128KB of the BIOS in ISA space */
     isa_bios_size = MIN(flash_size, 128 * KiB);
     isa_bios = g_malloc(sizeof(*isa_bios));
-    memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
-                           &error_fatal);
+    if (machine_require_guest_memfd(current_machine)) {
+        memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
+                                           isa_bios_size, &error_fatal);
+    } else {
+        memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
+                               &error_fatal);
+    }
     memory_region_add_subregion_overlap(rom_memory,
                                         0x100000 - isa_bios_size,
                                         isa_bios,
@@ -68,7 +73,9 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
            ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
            isa_bios_size);
 
-    memory_region_set_readonly(isa_bios, true);
+    if (!machine_require_guest_memfd(current_machine)) {
+        memory_region_set_readonly(isa_bios, true);
+    }
 }
 
 static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* [PATCH v3 49/49] hw/i386: Add support for loading BIOS using guest_memfd
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (47 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs Michael Roth
@ 2024-03-20  8:39 ` Michael Roth
  2024-03-20  9:59 ` [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Paolo Bonzini
                   ` (2 subsequent siblings)
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20  8:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

TODO: - Add proper handling for non-64K-aligned BIOS images.
      - Add proper handling for BIOS pflash area which should be
        initially mapped as shared, resulting in unecessary
        KVM_EXIT_MEMORY_FAULTs

When guest_memfd is enabled, the BIOS is generally part of the initial
encrypted guest image and will be accessed as private guest memory. Add
the necessary changes to set up the associated RAM region with a
guest_memfd backend to allow for this.

Current support centers around using -bios to load the BIOS data.
Support for loading the BIOS via pflash requires additional enablement
since those interfaces rely on the use of ROM memory regions which make
use of the KVM_MEM_READONLY memslot flag, which is not supported for
guest_memfd-backed memslots.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 hw/i386/x86.c | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index e3ddc39133..ea2d03cc02 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -1147,10 +1147,18 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware,
     }
     if (bios_size <= 0 ||
         (bios_size % 65536) != 0) {
-        goto bios_error;
+        g_warning("%s: Unaligned BIOS size %d", __func__, bios_size);
+        if (!machine_require_guest_memfd(ms)) {
+            goto bios_error;
+        }
     }
     bios = g_malloc(sizeof(*bios));
-    memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal);
+    if (machine_require_guest_memfd(ms)) {
+        memory_region_init_ram_guest_memfd(bios, NULL, "pc.bios", bios_size,
+                                           &error_fatal);
+    } else {
+        memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal);
+    }
     if (sev_enabled()) {
         /*
          * The concept of a "reset" simply doesn't exist for
@@ -1173,17 +1181,19 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware,
     }
     g_free(filename);
 
-    /* map the last 128KB of the BIOS in ISA space */
-    isa_bios_size = MIN(bios_size, 128 * KiB);
-    isa_bios = g_malloc(sizeof(*isa_bios));
-    memory_region_init_alias(isa_bios, NULL, "isa-bios", bios,
-                             bios_size - isa_bios_size, isa_bios_size);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        0x100000 - isa_bios_size,
-                                        isa_bios,
-                                        1);
-    if (!isapc_ram_fw) {
-        memory_region_set_readonly(isa_bios, true);
+    if (!machine_require_guest_memfd(ms)) {
+        /* map the last 128KB of the BIOS in ISA space */
+        isa_bios_size = MIN(bios_size, 128 * KiB);
+        isa_bios = g_malloc(sizeof(*isa_bios));
+        memory_region_init_alias(isa_bios, NULL, "isa-bios", bios,
+                                 bios_size - isa_bios_size, isa_bios_size);
+        memory_region_add_subregion_overlap(rom_memory,
+                                            0x100000 - isa_bios_size,
+                                            isa_bios,
+                                            1);
+        if (!isapc_ram_fw) {
+            memory_region_set_readonly(isa_bios, true);
+        }
     }
 
     /* map all the bios at the top of memory */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list
  2024-03-20  8:38 ` [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list Michael Roth
@ 2024-03-20  9:19   ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20  9:19 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:38, Michael Roth wrote:
> Data structures like struct setup_data have been moved to a separate
> setup_data.h header which bootparam.h relies on. Add setup_data.h to
> the cp_portable() list and sync it along with the other header files.
> 
> Note that currently struct setup_data is stripped away as part of
> generating bootparam.h, but that handling is no currently needed for
> setup_data.h since it doesn't pull in many external
> headers/dependencies. However, QEMU currently redefines struct
> setup_data in hw/i386/x86.c, so that will need to be removed as part of
> any header update that pulls in the new setup_data.h to avoid build
> bisect breakage.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>

Including Linux headers from standard-headers breaks build on
non-Linux systems, and <asm/setup_data.h> is the first architecture
specific #include in include/standard-headers/.

So this needs a small fixup, to rewrite asm/ include to the
standard-headers/asm-* subdirectory for the current architecture.
     
While at it, we should remove asm-generic/kvm_para.h from the list of
allowed includes: it does not have a matching substitution, so if it
appeared it would break the build it on non-Linux systems where there
is no /usr/include/asm-generic/ directory.

Applied patches 2-5 to my QEMU coco tree - still temporary, but
certainly better than the hack that I posted yesterday.  By the time
QEMU 9.1 opens there will be something more stable to import from.

Paolo

diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 579b03dc824..d48856f9e24 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -61,7 +61,6 @@ cp_portable() {
                                       -e 'linux/const' \
                                       -e 'linux/kernel' \
                                       -e 'linux/sysinfo' \
-                                     -e 'asm-generic/kvm_para' \
                                       -e 'asm/setup_data.h' \
                                       > /dev/null
      then
@@ -78,6 +77,7 @@ cp_portable() {
          -e 's/__be\([0-9][0-9]*\)/uint\1_t/g' \
          -e 's/"\(input-event-codes\.h\)"/"standard-headers\/linux\/\1"/' \
          -e 's/<linux\/\([^>]*\)>/"standard-headers\/linux\/\1"/' \
+        -e 's/<asm\/\([^>]*\)>/"standard-headers\/asm-'$arch'\/\1"/' \
          -e 's/__bitwise//' \
          -e 's/__attribute__((packed))/QEMU_PACKED/' \
          -e 's/__inline__/inline/' \
@@ -157,12 +157,13 @@ for arch in $ARCHLIST; do
          cp_portable "$tmpdir/bootparam.h" \
                      "$output/include/standard-headers/asm-$arch"
          cp_portable "$tmpdir/include/asm/setup_data.h" \
-                    "$output/linux-headers/asm-x86"
+                    "$output/standard-headers/asm-x86"
      fi
      if [ $arch = riscv ]; then
          cp "$tmpdir/include/asm/ptrace.h" "$output/linux-headers/asm-riscv/"
      fi
  done
+arch=
  
  rm -rf "$output/linux-headers/linux"
  mkdir -p "$output/linux-headers/linux"


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 24/49] target/i386: Add handling for KVM_X86_SNP_VM VM type
  2024-03-20  8:39 ` [PATCH v3 24/49] target/i386: Add handling for KVM_X86_SNP_VM VM type Michael Roth
@ 2024-03-20  9:33   ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20  9:33 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:39, Michael Roth wrote:
> An SNP VM requires VM type KVM_X86_SNP_VM to be passed to
> kvm_ioctl(KVM_CREATE_VM). Add it to the list of supported VM types, and
> return it appropriately via X86ConfidentialGuestClass->kvm_type().
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   target/i386/kvm/kvm.c |  1 +
>   target/i386/sev.c     | 10 ++++++++--
>   2 files changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
> index e109648f26..59e9048e61 100644
> --- a/target/i386/kvm/kvm.c
> +++ b/target/i386/kvm/kvm.c
> @@ -164,6 +164,7 @@ static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value);
>   
>   static const char *vm_type_name[] = {
>       [KVM_X86_DEFAULT_VM] = "default",
> +    [KVM_X86_SNP_VM] = "snp"
>   };
>   
>   bool kvm_is_vm_type_supported(int type)
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 2eb13ba639..61af312a11 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -853,14 +853,20 @@ sev_vm_state_change(void *opaque, bool running, RunState state)
>   static int sev_kvm_type(X86ConfidentialGuest *cg)
>   {
>       SevCommonState *sev_common = SEV_COMMON(cg);
> -    SevGuestState *sev_guest = SEV_GUEST(sev_common);
>       int kvm_type;
>   
>       if (sev_common->kvm_type != -1) {
>           goto out;
>       }
>   
> -    kvm_type = (sev_guest->policy & SEV_POLICY_ES) ? KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
> +    if (sev_snp_enabled()) {
> +        kvm_type = KVM_X86_SNP_VM;
> +    } else if (sev_es_enabled()) {
> +        kvm_type = KVM_X86_SEV_ES_VM;
> +    } else {
> +        kvm_type = KVM_X86_SEV_VM;
> +    }

I don't really like this, the kvm_type method can be implemented 
separately in sev-guest and sev-snp-guest.

This is for two reasons:

1) it makes sev_kvm_type self-contained, instead of poking in 
current_machine via sev_*_enabled()

2) sev-snp-guest can just return KVM_X86_SNP_VM, relying on the "vm type 
supported" checks from common target/i386/kvm/kvm.c code.  Instead, 
sev-guest has to check kvm_is_vm_type_supported() in order to support 
the legacy ioctls (and that is why my patches didn't add the SEV/SEV-ES 
types to vm_type_name[], too).

Thanks,

Paolo

> +
>       if (kvm_is_vm_type_supported(kvm_type)) {
>           sev_common->kvm_type = kvm_type;
>       } else {


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20  8:39 ` [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range() Michael Roth
@ 2024-03-20  9:37   ` David Hildenbrand
  2024-03-20 12:43     ` Xiaoyao Li
  2024-03-20 17:38     ` Michael Roth
  0 siblings, 2 replies; 110+ messages in thread
From: David Hildenbrand @ 2024-03-20  9:37 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 20.03.24 09:39, Michael Roth wrote:
> From: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> When memory page is converted from private to shared, the original
> private memory is back'ed by guest_memfd. Introduce
> ram_block_discard_guest_memfd_range() for discarding memory in
> guest_memfd.
> 
> Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
> Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>

"Co-developed-by"

> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Reviewed-by: David Hildenbrand <david@redhat.com>

Your SOB should go here.

> ---
> Changes in v5:
> - Collect Reviewed-by from David;
> 
> Changes in in v4:
> - Drop ram_block_convert_range() and open code its implementation in the
>    next Patch.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>

I only received 3 patches from this series, and now I am confused: 
changelog talks about v5 and this is "PATCH v3"

Please make sure to send at least the cover letter along (I might not 
need the other 46 patches :D ).

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP
  2024-03-20  8:39 ` [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP Michael Roth
@ 2024-03-20  9:46   ` Paolo Bonzini
  2024-03-20 22:14     ` Michael Roth
  0 siblings, 1 reply; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20  9:46 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:39, Michael Roth wrote:
> SEV uses these notifiers to register/pin pages prior to guest use, since
> they could potentially be used for private memory where page migration
> is not supported. But SNP only uses guest_memfd-provided pages for
> private memory, which has its own kernel-internal mechanisms for
> registering/pinning memory.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   target/i386/sev.c | 10 +++++++++-
>   1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 61af312a11..774262d834 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -982,7 +982,15 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>           goto err;
>       }
>   
> -    ram_block_notifier_add(&sev_ram_notifier);
> +    if (!sev_snp_enabled()) {
> +        /*
> +         * SEV uses these notifiers to register/pin pages prior to guest use,
> +         * but SNP relies on guest_memfd for private pages, which has it's
> +         * own internal mechanisms for registering/pinning private memory.
> +         */
> +        ram_block_notifier_add(&sev_ram_notifier);
> +    }
> +
>       qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
>       qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
>   

These three lines can be done in any order, so I suggest removing 
ram_block_notifier_add + qemu_add_machine_init_done_notifier from the 
sev-common implementation of kvm_init (let's call it 
sev_common_kvm_init); and add an override in sev-guest that calls them 
if sev_common_kvm_init() succeeds.

(treat this as a review for 25/26/29).

Paolo


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 27/49] i386/sev: Set ms->require_guest_memfd for SNP
  2024-03-20  8:39 ` [PATCH v3 27/49] i386/sev: Set ms->require_guest_memfd " Michael Roth
@ 2024-03-20  9:48   ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20  9:48 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:39, Michael Roth wrote:
> SNP requires guest_memfd for private guest memory, so enable it so that
> the appropriate guest_memfd backend will be available for normal RAM
> regions.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   target/i386/sev.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index e4deb7b41e..b06c796aae 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -880,6 +880,7 @@ out:
>   static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>   {
>       SevCommonState *sev_common = SEV_COMMON(cgs);
> +    MachineState *ms = MACHINE(qdev_get_machine());
>       char *devname;
>       int ret, fw_error, cmd;
>       uint32_t ebx;
> @@ -1000,6 +1001,10 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>           qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
>       }
>   
> +    if (sev_snp_enabled()) {
> +        ms->require_guest_memfd = true;
> +    }

Likewise, this and the following patch should be done in the 
sev-snp-guest's override of kvm_init.

Paolo

>       qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
>   
>       cgs->ready = true;


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 37/49] i386/sev: Add the SNP launch start context
  2024-03-20  8:39 ` [PATCH v3 37/49] i386/sev: Add the SNP launch start context Michael Roth
@ 2024-03-20  9:58   ` Paolo Bonzini
  2024-03-20 22:32     ` Michael Roth
  0 siblings, 1 reply; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20  9:58 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

On 3/20/24 09:39, Michael Roth wrote:
> From: Brijesh Singh <brijesh.singh@amd.com>
> 
> The SNP_LAUNCH_START is called first to create a cryptographic launch
> context within the firmware.
> 
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   target/i386/sev.c        | 42 +++++++++++++++++++++++++++++++++++++++-
>   target/i386/trace-events |  1 +
>   2 files changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 3b4dbc63b1..9f63a41f08 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -39,6 +39,7 @@
>   #include "confidential-guest.h"
>   #include "hw/i386/pc.h"
>   #include "exec/address-spaces.h"
> +#include "qemu/queue.h"
>   
>   OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
>   OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> @@ -106,6 +107,16 @@ struct SevSnpGuestState {
>   #define DEFAULT_SEV_DEVICE      "/dev/sev"
>   #define DEFAULT_SEV_SNP_POLICY  0x30000
>   
> +typedef struct SevLaunchUpdateData {
> +    QTAILQ_ENTRY(SevLaunchUpdateData) next;
> +    hwaddr gpa;
> +    void *hva;
> +    uint64_t len;
> +    int type;
> +} SevLaunchUpdateData;
> +
> +static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
> +
>   #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
>   typedef struct __attribute__((__packed__)) SevInfoBlock {
>       /* SEV-ES Reset Vector Address */
> @@ -668,6 +679,30 @@ sev_read_file_base64(const char *filename, guchar **data, gsize *len)
>       return 0;
>   }
>   
> +static int
> +sev_snp_launch_start(SevSnpGuestState *sev_snp_guest)
> +{
> +    int fw_error, rc;
> +    SevCommonState *sev_common = SEV_COMMON(sev_snp_guest);
> +    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
> +
> +    trace_kvm_sev_snp_launch_start(start->policy, sev_snp_guest->guest_visible_workarounds);
> +
> +    rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
> +                   start, &fw_error);
> +    if (rc < 0) {
> +        error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'",
> +                __func__, rc, fw_error, fw_error_to_str(fw_error));
> +        return 1;
> +    }
> +
> +    QTAILQ_INIT(&launch_update);
> +
> +    sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
> +
> +    return 0;
> +}
> +
>   static int
>   sev_launch_start(SevGuestState *sev_guest)
>   {
> @@ -1007,7 +1042,12 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>           goto err;
>       }
>   
> -    ret = sev_launch_start(SEV_GUEST(sev_common));
> +    if (sev_snp_enabled()) {
> +        ret = sev_snp_launch_start(SEV_SNP_GUEST(sev_common));
> +    } else {
> +        ret = sev_launch_start(SEV_GUEST(sev_common));
> +    }

Instead of an "if", this should be a method in sev-common.  Likewise for 
launch_finish in the next patch.

Also, patch 47 should introduce an "int (*launch_update_data)(hwaddr 
gpa, uint8_t *ptr, uint64_t len)" method whose implementation is either 
the existing sev_launch_update_data() for sev-guest, or a wrapper around 
snp_launch_update_data() (to add KVM_SEV_SNP_PAGE_TYPE_NORMAL) for 
sev-snp-guest.

In general, the only uses of sev_snp_enabled() should be in 
sev_add_kernel_loader_hashes() and kvm_handle_vmgexit_ext_req().  I 
would not be that strict for the QMP and HMP functions, but if you want 
to make those methods of sev-common I wouldn't complain.

Paolo

>       if (ret) {
>           error_setg(errp, "%s: failed to create encryption context", __func__);
>           goto err;
> diff --git a/target/i386/trace-events b/target/i386/trace-events
> index 2cd8726eeb..cb26d8a925 100644
> --- a/target/i386/trace-events
> +++ b/target/i386/trace-events
> @@ -11,3 +11,4 @@ kvm_sev_launch_measurement(const char *value) "data %s"
>   kvm_sev_launch_finish(void) ""
>   kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
>   kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
> +kvm_sev_snp_launch_start(uint64_t policy, char *gosvw) "policy 0x%" PRIx64 " gosvw %s"


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (48 preceding siblings ...)
  2024-03-20  8:39 ` [PATCH v3 49/49] hw/i386: Add support for loading BIOS using guest_memfd Michael Roth
@ 2024-03-20  9:59 ` Paolo Bonzini
  2024-03-20 17:08   ` Paolo Bonzini
  2024-03-21 20:26 ` Michael Roth
  2024-04-18 11:37 ` Ani Sinha
  51 siblings, 1 reply; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20  9:59 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:38, Michael Roth wrote:
> These patches implement SEV-SNP base support along with CPUID enforcement
> support for QEMU, and are also available at:
> 
>    https://github.com/amdese/qemu/commits/snp-v3-rfc
> 
> they are based on top of the following patchset from Paolo:
> 
>    "[PATCH 0/7] target/i386: VM type infrastructure and KVM_SEV_INIT2 support"
>    https://lists.gnu.org/archive/html/qemu-devel/2024-03/msg04663.html
> 
> 
> Patch Layout
> ------------
> 
> 01-05: Various changes needed to handle new header files in kvm-next tree
>         and some hacks to get a functional header sync in place for building
>         this series.
> 06-18: These are patches directly plucked from Xiaoyao's TDX v5 patchset[1]
>         that implement common dependencies between SNP/TDX like base
>         guest_memfd, KVM_EXIT_MEMORY_FAULT handling (with a small FIXUP), and
>         mechanisms to disable SMM. We would've also needed some of the basic
>         infrastructure for handling specifying VM types for KVM_CREATE, but
>         much of that is now part of the sevinit2 series this patchset is based
>         on. Ideally all these patches, once stable, could be maintained in a
>         common tree so that future SNP/TDX patchsets can be more easily
>         iterated on/reviewed.
> 19-20: Patches introduced by this series that are  possible candidate for a
>         common tree.
>         shared/private pages when things like VFIO are in use.
> 21-32: Introduction of sev-snp-guest object and various configuration
>         requirements for SNP.
> 33-36: Handling for various KVM_EXIT_VMGEXIT events that are handled in
>         userspace.
> 37-49: Support for creating a cryptographic "launch" context and populating
>         various OVMF metadata pages, BIOS regions, and vCPU/VMSA pages with
>         the initial encrypted/measured/validated launch data prior to
>         launching the SNP guest.

I reviewed the non-SEV bits of patches 21-46 and it looks nicely 
self-contained.  That's pretty much expected but still good news.

I didn't look closely at the SEV-SNP code for obvious reasons (it's only 
been one hour :)), except for the object-oriented aesthetics which I 
have remarked upon.  However, they seem to be in good shape.

I will now focus on reviewing patches 6-20.  This way we can prepare a 
common tree for SEV_INIT2/SNP/TDX, for both vendors to build upon.

Thanks for posting this, and thanks to the Intel people too for the 
previous work on the guest_memfd parts!

Paolo


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20  8:39 ` [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state Michael Roth
@ 2024-03-20 11:44   ` Daniel P. Berrangé
  2024-03-20 21:36       ` Michael Roth via
  2024-03-27 15:22     ` Markus Armbruster
  2024-03-20 11:47   ` Daniel P. Berrangé
  2024-04-22 13:06   ` Markus Armbruster
  2 siblings, 2 replies; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 11:44 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
> Currently all SEV/SEV-ES functionality is managed through a single
> 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> same approach won't work well since some of the properties/state
> managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> rely on a new QOM type with its own set of properties/state.
> 
> To prepare for this, this patch moves common state into an abstract
> 'sev-common' parent type to encapsulate properties/state that are
> common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> properties/state in the current 'sev-guest' type. This should not
> affect current behavior or command-line options.
> 
> As part of this patch, some related changes are also made:
> 
>   - a static 'sev_guest' variable is currently used to keep track of
>     the 'sev-guest' instance. SEV-SNP would similarly introduce an
>     'sev_snp_guest' static variable. But these instances are now
>     available via qdev_get_machine()->cgs, so switch to using that
>     instead and drop the static variable.
> 
>   - 'sev_guest' is currently used as the name for the static variable
>     holding a pointer to the 'sev-guest' instance. Re-purpose the name
>     as a local variable referring the 'sev-guest' instance, and use
>     that consistently throughout the code so it can be easily
>     distinguished from sev-common/sev-snp-guest instances.
> 
>   - 'sev' is generally used as the name for local variables holding a
>     pointer to the 'sev-guest' instance. In cases where that now points
>     to common state, use the name 'sev_common'; in cases where that now
>     points to state specific to 'sev-guest' instance, use the name
>     'sev_guest'
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  qapi/qom.json     |  32 ++--
>  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
>  target/i386/sev.h |   3 +
>  3 files changed, 281 insertions(+), 211 deletions(-)
> 
> diff --git a/qapi/qom.json b/qapi/qom.json
> index baae3a183f..66b5781ca6 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -875,12 +875,29 @@
>    'data': { '*filename': 'str' } }
>  
>  ##
> -# @SevGuestProperties:
> +# @SevCommonProperties:
>  #
> -# Properties for sev-guest objects.
> +# Properties common to objects that are derivatives of sev-common.
>  #
>  # @sev-device: SEV device to use (default: "/dev/sev")
>  #
> +# @cbitpos: C-bit location in page table entry (default: 0)
> +#
> +# @reduced-phys-bits: number of bits in physical addresses that become
> +#     unavailable when SEV is enabled
> +#
> +# Since: 2.12

Not quite sure what we've done in this scenario before.
It feels wierd to use '2.12' for the new base type, even
though in effect the properties all existed since 2.12 in
the sub-class.

Perhaps 'Since: 9.1' for the type, but 'Since: 2.12' for the
properties, along with an explanatory comment about stuff
moving into the new base type ?

Markus, opinions ?

> +##
> +{ 'struct': 'SevCommonProperties',
> +  'data': { '*sev-device': 'str',
> +            '*cbitpos': 'uint32',
> +            'reduced-phys-bits': 'uint32' } }
> +
> +##
> +# @SevGuestProperties:
> +#
> +# Properties for sev-guest objects.
> +#
>  # @dh-cert-file: guest owners DH certificate (encoded with base64)
>  #
>  # @session-file: guest owners session parameters (encoded with base64)
> @@ -889,11 +906,6 @@
>  #
>  # @handle: SEV firmware handle (default: 0)
>  #
> -# @cbitpos: C-bit location in page table entry (default: 0)
> -#
> -# @reduced-phys-bits: number of bits in physical addresses that become
> -#     unavailable when SEV is enabled
> -#
>  # @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
>  #     designated guest firmware page for measured boot with -kernel
>  #     (default: false) (since 6.2)
> @@ -901,13 +913,11 @@
>  # Since: 2.12
>  ##
>  { 'struct': 'SevGuestProperties',
> -  'data': { '*sev-device': 'str',
> -            '*dh-cert-file': 'str',
> +  'base': 'SevCommonProperties',
> +  'data': { '*dh-cert-file': 'str',
>              '*session-file': 'str',
>              '*policy': 'uint32',
>              '*handle': 'uint32',
> -            '*cbitpos': 'uint32',
> -            'reduced-phys-bits': 'uint32',
>              '*kernel-hashes': 'bool' } }
>  
>  ##

> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 9dab4060b8..63a220de5e 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -40,48 +40,53 @@
>  #include "hw/i386/pc.h"
>  #include "exec/address-spaces.h"
>  
> -#define TYPE_SEV_GUEST "sev-guest"
> +OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
>  OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
>  
> -
> -/**
> - * SevGuestState:
> - *
> - * The SevGuestState object is used for creating and managing a SEV
> - * guest.
> - *
> - * # $QEMU \
> - *         -object sev-guest,id=sev0 \
> - *         -machine ...,memory-encryption=sev0
> - */
> -struct SevGuestState {
> +struct SevCommonState {
>      X86ConfidentialGuest parent_obj;
>  
>      int kvm_type;
>  
>      /* configuration parameters */
>      char *sev_device;
> -    uint32_t policy;
> -    char *dh_cert_file;
> -    char *session_file;
>      uint32_t cbitpos;
>      uint32_t reduced_phys_bits;
> -    bool kernel_hashes;
>  
>      /* runtime state */
> -    uint32_t handle;
>      uint8_t api_major;
>      uint8_t api_minor;
>      uint8_t build_id;
>      int sev_fd;
>      SevState state;
> -    gchar *measurement;
>  
>      uint32_t reset_cs;
>      uint32_t reset_ip;
>      bool reset_data_valid;
>  };
>  
> +/**
> + * SevGuestState:
> + *
> + * The SevGuestState object is used for creating and managing a SEV
> + * guest.
> + *
> + * # $QEMU \
> + *         -object sev-guest,id=sev0 \
> + *         -machine ...,memory-encryption=sev0
> + */
> +struct SevGuestState {
> +    SevCommonState sev_common;
> +    gchar *measurement;
> +
> +    /* configuration parameters */
> +    uint32_t handle;
> +    uint32_t policy;
> +    char *dh_cert_file;
> +    char *session_file;
> +    bool kernel_hashes;
> +};
> +
>  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
>  #define DEFAULT_SEV_DEVICE      "/dev/sev"
>  
> @@ -127,7 +132,6 @@ typedef struct QEMU_PACKED PaddedSevHashTable {
>  
>  QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
>  
> -static SevGuestState *sev_guest;
>  static Error *sev_mig_blocker;
>  
>  static const char *const sev_fw_errlist[] = {
> @@ -208,21 +212,21 @@ fw_error_to_str(int code)
>  }
>  
>  static bool
> -sev_check_state(const SevGuestState *sev, SevState state)
> +sev_check_state(const SevCommonState *sev_common, SevState state)
>  {
> -    assert(sev);
> -    return sev->state == state ? true : false;
> +    assert(sev_common);
> +    return sev_common->state == state ? true : false;
>  }
>  
>  static void
> -sev_set_guest_state(SevGuestState *sev, SevState new_state)
> +sev_set_guest_state(SevCommonState *sev_common, SevState new_state)
>  {
>      assert(new_state < SEV_STATE__MAX);
> -    assert(sev);
> +    assert(sev_common);
>  
> -    trace_kvm_sev_change_state(SevState_str(sev->state),
> +    trace_kvm_sev_change_state(SevState_str(sev_common->state),
>                                 SevState_str(new_state));
> -    sev->state = new_state;
> +    sev_common->state = new_state;
>  }
>  
>  static void
> @@ -289,111 +293,61 @@ static struct RAMBlockNotifier sev_ram_notifier = {
>      .ram_block_removed = sev_ram_block_removed,
>  };
>  
> -static void
> -sev_guest_finalize(Object *obj)
> -{
> -}
> -
> -static char *
> -sev_guest_get_session_file(Object *obj, Error **errp)
> -{
> -    SevGuestState *s = SEV_GUEST(obj);
> -
> -    return s->session_file ? g_strdup(s->session_file) : NULL;
> -}
> -
> -static void
> -sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
> -{
> -    SevGuestState *s = SEV_GUEST(obj);
> -
> -    s->session_file = g_strdup(value);
> -}
> -
> -static char *
> -sev_guest_get_dh_cert_file(Object *obj, Error **errp)
> -{
> -    SevGuestState *s = SEV_GUEST(obj);
> -
> -    return g_strdup(s->dh_cert_file);
> -}
> -
> -static void
> -sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
> -{
> -    SevGuestState *s = SEV_GUEST(obj);
> -
> -    s->dh_cert_file = g_strdup(value);
> -}
> -
> -static char *
> -sev_guest_get_sev_device(Object *obj, Error **errp)
> -{
> -    SevGuestState *sev = SEV_GUEST(obj);
> -
> -    return g_strdup(sev->sev_device);
> -}
> -
> -static void
> -sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
> -{
> -    SevGuestState *sev = SEV_GUEST(obj);
> -
> -    sev->sev_device = g_strdup(value);
> -}
> -
> -static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
> -{
> -    SevGuestState *sev = SEV_GUEST(obj);
> -
> -    return sev->kernel_hashes;
> -}
> -
> -static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
> -{
> -    SevGuestState *sev = SEV_GUEST(obj);
> -
> -    sev->kernel_hashes = value;
> -}
> -
>  bool
>  sev_enabled(void)
>  {
> -    return !!sev_guest;
> +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> +
> +    return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
>  }
>  
>  bool
>  sev_es_enabled(void)
>  {
> -    return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
> +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> +
> +    return sev_enabled() && (SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
>  }
>  
>  uint32_t
>  sev_get_cbit_position(void)
>  {
> -    return sev_guest ? sev_guest->cbitpos : 0;
> +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> +
> +    return sev_common ? sev_common->cbitpos : 0;
>  }
>  
>  uint32_t
>  sev_get_reduced_phys_bits(void)
>  {
> -    return sev_guest ? sev_guest->reduced_phys_bits : 0;
> +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> +
> +    return sev_common ? sev_common->reduced_phys_bits : 0;
>  }
>  
>  static SevInfo *sev_get_info(void)
>  {
>      SevInfo *info;
> +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> +    SevGuestState *sev_guest =
> +        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> +                                             TYPE_SEV_GUEST);
>  
>      info = g_new0(SevInfo, 1);
>      info->enabled = sev_enabled();
>  
>      if (info->enabled) {
> -        info->api_major = sev_guest->api_major;
> -        info->api_minor = sev_guest->api_minor;
> -        info->build_id = sev_guest->build_id;
> -        info->policy = sev_guest->policy;
> -        info->state = sev_guest->state;
> -        info->handle = sev_guest->handle;
> +        if (sev_guest) {
> +            info->handle = sev_guest->handle;
> +        }
> +        info->api_major = sev_common->api_major;
> +        info->api_minor = sev_common->api_minor;
> +        info->build_id = sev_common->build_id;
> +        info->state = sev_common->state;
> +        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> +        info->policy =
> +            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> +                                               "policy", NULL);
>      }

I think we can change this 'policy' field to 'int64'.

Going from int32 to int64 doesn't change the encoding in JSON
or cli properites. SEV/SEV-ES guests will still only use values
that fit within int32, so existing users of QEMU won't notice
a change.

Apps that want to use SEV-SNP will know that they can have
policy values exceeding int32, but since that's net new code
to suupport SEV-SNP there's no back compat issue.


> @@ -519,6 +473,8 @@ static SevCapability *sev_get_capabilities(Error **errp)
>      size_t pdh_len = 0, cert_chain_len = 0, cpu0_id_len = 0;
>      uint32_t ebx;
>      int fd;
> +    SevCommonState *sev_common;
> +    char *sev_device;

Declare 'g_autofree char *sev_device = NULL;'

>  
>      if (!kvm_enabled()) {
>          error_setg(errp, "KVM not enabled");
> @@ -529,12 +485,21 @@ static SevCapability *sev_get_capabilities(Error **errp)
>          return NULL;
>      }
>  
> -    fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
> +    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> +    if (!sev_common) {
> +        error_setg(errp, "SEV is not configured");
> +    }

Missing 'return' ?

> +
> +    sev_device = object_property_get_str(OBJECT(sev_common), "sev-device",
> +                                         &error_abort);
> +    fd = open(sev_device, O_RDWR);
>      if (fd < 0) {
>          error_setg_errno(errp, errno, "SEV: Failed to open %s",
>                           DEFAULT_SEV_DEVICE);
> +        g_free(sev_device);
>          return NULL;
>      }
> +    g_free(sev_device);

These 'g_free' are redundant with g_autofree usage on the declaration.

>  
>      if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
>                           &cert_chain_data, &cert_chain_len, errp)) {
> @@ -577,7 +542,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
>  {
>      struct kvm_sev_attestation_report input = {};
>      SevAttestationReport *report = NULL;
> -    SevGuestState *sev = sev_guest;
> +    SevCommonState *sev_common;

I think it would have been nicer to just keep the variable
just called 'sev', except in the few cases where you needed to
have variables for both parent & subclass in the same method.
This diff would be much smaller too.

That's a bit bikeshedding though, so not too bothered either
way.

>      g_autofree guchar *data = NULL;
>      g_autofree guchar *buf = NULL;
>      gsize len;
> @@ -602,8 +567,10 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
>          return NULL;
>      }
>  
> +    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> +
>      /* Query the report length */
> -    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> +    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
>              &input, &err);
>      if (ret < 0) {
>          if (err != SEV_RET_INVALID_LEN) {
> @@ -619,7 +586,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
>      memcpy(input.mnonce, buf, sizeof(input.mnonce));
>  
>      /* Query the report */
> -    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> +    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
>              &input, &err);
>      if (ret) {
>          error_setg_errno(errp, errno, "SEV: Failed to get attestation report"

> +
> +/* sev guest info common to sev/sev-es/sev-snp */
> +static const TypeInfo sev_common_info = {
> +    .parent = TYPE_X86_CONFIDENTIAL_GUEST,
> +    .name = TYPE_SEV_COMMON,
> +    .instance_size = sizeof(SevCommonState),
> +    .class_init = sev_common_class_init,
> +    .instance_init = sev_common_instance_init,
> +    .abstract = true,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_USER_CREATABLE },
> +        { }
> +    }
> +};

It feels wierd to declare a type as "abstract", and at
the same time declare it "user creatable". I know this
was a simple short-cut to avoid repeating the .interfaces
on every sub-class, but I still think it would be better
to put the "user creatable" marker on the concrete impls
instead.

Also how about using OBJECT_DEFINE_ABSTRACT_TYPE here
and also converting the subclasses to use
OBJECT_DEFINE_TYPE_WITH_INTERFACES ?



With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20  8:39 ` [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state Michael Roth
  2024-03-20 11:44   ` Daniel P. Berrangé
@ 2024-03-20 11:47   ` Daniel P. Berrangé
  2024-03-20 21:45       ` Michael Roth via
  2024-04-22 13:06   ` Markus Armbruster
  2 siblings, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 11:47 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
> Currently all SEV/SEV-ES functionality is managed through a single
> 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> same approach won't work well since some of the properties/state
> managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> rely on a new QOM type with its own set of properties/state.
> 
> To prepare for this, this patch moves common state into an abstract
> 'sev-common' parent type to encapsulate properties/state that are
> common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> properties/state in the current 'sev-guest' type. This should not
> affect current behavior or command-line options.
> 
> As part of this patch, some related changes are also made:
> 
>   - a static 'sev_guest' variable is currently used to keep track of
>     the 'sev-guest' instance. SEV-SNP would similarly introduce an
>     'sev_snp_guest' static variable. But these instances are now
>     available via qdev_get_machine()->cgs, so switch to using that
>     instead and drop the static variable.
> 
>   - 'sev_guest' is currently used as the name for the static variable
>     holding a pointer to the 'sev-guest' instance. Re-purpose the name
>     as a local variable referring the 'sev-guest' instance, and use
>     that consistently throughout the code so it can be easily
>     distinguished from sev-common/sev-snp-guest instances.
> 
>   - 'sev' is generally used as the name for local variables holding a
>     pointer to the 'sev-guest' instance. In cases where that now points
>     to common state, use the name 'sev_common'; in cases where that now
>     points to state specific to 'sev-guest' instance, use the name
>     'sev_guest'
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  qapi/qom.json     |  32 ++--
>  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
>  target/i386/sev.h |   3 +
>  3 files changed, 281 insertions(+), 211 deletions(-)
> 

>  static SevInfo *sev_get_info(void)
>  {
>      SevInfo *info;
> +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> +    SevGuestState *sev_guest =
> +        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> +                                             TYPE_SEV_GUEST);
>  
>      info = g_new0(SevInfo, 1);
>      info->enabled = sev_enabled();
>  
>      if (info->enabled) {
> -        info->api_major = sev_guest->api_major;
> -        info->api_minor = sev_guest->api_minor;
> -        info->build_id = sev_guest->build_id;
> -        info->policy = sev_guest->policy;
> -        info->state = sev_guest->state;
> -        info->handle = sev_guest->handle;
> +        if (sev_guest) {
> +            info->handle = sev_guest->handle;
> +        }

If we're not going to provide a value for 'handle', then
we should update the QAPI for this to mark the property
as optional, which would then require doing

  info->has_handle = true;

inside this 'if' block.

> +        info->api_major = sev_common->api_major;
> +        info->api_minor = sev_common->api_minor;
> +        info->build_id = sev_common->build_id;
> +        info->state = sev_common->state;
> +        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> +        info->policy =
> +            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> +                                               "policy", NULL);
>      }

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object
  2024-03-20  8:39 ` [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object Michael Roth
@ 2024-03-20 11:58   ` Daniel P. Berrangé
  2024-03-20 22:09       ` Michael Roth via
  2024-04-22 13:52   ` Markus Armbruster
  1 sibling, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 11:58 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata, Brijesh Singh

On Wed, Mar 20, 2024 at 03:39:18AM -0500, Michael Roth wrote:
> From: Brijesh Singh <brijesh.singh@amd.com>
> 
> SEV-SNP support relies on a different set of properties/state than the
> existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
> object, which can be used to configure an SEV-SNP guest. For example,
> a default-configured SEV-SNP guest with no additional information
> passed in for use with attestation:
> 
>   -object sev-snp-guest,id=sev0
> 
> or a fully-specified SEV-SNP guest where all spec-defined binary
> blobs are passed in as base64-encoded strings:
> 
>   -object sev-snp-guest,id=sev0, \
>     policy=0x30000, \
>     init-flags=0, \
>     id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
>     id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
>     auth-key-enabled=on, \
>     host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
>     guest-visible-workarounds=AA==, \
> 
> See the QAPI schema updates included in this patch for more usage
> details.
> 
> In some cases these blobs may be up to 4096 characters, but this is
> generally well below the default limit for linux hosts where
> command-line sizes are defined by the sysconf-configurable ARG_MAX
> value, which defaults to 2097152 characters for Ubuntu hosts, for
> example.
> 
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> Co-developed-by: Michael Roth <michael.roth@amd.com>
> Acked-by: Markus Armbruster <armbru@redhat.com> (for QAPI schema)
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  docs/system/i386/amd-memory-encryption.rst |  78 ++++++-
>  qapi/qom.json                              |  51 +++++
>  target/i386/sev.c                          | 241 +++++++++++++++++++++
>  target/i386/sev.h                          |   1 +
>  4 files changed, 369 insertions(+), 2 deletions(-)
> 

> +##
> +# @SevSnpGuestProperties:
> +#
> +# Properties for sev-snp-guest objects. Most of these are direct arguments
> +# for the KVM_SNP_* interfaces documented in the linux kernel source
> +# under Documentation/virt/kvm/amd-memory-encryption.rst, which are in
> +# turn closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
> +# documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).
> +#
> +# More usage information is also available in the QEMU source tree under
> +# docs/amd-memory-encryption.
> +#
> +# @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
> +#          defined in the SEV-SNP firmware ABI (default: 0x30000)
> +#
> +# @guest-visible-workarounds: 16-byte, base64-encoded blob to report
> +#                             hypervisor-defined workarounds, corresponding
> +#                             to the 'GOSVW' parameter of the
> +#                             SNP_LAUNCH_START command defined in the
> +#                             SEV-SNP firmware ABI (default: all-zero)
> +#
> +# @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
> +#            structure for the SNP_LAUNCH_FINISH command defined in the
> +#            SEV-SNP firmware ABI (default: all-zero)
> +#
> +# @id-auth: 4096-byte, base64-encoded blob to provide the 'ID Authentication
> +#           Information Structure' for the SNP_LAUNCH_FINISH command defined
> +#           in the SEV-SNP firmware ABI (default: all-zero)
> +#
> +# @auth-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY' field
> +#                    defined SEV-SNP firmware ABI (default: false)
> +#
> +# @host-data: 32-byte, base64-encoded, user-defined blob to provide to the
> +#             guest, as documented for the 'HOST_DATA' parameter of the
> +#             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
> +#             (default: all-zero)
> +#
> +# Since: 7.2

This will be 9.1 at the earliest now.

> +##
> +{ 'struct': 'SevSnpGuestProperties',
> +  'base': 'SevCommonProperties',
> +  'data': {
> +            '*policy': 'uint64',
> +            '*guest-visible-workarounds': 'str',
> +            '*id-block': 'str',
> +            '*id-auth': 'str',
> +            '*auth-key-enabled': 'bool',
> +            '*host-data': 'str' } }
> +

> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 63a220de5e..7e6dab642a 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -42,6 +42,7 @@
>  
>  OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
>  OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> +OBJECT_DECLARE_SIMPLE_TYPE(SevSnpGuestState, SEV_SNP_GUEST)
>  
>  struct SevCommonState {
>      X86ConfidentialGuest parent_obj;
> @@ -87,8 +88,22 @@ struct SevGuestState {
>      bool kernel_hashes;
>  };
>  
> +struct SevSnpGuestState {
> +    SevCommonState sev_common;
> +
> +    /* configuration parameters */
> +    char *guest_visible_workarounds;
> +    char *id_block;
> +    char *id_auth;
> +    char *host_data;
> +
> +    struct kvm_sev_snp_launch_start kvm_start_conf;
> +    struct kvm_sev_snp_launch_finish kvm_finish_conf;
> +};
> +
>  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
>  #define DEFAULT_SEV_DEVICE      "/dev/sev"
> +#define DEFAULT_SEV_SNP_POLICY  0x30000
>  
>  #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
>  typedef struct __attribute__((__packed__)) SevInfoBlock {
> @@ -1473,11 +1488,237 @@ static const TypeInfo sev_guest_info = {
>      .class_init = sev_guest_class_init,

> +
> +static char *
> +sev_snp_guest_get_guest_visible_workarounds(Object *obj, Error **errp)
> +{
> +    return g_strdup(SEV_SNP_GUEST(obj)->guest_visible_workarounds);
> +}
> +
> +static void
> +sev_snp_guest_set_guest_visible_workarounds(Object *obj, const char *value,
> +                                            Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
> +    g_autofree guchar *blob;
> +    gsize len;
> +
> +    if (sev_snp_guest->guest_visible_workarounds) {
> +        g_free(sev_snp_guest->guest_visible_workarounds);
> +    }

Redundant 'if' test - g_free is happy with NULL

> +
> +    /* store the base64 str so we don't need to re-encode in getter */
> +    sev_snp_guest->guest_visible_workarounds = g_strdup(value);
> +
> +    blob = qbase64_decode(sev_snp_guest->guest_visible_workarounds, -1, &len, errp);
> +    if (!blob) {
> +        return;
> +    }
> +
> +    if (len > sizeof(start->gosvw)) {

The QAPI docs said this property must be '16 bytes', so I'd
suggest we do a strict equality test, rather than min size
test to catch a wider set of mistakes.

> +        error_setg(errp, "parameter length of %lu exceeds max of %lu",
> +                   len, sizeof(start->gosvw));
> +        return;
> +    }
> +
> +    memcpy(start->gosvw, blob, len);
> +}
> +
> +static char *
> +sev_snp_guest_get_id_block(Object *obj, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    return g_strdup(sev_snp_guest->id_block);
> +}
> +
> +static void
> +sev_snp_guest_set_id_block(Object *obj, const char *value, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> +    gsize len;
> +
> +    if (sev_snp_guest->id_block) {
> +        g_free(sev_snp_guest->id_block);
> +        g_free((guchar *)finish->id_block_uaddr);
> +    }

Assuming 'id_block_uaddr' is also initialized to 0, when id_block
is NULL, then you can remove the 'if' conditional.

> +
> +    /* store the base64 str so we don't need to re-encode in getter */
> +    sev_snp_guest->id_block = g_strdup(value);
> +
> +    finish->id_block_uaddr =
> +        (uint64_t)qbase64_decode(sev_snp_guest->id_block, -1, &len, errp);
> +
> +    if (!finish->id_block_uaddr) {
> +        return;
> +    }
> +
> +    if (len > KVM_SEV_SNP_ID_BLOCK_SIZE) {

Again, lets do a strict equality test to match the documented
required size.

> +        error_setg(errp, "parameter length of %lu exceeds max of %u",
> +                   len, KVM_SEV_SNP_ID_BLOCK_SIZE);
> +        return;
> +    }
> +
> +    finish->id_block_en = (len) ? 1 : 0;
> +}
> +
> +static char *
> +sev_snp_guest_get_id_auth(Object *obj, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    return g_strdup(sev_snp_guest->id_auth);
> +}
> +
> +static void
> +sev_snp_guest_set_id_auth(Object *obj, const char *value, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> +    gsize len;
> +
> +    if (sev_snp_guest->id_auth) {
> +        g_free(sev_snp_guest->id_auth);
> +        g_free((guchar *)finish->id_auth_uaddr);
> +    }

Same probably redundant 'if'

> +
> +    /* store the base64 str so we don't need to re-encode in getter */
> +    sev_snp_guest->id_auth = g_strdup(value);
> +
> +    finish->id_auth_uaddr =
> +        (uint64_t)qbase64_decode(sev_snp_guest->id_auth, -1, &len, errp);
> +
> +    if (!finish->id_auth_uaddr) {
> +        return;
> +    }
> +
> +    if (len > KVM_SEV_SNP_ID_AUTH_SIZE) {

Equality test.

> +        error_setg(errp, "parameter length of %lu exceeds max of %u",
> +                   len, KVM_SEV_SNP_ID_AUTH_SIZE);
> +        return;
> +    }
> +}
> +
> +static bool
> +sev_snp_guest_get_auth_key_en(Object *obj, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    return !!sev_snp_guest->kvm_finish_conf.auth_key_en;
> +}
> +
> +static void
> +sev_snp_guest_set_auth_key_en(Object *obj, bool value, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    sev_snp_guest->kvm_finish_conf.auth_key_en = value;
> +}
> +
> +static char *
> +sev_snp_guest_get_host_data(Object *obj, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    return g_strdup(sev_snp_guest->host_data);
> +}
> +
> +static void
> +sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> +    g_autofree guchar *blob;
> +    gsize len;
> +
> +    if (sev_snp_guest->host_data) {
> +        g_free(sev_snp_guest->host_data);
> +    }

Redundant 'if'

> +
> +    /* store the base64 str so we don't need to re-encode in getter */
> +    sev_snp_guest->host_data = g_strdup(value);
> +
> +    blob = qbase64_decode(sev_snp_guest->host_data, -1, &len, errp);
> +
> +    if (!blob) {
> +        return;
> +    }
> +
> +    if (len > sizeof(finish->host_data)) {

Equality test

> +        error_setg(errp, "parameter length of %lu exceeds max of %lu",
> +                   len, sizeof(finish->host_data));
> +        return;
> +    }
> +
> +    memcpy(finish->host_data, blob, len);
> +}
> +
> +static void
> +sev_snp_guest_class_init(ObjectClass *oc, void *data)
> +{
> +    object_class_property_add(oc, "policy", "uint64",
> +                              sev_snp_guest_get_policy,
> +                              sev_snp_guest_set_policy, NULL, NULL);
> +    object_class_property_add_str(oc, "guest-visible-workarounds",
> +                                  sev_snp_guest_get_guest_visible_workarounds,
> +                                  sev_snp_guest_set_guest_visible_workarounds);
> +    object_class_property_add_str(oc, "id-block",
> +                                  sev_snp_guest_get_id_block,
> +                                  sev_snp_guest_set_id_block);
> +    object_class_property_add_str(oc, "id-auth",
> +                                  sev_snp_guest_get_id_auth,
> +                                  sev_snp_guest_set_id_auth);
> +    object_class_property_add_bool(oc, "auth-key-enabled",
> +                                   sev_snp_guest_get_auth_key_en,
> +                                   sev_snp_guest_set_auth_key_en);
> +    object_class_property_add_str(oc, "host-data",
> +                                  sev_snp_guest_get_host_data,
> +                                  sev_snp_guest_set_host_data);
> +}
> +
> +static void
> +sev_snp_guest_instance_init(Object *obj)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    /* default init/start/finish params for kvm */
> +    sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
> +}
> +
> +/* guest info specific to sev-snp */
> +static const TypeInfo sev_snp_guest_info = {
> +    .parent = TYPE_SEV_COMMON,
> +    .name = TYPE_SEV_SNP_GUEST,
> +    .instance_size = sizeof(SevSnpGuestState),
> +    .class_init = sev_snp_guest_class_init,
> +    .instance_init = sev_snp_guest_instance_init,
> +};

Use the OBJECT_DEFINE_TYPE_WITH_INTERFACES macro here.

> +
>  static void
>  sev_register_types(void)
>  {
>      type_register_static(&sev_common_info);
>      type_register_static(&sev_guest_info);
> +    type_register_static(&sev_snp_guest_info);
>  }
>  
>  type_init(sev_register_types);
> diff --git a/target/i386/sev.h b/target/i386/sev.h
> index 668374eef3..bedc667eeb 100644
> --- a/target/i386/sev.h
> +++ b/target/i386/sev.h
> @@ -22,6 +22,7 @@
>  
>  #define TYPE_SEV_COMMON "sev-common"
>  #define TYPE_SEV_GUEST "sev-guest"
> +#define TYPE_SEV_SNP_GUEST "sev-snp-guest"
>  
>  #define SEV_POLICY_NODBG        0x1
>  #define SEV_POLICY_NOKS         0x2
> -- 
> 2.25.1
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP
  2024-03-20  8:39 ` [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP Michael Roth
@ 2024-03-20 12:10   ` Daniel P. Berrangé
  2024-03-20 22:23       ` Michael Roth via
  2024-04-22 15:01   ` Markus Armbruster
  1 sibling, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:10 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:27AM -0500, Michael Roth wrote:
> Most of the current 'query-sev' command is relevant to both legacy
> SEV/SEV-ES guests and SEV-SNP guests, with 2 exceptions:
> 
>   - 'policy' is a 64-bit field for SEV-SNP, not 32-bit, and
>     the meaning of the bit positions has changed
>   - 'handle' is not relevant to SEV-SNP
> 
> To address this, this patch adds a new 'sev-type' field that can be
> used as a discriminator to select between SEV and SEV-SNP-specific
> fields/formats without breaking compatibility for existing management
> tools (so long as management tools that add support for launching
> SEV-SNP guest update their handling of query-sev appropriately).
> 
> The corresponding HMP command has also been fixed up similarly.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  qapi/misc-target.json | 71 ++++++++++++++++++++++++++++++++++---------
>  target/i386/sev.c     | 50 ++++++++++++++++++++----------
>  target/i386/sev.h     |  3 ++
>  3 files changed, 94 insertions(+), 30 deletions(-)
> 
> diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> index 4e0a6492a9..daceb85d95 100644
> --- a/qapi/misc-target.json
> +++ b/qapi/misc-target.json
> @@ -47,6 +47,49 @@
>             'send-update', 'receive-update' ],
>    'if': 'TARGET_I386' }
>  
> +##
> +# @SevGuestType:
> +#
> +# An enumeration indicating the type of SEV guest being run.
> +#
> +# @sev:     The guest is a legacy SEV or SEV-ES guest.
> +# @sev-snp: The guest is an SEV-SNP guest.
> +#
> +# Since: 6.2

Now 9.1 at the earliest.

> +##
> +{ 'enum': 'SevGuestType',
> +  'data': [ 'sev', 'sev-snp' ],
> +  'if': 'TARGET_I386' }
> +
> +##
> +# @SevGuestInfo:
> +#
> +# Information specific to legacy SEV/SEV-ES guests.
> +#
> +# @policy: SEV policy value
> +#
> +# @handle: SEV firmware handle
> +#
> +# Since: 2.12
> +##
> +{ 'struct': 'SevGuestInfo',
> +  'data': { 'policy': 'uint32',
> +            'handle': 'uint32' },
> +  'if': 'TARGET_I386' }
> +
> +##
> +# @SevSnpGuestInfo:
> +#
> +# Information specific to SEV-SNP guests.
> +#
> +# @snp-policy: SEV-SNP policy value
> +#
> +# Since: 6.2
> +##
> +{ 'struct': 'SevSnpGuestInfo',
> +  'data': { 'snp-policy': 'uint64' },
> +  'if': 'TARGET_I386' }

IMHO it can just be called 'policy' still, since
it is implicitly within a 'Snp' specific type.


> +
>  ##
>  # @SevInfo:
>  #
> @@ -60,25 +103,25 @@
>  #
>  # @build-id: SEV FW build id
>  #
> -# @policy: SEV policy value
> -#
>  # @state: SEV guest state
>  #
> -# @handle: SEV firmware handle
> +# @sev-type: Type of SEV guest being run
>  #
>  # Since: 2.12
>  ##
> -{ 'struct': 'SevInfo',
> -    'data': { 'enabled': 'bool',
> -              'api-major': 'uint8',
> -              'api-minor' : 'uint8',
> -              'build-id' : 'uint8',
> -              'policy' : 'uint32',
> -              'state' : 'SevState',
> -              'handle' : 'uint32'
> -            },
> -  'if': 'TARGET_I386'
> -}
> +{ 'union': 'SevInfo',
> +  'base': { 'enabled': 'bool',
> +            'api-major': 'uint8',
> +            'api-minor' : 'uint8',
> +            'build-id' : 'uint8',
> +            'state' : 'SevState',
> +            'sev-type' : 'SevGuestType' },
> +  'discriminator': 'sev-type',
> +  'data': {
> +      'sev': 'SevGuestInfo',
> +      'sev-snp': 'SevSnpGuestInfo' },
> +  'if': 'TARGET_I386' }
> +
>  
>  ##
>  # @query-sev:
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 43e6c0172f..b03d70a3d1 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -353,25 +353,27 @@ static SevInfo *sev_get_info(void)
>  {
>      SevInfo *info;
>      SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> -    SevGuestState *sev_guest =
> -        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> -                                             TYPE_SEV_GUEST);
>  
>      info = g_new0(SevInfo, 1);
>      info->enabled = sev_enabled();
>  
>      if (info->enabled) {
> -        if (sev_guest) {
> -            info->handle = sev_guest->handle;
> -        }
>          info->api_major = sev_common->api_major;
>          info->api_minor = sev_common->api_minor;
>          info->build_id = sev_common->build_id;
>          info->state = sev_common->state;
> -        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> -        info->policy =
> -            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> -                                               "policy", NULL);
> +
> +        if (sev_snp_enabled()) {
> +            info->sev_type = SEV_GUEST_TYPE_SEV_SNP;
> +            info->u.sev_snp.snp_policy =
> +                object_property_get_uint(OBJECT(sev_common), "policy", NULL);
> +        } else {
> +            info->sev_type = SEV_GUEST_TYPE_SEV;
> +            info->u.sev.handle = SEV_GUEST(sev_common)->handle;
> +            info->u.sev.policy =
> +                (uint32_t)object_property_get_uint(OBJECT(sev_common),
> +                                                   "policy", NULL);
> +        }
>      }

Ok, this is fixing the issues I reported earlier.

For 'policy' I do wonder if we really need to push it into the
type specific part of the union, as oppposed to having a common
'policy' field that is uint64 in size.

As mentioned earlier, on the wire there's no distinction between
int32/int64s, so there's no compat issues with changing it from
int32 to int64.

>  
>      return info;
> @@ -394,20 +396,36 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict)
>  {
>      SevInfo *info = sev_get_info();
>  
> -    if (info && info->enabled) {
> -        monitor_printf(mon, "handle: %d\n", info->handle);
> +    if (!info || !info->enabled) {
> +        monitor_printf(mon, "SEV is not enabled\n");
> +        goto out;
> +    }
> +
> +    if (sev_snp_enabled()) {
>          monitor_printf(mon, "state: %s\n", SevState_str(info->state));
>          monitor_printf(mon, "build: %d\n", info->build_id);
>          monitor_printf(mon, "api version: %d.%d\n",
>                         info->api_major, info->api_minor);
>          monitor_printf(mon, "debug: %s\n",
> -                       info->policy & SEV_POLICY_NODBG ? "off" : "on");
> -        monitor_printf(mon, "key-sharing: %s\n",
> -                       info->policy & SEV_POLICY_NOKS ? "off" : "on");
> +                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_DBG ? "on"
> +                                                                       : "off");
> +        monitor_printf(mon, "SMT allowed: %s\n",
> +                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_SMT ? "on"
> +                                                                       : "off");
>      } else {
> -        monitor_printf(mon, "SEV is not enabled\n");
> +        monitor_printf(mon, "handle: %d\n", info->u.sev.handle);
> +        monitor_printf(mon, "state: %s\n", SevState_str(info->state));
> +        monitor_printf(mon, "build: %d\n", info->build_id);
> +        monitor_printf(mon, "api version: %d.%d\n",
> +                       info->api_major, info->api_minor);

This set of three fields is identical in both branches, so the duplication
in printing it should be eliminated.

> +        monitor_printf(mon, "debug: %s\n",
> +                       info->u.sev.policy & SEV_POLICY_NODBG ? "off" : "on");
> +        monitor_printf(mon, "key-sharing: %s\n",
> +                       info->u.sev.policy & SEV_POLICY_NOKS ? "off" : "on");
>      }
> +    monitor_printf(mon, "SEV type: %s\n", SevGuestType_str(info->sev_type));

I'd say 'SEV type' should be printed  before everything else, since
that value is the discriminator for interpreting the other data that
is printed.

>  
> +out:
>      qapi_free_SevInfo(info);
>  }

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests
  2024-03-20  8:39 ` [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests Michael Roth
@ 2024-03-20 12:15   ` Daniel P. Berrangé
  2024-03-20 12:27     ` Daniel P. Berrangé
  0 siblings, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:15 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:28AM -0500, Michael Roth wrote:
> For SEV-SNP guests, launch measurement is queried from within the guest
> during attestation, so don't attempt to return it as part of
> query-sev-launch-measure.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  target/i386/sev.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index b03d70a3d1..0c8e4bdb4c 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -803,7 +803,9 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
>  
>  static char *sev_get_launch_measurement(void)
>  {
> -    SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
> +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> +    SevGuestState *sev_guest =
> +        (SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
>  
>      if (sev_guest &&
>          SEV_COMMON(sev_guest)->state >= SEV_STATE_LAUNCH_SECRET) {

The QAPI docs for query-sev-launch-measurement should be updated
to reflect that this command is only valid to call for SEV/SEV-ES,
not SNP.

The error reoprting in qmp_query_sev_launch_measure leaves a little
to be desired just giving a generic message

   "SEV launch measurement is not available"

I think that this sev_get_launch_measurement method should report
a more fine grained error, to distinguish

  * Unavailable because we're not a SEV/SEV-ES guest
  * Unavailable because the guest hasn't reached launch state

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 42/49] i386/sev: Add support for SNP CPUID validation
  2024-03-20  8:39 ` [PATCH v3 42/49] i386/sev: Add support for SNP CPUID validation Michael Roth
@ 2024-03-20 12:18   ` Daniel P. Berrangé
  0 siblings, 0 replies; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:18 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:38AM -0500, Michael Roth wrote:
> SEV-SNP firmware allows a special guest page to be populated with a
> table of guest CPUID values so that they can be validated through
> firmware before being loaded into encrypted guest memory where they can
> be used in place of hypervisor-provided values[1].
> 
> As part of SEV-SNP guest initialization, use this interface to validate
> the CPUID entries reported by KVM_GET_CPUID2 prior to initial guest
> start and populate the CPUID page reserved by OVMF with the resulting
> encrypted data.
> 
> [1] SEV SNP Firmware ABI Specification, Rev. 0.8, 8.13.2.6
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  target/i386/sev.c | 159 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 158 insertions(+), 1 deletion(-)
> 

> +static void
> +sev_snp_cpuid_report_mismatches(SnpCpuidInfo *old,
> +                                SnpCpuidInfo *new)
> +{
> +    size_t i;
> +
> +    if (old->count != new->count) {
> +        error_report("SEV-SNP: CPUID validation failed due to count mismatch, provided: %d, expected: %d",
> +                     old->count, new->count);
> +    }

Missing 'return' here, may result in array out of bounds on 'new->entries'
in the next loop

> +
> +    for (i = 0; i < old->count; i++) {
> +        SnpCpuidFunc *old_func, *new_func;
> +
> +        old_func = &old->entries[i];
> +        new_func = &new->entries[i];
> +
> +        if (memcmp(old_func, new_func, sizeof(SnpCpuidFunc))) {
> +            error_report("SEV-SNP: CPUID validation failed for function 0x%x, index: 0x%x.\n"
> +                         "provided: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n"
> +                         "expected: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x",
> +                         old_func->eax_in, old_func->ecx_in,
> +                         old_func->eax, old_func->ebx, old_func->ecx, old_func->edx,
> +                         new_func->eax, new_func->ebx, new_func->ecx, new_func->edx);
> +        }
> +    }
> +}
> +


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties
  2024-03-20  8:39 ` [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties Michael Roth
@ 2024-03-20 12:20   ` Daniel P. Berrangé
  2024-04-22 15:03     ` Markus Armbruster
  0 siblings, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:20 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata, Dov Murik

On Wed, Mar 20, 2024 at 03:39:39AM -0500, Michael Roth wrote:
> From: Dov Murik <dovmurik@linux.ibm.com>
> 
> In order to enable kernel-hashes for SNP, pull it from
> SevGuestProperties to its parent SevCommonProperties so
> it will be available for both SEV and SNP.
> 
> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  qapi/qom.json     | 14 +++++++-------
>  target/i386/sev.c | 44 ++++++++++++++++++--------------------------
>  2 files changed, 25 insertions(+), 33 deletions(-)

This change ought to be squashed into the earlier patch
that introduce sev-guest-common.

> 
> diff --git a/qapi/qom.json b/qapi/qom.json
> index 7ba778af91..ea8832a8c3 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -886,12 +886,17 @@
>  # @reduced-phys-bits: number of bits in physical addresses that become
>  #     unavailable when SEV is enabled
>  #
> +# @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
> +#     designated guest firmware page for measured boot with -kernel
> +#     (default: false) (since 6.2)
> +#
>  # Since: 2.12
>  ##
>  { 'struct': 'SevCommonProperties',
>    'data': { '*sev-device': 'str',
>              '*cbitpos': 'uint32',
> -            'reduced-phys-bits': 'uint32' } }
> +            'reduced-phys-bits': 'uint32',
> +            '*kernel-hashes': 'bool' } }
>  
>  ##
>  # @SevGuestProperties:
> @@ -906,10 +911,6 @@
>  #
>  # @handle: SEV firmware handle (default: 0)
>  #
> -# @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
> -#     designated guest firmware page for measured boot with -kernel
> -#     (default: false) (since 6.2)
> -#
>  # Since: 2.12
>  ##
>  { 'struct': 'SevGuestProperties',
> @@ -917,8 +918,7 @@
>    'data': { '*dh-cert-file': 'str',
>              '*session-file': 'str',
>              '*policy': 'uint32',
> -            '*handle': 'uint32',
> -            '*kernel-hashes': 'bool' } }
> +            '*handle': 'uint32' } }
>  
>  ##
>  # @SevSnpGuestProperties:
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index db888afb53..3187b3dee8 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -54,6 +54,7 @@ struct SevCommonState {
>      char *sev_device;
>      uint32_t cbitpos;
>      uint32_t reduced_phys_bits;
> +    bool kernel_hashes;
>  
>      /* runtime state */
>      uint8_t api_major;
> @@ -86,7 +87,6 @@ struct SevGuestState {
>      uint32_t policy;
>      char *dh_cert_file;
>      char *session_file;
> -    bool kernel_hashes;
>  };
>  
>  struct SevSnpGuestState {
> @@ -1696,16 +1696,12 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
>      MemTxAttrs attrs = { 0 };
>      bool ret = true;
>      SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> -    SevGuestState *sev_guest =
> -        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> -                                             TYPE_SEV_GUEST);
>  
>      /*
>       * Only add the kernel hashes if the sev-guest configuration explicitly
> -     * stated kernel-hashes=on. Currently only enabled for SEV/SEV-ES guests,
> -     * so check for TYPE_SEV_GUEST as well.
> +     * stated kernel-hashes=on.
>       */
> -    if (sev_guest && !sev_guest->kernel_hashes) {
> +    if (!sev_common->kernel_hashes) {
>          return false;
>      }
>  
> @@ -2037,6 +2033,16 @@ sev_common_set_sev_device(Object *obj, const char *value, Error **errp)
>      SEV_COMMON(obj)->sev_device = g_strdup(value);
>  }
>  
> +static bool sev_common_get_kernel_hashes(Object *obj, Error **errp)
> +{
> +    return SEV_COMMON(obj)->kernel_hashes;
> +}
> +
> +static void sev_common_set_kernel_hashes(Object *obj, bool value, Error **errp)
> +{
> +    SEV_COMMON(obj)->kernel_hashes = value;
> +}
> +
>  static void
>  sev_common_class_init(ObjectClass *oc, void *data)
>  {
> @@ -2051,6 +2057,11 @@ sev_common_class_init(ObjectClass *oc, void *data)
>                                    sev_common_set_sev_device);
>      object_class_property_set_description(oc, "sev-device",
>              "SEV device to use");
> +    object_class_property_add_bool(oc, "kernel-hashes",
> +                                   sev_common_get_kernel_hashes,
> +                                   sev_common_set_kernel_hashes);
> +    object_class_property_set_description(oc, "kernel-hashes",
> +            "add kernel hashes to guest firmware for measured Linux boot");
>  }
>  
>  static void
> @@ -2109,20 +2120,6 @@ sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
>      SEV_GUEST(obj)->session_file = g_strdup(value);
>  }
>  
> -static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
> -{
> -    SevGuestState *sev_guest = SEV_GUEST(obj);
> -
> -    return sev_guest->kernel_hashes;
> -}
> -
> -static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
> -{
> -    SevGuestState *sev = SEV_GUEST(obj);
> -
> -    sev->kernel_hashes = value;
> -}
> -
>  static void
>  sev_guest_class_init(ObjectClass *oc, void *data)
>  {
> @@ -2136,11 +2133,6 @@ sev_guest_class_init(ObjectClass *oc, void *data)
>                                    sev_guest_set_session_file);
>      object_class_property_set_description(oc, "session-file",
>              "guest owners session parameters (encoded with base64)");
> -    object_class_property_add_bool(oc, "kernel-hashes",
> -                                   sev_guest_get_kernel_hashes,
> -                                   sev_guest_set_kernel_hashes);
> -    object_class_property_set_description(oc, "kernel-hashes",
> -            "add kernel hashes to guest firmware for measured Linux boot");
>  }
>  
>  static void
> -- 
> 2.25.1
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
  2024-03-20  8:39 ` [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled Michael Roth
@ 2024-03-20 12:22   ` Daniel P. Berrangé
  2024-03-21 13:42       ` Michael Roth via
  0 siblings, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:22 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:43AM -0500, Michael Roth wrote:
> TODO: Brijesh as author, me as co-author (vice-versa depending)
>       drop flash handling? we only support BIOS now

A reminder that this commit message needs fixing.

> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  hw/i386/pc_sysfw.c            | 12 +++++++-----
>  hw/i386/x86.c                 |  2 +-
>  include/hw/i386/x86.h         |  2 +-
>  target/i386/sev-sysemu-stub.c |  2 +-
>  target/i386/sev.c             | 15 +++++++++++----
>  target/i386/sev.h             |  2 +-
>  6 files changed, 22 insertions(+), 13 deletions(-)

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests
  2024-03-20 12:15   ` Daniel P. Berrangé
@ 2024-03-20 12:27     ` Daniel P. Berrangé
  0 siblings, 0 replies; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:27 UTC (permalink / raw)
  To: Michael Roth, qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:15:00PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:28AM -0500, Michael Roth wrote:
> > For SEV-SNP guests, launch measurement is queried from within the guest
> > during attestation, so don't attempt to return it as part of
> > query-sev-launch-measure.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  target/i386/sev.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index b03d70a3d1..0c8e4bdb4c 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -803,7 +803,9 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
> >  
> >  static char *sev_get_launch_measurement(void)
> >  {
> > -    SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
> > +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> > +    SevGuestState *sev_guest =
> > +        (SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
> >  
> >      if (sev_guest &&
> >          SEV_COMMON(sev_guest)->state >= SEV_STATE_LAUNCH_SECRET) {
> 
> The QAPI docs for query-sev-launch-measurement should be updated
> to reflect that this command is only valid to call for SEV/SEV-ES,
> not SNP.

Also, the same question about whether query-sev-attestation-report
and sev-inject-launch-secret need updating to declare them SEV/SEV-ES
only, or if they are expected work with SNP too ?


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 28/49] i386/sev: Disable SMM for SNP
  2024-03-20  8:39 ` [PATCH v3 28/49] i386/sev: Disable SMM " Michael Roth
@ 2024-03-20 12:32   ` Daniel P. Berrangé
  0 siblings, 0 replies; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:32 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:24AM -0500, Michael Roth wrote:
> SNP does not support SMM.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  target/i386/sev.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index b06c796aae..134e8f7c22 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -881,6 +881,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>  {
>      SevCommonState *sev_common = SEV_COMMON(cgs);
>      MachineState *ms = MACHINE(qdev_get_machine());
> +    X86MachineState *x86ms = X86_MACHINE(ms);
>      char *devname;
>      int ret, fw_error, cmd;
>      uint32_t ebx;
> @@ -1003,6 +1004,13 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>  
>      if (sev_snp_enabled()) {
>          ms->require_guest_memfd = true;
> +
> +        if (x86ms->smm == ON_OFF_AUTO_AUTO) {
> +            x86ms->smm = ON_OFF_AUTO_OFF;
> +        } else if (x86ms->smm == ON_OFF_AUTO_ON) {
> +            error_report("SEV-SNP does not support SMM.");
> +            goto err;
> +        }
>      }

This method has a 'Error **errp' parameter, so you must use
error_setg, not error_report.



With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 29/49] i386/sev: Don't disable block discarding for SNP
  2024-03-20  8:39 ` [PATCH v3 29/49] i386/sev: Don't disable block discarding " Michael Roth
@ 2024-03-20 12:33   ` Daniel P. Berrangé
  0 siblings, 0 replies; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:33 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:25AM -0500, Michael Roth wrote:
> SEV/SEV-ES rely on pinned memory to back guest RAM so discarding
> isn't actually possible. With SNP, only guest_memfd pages are used
> for private guest memory, so discarding of shared memory is still
> possible, so only disable discard for SEV/SEV-ES.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  target/i386/sev.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 134e8f7c22..43e6c0172f 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -888,10 +888,18 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>      uint32_t host_cbitpos;
>      struct sev_user_data_status status = {};
>  
> -    ret = ram_block_discard_disable(true);
> -    if (ret) {
> -        error_report("%s: cannot disable RAM discard", __func__);
> -        return -1;
> +    /*
> +     * SEV/SEV-ES rely on pinned memory to back guest RAM so discarding
> +     * isn't actually possible. With SNP, only guest_memfd pages are used
> +     * for private guest memory, so discarding of shared memory is still
> +     * possible..
> +     */
> +    if (!sev_snp_enabled()) {
> +        ret = ram_block_discard_disable(true);
> +        if (ret) {
> +            error_report("%s: cannot disable RAM discard", __func__);
> +            return -1;
> +        }
>      }

Pre-existing code bug, but this method must use 'error_setg' to fill
the 'Error **errp' parameter.


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper
  2024-03-20  8:39 ` [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper Michael Roth
@ 2024-03-20 12:35   ` Daniel P. Berrangé
  2024-03-20 22:11       ` Michael Roth via
  0 siblings, 1 reply; 110+ messages in thread
From: Daniel P. Berrangé @ 2024-03-20 12:35 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:39:19AM -0500, Michael Roth wrote:
> Add a simple helper to check if the current guest type is SNP. Also have
> SNP-enabled imply that SEV-ES is enabled as well, and fix up any places
> where the sev_es_enabled() check is expecting a pure/non-SNP guest.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  target/i386/sev.c | 13 ++++++++++++-
>  target/i386/sev.h |  2 ++
>  2 files changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 7e6dab642a..2eb13ba639 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c


> @@ -933,7 +942,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
>                           __func__);
>              goto err;
>          }
> +    }
>  
> +    if (sev_es_enabled() && !sev_snp_enabled()) {
>          if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
>              error_report("%s: guest policy requires SEV-ES, but "
>                           "host SEV-ES support unavailable",

Opps, pre-existing bug here - this method has an 'Error **errp'
parameter, so should be using 'error_report'.

There are several more examples of this in this method that
predate your patch series.  Can you put a patch at the start
of this series that fixes them before introducing SNP.


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20  9:37   ` David Hildenbrand
@ 2024-03-20 12:43     ` Xiaoyao Li
  2024-03-20 12:58       ` David Hildenbrand
  2024-03-20 17:38     ` Michael Roth
  1 sibling, 1 reply; 110+ messages in thread
From: Xiaoyao Li @ 2024-03-20 12:43 UTC (permalink / raw)
  To: David Hildenbrand, Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Isaku Yamahata

On 3/20/2024 5:37 PM, David Hildenbrand wrote:
> On 20.03.24 09:39, Michael Roth wrote:
>> From: Xiaoyao Li <xiaoyao.li@intel.com>
>>
>> When memory page is converted from private to shared, the original
>> private memory is back'ed by guest_memfd. Introduce
>> ram_block_discard_guest_memfd_range() for discarding memory in
>> guest_memfd.
>>
>> Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
>> Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> "Co-developed-by"

Michael is using the patch from my TDX-QEMU v5 series[1]. I need to fix it.

>> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
>> Reviewed-by: David Hildenbrand <david@redhat.com>
> 
> Your SOB should go here.
> 
>> ---
>> Changes in v5:
>> - Collect Reviewed-by from David;
>>
>> Changes in in v4:
>> - Drop ram_block_convert_range() and open code its implementation in the
>>    next Patch.
>>
>> Signed-off-by: Michael Roth <michael.roth@amd.com>
> 
> I only received 3 patches from this series, and now I am confused: 
> changelog talks about v5 and this is "PATCH v3"

As above, because the guest_memfd patches in my TDX-QEMU v5[1] were 
directly picked for this series, so the change history says v5. They are 
needed by SEV-SNP as well.

I want to raise the question, how do we want to proceed with the guest 
memfd patches (patch 2 to 10 in [1])? Can they be merged separately 
before TDX/SNP patches?

> Please make sure to send at least the cover letter along (I might not 
> need the other 46 patches :D ).
> 


[1] 
https://lore.kernel.org/qemu-devel/20240229063726.610065-1-xiaoyao.li@intel.com/

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 13/49] [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size
  2024-03-20  8:39 ` [PATCH v3 13/49] [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size Michael Roth
@ 2024-03-20 12:46   ` Xiaoyao Li
  0 siblings, 0 replies; 110+ messages in thread
From: Xiaoyao Li @ 2024-03-20 12:46 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Isaku Yamahata

On 3/20/2024 4:39 PM, Michael Roth wrote:
> TODO: squash into "kvm: handle KVM_EXIT_MEMORY_FAULT"
> 
> qemu_host_page_size has been superseded by qemu_real_host_page_size()
> in newer QEMU, so update the patch accordingly.

I found it today as well when rebase to qemu v9.0.0-rc0.

Fix it locally, will show up on my next post of TDX-QEMU patches. :)

> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   accel/kvm/kvm-all.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> index 2fdc07a472..a9c19ab9a1 100644
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c
> @@ -2912,8 +2912,8 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
>       void *addr;
>       int ret = -1;
>   
> -    if (!QEMU_PTR_IS_ALIGNED(start, qemu_host_page_size) ||
> -        !QEMU_PTR_IS_ALIGNED(size, qemu_host_page_size)) {
> +    if (!QEMU_PTR_IS_ALIGNED(start, qemu_real_host_page_size()) ||
> +        !QEMU_PTR_IS_ALIGNED(size, qemu_real_host_page_size())) {
>           return -1;
>       }
>   
> @@ -2943,7 +2943,7 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
>           rb = qemu_ram_block_from_host(addr, false, &offset);
>   
>           if (to_private) {
> -            if (rb->page_size != qemu_host_page_size) {
> +            if (rb->page_size != qemu_real_host_page_size()) {
>                   /*
>                   * shared memory is back'ed by  hugetlb, which is supposed to be
>                   * pre-allocated and doesn't need to be discarded


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20 12:43     ` Xiaoyao Li
@ 2024-03-20 12:58       ` David Hildenbrand
  0 siblings, 0 replies; 110+ messages in thread
From: David Hildenbrand @ 2024-03-20 12:58 UTC (permalink / raw)
  To: Xiaoyao Li, Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Isaku Yamahata

On 20.03.24 13:43, Xiaoyao Li wrote:
> On 3/20/2024 5:37 PM, David Hildenbrand wrote:
>> On 20.03.24 09:39, Michael Roth wrote:
>>> From: Xiaoyao Li <xiaoyao.li@intel.com>
>>>
>>> When memory page is converted from private to shared, the original
>>> private memory is back'ed by guest_memfd. Introduce
>>> ram_block_discard_guest_memfd_range() for discarding memory in
>>> guest_memfd.
>>>
>>> Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
>>> Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>
>>
>> "Co-developed-by"
> 
> Michael is using the patch from my TDX-QEMU v5 series[1]. I need to fix it.
> 
>>> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
>>> Reviewed-by: David Hildenbrand <david@redhat.com>
>>
>> Your SOB should go here.
>>
>>> ---
>>> Changes in v5:
>>> - Collect Reviewed-by from David;
>>>
>>> Changes in in v4:
>>> - Drop ram_block_convert_range() and open code its implementation in the
>>>     next Patch.
>>>
>>> Signed-off-by: Michael Roth <michael.roth@amd.com>
>>
>> I only received 3 patches from this series, and now I am confused:
>> changelog talks about v5 and this is "PATCH v3"
> 
> As above, because the guest_memfd patches in my TDX-QEMU v5[1] were
> directly picked for this series, so the change history says v5. They are
> needed by SEV-SNP as well.

Thanks, I was missing the context without a cover letter. These comments 
here likely should be dropped here.

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 09/49] kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot
  2024-03-20  8:39 ` [PATCH v3 09/49] kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot Michael Roth
@ 2024-03-20 15:56   ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20 15:56 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Chao Peng

On 3/20/24 09:39, Michael Roth wrote:
> +    if (cap_user_memory2 == -1) {
> +        cap_user_memory2 = kvm_check_extension(s, KVM_CAP_USER_MEMORY2);
> +    }
> +
> +    if (!cap_user_memory2 && slot->guest_memfd >= 0) {
> +        error_report("%s, KVM doesn't support KVM_CAP_USER_MEMORY2,"
> +                     " which is required by guest memfd!", __func__);
> +        exit(1);
> +    }

It's easier and more robust (for error reporting purposes) to check both
KVM_CAP_GUEST_MEMFD and KVM_CAP_USER_MEMORY2 at once in the earlier
patches:

-    kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);
+    kvm_guest_memfd_supported =
+        kvm_check_extension(s, KVM_CAP_GUEST_MEMFD) &&
+        kvm_check_extension(s, KVM_CAP_USER_MEMORY2);

since KVM cannot really support guest_memfd if it cannot then use it
to create private memory slots.

And then, this one can be changed to also use kvm_guest_memfd_supported:

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index e83429b31eb..afcf6f87045 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -284,19 +284,8 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, boo
  {
      KVMState *s = kvm_state;
      struct kvm_userspace_memory_region2 mem;
-    static int cap_user_memory2 = -1;
      int ret;

-    if (cap_user_memory2 == -1) {
-        cap_user_memory2 = kvm_check_extension(s, KVM_CAP_USER_MEMORY2);
-    }
-
-    if (!cap_user_memory2 && slot->guest_memfd >= 0) {
-        error_report("%s, KVM doesn't support KVM_CAP_USER_MEMORY2,"
-                     " which is required by guest memfd!", __func__);
-        exit(1);
-    }
-
      mem.slot = slot->slot | (kml->as_id << 16);
      mem.guest_phys_addr = slot->start_addr;
      mem.userspace_addr = (unsigned long)slot->ram;
@@ -309,7 +298,7 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, boo
           * value. This is needed based on KVM commit 75d61fbc. */
          mem.memory_size = 0;

-        if (cap_user_memory2) {
+        if (kvm_guest_memfd_supported) {
              ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
          } else {
              ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
@@ -319,7 +308,7 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, boo
          }
      }
      mem.memory_size = slot->memory_size;
-    if (cap_user_memory2) {
+    if (kvm_guest_memfd_supported) {
          ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
      } else {
          ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
@@ -331,7 +320,7 @@ err:
                                mem.userspace_addr, mem.guest_memfd,
                                mem.guest_memfd_offset, ret);
      if (ret < 0) {
-        if (cap_user_memory2) {
+        if (kvm_guest_memfd_supported) {
                  error_report("%s: KVM_SET_USER_MEMORY_REGION2 failed, slot=%d,"
                          " start=0x%" PRIx64 ", size=0x%" PRIx64 ","
                          " flags=0x%" PRIx32 ", guest_memfd=%" PRId32 ","
@@ -501,6 +490,7 @@ static int kvm_mem_flags(MemoryRegion *mr)
          flags |= KVM_MEM_READONLY;
      }
      if (memory_region_has_guest_memfd(mr)) {
+        assert(kvm_guest_memfd_supported);
          flags |= KVM_MEM_GUEST_MEMFD;
      }
      return flags;


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 10/49] kvm: Introduce support for memory_attributes
  2024-03-20  8:39 ` [PATCH v3 10/49] kvm: Introduce support for memory_attributes Michael Roth
@ 2024-03-20 16:00   ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20 16:00 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:39, Michael Roth wrote:
> From: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> Introduce the helper functions to set the attributes of a range of
> memory to private or shared.
> 
> This is necessary to notify KVM the private/shared attribute of each gpa
> range. KVM needs the information to decide the GPA needs to be mapped at
> hva-based shared memory or guest_memfd based private memory.
> 
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> ---
> Changes in v4:
> - move the check of kvm_supported_memory_attributes to the common
>    kvm_set_memory_attributes(); (Wang Wei)
> - change warn_report() to error_report() in kvm_set_memory_attributes()
>    and drop the __func__; (Daniel)
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   accel/kvm/kvm-all.c  | 44 ++++++++++++++++++++++++++++++++++++++++++++
>   include/sysemu/kvm.h |  3 +++
>   2 files changed, 47 insertions(+)
> 
> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> index e83429b31e..df7a32735a 100644
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c
> @@ -92,6 +92,7 @@ static bool kvm_has_guest_debug;
>   static int kvm_sstep_flags;
>   static bool kvm_immediate_exit;
>   static bool kvm_guest_memfd_supported;
> +static uint64_t kvm_supported_memory_attributes;
>   static hwaddr kvm_max_slot_size = ~0;
>   
>   static const KVMCapabilityInfo kvm_required_capabilites[] = {
> @@ -1304,6 +1305,46 @@ void kvm_set_max_memslot_size(hwaddr max_slot_size)
>       kvm_max_slot_size = max_slot_size;
>   }
>   
> +static int kvm_set_memory_attributes(hwaddr start, hwaddr size, uint64_t attr)
> +{
> +    struct kvm_memory_attributes attrs;
> +    int r;
> +
> +    if (kvm_supported_memory_attributes == 0) {
> +        error_report("No memory attribute supported by KVM\n");
> +        return -EINVAL;
> +    }
> +
> +    if ((attr & kvm_supported_memory_attributes) != attr) {
> +        error_report("memory attribute 0x%lx not supported by KVM,"
> +                     " supported bits are 0x%lx\n",
> +                     attr, kvm_supported_memory_attributes);
> +        return -EINVAL;
> +    }

This should also be tested at the same time as kvm_guest_memfd_supported.

Paolo

> +    attrs.attributes = attr;
> +    attrs.address = start;
> +    attrs.size = size;
> +    attrs.flags = 0;
> +
> +    r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ATTRIBUTES, &attrs);
> +    if (r) {
> +        error_report("failed to set memory (0x%lx+%#zx) with attr 0x%lx error '%s'",
> +                     start, size, attr, strerror(errno));
> +    }
> +    return r;
> +}
> +
> +int kvm_set_memory_attributes_private(hwaddr start, hwaddr size)
> +{
> +    return kvm_set_memory_attributes(start, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
> +}
> +
> +int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size)
> +{
> +    return kvm_set_memory_attributes(start, size, 0);
> +}
> +
>   /* Called with KVMMemoryListener.slots_lock held */
>   static void kvm_set_phys_mem(KVMMemoryListener *kml,
>                                MemoryRegionSection *section, bool add)
> @@ -2439,6 +2480,9 @@ static int kvm_init(MachineState *ms)
>   
>       kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);
>   
> +    ret = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
> +    kvm_supported_memory_attributes = ret > 0 ? ret : 0;
> +
>       if (object_property_find(OBJECT(current_machine), "kvm-type")) {
>           g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
>                                                               "kvm-type",
> diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
> index b4913281e2..2cb3192509 100644
> --- a/include/sysemu/kvm.h
> +++ b/include/sysemu/kvm.h
> @@ -538,4 +538,7 @@ void kvm_mark_guest_state_protected(void);
>   bool kvm_hwpoisoned_mem(void);
>   
>   int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp);
> +
> +int kvm_set_memory_attributes_private(hwaddr start, hwaddr size);
> +int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size);
>   #endif

This suggests that


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled()
  2024-03-20  8:39 ` [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled() Michael Roth
@ 2024-03-20 16:26   ` Paolo Bonzini
  2024-03-20 19:47     ` Michael Roth
  0 siblings, 1 reply; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20 16:26 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 3/20/24 09:39, Michael Roth wrote:
> Some subsystems like VFIO might disable ram block discard for
> uncoordinated cases. Since kvm_convert_memory()/guest_memfd don't
> implement a RamDiscardManager handler to convey discard operations to
> various listeners like VFIO. > Because of this, sequences like the
> following can result due to stale IOMMU mappings:

Alternatively, should guest-memfd memory regions call 
ram_block_discard_require(true)?  This will prevent VFIO from operating, 
but it will avoid consuming twice the memory.

If desirable, guest-memfd support can be changed to implement an 
extension of RamDiscardManager that notifies about private/shared memory 
changes, and then guest-memfd would be able to support coordinated 
discard.  But I wonder if that's doable at all - how common are 
shared<->private flips, and is it feasible to change the IOMMU page 
tables every time?

If the real solution is SEV-TIO (which means essentially guest_memfd 
support for VFIO), calling ram_block_discard_require(true) may be the 
simplest stopgap solution.

Paolo

>    - convert page shared->private
>    - discard shared page
>    - convert page private->shared
>    - new page is allocated
>    - issue DMA operations against that shared page
> 
> Address this by taking ram_block_discard_is_enabled() into account when
> deciding whether or not to discard pages.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>   accel/kvm/kvm-all.c | 8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> index 53ce4f091e..6ae03c880f 100644
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c
> @@ -2962,10 +2962,14 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
>                   */
>                   return 0;
>               } else {
> -                ret = ram_block_discard_range(rb, offset, size);
> +                ret = ram_block_discard_is_disabled()
> +                      ? ram_block_discard_range(rb, offset, size)
> +                      : 0;
>               }
>           } else {
> -            ret = ram_block_discard_guest_memfd_range(rb, offset, size);
> +            ret = ram_block_discard_is_disabled()
> +                  ? ram_block_discard_guest_memfd_range(rb, offset, size)
> +                  : 0;
>           }
>       } else {
>           error_report("Convert non guest_memfd backed memory region "


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 06/49] RAMBlock: Add support of KVM private guest memfd
  2024-03-20  8:39 ` [PATCH v3 06/49] RAMBlock: Add support of KVM private guest memfd Michael Roth
@ 2024-03-20 16:38   ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20 16:38 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	David Hildenbrand

On 3/20/24 09:39, Michael Roth wrote:
> @@ -1842,6 +1842,17 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
>           }
>       }
>   
> +    if (kvm_enabled() && (new_block->flags & RAM_GUEST_MEMFD)) {
> +        assert(new_block->guest_memfd < 0);
> +
> +        new_block->guest_memfd = kvm_create_guest_memfd(new_block->max_length,
> +                                                        0, errp);
> +        if (new_block->guest_memfd < 0) {
> +            qemu_mutex_unlock_ramlist();
> +            return;
> +        }
> +    }
> +

This potentially leaks new_block->host.  This can be squashed into the patch:

diff --git a/system/physmem.c b/system/physmem.c
index 3a4a3f10d5a..0836aff190e 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -1810,6 +1810,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
      const bool shared = qemu_ram_is_shared(new_block);
      RAMBlock *block;
      RAMBlock *last_block = NULL;
+    bool free_on_error = false;
      ram_addr_t old_ram_size, new_ram_size;
      Error *err = NULL;
  
@@ -1839,6 +1841,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
                  return;
              }
              memory_try_enable_merging(new_block->host, new_block->max_length);
+            free_on_error = true;
          }
      }
  
@@ -1849,7 +1852,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
                                                          0, errp);
          if (new_block->guest_memfd < 0) {
              qemu_mutex_unlock_ramlist();
-            return;
+            goto out_free;
          }
      }
  
@@ -1901,6 +1904,13 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
          ram_block_notify_add(new_block->host, new_block->used_length,
                               new_block->max_length);
      }
+    return;
+
+out_free:
+    if (free_on_error) {
+        qemu_anon_ram_free(new_block->host, new_block->max_length);
+        new_block->host = NULL;
+    }
  }
  
  #ifdef CONFIG_POSIX


^ permalink raw reply related	[flat|nested] 110+ messages in thread

* Re: [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support
  2024-03-20  9:59 ` [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Paolo Bonzini
@ 2024-03-20 17:08   ` Paolo Bonzini
  2024-03-20 20:54     ` Xiaoyao Li
  0 siblings, 1 reply; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-20 17:08 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

[-- Attachment #1: Type: text/plain, Size: 613 bytes --]

On Wed, Mar 20, 2024 at 10:59 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
> I will now focus on reviewing patches 6-20.  This way we can prepare a
> common tree for SEV_INIT2/SNP/TDX, for both vendors to build upon.

Ok, the attachment is the delta that I have. The only major change is
requiring discard (thus effectively blocking VFIO support for
SEV-SNP/TDX, at least for now).

I will push it shortly to the same sevinit2 branch, and will post the
patches sometime soon.

Xiaoyao, you can use that branch too (it's on
https://gitlab.com/bonzini/qemu) as the basis for your TDX work.

Paolo

[-- Attachment #2: ff.patch --]
[-- Type: application/x-patch, Size: 7158 bytes --]

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20  9:37   ` David Hildenbrand
  2024-03-20 12:43     ` Xiaoyao Li
@ 2024-03-20 17:38     ` Michael Roth
  2024-03-20 20:04       ` David Hildenbrand
  1 sibling, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20 17:38 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 10:37:14AM +0100, David Hildenbrand wrote:
> On 20.03.24 09:39, Michael Roth wrote:
> > From: Xiaoyao Li <xiaoyao.li@intel.com>
> > 
> > When memory page is converted from private to shared, the original
> > private memory is back'ed by guest_memfd. Introduce
> > ram_block_discard_guest_memfd_range() for discarding memory in
> > guest_memfd.
> > 
> > Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
> > Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> "Co-developed-by"
> 
> > Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > Reviewed-by: David Hildenbrand <david@redhat.com>
> 
> Your SOB should go here.
> 
> > ---
> > Changes in v5:
> > - Collect Reviewed-by from David;
> > 
> > Changes in in v4:
> > - Drop ram_block_convert_range() and open code its implementation in the
> >    next Patch.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> 
> I only received 3 patches from this series, and now I am confused: changelog
> talks about v5 and this is "PATCH v3"
> 
> Please make sure to send at least the cover letter along (I might not need
> the other 46 patches :D ).

Sorry for the confusion, you got auto-Cc'd by git, which is good, but
not sure there's a good way to make sure everyone gets a copy of the
cover letter. I could see how it would help useful to potential
reviewers though. I'll try to come up with a script for it and take that
approach in the future.

-Mike

> 
> -- 
> Cheers,
> 
> David / dhildenb
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header
  2024-03-20  8:39 ` [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header Michael Roth
@ 2024-03-20 17:55   ` Isaku Yamahata
  2024-03-20 22:35     ` Michael Roth
  0 siblings, 1 reply; 110+ messages in thread
From: Isaku Yamahata @ 2024-03-20 17:55 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh, isaku.yamahata

On Wed, Mar 20, 2024 at 03:39:36AM -0500,
Michael Roth <michael.roth@amd.com> wrote:

> From: Brijesh Singh <brijesh.singh@amd.com>
> 
> A recent version of OVMF expanded the reset vector GUID list to add
> SEV-specific metadata GUID. The SEV metadata describes the reserved
> memory regions such as the secrets and CPUID page used during the SEV-SNP
> guest launch.
> 
> The pc_system_get_ovmf_sev_metadata_ptr() is used to retieve the SEV
> metadata pointer from the OVMF GUID list.
> 
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  hw/i386/pc_sysfw_ovmf.c | 33 +++++++++++++++++++++++++++++++++
>  include/hw/i386/pc.h    | 26 ++++++++++++++++++++++++++
>  2 files changed, 59 insertions(+)
> 
> diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c
> index 07a4c267fa..32efa34614 100644
> --- a/hw/i386/pc_sysfw_ovmf.c
> +++ b/hw/i386/pc_sysfw_ovmf.c
> @@ -35,6 +35,31 @@ static const int bytes_after_table_footer = 32;
>  static bool ovmf_flash_parsed;
>  static uint8_t *ovmf_table;
>  static int ovmf_table_len;
> +static OvmfSevMetadata *ovmf_sev_metadata_table;
> +
> +#define OVMF_SEV_META_DATA_GUID "dc886566-984a-4798-A75e-5585a7bf67cc"
> +typedef struct __attribute__((__packed__)) OvmfSevMetadataOffset {
> +    uint32_t offset;
> +} OvmfSevMetadataOffset;
> +
> +static void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
> +{
> +    OvmfSevMetadata     *metadata;
> +    OvmfSevMetadataOffset  *data;
> +
> +    if (!pc_system_ovmf_table_find(OVMF_SEV_META_DATA_GUID, (uint8_t **)&data,
> +                                   NULL)) {
> +        return;
> +    }
> +
> +    metadata = (OvmfSevMetadata *)(flash_ptr + flash_size - data->offset);
> +    if (memcmp(metadata->signature, "ASEV", 4) != 0) {
> +        return;
> +    }
> +
> +    ovmf_sev_metadata_table = g_malloc(metadata->len);
> +    memcpy(ovmf_sev_metadata_table, metadata, metadata->len);
> +}
>  
>  void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
>  {
> @@ -90,6 +115,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
>       */
>      memcpy(ovmf_table, ptr - tot_len, tot_len);
>      ovmf_table += tot_len;
> +
> +    /* Copy the SEV metadata table (if exist) */
> +    pc_system_parse_sev_metadata(flash_ptr, flash_size);
>  }

Can we move this call to x86_firmware_configure() @ pc_sysfw.c, and move sev
specific bits to somewhere to sev specific file?  We don't have to parse sev
metadata for non-SEV case, right?

We don't have to touch common ovmf file. It also will be consistent with tdx
case.  TDX patch series adds tdx_parse_tdvf() to x86_firmware_configure().

thanks,

>  
>  /**
> @@ -159,3 +187,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
>      }
>      return false;
>  }
> +
> +OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void)
> +{
> +    return ovmf_sev_metadata_table;
> +}
> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index fb1d4106e5..df9a61540d 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -163,6 +163,32 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
>  #define PCI_HOST_ABOVE_4G_MEM_SIZE     "above-4g-mem-size"
>  #define PCI_HOST_PROP_SMM_RANGES       "smm-ranges"
>  
> +typedef enum {
> +    SEV_DESC_TYPE_UNDEF,
> +    /* The section contains the region that must be validated by the VMM. */
> +    SEV_DESC_TYPE_SNP_SEC_MEM,
> +    /* The section contains the SNP secrets page */
> +    SEV_DESC_TYPE_SNP_SECRETS,
> +    /* The section contains address that can be used as a CPUID page */
> +    SEV_DESC_TYPE_CPUID,
> +
> +} ovmf_sev_metadata_desc_type;
> +
> +typedef struct __attribute__((__packed__)) OvmfSevMetadataDesc {
> +    uint32_t base;
> +    uint32_t len;
> +    ovmf_sev_metadata_desc_type type;
> +} OvmfSevMetadataDesc;
> +
> +typedef struct __attribute__((__packed__)) OvmfSevMetadata {
> +    uint8_t signature[4];
> +    uint32_t len;
> +    uint32_t version;
> +    uint32_t num_desc;
> +    OvmfSevMetadataDesc descs[];
> +} OvmfSevMetadata;
> +
> +OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void);
>  
>  void pc_pci_as_mapping_init(MemoryRegion *system_memory,
>                              MemoryRegion *pci_address_space);
> -- 
> 2.25.1
> 
> 

-- 
Isaku Yamahata <isaku.yamahata@intel.com>

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs
  2024-03-20  8:39 ` [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs Michael Roth
@ 2024-03-20 18:12   ` Isaku Yamahata
  2024-03-28  0:45     ` Xiaoyao Li
  0 siblings, 1 reply; 110+ messages in thread
From: Isaku Yamahata @ 2024-03-20 18:12 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	isaku.yamahata

On Wed, Mar 20, 2024 at 03:39:44AM -0500,
Michael Roth <michael.roth@amd.com> wrote:

> TODO: make this SNP-specific if TDX disables legacy ROMs in general

TDX disables pc.rom, not disable isa-bios. IIRC, TDX doesn't need pc pflash.
Xiaoyao can chime in.

Thanks,

> 
> Current SNP guest kernels will attempt to access these regions with
> with C-bit set, so guest_memfd is needed to handle that. Otherwise,
> kvm_convert_memory() will fail when the guest kernel tries to access it
> and QEMU attempts to call KVM_SET_MEMORY_ATTRIBUTES to set these ranges
> to private.
> 
> Whether guests should actually try to access ROM regions in this way (or
> need to deal with legacy ROM regions at all), is a separate issue to be
> addressed on kernel side, but current SNP guest kernels will exhibit
> this behavior and so this handling is needed to allow QEMU to continue
> running existing SNP guest kernels.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  hw/i386/pc.c       | 13 +++++++++----
>  hw/i386/pc_sysfw.c | 13 ++++++++++---
>  2 files changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index feb7a93083..5feaeb43ee 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -1011,10 +1011,15 @@ void pc_memory_init(PCMachineState *pcms,
>      pc_system_firmware_init(pcms, rom_memory);
>  
>      option_rom_mr = g_malloc(sizeof(*option_rom_mr));
> -    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
> -                           &error_fatal);
> -    if (pcmc->pci_enabled) {
> -        memory_region_set_readonly(option_rom_mr, true);
> +    if (machine_require_guest_memfd(machine)) {
> +        memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
> +                                           PC_ROM_SIZE, &error_fatal);
> +    } else {
> +        memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
> +                               &error_fatal);
> +        if (pcmc->pci_enabled) {
> +            memory_region_set_readonly(option_rom_mr, true);
> +        }
>      }
>      memory_region_add_subregion_overlap(rom_memory,
>                                          PC_ROM_MIN_VGA,
> diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
> index 9dbb3f7337..850f86edd4 100644
> --- a/hw/i386/pc_sysfw.c
> +++ b/hw/i386/pc_sysfw.c
> @@ -54,8 +54,13 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
>      /* map the last 128KB of the BIOS in ISA space */
>      isa_bios_size = MIN(flash_size, 128 * KiB);
>      isa_bios = g_malloc(sizeof(*isa_bios));
> -    memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
> -                           &error_fatal);
> +    if (machine_require_guest_memfd(current_machine)) {
> +        memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
> +                                           isa_bios_size, &error_fatal);
> +    } else {
> +        memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
> +                               &error_fatal);
> +    }
>      memory_region_add_subregion_overlap(rom_memory,
>                                          0x100000 - isa_bios_size,
>                                          isa_bios,
> @@ -68,7 +73,9 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
>             ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
>             isa_bios_size);
>  
> -    memory_region_set_readonly(isa_bios, true);
> +    if (!machine_require_guest_memfd(current_machine)) {
> +        memory_region_set_readonly(isa_bios, true);
> +    }
>  }
>  
>  static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
> -- 
> 2.25.1
> 
> 

-- 
Isaku Yamahata <isaku.yamahata@intel.com>

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled()
  2024-03-20 16:26   ` Paolo Bonzini
@ 2024-03-20 19:47     ` Michael Roth
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 19:47 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 05:26:00PM +0100, Paolo Bonzini wrote:
> On 3/20/24 09:39, Michael Roth wrote:
> > Some subsystems like VFIO might disable ram block discard for
> > uncoordinated cases. Since kvm_convert_memory()/guest_memfd don't
> > implement a RamDiscardManager handler to convey discard operations to
> > various listeners like VFIO. > Because of this, sequences like the
> > following can result due to stale IOMMU mappings:
> 
> Alternatively, should guest-memfd memory regions call
> ram_block_discard_require(true)?  This will prevent VFIO from operating, but
> it will avoid consuming twice the memory.
> 
> If desirable, guest-memfd support can be changed to implement an extension
> of RamDiscardManager that notifies about private/shared memory changes, and
> then guest-memfd would be able to support coordinated discard.  But I wonder

In an earlier/internal version of the SNP+gmem patches (when there was still
a dedicated hostmem-memfd-private backend for restrictedmem/gmem), we had a
rough implementation of RamDiscardManager that did this:

  https://github.com/AMDESE/qemu/blob/snp-latest-gmem-v12/backends/hostmem-memfd-private.c#L75

Now that gmem handling is mostly done transparently to the HostMem
backend in use I'm not sure what the right place would be to implement
something similar, but maybe it can be done in a more generic way.

There were some notable downsides to that approach though that I'm a
little hazy on now, but I think they were both kernel limitations:

  - VFIO seemed to have some limitation where it expects that the
    DMA mapping for a particular iova will be unmapped/mapped with
    the same granularity, but for an SNP guest there's no guarantee
    that if you flip a 2MB page from shared->private, that it won't
    later be flipped private->shared again but this time with a 4K
    granularity/sub-range. I think the current code still treats
    this as an -EINVAL case. So we end up needing to do everything
    with 4K granularity, which I *think* results in 4K IOMMU page
    table mappings, but I'd need to confirm.

  - VFIO doesn't seem to be optimized for this sort of use case and
    generally expects a much larger granularity and defaults to 64K
    max DMA entries, so for a 16GB guest you need to configure VFIO
    with something like:

      vfio_iommu_type1.dma_entry_limit=4194304

    I didn't see any reason to suggest that's problematic but it
    makes we wonder if there's other stuff me might run into.

> if that's doable at all - how common are shared<->private flips, and is it
> feasible to change the IOMMU page tables every time?

- For OVMF+guest kernel that don't do lazy-acceptance:

  I think the bulk of the flipping is during boot where most of
  shared GPA ranges get converted to private memory, and then
  later on the guest kernel switches memory back to to shared
  for stuff like SWIOTLB, and after that I think DMA mappings
  would be fairly stable.

- For OVMF+guest kernel that support lazy-acceptance:

  The first 4GB get converted to private, and the rest remains
  shared until guest kernel needs to allocate memory from it.
  I'm not sure if SWIOTLB allocation is optimized to avoid
  unecessary flipping if it's allocated from that pool of
  still-shared memory, but normal/private allocations will
  result in a steady stream of DMA unmap operations as the
  guest faults in its working set.

> 
> If the real solution is SEV-TIO (which means essentially guest_memfd support
> for VFIO), calling ram_block_discard_require(true) may be the simplest
> stopgap solution.

Hard to guess how cloud vendors will feel about waiting for trusted I/O.
It does make sense in the context of CoCo to expect them to wait, but
would be nice to have a stop-gap to offer like disabling discard, since
it has minimal requirements on the QEMU/VFIO side and might be enough to
get early adopters up and running at least.

All that said, if you think something based around RamDiscardManager
seems tenable given all above then we can re-visit that approach as well.

-Mike

> 
> Paolo
> 
> >    - convert page shared->private
> >    - discard shared page
> >    - convert page private->shared
> >    - new page is allocated
> >    - issue DMA operations against that shared page
> > 
> > Address this by taking ram_block_discard_is_enabled() into account when
> > deciding whether or not to discard pages.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >   accel/kvm/kvm-all.c | 8 ++++++--
> >   1 file changed, 6 insertions(+), 2 deletions(-)
> > 
> > diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> > index 53ce4f091e..6ae03c880f 100644
> > --- a/accel/kvm/kvm-all.c
> > +++ b/accel/kvm/kvm-all.c
> > @@ -2962,10 +2962,14 @@ static int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
> >                   */
> >                   return 0;
> >               } else {
> > -                ret = ram_block_discard_range(rb, offset, size);
> > +                ret = ram_block_discard_is_disabled()
> > +                      ? ram_block_discard_range(rb, offset, size)
> > +                      : 0;
> >               }
> >           } else {
> > -            ret = ram_block_discard_guest_memfd_range(rb, offset, size);
> > +            ret = ram_block_discard_is_disabled()
> > +                  ? ram_block_discard_guest_memfd_range(rb, offset, size)
> > +                  : 0;
> >           }
> >       } else {
> >           error_report("Convert non guest_memfd backed memory region "
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20 17:38     ` Michael Roth
@ 2024-03-20 20:04       ` David Hildenbrand
  2024-03-21 20:24         ` Michael Roth
  0 siblings, 1 reply; 110+ messages in thread
From: David Hildenbrand @ 2024-03-20 20:04 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P. Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On 20.03.24 18:38, Michael Roth wrote:
> On Wed, Mar 20, 2024 at 10:37:14AM +0100, David Hildenbrand wrote:
>> On 20.03.24 09:39, Michael Roth wrote:
>>> From: Xiaoyao Li <xiaoyao.li@intel.com>
>>>
>>> When memory page is converted from private to shared, the original
>>> private memory is back'ed by guest_memfd. Introduce
>>> ram_block_discard_guest_memfd_range() for discarding memory in
>>> guest_memfd.
>>>
>>> Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
>>> Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>
>>
>> "Co-developed-by"
>>
>>> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
>>> Reviewed-by: David Hildenbrand <david@redhat.com>
>>
>> Your SOB should go here.
>>
>>> ---
>>> Changes in v5:
>>> - Collect Reviewed-by from David;
>>>
>>> Changes in in v4:
>>> - Drop ram_block_convert_range() and open code its implementation in the
>>>     next Patch.
>>>
>>> Signed-off-by: Michael Roth <michael.roth@amd.com>
>>
>> I only received 3 patches from this series, and now I am confused: changelog
>> talks about v5 and this is "PATCH v3"
>>
>> Please make sure to send at least the cover letter along (I might not need
>> the other 46 patches :D ).
> 
> Sorry for the confusion, you got auto-Cc'd by git, which is good, but
> not sure there's a good way to make sure everyone gets a copy of the
> cover letter. I could see how it would help useful to potential
> reviewers though. I'll try to come up with a script for it and take that
> approach in the future.

A script shared with me in the past to achieve that in most cases:

$ cat cc-cmd.sh
#!/bin/bash

if [[ $1 == *gitsendemail.msg* || $1 == *cover-letter* ]]; then
         grep ': .* <.*@.*>' -h *.patch | sed 's/^.*: //' | sort | uniq
fi


And attach to "git send-email ... *.patch": --cc-cmd=./cc-cmd.sh

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support
  2024-03-20 17:08   ` Paolo Bonzini
@ 2024-03-20 20:54     ` Xiaoyao Li
  0 siblings, 0 replies; 110+ messages in thread
From: Xiaoyao Li @ 2024-03-20 20:54 UTC (permalink / raw)
  To: Paolo Bonzini, Michael Roth, qemu-devel
  Cc: kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Isaku Yamahata

On 3/21/2024 1:08 AM, Paolo Bonzini wrote:
> On Wed, Mar 20, 2024 at 10:59 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
>> I will now focus on reviewing patches 6-20.  This way we can prepare a
>> common tree for SEV_INIT2/SNP/TDX, for both vendors to build upon.
> 
> Ok, the attachment is the delta that I have. The only major change is
> requiring discard (thus effectively blocking VFIO support for
> SEV-SNP/TDX, at least for now).
> 
> I will push it shortly to the same sevinit2 branch, and will post the
> patches sometime soon.
> 
> Xiaoyao, you can use that branch too (it's on
> https://gitlab.com/bonzini/qemu) as the basis for your TDX work.

Sure, it's really a good news for us.

BTW, there are some minor comments on guest_memfd patches of my v5 
post[*]. Could you please resolve them it your branch?

[*] 
https://lore.kernel.org/qemu-devel/20240229063726.610065-1-xiaoyao.li@intel.com/

> Paolo


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20 11:44   ` Daniel P. Berrangé
@ 2024-03-20 21:36       ` Michael Roth via
  2024-03-27 15:22     ` Markus Armbruster
  1 sibling, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 21:36 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 11:44:13AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
> > Currently all SEV/SEV-ES functionality is managed through a single
> > 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> > same approach won't work well since some of the properties/state
> > managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> > rely on a new QOM type with its own set of properties/state.
> > 
> > To prepare for this, this patch moves common state into an abstract
> > 'sev-common' parent type to encapsulate properties/state that are
> > common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> > properties/state in the current 'sev-guest' type. This should not
> > affect current behavior or command-line options.
> > 
> > As part of this patch, some related changes are also made:
> > 
> >   - a static 'sev_guest' variable is currently used to keep track of
> >     the 'sev-guest' instance. SEV-SNP would similarly introduce an
> >     'sev_snp_guest' static variable. But these instances are now
> >     available via qdev_get_machine()->cgs, so switch to using that
> >     instead and drop the static variable.
> > 
> >   - 'sev_guest' is currently used as the name for the static variable
> >     holding a pointer to the 'sev-guest' instance. Re-purpose the name
> >     as a local variable referring the 'sev-guest' instance, and use
> >     that consistently throughout the code so it can be easily
> >     distinguished from sev-common/sev-snp-guest instances.
> > 
> >   - 'sev' is generally used as the name for local variables holding a
> >     pointer to the 'sev-guest' instance. In cases where that now points
> >     to common state, use the name 'sev_common'; in cases where that now
> >     points to state specific to 'sev-guest' instance, use the name
> >     'sev_guest'
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  qapi/qom.json     |  32 ++--
> >  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
> >  target/i386/sev.h |   3 +
> >  3 files changed, 281 insertions(+), 211 deletions(-)
> > 
> > diff --git a/qapi/qom.json b/qapi/qom.json
> > index baae3a183f..66b5781ca6 100644
> > --- a/qapi/qom.json
> > +++ b/qapi/qom.json
> > @@ -875,12 +875,29 @@
> >    'data': { '*filename': 'str' } }
> >  
> >  ##
> > -# @SevGuestProperties:
> > +# @SevCommonProperties:
> >  #
> > -# Properties for sev-guest objects.
> > +# Properties common to objects that are derivatives of sev-common.
> >  #
> >  # @sev-device: SEV device to use (default: "/dev/sev")
> >  #
> > +# @cbitpos: C-bit location in page table entry (default: 0)
> > +#
> > +# @reduced-phys-bits: number of bits in physical addresses that become
> > +#     unavailable when SEV is enabled
> > +#
> > +# Since: 2.12
> 
> Not quite sure what we've done in this scenario before.
> It feels wierd to use '2.12' for the new base type, even
> though in effect the properties all existed since 2.12 in
> the sub-class.
> 
> Perhaps 'Since: 9.1' for the type, but 'Since: 2.12' for the
> properties, along with an explanatory comment about stuff
> moving into the new base type ?
> 
> Markus, opinions ?

My thinking is that the internal details are less important than what's
actually exposed to users in the form of command-line options/etc. So
in that context the "Since: 2.12" sort of becomes the "default" for when
those properties were first made available to users, and then anything we
add after would then get special treatment with the per-property
versioning. But no issue with taking a different approach if that's
preferred.

> 
> > +##
> > +{ 'struct': 'SevCommonProperties',
> > +  'data': { '*sev-device': 'str',
> > +            '*cbitpos': 'uint32',
> > +            'reduced-phys-bits': 'uint32' } }
> > +
> > +##
> > +# @SevGuestProperties:
> > +#
> > +# Properties for sev-guest objects.
> > +#
> >  # @dh-cert-file: guest owners DH certificate (encoded with base64)
> >  #
> >  # @session-file: guest owners session parameters (encoded with base64)
> > @@ -889,11 +906,6 @@
> >  #
> >  # @handle: SEV firmware handle (default: 0)
> >  #
> > -# @cbitpos: C-bit location in page table entry (default: 0)
> > -#
> > -# @reduced-phys-bits: number of bits in physical addresses that become
> > -#     unavailable when SEV is enabled
> > -#
> >  # @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
> >  #     designated guest firmware page for measured boot with -kernel
> >  #     (default: false) (since 6.2)
> > @@ -901,13 +913,11 @@
> >  # Since: 2.12
> >  ##
> >  { 'struct': 'SevGuestProperties',
> > -  'data': { '*sev-device': 'str',
> > -            '*dh-cert-file': 'str',
> > +  'base': 'SevCommonProperties',
> > +  'data': { '*dh-cert-file': 'str',
> >              '*session-file': 'str',
> >              '*policy': 'uint32',
> >              '*handle': 'uint32',
> > -            '*cbitpos': 'uint32',
> > -            'reduced-phys-bits': 'uint32',
> >              '*kernel-hashes': 'bool' } }
> >  
> >  ##
> 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 9dab4060b8..63a220de5e 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -40,48 +40,53 @@
> >  #include "hw/i386/pc.h"
> >  #include "exec/address-spaces.h"
> >  
> > -#define TYPE_SEV_GUEST "sev-guest"
> > +OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
> >  OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> >  
> > -
> > -/**
> > - * SevGuestState:
> > - *
> > - * The SevGuestState object is used for creating and managing a SEV
> > - * guest.
> > - *
> > - * # $QEMU \
> > - *         -object sev-guest,id=sev0 \
> > - *         -machine ...,memory-encryption=sev0
> > - */
> > -struct SevGuestState {
> > +struct SevCommonState {
> >      X86ConfidentialGuest parent_obj;
> >  
> >      int kvm_type;
> >  
> >      /* configuration parameters */
> >      char *sev_device;
> > -    uint32_t policy;
> > -    char *dh_cert_file;
> > -    char *session_file;
> >      uint32_t cbitpos;
> >      uint32_t reduced_phys_bits;
> > -    bool kernel_hashes;
> >  
> >      /* runtime state */
> > -    uint32_t handle;
> >      uint8_t api_major;
> >      uint8_t api_minor;
> >      uint8_t build_id;
> >      int sev_fd;
> >      SevState state;
> > -    gchar *measurement;
> >  
> >      uint32_t reset_cs;
> >      uint32_t reset_ip;
> >      bool reset_data_valid;
> >  };
> >  
> > +/**
> > + * SevGuestState:
> > + *
> > + * The SevGuestState object is used for creating and managing a SEV
> > + * guest.
> > + *
> > + * # $QEMU \
> > + *         -object sev-guest,id=sev0 \
> > + *         -machine ...,memory-encryption=sev0
> > + */
> > +struct SevGuestState {
> > +    SevCommonState sev_common;
> > +    gchar *measurement;
> > +
> > +    /* configuration parameters */
> > +    uint32_t handle;
> > +    uint32_t policy;
> > +    char *dh_cert_file;
> > +    char *session_file;
> > +    bool kernel_hashes;
> > +};
> > +
> >  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
> >  #define DEFAULT_SEV_DEVICE      "/dev/sev"
> >  
> > @@ -127,7 +132,6 @@ typedef struct QEMU_PACKED PaddedSevHashTable {
> >  
> >  QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
> >  
> > -static SevGuestState *sev_guest;
> >  static Error *sev_mig_blocker;
> >  
> >  static const char *const sev_fw_errlist[] = {
> > @@ -208,21 +212,21 @@ fw_error_to_str(int code)
> >  }
> >  
> >  static bool
> > -sev_check_state(const SevGuestState *sev, SevState state)
> > +sev_check_state(const SevCommonState *sev_common, SevState state)
> >  {
> > -    assert(sev);
> > -    return sev->state == state ? true : false;
> > +    assert(sev_common);
> > +    return sev_common->state == state ? true : false;
> >  }
> >  
> >  static void
> > -sev_set_guest_state(SevGuestState *sev, SevState new_state)
> > +sev_set_guest_state(SevCommonState *sev_common, SevState new_state)
> >  {
> >      assert(new_state < SEV_STATE__MAX);
> > -    assert(sev);
> > +    assert(sev_common);
> >  
> > -    trace_kvm_sev_change_state(SevState_str(sev->state),
> > +    trace_kvm_sev_change_state(SevState_str(sev_common->state),
> >                                 SevState_str(new_state));
> > -    sev->state = new_state;
> > +    sev_common->state = new_state;
> >  }
> >  
> >  static void
> > @@ -289,111 +293,61 @@ static struct RAMBlockNotifier sev_ram_notifier = {
> >      .ram_block_removed = sev_ram_block_removed,
> >  };
> >  
> > -static void
> > -sev_guest_finalize(Object *obj)
> > -{
> > -}
> > -
> > -static char *
> > -sev_guest_get_session_file(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    return s->session_file ? g_strdup(s->session_file) : NULL;
> > -}
> > -
> > -static void
> > -sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    s->session_file = g_strdup(value);
> > -}
> > -
> > -static char *
> > -sev_guest_get_dh_cert_file(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    return g_strdup(s->dh_cert_file);
> > -}
> > -
> > -static void
> > -sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    s->dh_cert_file = g_strdup(value);
> > -}
> > -
> > -static char *
> > -sev_guest_get_sev_device(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    return g_strdup(sev->sev_device);
> > -}
> > -
> > -static void
> > -sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    sev->sev_device = g_strdup(value);
> > -}
> > -
> > -static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    return sev->kernel_hashes;
> > -}
> > -
> > -static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    sev->kernel_hashes = value;
> > -}
> > -
> >  bool
> >  sev_enabled(void)
> >  {
> > -    return !!sev_guest;
> > +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> > +
> > +    return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
> >  }
> >  
> >  bool
> >  sev_es_enabled(void)
> >  {
> > -    return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
> > +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> > +
> > +    return sev_enabled() && (SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
> >  }
> >  
> >  uint32_t
> >  sev_get_cbit_position(void)
> >  {
> > -    return sev_guest ? sev_guest->cbitpos : 0;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +
> > +    return sev_common ? sev_common->cbitpos : 0;
> >  }
> >  
> >  uint32_t
> >  sev_get_reduced_phys_bits(void)
> >  {
> > -    return sev_guest ? sev_guest->reduced_phys_bits : 0;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +
> > +    return sev_common ? sev_common->reduced_phys_bits : 0;
> >  }
> >  
> >  static SevInfo *sev_get_info(void)
> >  {
> >      SevInfo *info;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +    SevGuestState *sev_guest =
> > +        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> > +                                             TYPE_SEV_GUEST);
> >  
> >      info = g_new0(SevInfo, 1);
> >      info->enabled = sev_enabled();
> >  
> >      if (info->enabled) {
> > -        info->api_major = sev_guest->api_major;
> > -        info->api_minor = sev_guest->api_minor;
> > -        info->build_id = sev_guest->build_id;
> > -        info->policy = sev_guest->policy;
> > -        info->state = sev_guest->state;
> > -        info->handle = sev_guest->handle;
> > +        if (sev_guest) {
> > +            info->handle = sev_guest->handle;
> > +        }
> > +        info->api_major = sev_common->api_major;
> > +        info->api_minor = sev_common->api_minor;
> > +        info->build_id = sev_common->build_id;
> > +        info->state = sev_common->state;
> > +        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> > +        info->policy =
> > +            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > +                                               "policy", NULL);
> >      }
> 
> I think we can change this 'policy' field to 'int64'.
> 
> Going from int32 to int64 doesn't change the encoding in JSON
> or cli properites. SEV/SEV-ES guests will still only use values
> that fit within int32, so existing users of QEMU won't notice
> a change.
> 
> Apps that want to use SEV-SNP will know that they can have
> policy values exceeding int32, but since that's net new code
> to suupport SEV-SNP there's no back compat issue.

In subsequent patch:

  "i386/sev: Update query-sev QAPI format to handle SEV-SNP"

we end up reporting SNP policy via a new 64-bit field, 'snp_policy',
based on a discussion:

  https://lore.kernel.org/kvm/YTdSlg5NymDQex5T@work-vm/T/#mac6758af9bfc41ee49ff3ef5c3ec3779ec275ff9

I think the concern was some 'old_mgmt' tool trying to interact with an
SNP guest launched through other means and misinterpreting SNP-specific
policy bits as SEV ones.

So because if that, there isn't really a need to make the policy bit
64-bit as part of this patch.

One thing that does need to be addressed here in the confusing comment:

  /* we only report the lower 32-bits of policy for SNP, ok for now... */

which I think was a relic from v2 that can be dropped now.

> 
> 
> > @@ -519,6 +473,8 @@ static SevCapability *sev_get_capabilities(Error **errp)
> >      size_t pdh_len = 0, cert_chain_len = 0, cpu0_id_len = 0;
> >      uint32_t ebx;
> >      int fd;
> > +    SevCommonState *sev_common;
> > +    char *sev_device;
> 
> Declare 'g_autofree char *sev_device = NULL;'
> 
> >  
> >      if (!kvm_enabled()) {
> >          error_setg(errp, "KVM not enabled");
> > @@ -529,12 +485,21 @@ static SevCapability *sev_get_capabilities(Error **errp)
> >          return NULL;
> >      }
> >  
> > -    fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
> > +    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +    if (!sev_common) {
> > +        error_setg(errp, "SEV is not configured");
> > +    }
> 
> Missing 'return' ?
> 
> > +
> > +    sev_device = object_property_get_str(OBJECT(sev_common), "sev-device",
> > +                                         &error_abort);
> > +    fd = open(sev_device, O_RDWR);
> >      if (fd < 0) {
> >          error_setg_errno(errp, errno, "SEV: Failed to open %s",
> >                           DEFAULT_SEV_DEVICE);
> > +        g_free(sev_device);
> >          return NULL;
> >      }
> > +    g_free(sev_device);
> 
> These 'g_free' are redundant with g_autofree usage on the declaration.
> 
> >  
> >      if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
> >                           &cert_chain_data, &cert_chain_len, errp)) {
> > @@ -577,7 +542,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
> >  {
> >      struct kvm_sev_attestation_report input = {};
> >      SevAttestationReport *report = NULL;
> > -    SevGuestState *sev = sev_guest;
> > +    SevCommonState *sev_common;
> 
> I think it would have been nicer to just keep the variable
> just called 'sev', except in the few cases where you needed to
> have variables for both parent & subclass in the same method.
> This diff would be much smaller too.
> 
> That's a bit bikeshedding though, so not too bothered either
> way.

Yah, I think at the time I'd considered that, but always anchoring
the variable name to the underlying type makes it easy to always
know what type of instance you're working with which I'm hoping is
worth the initial investment of doing the conversion consistently.

> 
> >      g_autofree guchar *data = NULL;
> >      g_autofree guchar *buf = NULL;
> >      gsize len;
> > @@ -602,8 +567,10 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
> >          return NULL;
> >      }
> >  
> > +    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +
> >      /* Query the report length */
> > -    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> > +    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> >              &input, &err);
> >      if (ret < 0) {
> >          if (err != SEV_RET_INVALID_LEN) {
> > @@ -619,7 +586,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
> >      memcpy(input.mnonce, buf, sizeof(input.mnonce));
> >  
> >      /* Query the report */
> > -    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> > +    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> >              &input, &err);
> >      if (ret) {
> >          error_setg_errno(errp, errno, "SEV: Failed to get attestation report"
> 
> > +
> > +/* sev guest info common to sev/sev-es/sev-snp */
> > +static const TypeInfo sev_common_info = {
> > +    .parent = TYPE_X86_CONFIDENTIAL_GUEST,
> > +    .name = TYPE_SEV_COMMON,
> > +    .instance_size = sizeof(SevCommonState),
> > +    .class_init = sev_common_class_init,
> > +    .instance_init = sev_common_instance_init,
> > +    .abstract = true,
> > +    .interfaces = (InterfaceInfo[]) {
> > +        { TYPE_USER_CREATABLE },
> > +        { }
> > +    }
> > +};
> 
> It feels wierd to declare a type as "abstract", and at
> the same time declare it "user creatable". I know this
> was a simple short-cut to avoid repeating the .interfaces
> on every sub-class, but I still think it would be better
> to put the "user creatable" marker on the concrete impls
> instead.
> 
> Also how about using OBJECT_DEFINE_ABSTRACT_TYPE here
> and also converting the subclasses to use
> OBJECT_DEFINE_TYPE_WITH_INTERFACES ?

Makes sense, will implement these for v4.

-Mike

> 
> 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
@ 2024-03-20 21:36       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth via @ 2024-03-20 21:36 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 11:44:13AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
> > Currently all SEV/SEV-ES functionality is managed through a single
> > 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> > same approach won't work well since some of the properties/state
> > managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> > rely on a new QOM type with its own set of properties/state.
> > 
> > To prepare for this, this patch moves common state into an abstract
> > 'sev-common' parent type to encapsulate properties/state that are
> > common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> > properties/state in the current 'sev-guest' type. This should not
> > affect current behavior or command-line options.
> > 
> > As part of this patch, some related changes are also made:
> > 
> >   - a static 'sev_guest' variable is currently used to keep track of
> >     the 'sev-guest' instance. SEV-SNP would similarly introduce an
> >     'sev_snp_guest' static variable. But these instances are now
> >     available via qdev_get_machine()->cgs, so switch to using that
> >     instead and drop the static variable.
> > 
> >   - 'sev_guest' is currently used as the name for the static variable
> >     holding a pointer to the 'sev-guest' instance. Re-purpose the name
> >     as a local variable referring the 'sev-guest' instance, and use
> >     that consistently throughout the code so it can be easily
> >     distinguished from sev-common/sev-snp-guest instances.
> > 
> >   - 'sev' is generally used as the name for local variables holding a
> >     pointer to the 'sev-guest' instance. In cases where that now points
> >     to common state, use the name 'sev_common'; in cases where that now
> >     points to state specific to 'sev-guest' instance, use the name
> >     'sev_guest'
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  qapi/qom.json     |  32 ++--
> >  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
> >  target/i386/sev.h |   3 +
> >  3 files changed, 281 insertions(+), 211 deletions(-)
> > 
> > diff --git a/qapi/qom.json b/qapi/qom.json
> > index baae3a183f..66b5781ca6 100644
> > --- a/qapi/qom.json
> > +++ b/qapi/qom.json
> > @@ -875,12 +875,29 @@
> >    'data': { '*filename': 'str' } }
> >  
> >  ##
> > -# @SevGuestProperties:
> > +# @SevCommonProperties:
> >  #
> > -# Properties for sev-guest objects.
> > +# Properties common to objects that are derivatives of sev-common.
> >  #
> >  # @sev-device: SEV device to use (default: "/dev/sev")
> >  #
> > +# @cbitpos: C-bit location in page table entry (default: 0)
> > +#
> > +# @reduced-phys-bits: number of bits in physical addresses that become
> > +#     unavailable when SEV is enabled
> > +#
> > +# Since: 2.12
> 
> Not quite sure what we've done in this scenario before.
> It feels wierd to use '2.12' for the new base type, even
> though in effect the properties all existed since 2.12 in
> the sub-class.
> 
> Perhaps 'Since: 9.1' for the type, but 'Since: 2.12' for the
> properties, along with an explanatory comment about stuff
> moving into the new base type ?
> 
> Markus, opinions ?

My thinking is that the internal details are less important than what's
actually exposed to users in the form of command-line options/etc. So
in that context the "Since: 2.12" sort of becomes the "default" for when
those properties were first made available to users, and then anything we
add after would then get special treatment with the per-property
versioning. But no issue with taking a different approach if that's
preferred.

> 
> > +##
> > +{ 'struct': 'SevCommonProperties',
> > +  'data': { '*sev-device': 'str',
> > +            '*cbitpos': 'uint32',
> > +            'reduced-phys-bits': 'uint32' } }
> > +
> > +##
> > +# @SevGuestProperties:
> > +#
> > +# Properties for sev-guest objects.
> > +#
> >  # @dh-cert-file: guest owners DH certificate (encoded with base64)
> >  #
> >  # @session-file: guest owners session parameters (encoded with base64)
> > @@ -889,11 +906,6 @@
> >  #
> >  # @handle: SEV firmware handle (default: 0)
> >  #
> > -# @cbitpos: C-bit location in page table entry (default: 0)
> > -#
> > -# @reduced-phys-bits: number of bits in physical addresses that become
> > -#     unavailable when SEV is enabled
> > -#
> >  # @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
> >  #     designated guest firmware page for measured boot with -kernel
> >  #     (default: false) (since 6.2)
> > @@ -901,13 +913,11 @@
> >  # Since: 2.12
> >  ##
> >  { 'struct': 'SevGuestProperties',
> > -  'data': { '*sev-device': 'str',
> > -            '*dh-cert-file': 'str',
> > +  'base': 'SevCommonProperties',
> > +  'data': { '*dh-cert-file': 'str',
> >              '*session-file': 'str',
> >              '*policy': 'uint32',
> >              '*handle': 'uint32',
> > -            '*cbitpos': 'uint32',
> > -            'reduced-phys-bits': 'uint32',
> >              '*kernel-hashes': 'bool' } }
> >  
> >  ##
> 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 9dab4060b8..63a220de5e 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -40,48 +40,53 @@
> >  #include "hw/i386/pc.h"
> >  #include "exec/address-spaces.h"
> >  
> > -#define TYPE_SEV_GUEST "sev-guest"
> > +OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
> >  OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> >  
> > -
> > -/**
> > - * SevGuestState:
> > - *
> > - * The SevGuestState object is used for creating and managing a SEV
> > - * guest.
> > - *
> > - * # $QEMU \
> > - *         -object sev-guest,id=sev0 \
> > - *         -machine ...,memory-encryption=sev0
> > - */
> > -struct SevGuestState {
> > +struct SevCommonState {
> >      X86ConfidentialGuest parent_obj;
> >  
> >      int kvm_type;
> >  
> >      /* configuration parameters */
> >      char *sev_device;
> > -    uint32_t policy;
> > -    char *dh_cert_file;
> > -    char *session_file;
> >      uint32_t cbitpos;
> >      uint32_t reduced_phys_bits;
> > -    bool kernel_hashes;
> >  
> >      /* runtime state */
> > -    uint32_t handle;
> >      uint8_t api_major;
> >      uint8_t api_minor;
> >      uint8_t build_id;
> >      int sev_fd;
> >      SevState state;
> > -    gchar *measurement;
> >  
> >      uint32_t reset_cs;
> >      uint32_t reset_ip;
> >      bool reset_data_valid;
> >  };
> >  
> > +/**
> > + * SevGuestState:
> > + *
> > + * The SevGuestState object is used for creating and managing a SEV
> > + * guest.
> > + *
> > + * # $QEMU \
> > + *         -object sev-guest,id=sev0 \
> > + *         -machine ...,memory-encryption=sev0
> > + */
> > +struct SevGuestState {
> > +    SevCommonState sev_common;
> > +    gchar *measurement;
> > +
> > +    /* configuration parameters */
> > +    uint32_t handle;
> > +    uint32_t policy;
> > +    char *dh_cert_file;
> > +    char *session_file;
> > +    bool kernel_hashes;
> > +};
> > +
> >  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
> >  #define DEFAULT_SEV_DEVICE      "/dev/sev"
> >  
> > @@ -127,7 +132,6 @@ typedef struct QEMU_PACKED PaddedSevHashTable {
> >  
> >  QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
> >  
> > -static SevGuestState *sev_guest;
> >  static Error *sev_mig_blocker;
> >  
> >  static const char *const sev_fw_errlist[] = {
> > @@ -208,21 +212,21 @@ fw_error_to_str(int code)
> >  }
> >  
> >  static bool
> > -sev_check_state(const SevGuestState *sev, SevState state)
> > +sev_check_state(const SevCommonState *sev_common, SevState state)
> >  {
> > -    assert(sev);
> > -    return sev->state == state ? true : false;
> > +    assert(sev_common);
> > +    return sev_common->state == state ? true : false;
> >  }
> >  
> >  static void
> > -sev_set_guest_state(SevGuestState *sev, SevState new_state)
> > +sev_set_guest_state(SevCommonState *sev_common, SevState new_state)
> >  {
> >      assert(new_state < SEV_STATE__MAX);
> > -    assert(sev);
> > +    assert(sev_common);
> >  
> > -    trace_kvm_sev_change_state(SevState_str(sev->state),
> > +    trace_kvm_sev_change_state(SevState_str(sev_common->state),
> >                                 SevState_str(new_state));
> > -    sev->state = new_state;
> > +    sev_common->state = new_state;
> >  }
> >  
> >  static void
> > @@ -289,111 +293,61 @@ static struct RAMBlockNotifier sev_ram_notifier = {
> >      .ram_block_removed = sev_ram_block_removed,
> >  };
> >  
> > -static void
> > -sev_guest_finalize(Object *obj)
> > -{
> > -}
> > -
> > -static char *
> > -sev_guest_get_session_file(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    return s->session_file ? g_strdup(s->session_file) : NULL;
> > -}
> > -
> > -static void
> > -sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    s->session_file = g_strdup(value);
> > -}
> > -
> > -static char *
> > -sev_guest_get_dh_cert_file(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    return g_strdup(s->dh_cert_file);
> > -}
> > -
> > -static void
> > -sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
> > -{
> > -    SevGuestState *s = SEV_GUEST(obj);
> > -
> > -    s->dh_cert_file = g_strdup(value);
> > -}
> > -
> > -static char *
> > -sev_guest_get_sev_device(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    return g_strdup(sev->sev_device);
> > -}
> > -
> > -static void
> > -sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    sev->sev_device = g_strdup(value);
> > -}
> > -
> > -static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    return sev->kernel_hashes;
> > -}
> > -
> > -static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
> > -{
> > -    SevGuestState *sev = SEV_GUEST(obj);
> > -
> > -    sev->kernel_hashes = value;
> > -}
> > -
> >  bool
> >  sev_enabled(void)
> >  {
> > -    return !!sev_guest;
> > +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> > +
> > +    return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
> >  }
> >  
> >  bool
> >  sev_es_enabled(void)
> >  {
> > -    return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
> > +    ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
> > +
> > +    return sev_enabled() && (SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
> >  }
> >  
> >  uint32_t
> >  sev_get_cbit_position(void)
> >  {
> > -    return sev_guest ? sev_guest->cbitpos : 0;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +
> > +    return sev_common ? sev_common->cbitpos : 0;
> >  }
> >  
> >  uint32_t
> >  sev_get_reduced_phys_bits(void)
> >  {
> > -    return sev_guest ? sev_guest->reduced_phys_bits : 0;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +
> > +    return sev_common ? sev_common->reduced_phys_bits : 0;
> >  }
> >  
> >  static SevInfo *sev_get_info(void)
> >  {
> >      SevInfo *info;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +    SevGuestState *sev_guest =
> > +        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> > +                                             TYPE_SEV_GUEST);
> >  
> >      info = g_new0(SevInfo, 1);
> >      info->enabled = sev_enabled();
> >  
> >      if (info->enabled) {
> > -        info->api_major = sev_guest->api_major;
> > -        info->api_minor = sev_guest->api_minor;
> > -        info->build_id = sev_guest->build_id;
> > -        info->policy = sev_guest->policy;
> > -        info->state = sev_guest->state;
> > -        info->handle = sev_guest->handle;
> > +        if (sev_guest) {
> > +            info->handle = sev_guest->handle;
> > +        }
> > +        info->api_major = sev_common->api_major;
> > +        info->api_minor = sev_common->api_minor;
> > +        info->build_id = sev_common->build_id;
> > +        info->state = sev_common->state;
> > +        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> > +        info->policy =
> > +            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > +                                               "policy", NULL);
> >      }
> 
> I think we can change this 'policy' field to 'int64'.
> 
> Going from int32 to int64 doesn't change the encoding in JSON
> or cli properites. SEV/SEV-ES guests will still only use values
> that fit within int32, so existing users of QEMU won't notice
> a change.
> 
> Apps that want to use SEV-SNP will know that they can have
> policy values exceeding int32, but since that's net new code
> to suupport SEV-SNP there's no back compat issue.

In subsequent patch:

  "i386/sev: Update query-sev QAPI format to handle SEV-SNP"

we end up reporting SNP policy via a new 64-bit field, 'snp_policy',
based on a discussion:

  https://lore.kernel.org/kvm/YTdSlg5NymDQex5T@work-vm/T/#mac6758af9bfc41ee49ff3ef5c3ec3779ec275ff9

I think the concern was some 'old_mgmt' tool trying to interact with an
SNP guest launched through other means and misinterpreting SNP-specific
policy bits as SEV ones.

So because if that, there isn't really a need to make the policy bit
64-bit as part of this patch.

One thing that does need to be addressed here in the confusing comment:

  /* we only report the lower 32-bits of policy for SNP, ok for now... */

which I think was a relic from v2 that can be dropped now.

> 
> 
> > @@ -519,6 +473,8 @@ static SevCapability *sev_get_capabilities(Error **errp)
> >      size_t pdh_len = 0, cert_chain_len = 0, cpu0_id_len = 0;
> >      uint32_t ebx;
> >      int fd;
> > +    SevCommonState *sev_common;
> > +    char *sev_device;
> 
> Declare 'g_autofree char *sev_device = NULL;'
> 
> >  
> >      if (!kvm_enabled()) {
> >          error_setg(errp, "KVM not enabled");
> > @@ -529,12 +485,21 @@ static SevCapability *sev_get_capabilities(Error **errp)
> >          return NULL;
> >      }
> >  
> > -    fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
> > +    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +    if (!sev_common) {
> > +        error_setg(errp, "SEV is not configured");
> > +    }
> 
> Missing 'return' ?
> 
> > +
> > +    sev_device = object_property_get_str(OBJECT(sev_common), "sev-device",
> > +                                         &error_abort);
> > +    fd = open(sev_device, O_RDWR);
> >      if (fd < 0) {
> >          error_setg_errno(errp, errno, "SEV: Failed to open %s",
> >                           DEFAULT_SEV_DEVICE);
> > +        g_free(sev_device);
> >          return NULL;
> >      }
> > +    g_free(sev_device);
> 
> These 'g_free' are redundant with g_autofree usage on the declaration.
> 
> >  
> >      if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
> >                           &cert_chain_data, &cert_chain_len, errp)) {
> > @@ -577,7 +542,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
> >  {
> >      struct kvm_sev_attestation_report input = {};
> >      SevAttestationReport *report = NULL;
> > -    SevGuestState *sev = sev_guest;
> > +    SevCommonState *sev_common;
> 
> I think it would have been nicer to just keep the variable
> just called 'sev', except in the few cases where you needed to
> have variables for both parent & subclass in the same method.
> This diff would be much smaller too.
> 
> That's a bit bikeshedding though, so not too bothered either
> way.

Yah, I think at the time I'd considered that, but always anchoring
the variable name to the underlying type makes it easy to always
know what type of instance you're working with which I'm hoping is
worth the initial investment of doing the conversion consistently.

> 
> >      g_autofree guchar *data = NULL;
> >      g_autofree guchar *buf = NULL;
> >      gsize len;
> > @@ -602,8 +567,10 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
> >          return NULL;
> >      }
> >  
> > +    sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +
> >      /* Query the report length */
> > -    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> > +    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> >              &input, &err);
> >      if (ret < 0) {
> >          if (err != SEV_RET_INVALID_LEN) {
> > @@ -619,7 +586,7 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
> >      memcpy(input.mnonce, buf, sizeof(input.mnonce));
> >  
> >      /* Query the report */
> > -    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> > +    ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
> >              &input, &err);
> >      if (ret) {
> >          error_setg_errno(errp, errno, "SEV: Failed to get attestation report"
> 
> > +
> > +/* sev guest info common to sev/sev-es/sev-snp */
> > +static const TypeInfo sev_common_info = {
> > +    .parent = TYPE_X86_CONFIDENTIAL_GUEST,
> > +    .name = TYPE_SEV_COMMON,
> > +    .instance_size = sizeof(SevCommonState),
> > +    .class_init = sev_common_class_init,
> > +    .instance_init = sev_common_instance_init,
> > +    .abstract = true,
> > +    .interfaces = (InterfaceInfo[]) {
> > +        { TYPE_USER_CREATABLE },
> > +        { }
> > +    }
> > +};
> 
> It feels wierd to declare a type as "abstract", and at
> the same time declare it "user creatable". I know this
> was a simple short-cut to avoid repeating the .interfaces
> on every sub-class, but I still think it would be better
> to put the "user creatable" marker on the concrete impls
> instead.
> 
> Also how about using OBJECT_DEFINE_ABSTRACT_TYPE here
> and also converting the subclasses to use
> OBJECT_DEFINE_TYPE_WITH_INTERFACES ?

Makes sense, will implement these for v4.

-Mike

> 
> 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20 11:47   ` Daniel P. Berrangé
@ 2024-03-20 21:45       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 21:45 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 11:47:28AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
> > Currently all SEV/SEV-ES functionality is managed through a single
> > 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> > same approach won't work well since some of the properties/state
> > managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> > rely on a new QOM type with its own set of properties/state.
> > 
> > To prepare for this, this patch moves common state into an abstract
> > 'sev-common' parent type to encapsulate properties/state that are
> > common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> > properties/state in the current 'sev-guest' type. This should not
> > affect current behavior or command-line options.
> > 
> > As part of this patch, some related changes are also made:
> > 
> >   - a static 'sev_guest' variable is currently used to keep track of
> >     the 'sev-guest' instance. SEV-SNP would similarly introduce an
> >     'sev_snp_guest' static variable. But these instances are now
> >     available via qdev_get_machine()->cgs, so switch to using that
> >     instead and drop the static variable.
> > 
> >   - 'sev_guest' is currently used as the name for the static variable
> >     holding a pointer to the 'sev-guest' instance. Re-purpose the name
> >     as a local variable referring the 'sev-guest' instance, and use
> >     that consistently throughout the code so it can be easily
> >     distinguished from sev-common/sev-snp-guest instances.
> > 
> >   - 'sev' is generally used as the name for local variables holding a
> >     pointer to the 'sev-guest' instance. In cases where that now points
> >     to common state, use the name 'sev_common'; in cases where that now
> >     points to state specific to 'sev-guest' instance, use the name
> >     'sev_guest'
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  qapi/qom.json     |  32 ++--
> >  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
> >  target/i386/sev.h |   3 +
> >  3 files changed, 281 insertions(+), 211 deletions(-)
> > 
> 
> >  static SevInfo *sev_get_info(void)
> >  {
> >      SevInfo *info;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +    SevGuestState *sev_guest =
> > +        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> > +                                             TYPE_SEV_GUEST);
> >  
> >      info = g_new0(SevInfo, 1);
> >      info->enabled = sev_enabled();
> >  
> >      if (info->enabled) {
> > -        info->api_major = sev_guest->api_major;
> > -        info->api_minor = sev_guest->api_minor;
> > -        info->build_id = sev_guest->build_id;
> > -        info->policy = sev_guest->policy;
> > -        info->state = sev_guest->state;
> > -        info->handle = sev_guest->handle;
> > +        if (sev_guest) {
> > +            info->handle = sev_guest->handle;
> > +        }
> 
> If we're not going to provide a value for 'handle', then
> we should update the QAPI for this to mark the property
> as optional, which would then require doing
> 
>   info->has_handle = true;
> 
> inside this 'if' block.

I think this is another temporarily-awkward case that gets resolved
with:

  i386/sev: Update query-sev QAPI format to handle SEV-SNP

With that patch 'handle' is always available for SEV guests, and never
available for SNP, and that's managed through a discriminated union
type. I think that info->handle should be treated the same as the
other fields as part of this patch and any changes in how they are
reported should be kept in the above-mentioned patch.

This might be another artifact from v2's handling. Will get this fixed
up.

-Mike

> > +        }

> 
> > +        info->api_major = sev_common->api_major;
> > +        info->api_minor = sev_common->api_minor;
> > +        info->build_id = sev_common->build_id;
> > +        info->state = sev_common->state;
> > +        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> > +        info->policy =
> > +            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > +                                               "policy", NULL);
> >      }
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
@ 2024-03-20 21:45       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth via @ 2024-03-20 21:45 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 11:47:28AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
> > Currently all SEV/SEV-ES functionality is managed through a single
> > 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> > same approach won't work well since some of the properties/state
> > managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> > rely on a new QOM type with its own set of properties/state.
> > 
> > To prepare for this, this patch moves common state into an abstract
> > 'sev-common' parent type to encapsulate properties/state that are
> > common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> > properties/state in the current 'sev-guest' type. This should not
> > affect current behavior or command-line options.
> > 
> > As part of this patch, some related changes are also made:
> > 
> >   - a static 'sev_guest' variable is currently used to keep track of
> >     the 'sev-guest' instance. SEV-SNP would similarly introduce an
> >     'sev_snp_guest' static variable. But these instances are now
> >     available via qdev_get_machine()->cgs, so switch to using that
> >     instead and drop the static variable.
> > 
> >   - 'sev_guest' is currently used as the name for the static variable
> >     holding a pointer to the 'sev-guest' instance. Re-purpose the name
> >     as a local variable referring the 'sev-guest' instance, and use
> >     that consistently throughout the code so it can be easily
> >     distinguished from sev-common/sev-snp-guest instances.
> > 
> >   - 'sev' is generally used as the name for local variables holding a
> >     pointer to the 'sev-guest' instance. In cases where that now points
> >     to common state, use the name 'sev_common'; in cases where that now
> >     points to state specific to 'sev-guest' instance, use the name
> >     'sev_guest'
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  qapi/qom.json     |  32 ++--
> >  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
> >  target/i386/sev.h |   3 +
> >  3 files changed, 281 insertions(+), 211 deletions(-)
> > 
> 
> >  static SevInfo *sev_get_info(void)
> >  {
> >      SevInfo *info;
> > +    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > +    SevGuestState *sev_guest =
> > +        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> > +                                             TYPE_SEV_GUEST);
> >  
> >      info = g_new0(SevInfo, 1);
> >      info->enabled = sev_enabled();
> >  
> >      if (info->enabled) {
> > -        info->api_major = sev_guest->api_major;
> > -        info->api_minor = sev_guest->api_minor;
> > -        info->build_id = sev_guest->build_id;
> > -        info->policy = sev_guest->policy;
> > -        info->state = sev_guest->state;
> > -        info->handle = sev_guest->handle;
> > +        if (sev_guest) {
> > +            info->handle = sev_guest->handle;
> > +        }
> 
> If we're not going to provide a value for 'handle', then
> we should update the QAPI for this to mark the property
> as optional, which would then require doing
> 
>   info->has_handle = true;
> 
> inside this 'if' block.

I think this is another temporarily-awkward case that gets resolved
with:

  i386/sev: Update query-sev QAPI format to handle SEV-SNP

With that patch 'handle' is always available for SEV guests, and never
available for SNP, and that's managed through a discriminated union
type. I think that info->handle should be treated the same as the
other fields as part of this patch and any changes in how they are
reported should be kept in the above-mentioned patch.

This might be another artifact from v2's handling. Will get this fixed
up.

-Mike

> > +        }

> 
> > +        info->api_major = sev_common->api_major;
> > +        info->api_minor = sev_common->api_minor;
> > +        info->build_id = sev_common->build_id;
> > +        info->state = sev_common->state;
> > +        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> > +        info->policy =
> > +            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > +                                               "policy", NULL);
> >      }
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object
  2024-03-20 11:58   ` Daniel P. Berrangé
@ 2024-03-20 22:09       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 22:09 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata, Brijesh Singh

On Wed, Mar 20, 2024 at 11:58:57AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:18AM -0500, Michael Roth wrote:
> > From: Brijesh Singh <brijesh.singh@amd.com>
> > 
> > SEV-SNP support relies on a different set of properties/state than the
> > existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
> > object, which can be used to configure an SEV-SNP guest. For example,
> > a default-configured SEV-SNP guest with no additional information
> > passed in for use with attestation:
> > 
> >   -object sev-snp-guest,id=sev0
> > 
> > or a fully-specified SEV-SNP guest where all spec-defined binary
> > blobs are passed in as base64-encoded strings:
> > 
> >   -object sev-snp-guest,id=sev0, \
> >     policy=0x30000, \
> >     init-flags=0, \
> >     id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
> >     id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
> >     auth-key-enabled=on, \
> >     host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
> >     guest-visible-workarounds=AA==, \
> > 
> > See the QAPI schema updates included in this patch for more usage
> > details.
> > 
> > In some cases these blobs may be up to 4096 characters, but this is
> > generally well below the default limit for linux hosts where
> > command-line sizes are defined by the sysconf-configurable ARG_MAX
> > value, which defaults to 2097152 characters for Ubuntu hosts, for
> > example.
> > 
> > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> > Co-developed-by: Michael Roth <michael.roth@amd.com>
> > Acked-by: Markus Armbruster <armbru@redhat.com> (for QAPI schema)
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  docs/system/i386/amd-memory-encryption.rst |  78 ++++++-
> >  qapi/qom.json                              |  51 +++++
> >  target/i386/sev.c                          | 241 +++++++++++++++++++++
> >  target/i386/sev.h                          |   1 +
> >  4 files changed, 369 insertions(+), 2 deletions(-)
> > 
> 
> > +##
> > +# @SevSnpGuestProperties:
> > +#
> > +# Properties for sev-snp-guest objects. Most of these are direct arguments
> > +# for the KVM_SNP_* interfaces documented in the linux kernel source
> > +# under Documentation/virt/kvm/amd-memory-encryption.rst, which are in
> > +# turn closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
> > +# documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).
> > +#
> > +# More usage information is also available in the QEMU source tree under
> > +# docs/amd-memory-encryption.
> > +#
> > +# @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
> > +#          defined in the SEV-SNP firmware ABI (default: 0x30000)
> > +#
> > +# @guest-visible-workarounds: 16-byte, base64-encoded blob to report
> > +#                             hypervisor-defined workarounds, corresponding
> > +#                             to the 'GOSVW' parameter of the
> > +#                             SNP_LAUNCH_START command defined in the
> > +#                             SEV-SNP firmware ABI (default: all-zero)
> > +#
> > +# @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
> > +#            structure for the SNP_LAUNCH_FINISH command defined in the
> > +#            SEV-SNP firmware ABI (default: all-zero)
> > +#
> > +# @id-auth: 4096-byte, base64-encoded blob to provide the 'ID Authentication
> > +#           Information Structure' for the SNP_LAUNCH_FINISH command defined
> > +#           in the SEV-SNP firmware ABI (default: all-zero)
> > +#
> > +# @auth-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY' field
> > +#                    defined SEV-SNP firmware ABI (default: false)
> > +#
> > +# @host-data: 32-byte, base64-encoded, user-defined blob to provide to the
> > +#             guest, as documented for the 'HOST_DATA' parameter of the
> > +#             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
> > +#             (default: all-zero)
> > +#
> > +# Since: 7.2
> 
> This will be 9.1 at the earliest now.

Amazing how good I am at remembering these once I see a reply to a
schema patch I'd already hit 'send' on :)

> 
> > +##
> > +{ 'struct': 'SevSnpGuestProperties',
> > +  'base': 'SevCommonProperties',
> > +  'data': {
> > +            '*policy': 'uint64',
> > +            '*guest-visible-workarounds': 'str',
> > +            '*id-block': 'str',
> > +            '*id-auth': 'str',
> > +            '*auth-key-enabled': 'bool',
> > +            '*host-data': 'str' } }
> > +
> 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 63a220de5e..7e6dab642a 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -42,6 +42,7 @@
> >  
> >  OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
> >  OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> > +OBJECT_DECLARE_SIMPLE_TYPE(SevSnpGuestState, SEV_SNP_GUEST)
> >  
> >  struct SevCommonState {
> >      X86ConfidentialGuest parent_obj;
> > @@ -87,8 +88,22 @@ struct SevGuestState {
> >      bool kernel_hashes;
> >  };
> >  
> > +struct SevSnpGuestState {
> > +    SevCommonState sev_common;
> > +
> > +    /* configuration parameters */
> > +    char *guest_visible_workarounds;
> > +    char *id_block;
> > +    char *id_auth;
> > +    char *host_data;
> > +
> > +    struct kvm_sev_snp_launch_start kvm_start_conf;
> > +    struct kvm_sev_snp_launch_finish kvm_finish_conf;
> > +};
> > +
> >  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
> >  #define DEFAULT_SEV_DEVICE      "/dev/sev"
> > +#define DEFAULT_SEV_SNP_POLICY  0x30000
> >  
> >  #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
> >  typedef struct __attribute__((__packed__)) SevInfoBlock {
> > @@ -1473,11 +1488,237 @@ static const TypeInfo sev_guest_info = {
> >      .class_init = sev_guest_class_init,
> 
> > +
> > +static char *
> > +sev_snp_guest_get_guest_visible_workarounds(Object *obj, Error **errp)
> > +{
> > +    return g_strdup(SEV_SNP_GUEST(obj)->guest_visible_workarounds);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_guest_visible_workarounds(Object *obj, const char *value,
> > +                                            Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
> > +    g_autofree guchar *blob;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->guest_visible_workarounds) {
> > +        g_free(sev_snp_guest->guest_visible_workarounds);
> > +    }
> 
> Redundant 'if' test - g_free is happy with NULL
> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->guest_visible_workarounds = g_strdup(value);
> > +
> > +    blob = qbase64_decode(sev_snp_guest->guest_visible_workarounds, -1, &len, errp);
> > +    if (!blob) {
> > +        return;
> > +    }
> > +
> > +    if (len > sizeof(start->gosvw)) {
> 
> The QAPI docs said this property must be '16 bytes', so I'd
> suggest we do a strict equality test, rather than min size
> test to catch a wider set of mistakes.

Makes sense.

> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %lu",
> > +                   len, sizeof(start->gosvw));
> > +        return;
> > +    }
> > +
> > +    memcpy(start->gosvw, blob, len);
> > +}
> > +
> > +static char *
> > +sev_snp_guest_get_id_block(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return g_strdup(sev_snp_guest->id_block);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_id_block(Object *obj, const char *value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->id_block) {
> > +        g_free(sev_snp_guest->id_block);
> > +        g_free((guchar *)finish->id_block_uaddr);
> > +    }
> 
> Assuming 'id_block_uaddr' is also initialized to 0, when id_block
> is NULL, then you can remove the 'if' conditional.

id_block_uaddr only ever gets initialized after id_block gets
initialized via g_strdup() below, and the SevSnpGuestState struct is
zero'd during creation time so no need to worry about uninitialized
values. So I think we can indeed drop the if check.

> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->id_block = g_strdup(value);
> > +
> > +    finish->id_block_uaddr =
> > +        (uint64_t)qbase64_decode(sev_snp_guest->id_block, -1, &len, errp);
> > +
> > +    if (!finish->id_block_uaddr) {
> > +        return;
> > +    }
> > +
> > +    if (len > KVM_SEV_SNP_ID_BLOCK_SIZE) {
> 
> Again, lets do a strict equality test to match the documented
> required size.
> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %u",
> > +                   len, KVM_SEV_SNP_ID_BLOCK_SIZE);
> > +        return;
> > +    }
> > +
> > +    finish->id_block_en = (len) ? 1 : 0;
> > +}
> > +
> > +static char *
> > +sev_snp_guest_get_id_auth(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return g_strdup(sev_snp_guest->id_auth);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_id_auth(Object *obj, const char *value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->id_auth) {
> > +        g_free(sev_snp_guest->id_auth);
> > +        g_free((guchar *)finish->id_auth_uaddr);
> > +    }
> 
> Same probably redundant 'if'

Looks like it. Will address these and recurring cases below.

-Mike

> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->id_auth = g_strdup(value);
> > +
> > +    finish->id_auth_uaddr =
> > +        (uint64_t)qbase64_decode(sev_snp_guest->id_auth, -1, &len, errp);
> > +
> > +    if (!finish->id_auth_uaddr) {
> > +        return;
> > +    }
> > +
> > +    if (len > KVM_SEV_SNP_ID_AUTH_SIZE) {
> 
> Equality test.
> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %u",
> > +                   len, KVM_SEV_SNP_ID_AUTH_SIZE);
> > +        return;
> > +    }
> > +}
> > +
> > +static bool
> > +sev_snp_guest_get_auth_key_en(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return !!sev_snp_guest->kvm_finish_conf.auth_key_en;
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_auth_key_en(Object *obj, bool value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    sev_snp_guest->kvm_finish_conf.auth_key_en = value;
> > +}
> > +
> > +static char *
> > +sev_snp_guest_get_host_data(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return g_strdup(sev_snp_guest->host_data);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> > +    g_autofree guchar *blob;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->host_data) {
> > +        g_free(sev_snp_guest->host_data);
> > +    }
> 
> Redundant 'if'
> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->host_data = g_strdup(value);
> > +
> > +    blob = qbase64_decode(sev_snp_guest->host_data, -1, &len, errp);
> > +
> > +    if (!blob) {
> > +        return;
> > +    }
> > +
> > +    if (len > sizeof(finish->host_data)) {
> 
> Equality test
> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %lu",
> > +                   len, sizeof(finish->host_data));
> > +        return;
> > +    }
> > +
> > +    memcpy(finish->host_data, blob, len);
> > +}
> > +
> > +static void
> > +sev_snp_guest_class_init(ObjectClass *oc, void *data)
> > +{
> > +    object_class_property_add(oc, "policy", "uint64",
> > +                              sev_snp_guest_get_policy,
> > +                              sev_snp_guest_set_policy, NULL, NULL);
> > +    object_class_property_add_str(oc, "guest-visible-workarounds",
> > +                                  sev_snp_guest_get_guest_visible_workarounds,
> > +                                  sev_snp_guest_set_guest_visible_workarounds);
> > +    object_class_property_add_str(oc, "id-block",
> > +                                  sev_snp_guest_get_id_block,
> > +                                  sev_snp_guest_set_id_block);
> > +    object_class_property_add_str(oc, "id-auth",
> > +                                  sev_snp_guest_get_id_auth,
> > +                                  sev_snp_guest_set_id_auth);
> > +    object_class_property_add_bool(oc, "auth-key-enabled",
> > +                                   sev_snp_guest_get_auth_key_en,
> > +                                   sev_snp_guest_set_auth_key_en);
> > +    object_class_property_add_str(oc, "host-data",
> > +                                  sev_snp_guest_get_host_data,
> > +                                  sev_snp_guest_set_host_data);
> > +}
> > +
> > +static void
> > +sev_snp_guest_instance_init(Object *obj)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    /* default init/start/finish params for kvm */
> > +    sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
> > +}
> > +
> > +/* guest info specific to sev-snp */
> > +static const TypeInfo sev_snp_guest_info = {
> > +    .parent = TYPE_SEV_COMMON,
> > +    .name = TYPE_SEV_SNP_GUEST,
> > +    .instance_size = sizeof(SevSnpGuestState),
> > +    .class_init = sev_snp_guest_class_init,
> > +    .instance_init = sev_snp_guest_instance_init,
> > +};
> 
> Use the OBJECT_DEFINE_TYPE_WITH_INTERFACES macro here.
> 
> > +
> >  static void
> >  sev_register_types(void)
> >  {
> >      type_register_static(&sev_common_info);
> >      type_register_static(&sev_guest_info);
> > +    type_register_static(&sev_snp_guest_info);
> >  }
> >  
> >  type_init(sev_register_types);
> > diff --git a/target/i386/sev.h b/target/i386/sev.h
> > index 668374eef3..bedc667eeb 100644
> > --- a/target/i386/sev.h
> > +++ b/target/i386/sev.h
> > @@ -22,6 +22,7 @@
> >  
> >  #define TYPE_SEV_COMMON "sev-common"
> >  #define TYPE_SEV_GUEST "sev-guest"
> > +#define TYPE_SEV_SNP_GUEST "sev-snp-guest"
> >  
> >  #define SEV_POLICY_NODBG        0x1
> >  #define SEV_POLICY_NOKS         0x2
> > -- 
> > 2.25.1
> > 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object
@ 2024-03-20 22:09       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth via @ 2024-03-20 22:09 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata, Brijesh Singh

On Wed, Mar 20, 2024 at 11:58:57AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:18AM -0500, Michael Roth wrote:
> > From: Brijesh Singh <brijesh.singh@amd.com>
> > 
> > SEV-SNP support relies on a different set of properties/state than the
> > existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
> > object, which can be used to configure an SEV-SNP guest. For example,
> > a default-configured SEV-SNP guest with no additional information
> > passed in for use with attestation:
> > 
> >   -object sev-snp-guest,id=sev0
> > 
> > or a fully-specified SEV-SNP guest where all spec-defined binary
> > blobs are passed in as base64-encoded strings:
> > 
> >   -object sev-snp-guest,id=sev0, \
> >     policy=0x30000, \
> >     init-flags=0, \
> >     id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
> >     id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
> >     auth-key-enabled=on, \
> >     host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
> >     guest-visible-workarounds=AA==, \
> > 
> > See the QAPI schema updates included in this patch for more usage
> > details.
> > 
> > In some cases these blobs may be up to 4096 characters, but this is
> > generally well below the default limit for linux hosts where
> > command-line sizes are defined by the sysconf-configurable ARG_MAX
> > value, which defaults to 2097152 characters for Ubuntu hosts, for
> > example.
> > 
> > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> > Co-developed-by: Michael Roth <michael.roth@amd.com>
> > Acked-by: Markus Armbruster <armbru@redhat.com> (for QAPI schema)
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  docs/system/i386/amd-memory-encryption.rst |  78 ++++++-
> >  qapi/qom.json                              |  51 +++++
> >  target/i386/sev.c                          | 241 +++++++++++++++++++++
> >  target/i386/sev.h                          |   1 +
> >  4 files changed, 369 insertions(+), 2 deletions(-)
> > 
> 
> > +##
> > +# @SevSnpGuestProperties:
> > +#
> > +# Properties for sev-snp-guest objects. Most of these are direct arguments
> > +# for the KVM_SNP_* interfaces documented in the linux kernel source
> > +# under Documentation/virt/kvm/amd-memory-encryption.rst, which are in
> > +# turn closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
> > +# documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).
> > +#
> > +# More usage information is also available in the QEMU source tree under
> > +# docs/amd-memory-encryption.
> > +#
> > +# @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
> > +#          defined in the SEV-SNP firmware ABI (default: 0x30000)
> > +#
> > +# @guest-visible-workarounds: 16-byte, base64-encoded blob to report
> > +#                             hypervisor-defined workarounds, corresponding
> > +#                             to the 'GOSVW' parameter of the
> > +#                             SNP_LAUNCH_START command defined in the
> > +#                             SEV-SNP firmware ABI (default: all-zero)
> > +#
> > +# @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
> > +#            structure for the SNP_LAUNCH_FINISH command defined in the
> > +#            SEV-SNP firmware ABI (default: all-zero)
> > +#
> > +# @id-auth: 4096-byte, base64-encoded blob to provide the 'ID Authentication
> > +#           Information Structure' for the SNP_LAUNCH_FINISH command defined
> > +#           in the SEV-SNP firmware ABI (default: all-zero)
> > +#
> > +# @auth-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY' field
> > +#                    defined SEV-SNP firmware ABI (default: false)
> > +#
> > +# @host-data: 32-byte, base64-encoded, user-defined blob to provide to the
> > +#             guest, as documented for the 'HOST_DATA' parameter of the
> > +#             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
> > +#             (default: all-zero)
> > +#
> > +# Since: 7.2
> 
> This will be 9.1 at the earliest now.

Amazing how good I am at remembering these once I see a reply to a
schema patch I'd already hit 'send' on :)

> 
> > +##
> > +{ 'struct': 'SevSnpGuestProperties',
> > +  'base': 'SevCommonProperties',
> > +  'data': {
> > +            '*policy': 'uint64',
> > +            '*guest-visible-workarounds': 'str',
> > +            '*id-block': 'str',
> > +            '*id-auth': 'str',
> > +            '*auth-key-enabled': 'bool',
> > +            '*host-data': 'str' } }
> > +
> 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 63a220de5e..7e6dab642a 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -42,6 +42,7 @@
> >  
> >  OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
> >  OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> > +OBJECT_DECLARE_SIMPLE_TYPE(SevSnpGuestState, SEV_SNP_GUEST)
> >  
> >  struct SevCommonState {
> >      X86ConfidentialGuest parent_obj;
> > @@ -87,8 +88,22 @@ struct SevGuestState {
> >      bool kernel_hashes;
> >  };
> >  
> > +struct SevSnpGuestState {
> > +    SevCommonState sev_common;
> > +
> > +    /* configuration parameters */
> > +    char *guest_visible_workarounds;
> > +    char *id_block;
> > +    char *id_auth;
> > +    char *host_data;
> > +
> > +    struct kvm_sev_snp_launch_start kvm_start_conf;
> > +    struct kvm_sev_snp_launch_finish kvm_finish_conf;
> > +};
> > +
> >  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
> >  #define DEFAULT_SEV_DEVICE      "/dev/sev"
> > +#define DEFAULT_SEV_SNP_POLICY  0x30000
> >  
> >  #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
> >  typedef struct __attribute__((__packed__)) SevInfoBlock {
> > @@ -1473,11 +1488,237 @@ static const TypeInfo sev_guest_info = {
> >      .class_init = sev_guest_class_init,
> 
> > +
> > +static char *
> > +sev_snp_guest_get_guest_visible_workarounds(Object *obj, Error **errp)
> > +{
> > +    return g_strdup(SEV_SNP_GUEST(obj)->guest_visible_workarounds);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_guest_visible_workarounds(Object *obj, const char *value,
> > +                                            Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
> > +    g_autofree guchar *blob;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->guest_visible_workarounds) {
> > +        g_free(sev_snp_guest->guest_visible_workarounds);
> > +    }
> 
> Redundant 'if' test - g_free is happy with NULL
> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->guest_visible_workarounds = g_strdup(value);
> > +
> > +    blob = qbase64_decode(sev_snp_guest->guest_visible_workarounds, -1, &len, errp);
> > +    if (!blob) {
> > +        return;
> > +    }
> > +
> > +    if (len > sizeof(start->gosvw)) {
> 
> The QAPI docs said this property must be '16 bytes', so I'd
> suggest we do a strict equality test, rather than min size
> test to catch a wider set of mistakes.

Makes sense.

> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %lu",
> > +                   len, sizeof(start->gosvw));
> > +        return;
> > +    }
> > +
> > +    memcpy(start->gosvw, blob, len);
> > +}
> > +
> > +static char *
> > +sev_snp_guest_get_id_block(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return g_strdup(sev_snp_guest->id_block);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_id_block(Object *obj, const char *value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->id_block) {
> > +        g_free(sev_snp_guest->id_block);
> > +        g_free((guchar *)finish->id_block_uaddr);
> > +    }
> 
> Assuming 'id_block_uaddr' is also initialized to 0, when id_block
> is NULL, then you can remove the 'if' conditional.

id_block_uaddr only ever gets initialized after id_block gets
initialized via g_strdup() below, and the SevSnpGuestState struct is
zero'd during creation time so no need to worry about uninitialized
values. So I think we can indeed drop the if check.

> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->id_block = g_strdup(value);
> > +
> > +    finish->id_block_uaddr =
> > +        (uint64_t)qbase64_decode(sev_snp_guest->id_block, -1, &len, errp);
> > +
> > +    if (!finish->id_block_uaddr) {
> > +        return;
> > +    }
> > +
> > +    if (len > KVM_SEV_SNP_ID_BLOCK_SIZE) {
> 
> Again, lets do a strict equality test to match the documented
> required size.
> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %u",
> > +                   len, KVM_SEV_SNP_ID_BLOCK_SIZE);
> > +        return;
> > +    }
> > +
> > +    finish->id_block_en = (len) ? 1 : 0;
> > +}
> > +
> > +static char *
> > +sev_snp_guest_get_id_auth(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return g_strdup(sev_snp_guest->id_auth);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_id_auth(Object *obj, const char *value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->id_auth) {
> > +        g_free(sev_snp_guest->id_auth);
> > +        g_free((guchar *)finish->id_auth_uaddr);
> > +    }
> 
> Same probably redundant 'if'

Looks like it. Will address these and recurring cases below.

-Mike

> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->id_auth = g_strdup(value);
> > +
> > +    finish->id_auth_uaddr =
> > +        (uint64_t)qbase64_decode(sev_snp_guest->id_auth, -1, &len, errp);
> > +
> > +    if (!finish->id_auth_uaddr) {
> > +        return;
> > +    }
> > +
> > +    if (len > KVM_SEV_SNP_ID_AUTH_SIZE) {
> 
> Equality test.
> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %u",
> > +                   len, KVM_SEV_SNP_ID_AUTH_SIZE);
> > +        return;
> > +    }
> > +}
> > +
> > +static bool
> > +sev_snp_guest_get_auth_key_en(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return !!sev_snp_guest->kvm_finish_conf.auth_key_en;
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_auth_key_en(Object *obj, bool value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    sev_snp_guest->kvm_finish_conf.auth_key_en = value;
> > +}
> > +
> > +static char *
> > +sev_snp_guest_get_host_data(Object *obj, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    return g_strdup(sev_snp_guest->host_data);
> > +}
> > +
> > +static void
> > +sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +    struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
> > +    g_autofree guchar *blob;
> > +    gsize len;
> > +
> > +    if (sev_snp_guest->host_data) {
> > +        g_free(sev_snp_guest->host_data);
> > +    }
> 
> Redundant 'if'
> 
> > +
> > +    /* store the base64 str so we don't need to re-encode in getter */
> > +    sev_snp_guest->host_data = g_strdup(value);
> > +
> > +    blob = qbase64_decode(sev_snp_guest->host_data, -1, &len, errp);
> > +
> > +    if (!blob) {
> > +        return;
> > +    }
> > +
> > +    if (len > sizeof(finish->host_data)) {
> 
> Equality test
> 
> > +        error_setg(errp, "parameter length of %lu exceeds max of %lu",
> > +                   len, sizeof(finish->host_data));
> > +        return;
> > +    }
> > +
> > +    memcpy(finish->host_data, blob, len);
> > +}
> > +
> > +static void
> > +sev_snp_guest_class_init(ObjectClass *oc, void *data)
> > +{
> > +    object_class_property_add(oc, "policy", "uint64",
> > +                              sev_snp_guest_get_policy,
> > +                              sev_snp_guest_set_policy, NULL, NULL);
> > +    object_class_property_add_str(oc, "guest-visible-workarounds",
> > +                                  sev_snp_guest_get_guest_visible_workarounds,
> > +                                  sev_snp_guest_set_guest_visible_workarounds);
> > +    object_class_property_add_str(oc, "id-block",
> > +                                  sev_snp_guest_get_id_block,
> > +                                  sev_snp_guest_set_id_block);
> > +    object_class_property_add_str(oc, "id-auth",
> > +                                  sev_snp_guest_get_id_auth,
> > +                                  sev_snp_guest_set_id_auth);
> > +    object_class_property_add_bool(oc, "auth-key-enabled",
> > +                                   sev_snp_guest_get_auth_key_en,
> > +                                   sev_snp_guest_set_auth_key_en);
> > +    object_class_property_add_str(oc, "host-data",
> > +                                  sev_snp_guest_get_host_data,
> > +                                  sev_snp_guest_set_host_data);
> > +}
> > +
> > +static void
> > +sev_snp_guest_instance_init(Object *obj)
> > +{
> > +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> > +
> > +    /* default init/start/finish params for kvm */
> > +    sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
> > +}
> > +
> > +/* guest info specific to sev-snp */
> > +static const TypeInfo sev_snp_guest_info = {
> > +    .parent = TYPE_SEV_COMMON,
> > +    .name = TYPE_SEV_SNP_GUEST,
> > +    .instance_size = sizeof(SevSnpGuestState),
> > +    .class_init = sev_snp_guest_class_init,
> > +    .instance_init = sev_snp_guest_instance_init,
> > +};
> 
> Use the OBJECT_DEFINE_TYPE_WITH_INTERFACES macro here.
> 
> > +
> >  static void
> >  sev_register_types(void)
> >  {
> >      type_register_static(&sev_common_info);
> >      type_register_static(&sev_guest_info);
> > +    type_register_static(&sev_snp_guest_info);
> >  }
> >  
> >  type_init(sev_register_types);
> > diff --git a/target/i386/sev.h b/target/i386/sev.h
> > index 668374eef3..bedc667eeb 100644
> > --- a/target/i386/sev.h
> > +++ b/target/i386/sev.h
> > @@ -22,6 +22,7 @@
> >  
> >  #define TYPE_SEV_COMMON "sev-common"
> >  #define TYPE_SEV_GUEST "sev-guest"
> > +#define TYPE_SEV_SNP_GUEST "sev-snp-guest"
> >  
> >  #define SEV_POLICY_NODBG        0x1
> >  #define SEV_POLICY_NOKS         0x2
> > -- 
> > 2.25.1
> > 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper
  2024-03-20 12:35   ` Daniel P. Berrangé
@ 2024-03-20 22:11       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 22:11 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:35:09PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:19AM -0500, Michael Roth wrote:
> > Add a simple helper to check if the current guest type is SNP. Also have
> > SNP-enabled imply that SEV-ES is enabled as well, and fix up any places
> > where the sev_es_enabled() check is expecting a pure/non-SNP guest.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  target/i386/sev.c | 13 ++++++++++++-
> >  target/i386/sev.h |  2 ++
> >  2 files changed, 14 insertions(+), 1 deletion(-)
> > 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 7e6dab642a..2eb13ba639 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> 
> 
> > @@ -933,7 +942,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> >                           __func__);
> >              goto err;
> >          }
> > +    }
> >  
> > +    if (sev_es_enabled() && !sev_snp_enabled()) {
> >          if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
> >              error_report("%s: guest policy requires SEV-ES, but "
> >                           "host SEV-ES support unavailable",
> 
> Opps, pre-existing bug here - this method has an 'Error **errp'
> parameter, so should be using 'error_report'.
> 
> There are several more examples of this in this method that
> predate your patch series.  Can you put a patch at the start
> of this series that fixes them before introducing SNP.

Sure, will add a pre-patch to fix up all the pre-existing issues
you've noted.

-Mike

> 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper
@ 2024-03-20 22:11       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth via @ 2024-03-20 22:11 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:35:09PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:19AM -0500, Michael Roth wrote:
> > Add a simple helper to check if the current guest type is SNP. Also have
> > SNP-enabled imply that SEV-ES is enabled as well, and fix up any places
> > where the sev_es_enabled() check is expecting a pure/non-SNP guest.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  target/i386/sev.c | 13 ++++++++++++-
> >  target/i386/sev.h |  2 ++
> >  2 files changed, 14 insertions(+), 1 deletion(-)
> > 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 7e6dab642a..2eb13ba639 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> 
> 
> > @@ -933,7 +942,9 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> >                           __func__);
> >              goto err;
> >          }
> > +    }
> >  
> > +    if (sev_es_enabled() && !sev_snp_enabled()) {
> >          if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
> >              error_report("%s: guest policy requires SEV-ES, but "
> >                           "host SEV-ES support unavailable",
> 
> Opps, pre-existing bug here - this method has an 'Error **errp'
> parameter, so should be using 'error_report'.
> 
> There are several more examples of this in this method that
> predate your patch series.  Can you put a patch at the start
> of this series that fixes them before introducing SNP.

Sure, will add a pre-patch to fix up all the pre-existing issues
you've noted.

-Mike

> 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP
  2024-03-20  9:46   ` Paolo Bonzini
@ 2024-03-20 22:14     ` Michael Roth
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 22:14 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 10:46:29AM +0100, Paolo Bonzini wrote:
> On 3/20/24 09:39, Michael Roth wrote:
> > SEV uses these notifiers to register/pin pages prior to guest use, since
> > they could potentially be used for private memory where page migration
> > is not supported. But SNP only uses guest_memfd-provided pages for
> > private memory, which has its own kernel-internal mechanisms for
> > registering/pinning memory.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >   target/i386/sev.c | 10 +++++++++-
> >   1 file changed, 9 insertions(+), 1 deletion(-)
> > 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 61af312a11..774262d834 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -982,7 +982,15 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> >           goto err;
> >       }
> > -    ram_block_notifier_add(&sev_ram_notifier);
> > +    if (!sev_snp_enabled()) {
> > +        /*
> > +         * SEV uses these notifiers to register/pin pages prior to guest use,
> > +         * but SNP relies on guest_memfd for private pages, which has it's
> > +         * own internal mechanisms for registering/pinning private memory.
> > +         */
> > +        ram_block_notifier_add(&sev_ram_notifier);
> > +    }
> > +
> >       qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
> >       qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
> 
> These three lines can be done in any order, so I suggest removing
> ram_block_notifier_add + qemu_add_machine_init_done_notifier from the
> sev-common implementation of kvm_init (let's call it sev_common_kvm_init);
> and add an override in sev-guest that calls them if sev_common_kvm_init()
> succeeds.
> 
> (treat this as a review for 25/26/29).

Makes sense. Will split out the common bits of sev_kvm_init() and use
class methods for initialization specific to sev-guest and
sev-snp-guest.

-Mike

> 
> Paolo
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP
  2024-03-20 12:10   ` Daniel P. Berrangé
@ 2024-03-20 22:23       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 22:23 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:10:04PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:27AM -0500, Michael Roth wrote:
> > Most of the current 'query-sev' command is relevant to both legacy
> > SEV/SEV-ES guests and SEV-SNP guests, with 2 exceptions:
> > 
> >   - 'policy' is a 64-bit field for SEV-SNP, not 32-bit, and
> >     the meaning of the bit positions has changed
> >   - 'handle' is not relevant to SEV-SNP
> > 
> > To address this, this patch adds a new 'sev-type' field that can be
> > used as a discriminator to select between SEV and SEV-SNP-specific
> > fields/formats without breaking compatibility for existing management
> > tools (so long as management tools that add support for launching
> > SEV-SNP guest update their handling of query-sev appropriately).
> > 
> > The corresponding HMP command has also been fixed up similarly.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  qapi/misc-target.json | 71 ++++++++++++++++++++++++++++++++++---------
> >  target/i386/sev.c     | 50 ++++++++++++++++++++----------
> >  target/i386/sev.h     |  3 ++
> >  3 files changed, 94 insertions(+), 30 deletions(-)
> > 
> > diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> > index 4e0a6492a9..daceb85d95 100644
> > --- a/qapi/misc-target.json
> > +++ b/qapi/misc-target.json
> > @@ -47,6 +47,49 @@
> >             'send-update', 'receive-update' ],
> >    'if': 'TARGET_I386' }
> >  
> > +##
> > +# @SevGuestType:
> > +#
> > +# An enumeration indicating the type of SEV guest being run.
> > +#
> > +# @sev:     The guest is a legacy SEV or SEV-ES guest.
> > +# @sev-snp: The guest is an SEV-SNP guest.
> > +#
> > +# Since: 6.2
> 
> Now 9.1 at the earliest.
> 
> > +##
> > +{ 'enum': 'SevGuestType',
> > +  'data': [ 'sev', 'sev-snp' ],
> > +  'if': 'TARGET_I386' }
> > +
> > +##
> > +# @SevGuestInfo:
> > +#
> > +# Information specific to legacy SEV/SEV-ES guests.
> > +#
> > +# @policy: SEV policy value
> > +#
> > +# @handle: SEV firmware handle
> > +#
> > +# Since: 2.12
> > +##
> > +{ 'struct': 'SevGuestInfo',
> > +  'data': { 'policy': 'uint32',
> > +            'handle': 'uint32' },
> > +  'if': 'TARGET_I386' }
> > +
> > +##
> > +# @SevSnpGuestInfo:
> > +#
> > +# Information specific to SEV-SNP guests.
> > +#
> > +# @snp-policy: SEV-SNP policy value
> > +#
> > +# Since: 6.2
> > +##
> > +{ 'struct': 'SevSnpGuestInfo',
> > +  'data': { 'snp-policy': 'uint64' },
> > +  'if': 'TARGET_I386' }
> 
> IMHO it can just be called 'policy' still, since
> it is implicitly within a 'Snp' specific type.
> 
> 
> > +
> >  ##
> >  # @SevInfo:
> >  #
> > @@ -60,25 +103,25 @@
> >  #
> >  # @build-id: SEV FW build id
> >  #
> > -# @policy: SEV policy value
> > -#
> >  # @state: SEV guest state
> >  #
> > -# @handle: SEV firmware handle
> > +# @sev-type: Type of SEV guest being run
> >  #
> >  # Since: 2.12
> >  ##
> > -{ 'struct': 'SevInfo',
> > -    'data': { 'enabled': 'bool',
> > -              'api-major': 'uint8',
> > -              'api-minor' : 'uint8',
> > -              'build-id' : 'uint8',
> > -              'policy' : 'uint32',
> > -              'state' : 'SevState',
> > -              'handle' : 'uint32'
> > -            },
> > -  'if': 'TARGET_I386'
> > -}
> > +{ 'union': 'SevInfo',
> > +  'base': { 'enabled': 'bool',
> > +            'api-major': 'uint8',
> > +            'api-minor' : 'uint8',
> > +            'build-id' : 'uint8',
> > +            'state' : 'SevState',
> > +            'sev-type' : 'SevGuestType' },
> > +  'discriminator': 'sev-type',
> > +  'data': {
> > +      'sev': 'SevGuestInfo',
> > +      'sev-snp': 'SevSnpGuestInfo' },
> > +  'if': 'TARGET_I386' }
> > +
> >  
> >  ##
> >  # @query-sev:
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 43e6c0172f..b03d70a3d1 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -353,25 +353,27 @@ static SevInfo *sev_get_info(void)
> >  {
> >      SevInfo *info;
> >      SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > -    SevGuestState *sev_guest =
> > -        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> > -                                             TYPE_SEV_GUEST);
> >  
> >      info = g_new0(SevInfo, 1);
> >      info->enabled = sev_enabled();
> >  
> >      if (info->enabled) {
> > -        if (sev_guest) {
> > -            info->handle = sev_guest->handle;
> > -        }
> >          info->api_major = sev_common->api_major;
> >          info->api_minor = sev_common->api_minor;
> >          info->build_id = sev_common->build_id;
> >          info->state = sev_common->state;
> > -        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> > -        info->policy =
> > -            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > -                                               "policy", NULL);
> > +
> > +        if (sev_snp_enabled()) {
> > +            info->sev_type = SEV_GUEST_TYPE_SEV_SNP;
> > +            info->u.sev_snp.snp_policy =
> > +                object_property_get_uint(OBJECT(sev_common), "policy", NULL);
> > +        } else {
> > +            info->sev_type = SEV_GUEST_TYPE_SEV;
> > +            info->u.sev.handle = SEV_GUEST(sev_common)->handle;
> > +            info->u.sev.policy =
> > +                (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > +                                                   "policy", NULL);
> > +        }
> >      }
> 
> Ok, this is fixing the issues I reported earlier.
> 
> For 'policy' I do wonder if we really need to push it into the
> type specific part of the union, as oppposed to having a common
> 'policy' field that is uint64 in size.
> 
> As mentioned earlier, on the wire there's no distinction between
> int32/int64s, so there's no compat issues with changing it from
> int32 to int64.

Mentioned this in response to your earlier reply, but the renaming of
'policy' to 'snp_policy' was in response to Dave's query about old
management tools who don't understand/parse the new sev-type field
and blinding misinterpret an SNP 'policy' as an SEV one:

  https://lore.kernel.org/kvm/YTdSlg5NymDQex5T@work-vm/T/#mac6758af9bfc41ee49ff3ef5c3ec3779ec275ff9

I think the thinking is that it's better that they see nothing at all
(likely treating as policy 0x0) versus getting unexpected values and
reporting random policy features.

> 
> >  
> >      return info;
> > @@ -394,20 +396,36 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict)
> >  {
> >      SevInfo *info = sev_get_info();
> >  
> > -    if (info && info->enabled) {
> > -        monitor_printf(mon, "handle: %d\n", info->handle);
> > +    if (!info || !info->enabled) {
> > +        monitor_printf(mon, "SEV is not enabled\n");
> > +        goto out;
> > +    }
> > +
> > +    if (sev_snp_enabled()) {
> >          monitor_printf(mon, "state: %s\n", SevState_str(info->state));
> >          monitor_printf(mon, "build: %d\n", info->build_id);
> >          monitor_printf(mon, "api version: %d.%d\n",
> >                         info->api_major, info->api_minor);
> >          monitor_printf(mon, "debug: %s\n",
> > -                       info->policy & SEV_POLICY_NODBG ? "off" : "on");
> > -        monitor_printf(mon, "key-sharing: %s\n",
> > -                       info->policy & SEV_POLICY_NOKS ? "off" : "on");
> > +                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_DBG ? "on"
> > +                                                                       : "off");
> > +        monitor_printf(mon, "SMT allowed: %s\n",
> > +                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_SMT ? "on"
> > +                                                                       : "off");
> >      } else {
> > -        monitor_printf(mon, "SEV is not enabled\n");
> > +        monitor_printf(mon, "handle: %d\n", info->u.sev.handle);
> > +        monitor_printf(mon, "state: %s\n", SevState_str(info->state));
> > +        monitor_printf(mon, "build: %d\n", info->build_id);
> > +        monitor_printf(mon, "api version: %d.%d\n",
> > +                       info->api_major, info->api_minor);
> 
> This set of three fields is identical in both branches, so the duplication
> in printing it should be eliminated.

Makes sense.

> 
> > +        monitor_printf(mon, "debug: %s\n",
> > +                       info->u.sev.policy & SEV_POLICY_NODBG ? "off" : "on");
> > +        monitor_printf(mon, "key-sharing: %s\n",
> > +                       info->u.sev.policy & SEV_POLICY_NOKS ? "off" : "on");
> >      }
> > +    monitor_printf(mon, "SEV type: %s\n", SevGuestType_str(info->sev_type));
> 
> I'd say 'SEV type' should be printed  before everything else, since
> that value is the discriminator for interpreting the other data that
> is printed.

Will do.

Thanks,

Mike

> 
> >  
> > +out:
> >      qapi_free_SevInfo(info);
> >  }
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP
@ 2024-03-20 22:23       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth via @ 2024-03-20 22:23 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:10:04PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:27AM -0500, Michael Roth wrote:
> > Most of the current 'query-sev' command is relevant to both legacy
> > SEV/SEV-ES guests and SEV-SNP guests, with 2 exceptions:
> > 
> >   - 'policy' is a 64-bit field for SEV-SNP, not 32-bit, and
> >     the meaning of the bit positions has changed
> >   - 'handle' is not relevant to SEV-SNP
> > 
> > To address this, this patch adds a new 'sev-type' field that can be
> > used as a discriminator to select between SEV and SEV-SNP-specific
> > fields/formats without breaking compatibility for existing management
> > tools (so long as management tools that add support for launching
> > SEV-SNP guest update their handling of query-sev appropriately).
> > 
> > The corresponding HMP command has also been fixed up similarly.
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  qapi/misc-target.json | 71 ++++++++++++++++++++++++++++++++++---------
> >  target/i386/sev.c     | 50 ++++++++++++++++++++----------
> >  target/i386/sev.h     |  3 ++
> >  3 files changed, 94 insertions(+), 30 deletions(-)
> > 
> > diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> > index 4e0a6492a9..daceb85d95 100644
> > --- a/qapi/misc-target.json
> > +++ b/qapi/misc-target.json
> > @@ -47,6 +47,49 @@
> >             'send-update', 'receive-update' ],
> >    'if': 'TARGET_I386' }
> >  
> > +##
> > +# @SevGuestType:
> > +#
> > +# An enumeration indicating the type of SEV guest being run.
> > +#
> > +# @sev:     The guest is a legacy SEV or SEV-ES guest.
> > +# @sev-snp: The guest is an SEV-SNP guest.
> > +#
> > +# Since: 6.2
> 
> Now 9.1 at the earliest.
> 
> > +##
> > +{ 'enum': 'SevGuestType',
> > +  'data': [ 'sev', 'sev-snp' ],
> > +  'if': 'TARGET_I386' }
> > +
> > +##
> > +# @SevGuestInfo:
> > +#
> > +# Information specific to legacy SEV/SEV-ES guests.
> > +#
> > +# @policy: SEV policy value
> > +#
> > +# @handle: SEV firmware handle
> > +#
> > +# Since: 2.12
> > +##
> > +{ 'struct': 'SevGuestInfo',
> > +  'data': { 'policy': 'uint32',
> > +            'handle': 'uint32' },
> > +  'if': 'TARGET_I386' }
> > +
> > +##
> > +# @SevSnpGuestInfo:
> > +#
> > +# Information specific to SEV-SNP guests.
> > +#
> > +# @snp-policy: SEV-SNP policy value
> > +#
> > +# Since: 6.2
> > +##
> > +{ 'struct': 'SevSnpGuestInfo',
> > +  'data': { 'snp-policy': 'uint64' },
> > +  'if': 'TARGET_I386' }
> 
> IMHO it can just be called 'policy' still, since
> it is implicitly within a 'Snp' specific type.
> 
> 
> > +
> >  ##
> >  # @SevInfo:
> >  #
> > @@ -60,25 +103,25 @@
> >  #
> >  # @build-id: SEV FW build id
> >  #
> > -# @policy: SEV policy value
> > -#
> >  # @state: SEV guest state
> >  #
> > -# @handle: SEV firmware handle
> > +# @sev-type: Type of SEV guest being run
> >  #
> >  # Since: 2.12
> >  ##
> > -{ 'struct': 'SevInfo',
> > -    'data': { 'enabled': 'bool',
> > -              'api-major': 'uint8',
> > -              'api-minor' : 'uint8',
> > -              'build-id' : 'uint8',
> > -              'policy' : 'uint32',
> > -              'state' : 'SevState',
> > -              'handle' : 'uint32'
> > -            },
> > -  'if': 'TARGET_I386'
> > -}
> > +{ 'union': 'SevInfo',
> > +  'base': { 'enabled': 'bool',
> > +            'api-major': 'uint8',
> > +            'api-minor' : 'uint8',
> > +            'build-id' : 'uint8',
> > +            'state' : 'SevState',
> > +            'sev-type' : 'SevGuestType' },
> > +  'discriminator': 'sev-type',
> > +  'data': {
> > +      'sev': 'SevGuestInfo',
> > +      'sev-snp': 'SevSnpGuestInfo' },
> > +  'if': 'TARGET_I386' }
> > +
> >  
> >  ##
> >  # @query-sev:
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 43e6c0172f..b03d70a3d1 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -353,25 +353,27 @@ static SevInfo *sev_get_info(void)
> >  {
> >      SevInfo *info;
> >      SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> > -    SevGuestState *sev_guest =
> > -        (SevGuestState *)object_dynamic_cast(OBJECT(sev_common),
> > -                                             TYPE_SEV_GUEST);
> >  
> >      info = g_new0(SevInfo, 1);
> >      info->enabled = sev_enabled();
> >  
> >      if (info->enabled) {
> > -        if (sev_guest) {
> > -            info->handle = sev_guest->handle;
> > -        }
> >          info->api_major = sev_common->api_major;
> >          info->api_minor = sev_common->api_minor;
> >          info->build_id = sev_common->build_id;
> >          info->state = sev_common->state;
> > -        /* we only report the lower 32-bits of policy for SNP, ok for now... */
> > -        info->policy =
> > -            (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > -                                               "policy", NULL);
> > +
> > +        if (sev_snp_enabled()) {
> > +            info->sev_type = SEV_GUEST_TYPE_SEV_SNP;
> > +            info->u.sev_snp.snp_policy =
> > +                object_property_get_uint(OBJECT(sev_common), "policy", NULL);
> > +        } else {
> > +            info->sev_type = SEV_GUEST_TYPE_SEV;
> > +            info->u.sev.handle = SEV_GUEST(sev_common)->handle;
> > +            info->u.sev.policy =
> > +                (uint32_t)object_property_get_uint(OBJECT(sev_common),
> > +                                                   "policy", NULL);
> > +        }
> >      }
> 
> Ok, this is fixing the issues I reported earlier.
> 
> For 'policy' I do wonder if we really need to push it into the
> type specific part of the union, as oppposed to having a common
> 'policy' field that is uint64 in size.
> 
> As mentioned earlier, on the wire there's no distinction between
> int32/int64s, so there's no compat issues with changing it from
> int32 to int64.

Mentioned this in response to your earlier reply, but the renaming of
'policy' to 'snp_policy' was in response to Dave's query about old
management tools who don't understand/parse the new sev-type field
and blinding misinterpret an SNP 'policy' as an SEV one:

  https://lore.kernel.org/kvm/YTdSlg5NymDQex5T@work-vm/T/#mac6758af9bfc41ee49ff3ef5c3ec3779ec275ff9

I think the thinking is that it's better that they see nothing at all
(likely treating as policy 0x0) versus getting unexpected values and
reporting random policy features.

> 
> >  
> >      return info;
> > @@ -394,20 +396,36 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict)
> >  {
> >      SevInfo *info = sev_get_info();
> >  
> > -    if (info && info->enabled) {
> > -        monitor_printf(mon, "handle: %d\n", info->handle);
> > +    if (!info || !info->enabled) {
> > +        monitor_printf(mon, "SEV is not enabled\n");
> > +        goto out;
> > +    }
> > +
> > +    if (sev_snp_enabled()) {
> >          monitor_printf(mon, "state: %s\n", SevState_str(info->state));
> >          monitor_printf(mon, "build: %d\n", info->build_id);
> >          monitor_printf(mon, "api version: %d.%d\n",
> >                         info->api_major, info->api_minor);
> >          monitor_printf(mon, "debug: %s\n",
> > -                       info->policy & SEV_POLICY_NODBG ? "off" : "on");
> > -        monitor_printf(mon, "key-sharing: %s\n",
> > -                       info->policy & SEV_POLICY_NOKS ? "off" : "on");
> > +                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_DBG ? "on"
> > +                                                                       : "off");
> > +        monitor_printf(mon, "SMT allowed: %s\n",
> > +                       info->u.sev_snp.snp_policy & SEV_SNP_POLICY_SMT ? "on"
> > +                                                                       : "off");
> >      } else {
> > -        monitor_printf(mon, "SEV is not enabled\n");
> > +        monitor_printf(mon, "handle: %d\n", info->u.sev.handle);
> > +        monitor_printf(mon, "state: %s\n", SevState_str(info->state));
> > +        monitor_printf(mon, "build: %d\n", info->build_id);
> > +        monitor_printf(mon, "api version: %d.%d\n",
> > +                       info->api_major, info->api_minor);
> 
> This set of three fields is identical in both branches, so the duplication
> in printing it should be eliminated.

Makes sense.

> 
> > +        monitor_printf(mon, "debug: %s\n",
> > +                       info->u.sev.policy & SEV_POLICY_NODBG ? "off" : "on");
> > +        monitor_printf(mon, "key-sharing: %s\n",
> > +                       info->u.sev.policy & SEV_POLICY_NOKS ? "off" : "on");
> >      }
> > +    monitor_printf(mon, "SEV type: %s\n", SevGuestType_str(info->sev_type));
> 
> I'd say 'SEV type' should be printed  before everything else, since
> that value is the discriminator for interpreting the other data that
> is printed.

Will do.

Thanks,

Mike

> 
> >  
> > +out:
> >      qapi_free_SevInfo(info);
> >  }
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 37/49] i386/sev: Add the SNP launch start context
  2024-03-20  9:58   ` Paolo Bonzini
@ 2024-03-20 22:32     ` Michael Roth
  2024-03-21 11:55       ` Paolo Bonzini
  0 siblings, 1 reply; 110+ messages in thread
From: Michael Roth @ 2024-03-20 22:32 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

On Wed, Mar 20, 2024 at 10:58:30AM +0100, Paolo Bonzini wrote:
> On 3/20/24 09:39, Michael Roth wrote:
> > From: Brijesh Singh <brijesh.singh@amd.com>
> > 
> > The SNP_LAUNCH_START is called first to create a cryptographic launch
> > context within the firmware.
> > 
> > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >   target/i386/sev.c        | 42 +++++++++++++++++++++++++++++++++++++++-
> >   target/i386/trace-events |  1 +
> >   2 files changed, 42 insertions(+), 1 deletion(-)
> > 
> > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > index 3b4dbc63b1..9f63a41f08 100644
> > --- a/target/i386/sev.c
> > +++ b/target/i386/sev.c
> > @@ -39,6 +39,7 @@
> >   #include "confidential-guest.h"
> >   #include "hw/i386/pc.h"
> >   #include "exec/address-spaces.h"
> > +#include "qemu/queue.h"
> >   OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
> >   OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> > @@ -106,6 +107,16 @@ struct SevSnpGuestState {
> >   #define DEFAULT_SEV_DEVICE      "/dev/sev"
> >   #define DEFAULT_SEV_SNP_POLICY  0x30000
> > +typedef struct SevLaunchUpdateData {
> > +    QTAILQ_ENTRY(SevLaunchUpdateData) next;
> > +    hwaddr gpa;
> > +    void *hva;
> > +    uint64_t len;
> > +    int type;
> > +} SevLaunchUpdateData;
> > +
> > +static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
> > +
> >   #define SEV_INFO_BLOCK_GUID     "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
> >   typedef struct __attribute__((__packed__)) SevInfoBlock {
> >       /* SEV-ES Reset Vector Address */
> > @@ -668,6 +679,30 @@ sev_read_file_base64(const char *filename, guchar **data, gsize *len)
> >       return 0;
> >   }
> > +static int
> > +sev_snp_launch_start(SevSnpGuestState *sev_snp_guest)
> > +{
> > +    int fw_error, rc;
> > +    SevCommonState *sev_common = SEV_COMMON(sev_snp_guest);
> > +    struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
> > +
> > +    trace_kvm_sev_snp_launch_start(start->policy, sev_snp_guest->guest_visible_workarounds);
> > +
> > +    rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
> > +                   start, &fw_error);
> > +    if (rc < 0) {
> > +        error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'",
> > +                __func__, rc, fw_error, fw_error_to_str(fw_error));
> > +        return 1;
> > +    }
> > +
> > +    QTAILQ_INIT(&launch_update);
> > +
> > +    sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
> > +
> > +    return 0;
> > +}
> > +
> >   static int
> >   sev_launch_start(SevGuestState *sev_guest)
> >   {
> > @@ -1007,7 +1042,12 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> >           goto err;
> >       }
> > -    ret = sev_launch_start(SEV_GUEST(sev_common));
> > +    if (sev_snp_enabled()) {
> > +        ret = sev_snp_launch_start(SEV_SNP_GUEST(sev_common));
> > +    } else {
> > +        ret = sev_launch_start(SEV_GUEST(sev_common));
> > +    }
> 
> Instead of an "if", this should be a method in sev-common.  Likewise for
> launch_finish in the next patch.

Makes sense.

> 
> Also, patch 47 should introduce an "int (*launch_update_data)(hwaddr gpa,
> uint8_t *ptr, uint64_t len)" method whose implementation is either the
> existing sev_launch_update_data() for sev-guest, or a wrapper around
> snp_launch_update_data() (to add KVM_SEV_SNP_PAGE_TYPE_NORMAL) for
> sev-snp-guest.

I suppose if we end up introducing an unused 'gpa' parameter in the case
of sev_launch_update_data() that's still worth the change? Seems
reasonable to me.

> 
> In general, the only uses of sev_snp_enabled() should be in
> sev_add_kernel_loader_hashes() and kvm_handle_vmgexit_ext_req().  I would
> not be that strict for the QMP and HMP functions, but if you want to make
> those methods of sev-common I wouldn't complain.

There's a good bit of duplication in those cases which is a little
awkward to break out into a common helper. Will consider these as well
though.

Thanks,

Mike

> 
> Paolo
> 
> >       if (ret) {
> >           error_setg(errp, "%s: failed to create encryption context", __func__);
> >           goto err;
> > diff --git a/target/i386/trace-events b/target/i386/trace-events
> > index 2cd8726eeb..cb26d8a925 100644
> > --- a/target/i386/trace-events
> > +++ b/target/i386/trace-events
> > @@ -11,3 +11,4 @@ kvm_sev_launch_measurement(const char *value) "data %s"
> >   kvm_sev_launch_finish(void) ""
> >   kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
> >   kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
> > +kvm_sev_snp_launch_start(uint64_t policy, char *gosvw) "policy 0x%" PRIx64 " gosvw %s"
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header
  2024-03-20 17:55   ` Isaku Yamahata
@ 2024-03-20 22:35     ` Michael Roth
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-20 22:35 UTC (permalink / raw)
  To: Isaku Yamahata
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

On Wed, Mar 20, 2024 at 10:55:35AM -0700, Isaku Yamahata wrote:
> On Wed, Mar 20, 2024 at 03:39:36AM -0500,
> Michael Roth <michael.roth@amd.com> wrote:
> 
> > From: Brijesh Singh <brijesh.singh@amd.com>
> > 
> > A recent version of OVMF expanded the reset vector GUID list to add
> > SEV-specific metadata GUID. The SEV metadata describes the reserved
> > memory regions such as the secrets and CPUID page used during the SEV-SNP
> > guest launch.
> > 
> > The pc_system_get_ovmf_sev_metadata_ptr() is used to retieve the SEV
> > metadata pointer from the OVMF GUID list.
> > 
> > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  hw/i386/pc_sysfw_ovmf.c | 33 +++++++++++++++++++++++++++++++++
> >  include/hw/i386/pc.h    | 26 ++++++++++++++++++++++++++
> >  2 files changed, 59 insertions(+)
> > 
> > diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c
> > index 07a4c267fa..32efa34614 100644
> > --- a/hw/i386/pc_sysfw_ovmf.c
> > +++ b/hw/i386/pc_sysfw_ovmf.c
> > @@ -35,6 +35,31 @@ static const int bytes_after_table_footer = 32;
> >  static bool ovmf_flash_parsed;
> >  static uint8_t *ovmf_table;
> >  static int ovmf_table_len;
> > +static OvmfSevMetadata *ovmf_sev_metadata_table;
> > +
> > +#define OVMF_SEV_META_DATA_GUID "dc886566-984a-4798-A75e-5585a7bf67cc"
> > +typedef struct __attribute__((__packed__)) OvmfSevMetadataOffset {
> > +    uint32_t offset;
> > +} OvmfSevMetadataOffset;
> > +
> > +static void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
> > +{
> > +    OvmfSevMetadata     *metadata;
> > +    OvmfSevMetadataOffset  *data;
> > +
> > +    if (!pc_system_ovmf_table_find(OVMF_SEV_META_DATA_GUID, (uint8_t **)&data,
> > +                                   NULL)) {
> > +        return;
> > +    }
> > +
> > +    metadata = (OvmfSevMetadata *)(flash_ptr + flash_size - data->offset);
> > +    if (memcmp(metadata->signature, "ASEV", 4) != 0) {
> > +        return;
> > +    }
> > +
> > +    ovmf_sev_metadata_table = g_malloc(metadata->len);
> > +    memcpy(ovmf_sev_metadata_table, metadata, metadata->len);
> > +}
> >  
> >  void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
> >  {
> > @@ -90,6 +115,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
> >       */
> >      memcpy(ovmf_table, ptr - tot_len, tot_len);
> >      ovmf_table += tot_len;
> > +
> > +    /* Copy the SEV metadata table (if exist) */
> > +    pc_system_parse_sev_metadata(flash_ptr, flash_size);
> >  }
> 
> Can we move this call to x86_firmware_configure() @ pc_sysfw.c, and move sev
> specific bits to somewhere to sev specific file?  We don't have to parse sev
> metadata for non-SEV case, right?
> 
> We don't have to touch common ovmf file. It also will be consistent with tdx
> case.  TDX patch series adds tdx_parse_tdvf() to x86_firmware_configure().

Yep, makes sense to handle it similarly for SNP.

Thanks,

Mike

> 
> thanks,
> 
> >  
> >  /**
> > @@ -159,3 +187,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
> >      }
> >      return false;
> >  }
> > +
> > +OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void)
> > +{
> > +    return ovmf_sev_metadata_table;
> > +}
> > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > index fb1d4106e5..df9a61540d 100644
> > --- a/include/hw/i386/pc.h
> > +++ b/include/hw/i386/pc.h
> > @@ -163,6 +163,32 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
> >  #define PCI_HOST_ABOVE_4G_MEM_SIZE     "above-4g-mem-size"
> >  #define PCI_HOST_PROP_SMM_RANGES       "smm-ranges"
> >  
> > +typedef enum {
> > +    SEV_DESC_TYPE_UNDEF,
> > +    /* The section contains the region that must be validated by the VMM. */
> > +    SEV_DESC_TYPE_SNP_SEC_MEM,
> > +    /* The section contains the SNP secrets page */
> > +    SEV_DESC_TYPE_SNP_SECRETS,
> > +    /* The section contains address that can be used as a CPUID page */
> > +    SEV_DESC_TYPE_CPUID,
> > +
> > +} ovmf_sev_metadata_desc_type;
> > +
> > +typedef struct __attribute__((__packed__)) OvmfSevMetadataDesc {
> > +    uint32_t base;
> > +    uint32_t len;
> > +    ovmf_sev_metadata_desc_type type;
> > +} OvmfSevMetadataDesc;
> > +
> > +typedef struct __attribute__((__packed__)) OvmfSevMetadata {
> > +    uint8_t signature[4];
> > +    uint32_t len;
> > +    uint32_t version;
> > +    uint32_t num_desc;
> > +    OvmfSevMetadataDesc descs[];
> > +} OvmfSevMetadata;
> > +
> > +OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void);
> >  
> >  void pc_pci_as_mapping_init(MemoryRegion *system_memory,
> >                              MemoryRegion *pci_address_space);
> > -- 
> > 2.25.1
> > 
> > 
> 
> -- 
> Isaku Yamahata <isaku.yamahata@intel.com>

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 37/49] i386/sev: Add the SNP launch start context
  2024-03-20 22:32     ` Michael Roth
@ 2024-03-21 11:55       ` Paolo Bonzini
  0 siblings, 0 replies; 110+ messages in thread
From: Paolo Bonzini @ 2024-03-21 11:55 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata,
	Brijesh Singh

[-- Attachment #1: Type: text/plain, Size: 5658 bytes --]

Il mer 20 mar 2024, 23:33 Michael Roth <michael.roth@amd.com> ha scritto:

> On Wed, Mar 20, 2024 at 10:58:30AM +0100, Paolo Bonzini wrote:
> > On 3/20/24 09:39, Michael Roth wrote:
> > > From: Brijesh Singh <brijesh.singh@amd.com>
> > >
> > > The SNP_LAUNCH_START is called first to create a cryptographic launch
> > > context within the firmware.
> > >
> > > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > ---
> > >   target/i386/sev.c        | 42
> +++++++++++++++++++++++++++++++++++++++-
> > >   target/i386/trace-events |  1 +
> > >   2 files changed, 42 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/target/i386/sev.c b/target/i386/sev.c
> > > index 3b4dbc63b1..9f63a41f08 100644
> > > --- a/target/i386/sev.c
> > > +++ b/target/i386/sev.c
> > > @@ -39,6 +39,7 @@
> > >   #include "confidential-guest.h"
> > >   #include "hw/i386/pc.h"
> > >   #include "exec/address-spaces.h"
> > > +#include "qemu/queue.h"
> > >   OBJECT_DECLARE_SIMPLE_TYPE(SevCommonState, SEV_COMMON)
> > >   OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
> > > @@ -106,6 +107,16 @@ struct SevSnpGuestState {
> > >   #define DEFAULT_SEV_DEVICE      "/dev/sev"
> > >   #define DEFAULT_SEV_SNP_POLICY  0x30000
> > > +typedef struct SevLaunchUpdateData {
> > > +    QTAILQ_ENTRY(SevLaunchUpdateData) next;
> > > +    hwaddr gpa;
> > > +    void *hva;
> > > +    uint64_t len;
> > > +    int type;
> > > +} SevLaunchUpdateData;
> > > +
> > > +static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
> > > +
> > >   #define SEV_INFO_BLOCK_GUID
>  "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
> > >   typedef struct __attribute__((__packed__)) SevInfoBlock {
> > >       /* SEV-ES Reset Vector Address */
> > > @@ -668,6 +679,30 @@ sev_read_file_base64(const char *filename, guchar
> **data, gsize *len)
> > >       return 0;
> > >   }
> > > +static int
> > > +sev_snp_launch_start(SevSnpGuestState *sev_snp_guest)
> > > +{
> > > +    int fw_error, rc;
> > > +    SevCommonState *sev_common = SEV_COMMON(sev_snp_guest);
> > > +    struct kvm_sev_snp_launch_start *start =
> &sev_snp_guest->kvm_start_conf;
> > > +
> > > +    trace_kvm_sev_snp_launch_start(start->policy,
> sev_snp_guest->guest_visible_workarounds);
> > > +
> > > +    rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
> > > +                   start, &fw_error);
> > > +    if (rc < 0) {
> > > +        error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'",
> > > +                __func__, rc, fw_error, fw_error_to_str(fw_error));
> > > +        return 1;
> > > +    }
> > > +
> > > +    QTAILQ_INIT(&launch_update);
> > > +
> > > +    sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >   static int
> > >   sev_launch_start(SevGuestState *sev_guest)
> > >   {
> > > @@ -1007,7 +1042,12 @@ static int
> sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> > >           goto err;
> > >       }
> > > -    ret = sev_launch_start(SEV_GUEST(sev_common));
> > > +    if (sev_snp_enabled()) {
> > > +        ret = sev_snp_launch_start(SEV_SNP_GUEST(sev_common));
> > > +    } else {
> > > +        ret = sev_launch_start(SEV_GUEST(sev_common));
> > > +    }
> >
> > Instead of an "if", this should be a method in sev-common.  Likewise for
> > launch_finish in the next patch.
>
> Makes sense.
>
> >
> > Also, patch 47 should introduce an "int (*launch_update_data)(hwaddr gpa,
> > uint8_t *ptr, uint64_t len)" method whose implementation is either the
> > existing sev_launch_update_data() for sev-guest, or a wrapper around
> > snp_launch_update_data() (to add KVM_SEV_SNP_PAGE_TYPE_NORMAL) for
> > sev-snp-guest.
>
> I suppose if we end up introducing an unused 'gpa' parameter in the case
> of sev_launch_update_data() that's still worth the change? Seems
> reasonable to me.
>

Yeah, you most likely have the gpa anyway in the kind of board code that
calls UPDATE_DATA. It would put some challenges with migration to use gpas
everywhere instead of ram_addrs, but that doesn't use UPDATE_DATA and
there's no SEV/SEV-ES migration anyway.

>
> >
> > In general, the only uses of sev_snp_enabled() should be in
> > sev_add_kernel_loader_hashes() and kvm_handle_vmgexit_ext_req().  I would
> > not be that strict for the QMP and HMP functions, but if you want to make
> > those methods of sev-common I wouldn't complain.
>
> There's a good bit of duplication in those cases which is a little
> awkward to break out into a common helper. Will consider these as well
> though.
>

I would say especially in HMP do not bother since you have to start from a
QAPI union and not QOM objects. For QMP I am not sure but don't waste too
much effort in it. All I wanted to say is that the monitor is a fine place
to draw the line.

Paolo


> Thanks,
>
> Mike
>
> >
> > Paolo
> >
> > >       if (ret) {
> > >           error_setg(errp, "%s: failed to create encryption context",
> __func__);
> > >           goto err;
> > > diff --git a/target/i386/trace-events b/target/i386/trace-events
> > > index 2cd8726eeb..cb26d8a925 100644
> > > --- a/target/i386/trace-events
> > > +++ b/target/i386/trace-events
> > > @@ -11,3 +11,4 @@ kvm_sev_launch_measurement(const char *value) "data
> %s"
> > >   kvm_sev_launch_finish(void) ""
> > >   kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret,
> int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
> > >   kvm_sev_attestation_report(const char *mnonce, const char *data)
> "mnonce %s data %s"
> > > +kvm_sev_snp_launch_start(uint64_t policy, char *gosvw) "policy 0x%"
> PRIx64 " gosvw %s"
> >
>
>

[-- Attachment #2: Type: text/html, Size: 8072 bytes --]

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
  2024-03-20 12:22   ` Daniel P. Berrangé
@ 2024-03-21 13:42       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-21 13:42 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:22:34PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:43AM -0500, Michael Roth wrote:
> > TODO: Brijesh as author, me as co-author (vice-versa depending)
> >       drop flash handling? we only support BIOS now
> 
> A reminder that this commit message needs fixing.

Sorry, definitely meant to fix this one up before submitting. I've
gone ahead and force-pushed an updated tree to same qemu-v3-rc branch.
The only change is proper attribution/commit message for this patch:

  https://github.com/AMDESE/qemu/commit/c54618a1cc23f2398e6c3af6f3cf140c4901347c

-Mike

> 
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  hw/i386/pc_sysfw.c            | 12 +++++++-----
> >  hw/i386/x86.c                 |  2 +-
> >  include/hw/i386/x86.h         |  2 +-
> >  target/i386/sev-sysemu-stub.c |  2 +-
> >  target/i386/sev.c             | 15 +++++++++++----
> >  target/i386/sev.h             |  2 +-
> >  6 files changed, 22 insertions(+), 13 deletions(-)
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
@ 2024-03-21 13:42       ` Michael Roth via
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth via @ 2024-03-21 13:42 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Markus Armbruster,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 12:22:34PM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 20, 2024 at 03:39:43AM -0500, Michael Roth wrote:
> > TODO: Brijesh as author, me as co-author (vice-versa depending)
> >       drop flash handling? we only support BIOS now
> 
> A reminder that this commit message needs fixing.

Sorry, definitely meant to fix this one up before submitting. I've
gone ahead and force-pushed an updated tree to same qemu-v3-rc branch.
The only change is proper attribution/commit message for this patch:

  https://github.com/AMDESE/qemu/commit/c54618a1cc23f2398e6c3af6f3cf140c4901347c

-Mike

> 
> > 
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> >  hw/i386/pc_sysfw.c            | 12 +++++++-----
> >  hw/i386/x86.c                 |  2 +-
> >  include/hw/i386/x86.h         |  2 +-
> >  target/i386/sev-sysemu-stub.c |  2 +-
> >  target/i386/sev.c             | 15 +++++++++++----
> >  target/i386/sev.h             |  2 +-
> >  6 files changed, 22 insertions(+), 13 deletions(-)
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range()
  2024-03-20 20:04       ` David Hildenbrand
@ 2024-03-21 20:24         ` Michael Roth
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-21 20:24 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P. Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 09:04:52PM +0100, David Hildenbrand wrote:
> On 20.03.24 18:38, Michael Roth wrote:
> > On Wed, Mar 20, 2024 at 10:37:14AM +0100, David Hildenbrand wrote:
> > > On 20.03.24 09:39, Michael Roth wrote:
> > > > From: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > 
> > > > When memory page is converted from private to shared, the original
> > > > private memory is back'ed by guest_memfd. Introduce
> > > > ram_block_discard_guest_memfd_range() for discarding memory in
> > > > guest_memfd.
> > > > 
> > > > Originally-from: Isaku Yamahata <isaku.yamahata@intel.com>
> > > > Codeveloped-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > 
> > > "Co-developed-by"
> > > 
> > > > Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > Reviewed-by: David Hildenbrand <david@redhat.com>
> > > 
> > > Your SOB should go here.
> > > 
> > > > ---
> > > > Changes in v5:
> > > > - Collect Reviewed-by from David;
> > > > 
> > > > Changes in in v4:
> > > > - Drop ram_block_convert_range() and open code its implementation in the
> > > >     next Patch.
> > > > 
> > > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > 
> > > I only received 3 patches from this series, and now I am confused: changelog
> > > talks about v5 and this is "PATCH v3"
> > > 
> > > Please make sure to send at least the cover letter along (I might not need
> > > the other 46 patches :D ).
> > 
> > Sorry for the confusion, you got auto-Cc'd by git, which is good, but
> > not sure there's a good way to make sure everyone gets a copy of the
> > cover letter. I could see how it would help useful to potential
> > reviewers though. I'll try to come up with a script for it and take that
> > approach in the future.
> 
> A script shared with me in the past to achieve that in most cases:
> 
> $ cat cc-cmd.sh
> #!/bin/bash
> 
> if [[ $1 == *gitsendemail.msg* || $1 == *cover-letter* ]]; then
>         grep ': .* <.*@.*>' -h *.patch | sed 's/^.*: //' | sort | uniq
> fi
> 
> 
> And attach to "git send-email ... *.patch": --cc-cmd=./cc-cmd.sh

That should do the trick nicely. Thanks!

-Mike

> 
> -- 
> Cheers,
> 
> David / dhildenb
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (49 preceding siblings ...)
  2024-03-20  9:59 ` [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Paolo Bonzini
@ 2024-03-21 20:26 ` Michael Roth
  2024-04-18 11:37 ` Ani Sinha
  51 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-03-21 20:26 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Tom Lendacky, Paolo Bonzini, Daniel P . Berrangé,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

On Wed, Mar 20, 2024 at 03:38:56AM -0500, Michael Roth wrote:
> 
> Testing
> -------
> 
> This series has been tested against the following host kernel tree, which
> is a snapshot of the latest WIP SNP hypervisor tree at the time of this
> posting. It will likely not be kept up to date afterward, so please keep an
> eye upstream or official AMDESE github if you are looking for the latest
> some time after this posting:
> 
>   https://github.com/mdroth/linux/commits/snp-host-v12-wip40/

I just noticed I had a necessary local change that wasn't included in the
initial push of this branch. I've updated the branch now, but just wanted
to post a heads-up in case anyone was having issues.

-Mike

^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20 11:44   ` Daniel P. Berrangé
  2024-03-20 21:36       ` Michael Roth via
@ 2024-03-27 15:22     ` Markus Armbruster
  1 sibling, 0 replies; 110+ messages in thread
From: Markus Armbruster @ 2024-03-27 15:22 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Michael Roth, qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Daniel P. Berrangé <berrange@redhat.com> writes:

> On Wed, Mar 20, 2024 at 03:39:17AM -0500, Michael Roth wrote:
>> Currently all SEV/SEV-ES functionality is managed through a single
>> 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
>> same approach won't work well since some of the properties/state
>> managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
>> rely on a new QOM type with its own set of properties/state.
>> 
>> To prepare for this, this patch moves common state into an abstract
>> 'sev-common' parent type to encapsulate properties/state that are
>> common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
>> properties/state in the current 'sev-guest' type. This should not
>> affect current behavior or command-line options.
>> 
>> As part of this patch, some related changes are also made:
>> 
>>   - a static 'sev_guest' variable is currently used to keep track of
>>     the 'sev-guest' instance. SEV-SNP would similarly introduce an
>>     'sev_snp_guest' static variable. But these instances are now
>>     available via qdev_get_machine()->cgs, so switch to using that
>>     instead and drop the static variable.
>> 
>>   - 'sev_guest' is currently used as the name for the static variable
>>     holding a pointer to the 'sev-guest' instance. Re-purpose the name
>>     as a local variable referring the 'sev-guest' instance, and use
>>     that consistently throughout the code so it can be easily
>>     distinguished from sev-common/sev-snp-guest instances.
>> 
>>   - 'sev' is generally used as the name for local variables holding a
>>     pointer to the 'sev-guest' instance. In cases where that now points
>>     to common state, use the name 'sev_common'; in cases where that now
>>     points to state specific to 'sev-guest' instance, use the name
>>     'sev_guest'
>> 
>> Signed-off-by: Michael Roth <michael.roth@amd.com>
>> ---
>>  qapi/qom.json     |  32 ++--
>>  target/i386/sev.c | 457 ++++++++++++++++++++++++++--------------------
>>  target/i386/sev.h |   3 +
>>  3 files changed, 281 insertions(+), 211 deletions(-)
>> 
>> diff --git a/qapi/qom.json b/qapi/qom.json
>> index baae3a183f..66b5781ca6 100644
>> --- a/qapi/qom.json
>> +++ b/qapi/qom.json
>> @@ -875,12 +875,29 @@
>>    'data': { '*filename': 'str' } }
>>  
>>  ##
>> -# @SevGuestProperties:
>> +# @SevCommonProperties:
>>  #
>> -# Properties for sev-guest objects.
>> +# Properties common to objects that are derivatives of sev-common.
>>  #
>>  # @sev-device: SEV device to use (default: "/dev/sev")
>>  #
>> +# @cbitpos: C-bit location in page table entry (default: 0)
>> +#
>> +# @reduced-phys-bits: number of bits in physical addresses that become
>> +#     unavailable when SEV is enabled
>> +#
>> +# Since: 2.12
>
> Not quite sure what we've done in this scenario before.
> It feels wierd to use '2.12' for the new base type, even
> though in effect the properties all existed since 2.12 in
> the sub-class.
>
> Perhaps 'Since: 9.1' for the type, but 'Since: 2.12' for the
> properties, along with an explanatory comment about stuff
> moving into the new base type ?
>
> Markus, opinions ?

The confusion is due to us documenting the schema instead of the
external interface defined by it.  Let me explain.

The external interface is commands and their arguments, ignoring
results, errors and events for brevity's sake.

We use types to define the arguments.  How exactly we use types is not
part of the interface.  This permits refactorings.  However, since the
documentation is attached to the types, refactorings can easily mess it
up.

I'd like to demonstrate this for a simpler command first, then return to
object-add.

Consider nbd-server-add.  It is documented to be since 1.3.

From now on, I'm abbreviating "documented to be since X.Y" to "since
X.Y".

Its arguments are the members of struct NbdServerAddOptions.

NbdServerAddOptions is since 5.0.  Its base BlockExportOptionsNbdBase is
since 5.2.

BlockExportOptionsNbdBase member @name is since 2.12, and @description
is since 5.0.

NbdServerAddOptions member @bitmap is since 4.0.  Members @device and
@writable have no "since" documented, so they inherit it from the
struct, i.e. 5.0.

So, it looks like the command is since 1.3, argument @name since 2.12,
@bitmap since 4.0, @description, @device, and @writable since 5.0.

Wrong!  Arguments @device and @writable have always been there,
i.e. since 1.3.  We ended up with documentation incorrectly claiming 5.0
via several refactorings.

Initially, the command arguments were defined right with the command.
They simply inherited the command's since 1.3.

Commit c62d24e906e (blockdev-nbd: Boxed argument type for
nbd-server-add) moved them to a struct type BlockExportNbd.  The new
struct type was since 5.0.  Newer arguments retained their "since" tags,
but the initial arguments @device and @writable remained without one.
Their documented "since" changed from 1.3 to 5.0.

Aside: the new struct was then used as a branch of union BlockExport,
which was incorrectly documented to be since 4.2.

Messing up "since" when factoring out arguments into a new type was
avoidable: either lie and claim the new type is as old as its members,
or add suitable since tags to its members.

Having a struct with members older than itself looks weird.  Of course,
when a struct came to be is *immaterial*.  How exactly we assemble the
arguments from types is not part of the interface.  We could omit
"since" for the struct, and then require it for all members.  We don't,
because having to think (and then argue!) whether we want a "since" or
not would be a waste of mental capacity.

Here's another refactoring where that may not be possible.  Say you
discover two structs share several members.  You decide to factor them
out into a common base type.  Won't affect the external interface.  But
what if one of these common members has conflicting "since"?  Either we
refrain from the refactoring, or we resort to something like "since
X1.Y1 when used for USER1, since X1.Y2 when used for USER2".  Which
*sucks* as external interface documentation.

Aside: documentation text could clash similarly.  Same code, different
meaning.

I've come to the conclusion that manually recording "since" in the
documentation is dumb.  One, because we mess it up.  Two, because not
messing it up involves either lies or oddities, or too much thought.
Three, because keeping it correct can interfere with refactorings.

Some time ago, Michael Tsirkin suggested to generate "since" information
automatically.  I like the idea.  We'd have to record the external
interface at release time.  To fully replace existing "since" tags, we'd
have to record for old versions, too.  I'd expect this to fix quite a
few doc bugs.

I hope "The confusion is due to us documenting the schema instead of the
external interface defined by it" is now more clear.  The external
interface is derived from the types.  How exactly we construct it from
types is invisible at the interface.  But since we document the
interface by documenting the types, the structure of our interface
documentation mirrors our use of types.  We succeed at shielding the
interface from how we use types, but we fail to shield the
documentation.

Back to your problem at hand.  The external interface is command
object-add.  The command is since 2.0.

It has common arguments and variant arguments depending on the value of
common argument @type.  We specify all that via union ObjectOptions, and
the variant arguments for @type value "sev-guest" via struct
SevGuestProperties.

Union ObjectOptions is since 6.0, but that's immaterial; the type isn't
part of the external interface, only its members are.

Its members are the common arguments.  Since they don't have their own
"since" tag, they inherit it from ObjectOptions, i.e. since 6.0.  That's
simply wrong; they exist since 2.0 just like object-add.

Struct SevGuestProperties is since 2.12, but that's also immaterial.

The members of SevGuestProperties are the variant arguments for @type
value "sev-guest".  Since they don't have their own "since" tag, they
inherit it from SevGuestProperties, i.e. since 2.12.

Your patch moves some of the members to new base type
SevCommonProperties.  As Daniel observed, you can either claim
SevCommonProperties is since 2.12 (which is a lie), or you claim 9.1 for
the type and 2.12 for all its members (which is odd).

I prefer oddities to lies.

I'm not sure we need a comment explaining the oddity.  If you think it's
useful, please make it a non-doc comment.  Reminder:

    ##
    # This is a doc comment.  It goes into generated documentation.
    ##

    # This is is not a doc comment.  It does not go into generated
    # documentation.

Comments?

[...]


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs
  2024-03-20 18:12   ` Isaku Yamahata
@ 2024-03-28  0:45     ` Xiaoyao Li
  2024-04-24  0:08       ` Michael Roth
  0 siblings, 1 reply; 110+ messages in thread
From: Xiaoyao Li @ 2024-03-28  0:45 UTC (permalink / raw)
  To: Isaku Yamahata, Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P. Berrangé,
	Markus Armbruster, Pankaj Gupta, Isaku Yamahata

On 3/21/2024 2:12 AM, Isaku Yamahata wrote:
> On Wed, Mar 20, 2024 at 03:39:44AM -0500,
> Michael Roth <michael.roth@amd.com> wrote:
> 
>> TODO: make this SNP-specific if TDX disables legacy ROMs in general
> 
> TDX disables pc.rom, not disable isa-bios. IIRC, TDX doesn't need pc pflash.

Not TDX doesn't need pc pflash, but TDX cannot support pflash.

Can SNP support the behavior of pflash? That what's got changed will be 
synced back to OVMF file?

> Xiaoyao can chime in.
> 
> Thanks,
> 
>>
>> Current SNP guest kernels will attempt to access these regions with
>> with C-bit set, so guest_memfd is needed to handle that. Otherwise,
>> kvm_convert_memory() will fail when the guest kernel tries to access it
>> and QEMU attempts to call KVM_SET_MEMORY_ATTRIBUTES to set these ranges
>> to private.
>>
>> Whether guests should actually try to access ROM regions in this way (or
>> need to deal with legacy ROM regions at all), is a separate issue to be
>> addressed on kernel side, but current SNP guest kernels will exhibit
>> this behavior and so this handling is needed to allow QEMU to continue
>> running existing SNP guest kernels.
>>
>> Signed-off-by: Michael Roth <michael.roth@amd.com>
>> ---
>>   hw/i386/pc.c       | 13 +++++++++----
>>   hw/i386/pc_sysfw.c | 13 ++++++++++---
>>   2 files changed, 19 insertions(+), 7 deletions(-)
>>
>> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
>> index feb7a93083..5feaeb43ee 100644
>> --- a/hw/i386/pc.c
>> +++ b/hw/i386/pc.c
>> @@ -1011,10 +1011,15 @@ void pc_memory_init(PCMachineState *pcms,
>>       pc_system_firmware_init(pcms, rom_memory);
>>   
>>       option_rom_mr = g_malloc(sizeof(*option_rom_mr));
>> -    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
>> -                           &error_fatal);
>> -    if (pcmc->pci_enabled) {
>> -        memory_region_set_readonly(option_rom_mr, true);
>> +    if (machine_require_guest_memfd(machine)) {
>> +        memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
>> +                                           PC_ROM_SIZE, &error_fatal);
>> +    } else {
>> +        memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
>> +                               &error_fatal);
>> +        if (pcmc->pci_enabled) {
>> +            memory_region_set_readonly(option_rom_mr, true);
>> +        }
>>       }
>>       memory_region_add_subregion_overlap(rom_memory,
>>                                           PC_ROM_MIN_VGA,
>> diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
>> index 9dbb3f7337..850f86edd4 100644
>> --- a/hw/i386/pc_sysfw.c
>> +++ b/hw/i386/pc_sysfw.c
>> @@ -54,8 +54,13 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
>>       /* map the last 128KB of the BIOS in ISA space */
>>       isa_bios_size = MIN(flash_size, 128 * KiB);
>>       isa_bios = g_malloc(sizeof(*isa_bios));
>> -    memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
>> -                           &error_fatal);
>> +    if (machine_require_guest_memfd(current_machine)) {
>> +        memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
>> +                                           isa_bios_size, &error_fatal);
>> +    } else {
>> +        memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
>> +                               &error_fatal);
>> +    }
>>       memory_region_add_subregion_overlap(rom_memory,
>>                                           0x100000 - isa_bios_size,
>>                                           isa_bios,
>> @@ -68,7 +73,9 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
>>              ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
>>              isa_bios_size);
>>   
>> -    memory_region_set_readonly(isa_bios, true);
>> +    if (!machine_require_guest_memfd(current_machine)) {
>> +        memory_region_set_readonly(isa_bios, true);
>> +    }
>>   }
>>   
>>   static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
>> -- 
>> 2.25.1
>>
>>
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support
  2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
                   ` (50 preceding siblings ...)
  2024-03-21 20:26 ` Michael Roth
@ 2024-04-18 11:37 ` Ani Sinha
  51 siblings, 0 replies; 110+ messages in thread
From: Ani Sinha @ 2024-04-18 11:37 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini, Daniel Berrange,
	Markus Armbruster, Pankaj Gupta, Xiaoyao Li, Isaku Yamahata



> On 20 Mar 2024, at 14:08, Michael Roth <michael.roth@amd.com> wrote:
> 
> These patches implement SEV-SNP base support along with CPUID enforcement
> support for QEMU, and are also available at:
> 
>  https://github.com/amdese/qemu/commits/snp-v3-rfc
> 
> they are based on top of the following patchset from Paolo:
> 
>  "[PATCH 0/7] target/i386: VM type infrastructure and KVM_SEV_INIT2 support"
>  https://lists.gnu.org/archive/html/qemu-devel/2024-03/msg04663.html

Can you please also CC me on future revisions of this patchset? 

Thanks!


> 
> 
> Patch Layout
> ------------
> 
> 01-05: Various changes needed to handle new header files in kvm-next tree
>       and some hacks to get a functional header sync in place for building
>       this series.
> 06-18: These are patches directly plucked from Xiaoyao's TDX v5 patchset[1]
>       that implement common dependencies between SNP/TDX like base
>       guest_memfd, KVM_EXIT_MEMORY_FAULT handling (with a small FIXUP), and
>       mechanisms to disable SMM. We would've also needed some of the basic
>       infrastructure for handling specifying VM types for KVM_CREATE, but
>       much of that is now part of the sevinit2 series this patchset is based
>       on. Ideally all these patches, once stable, could be maintained in a
>       common tree so that future SNP/TDX patchsets can be more easily
>       iterated on/reviewed.
> 19-20: Patches introduced by this series that are  possible candidate for a
>       common tree.
>       shared/private pages when things like VFIO are in use.
> 21-32: Introduction of sev-snp-guest object and various configuration
>       requirements for SNP.
> 33-36: Handling for various KVM_EXIT_VMGEXIT events that are handled in
>       userspace.
> 37-49: Support for creating a cryptographic "launch" context and populating
>       various OVMF metadata pages, BIOS regions, and vCPU/VMSA pages with
>       the initial encrypted/measured/validated launch data prior to
>       launching the SNP guest.
> 
> 
> Testing
> -------
> 
> This series has been tested against the following host kernel tree, which
> is a snapshot of the latest WIP SNP hypervisor tree at the time of this
> posting. It will likely not be kept up to date afterward, so please keep an
> eye upstream or official AMDESE github if you are looking for the latest
> some time after this posting:
> 
>  https://github.com/mdroth/linux/commits/snp-host-v12-wip40/
> 
> A patched OVMF is also needed due to upstream KVM no longer supporting MMIO
> ranges that are mapped as private. It is recommended you build the AmdSevX64
> variant as it provides the kernel-hashing support present in this series:
> 
>  https://github.com/mdroth/edk2/commits/apic-mmio-fix1c/
> 
> A basic command-line invocation for SNP would be:
> 
> qemu-system-x86_64 -smp 32,maxcpus=255 -cpu EPYC-Milan-v2
>  -machine q35,confidential-guest-support=sev0,memory-backend=ram1
>  -object memory-backend-memfd,id=ram1,size=4G,share=true,reserve=false
>  -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,id-auth=
>  -bios /home/mroth/ovmf/OVMF_CODE-upstream-20240228-apicfix-1c-AmdSevX64.fd
> 
> With kernel-hashing and certificate data supplied:
> 
> qemu-system-x86_64 -smp 32,maxcpus=255 -cpu EPYC-Milan-v2
>  -machine q35,confidential-guest-support=sev0,memory-backend=ram1
>  -object memory-backend-memfd,id=ram1,size=4G,share=true,reserve=false
>  -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,id-auth=,certs-path=/home/mroth/cert.blob,kernel-hashes=on
>  -bios /home/mroth/ovmf/OVMF_CODE-upstream-20240228-apicfix-1c-AmdSevX64.fd
>  -kernel /boot/vmlinuz-6.8.0-snp-host-v12-wip40+
>  -initrd /boot/initrd.img-6.8.0-snp-host-v12-wip40+
>  -append "root=UUID=d72a6d1c-06cf-4b79-af43-f1bac4f620f9 ro console=ttyS0,115200n8"
> 
> Any comments/feedback would be very much appreciated.
> 
> [1] https://github.com/amdese/linux
>    https://github.com/amdese/amdsev/tree/snp-latest
> 
> Changes since rfc2:
> 
> - reworked on top of guest_memfd support
> - added handling for various KVM_EXIT_VMGEXIT events
> - various changes/considerations for PCI passthrough support
> - general bugfixes/hardening/cleanups
> - qapi cmdline doc fixes/rework (Dov, Markus)
> - switch to qbase64_decode, more error-checking for cmdline opts (Dov)
> - unset id_block_en for 0 input (Dov)
> - use error_setg in snp init (Dov)
> - report more info in trace_kvm_sev_init (Dov)
> - rework bounds-checking for kvm_cpuid_info, rework existing checks for readability, add additional checks (Dov)
> - fixups for validated_ranges handling (Dov)
> - rename 'policy' field to 'snp-policy' in query-sev when sev-type is SNP
> 
> Changes since rfc1:
> 
> - rebased onto latest master
> - drop SNP config file in favor of a new 'sev-snp-guest' object where all
>   SNP-related params are passed as strings/integers via command-line
> - report specific error if BIOS reports invalid address/len for
>   reserved/pre-validated regions (Connor)
> - use Range helpers for handling validated region overlaps (Dave)
> - simplify error handling in sev_snp_launch_start, and report the correct
>   return code when handling LAUNCH_START failures (Dov)
> - add SEV-SNP bit to CPUID 0x8000001f when SNP enabled
> - updated query-sev to handle differences between SEV and SEV-SNP
> - updated to work against v5 of SEV-SNP host kernel / hypervisor patches
> 
> ----------------------------------------------------------------
> Brijesh Singh (5):
>      i386/sev: Introduce 'sev-snp-guest' object
>      i386/sev: Add the SNP launch start context
>      i386/sev: Add handling to encrypt/finalize guest launch data
>      hw/i386/sev: Add function to get SEV metadata from OVMF header
>      i386/sev: Add support for populating OVMF metadata pages
> 
> Chao Peng (2):
>      kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot
>      kvm: handle KVM_EXIT_MEMORY_FAULT
> 
> Dov Murik (4):
>      qapi, i386: Move kernel-hashes to SevCommonProperties
>      i386/sev: Extract build_kernel_loader_hashes
>      i386/sev: Reorder struct declarations
>      i386/sev: Allow measured direct kernel boot on SNP
> 
> Isaku Yamahata (2):
>      pci-host/q35: Move PAM initialization above SMRAM initialization
>      q35: Introduce smm_ranges property for q35-pci-host
> 
> Michael Roth (30):
>      Revert "linux-headers hack" from sevinit2 base tree
>      scripts/update-linux-headers: Add setup_data.h to import list
>      scripts/update-linux-headers: Add bits.h to file imports
>      [HACK] linux-headers: Update headers for 6.8 + kvm-coco-queue + SNP
>      [TEMP] hw/i386: Remove redeclaration of struct setup_data
>      RAMBlock: Add support of KVM private guest memfd
>      [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size
>      trace/kvm: Add trace for page convertion between shared and private
>      kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled()
>      trace/kvm: Add trace for KVM_EXIT_MEMORY_FAULT
>      i386/sev: Introduce "sev-common" type to encapsulate common SEV state
>      i386/sev: Add a sev_snp_enabled() helper
>      target/i386: Add handling for KVM_X86_SNP_VM VM type
>      i386/sev: Skip RAMBlock notifiers for SNP
>      i386/sev: Skip machine-init-done notifiers for SNP
>      i386/sev: Set ms->require_guest_memfd for SNP
>      i386/sev: Disable SMM for SNP
>      i386/sev: Don't disable block discarding for SNP
>      i386/cpu: Set SEV-SNP CPUID bit when SNP enabled
>      i386/sev: Update query-sev QAPI format to handle SEV-SNP
>      i386/sev: Don't return launch measurements for SEV-SNP guests
>      kvm: Make kvm_convert_memory() non-static
>      i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes
>      i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based)
>      i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests
>      i386/sev: Set CPU state to protected once SNP guest payload is finalized
>      i386/sev: Add support for SNP CPUID validation
>      hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
>      hw/i386/sev: Use guest_memfd for legacy ROMs
>      hw/i386: Add support for loading BIOS using guest_memfd
> 
> Xiaoyao Li (6):
>      HostMem: Add mechanism to opt in kvm guest memfd via MachineState
>      trace/kvm: Split address space and slot id in trace_kvm_set_user_memory()
>      kvm: Introduce support for memory_attributes
>      physmem: Introduce ram_block_discard_guest_memfd_range()
>      kvm/memory: Make memory type private by default if it has guest memfd backend
>      memory: Introduce memory_region_init_ram_guest_memfd()
> 
> accel/kvm/kvm-all.c                                |  241 ++-
> accel/kvm/trace-events                             |    4 +-
> accel/stubs/kvm-stub.c                             |    5 +
> backends/hostmem-file.c                            |    1 +
> backends/hostmem-memfd.c                           |    1 +
> backends/hostmem-ram.c                             |    1 +
> backends/hostmem.c                                 |    1 +
> docs/system/i386/amd-memory-encryption.rst         |   78 +-
> hw/core/machine.c                                  |    5 +
> hw/i386/pc.c                                       |   13 +-
> hw/i386/pc_q35.c                                   |    2 +
> hw/i386/pc_sysfw.c                                 |   25 +-
> hw/i386/pc_sysfw_ovmf.c                            |   33 +
> hw/i386/x86.c                                      |   46 +-
> hw/pci-host/q35.c                                  |   61 +-
> include/exec/cpu-common.h                          |    2 +
> include/exec/memory.h                              |   26 +-
> include/exec/ram_addr.h                            |    2 +-
> include/exec/ramblock.h                            |    1 +
> include/hw/boards.h                                |    2 +
> include/hw/i386/pc.h                               |   31 +-
> include/hw/i386/x86.h                              |    2 +-
> include/hw/pci-host/q35.h                          |    1 +
> include/standard-headers/asm-x86/bootparam.h       |   17 +-
> include/standard-headers/asm-x86/kvm_para.h        |    3 +-
> include/standard-headers/linux/ethtool.h           |   48 +
> include/standard-headers/linux/fuse.h              |   39 +-
> include/standard-headers/linux/input-event-codes.h |    1 +
> include/standard-headers/linux/virtio_gpu.h        |    2 +
> include/standard-headers/linux/virtio_snd.h        |  154 ++
> include/sysemu/hostmem.h                           |    1 +
> include/sysemu/kvm.h                               |    7 +
> include/sysemu/kvm_int.h                           |    2 +
> linux-headers/asm-arm64/kvm.h                      |   15 +-
> linux-headers/asm-arm64/sve_context.h              |   11 +
> linux-headers/asm-generic/bitsperlong.h            |    4 +
> linux-headers/asm-loongarch/kvm.h                  |    2 -
> linux-headers/asm-mips/kvm.h                       |    2 -
> linux-headers/asm-powerpc/kvm.h                    |   45 +-
> linux-headers/asm-riscv/kvm.h                      |    3 +-
> linux-headers/asm-s390/kvm.h                       |  315 +++-
> linux-headers/asm-x86/kvm.h                        |  372 ++++-
> linux-headers/asm-x86/setup_data.h                 |   83 +
> linux-headers/linux/bits.h                         |   15 +
> linux-headers/linux/kvm.h                          |  719 +--------
> linux-headers/linux/psp-sev.h                      |   71 +
> qapi/misc-target.json                              |   71 +-
> qapi/qom.json                                      |   96 +-
> scripts/update-linux-headers.sh                    |    5 +-
> system/memory.c                                    |   30 +
> system/physmem.c                                   |   47 +-
> target/i386/cpu.c                                  |    1 +
> target/i386/kvm/kvm.c                              |    4 +
> target/i386/sev-sysemu-stub.c                      |    2 +-
> target/i386/sev.c                                  | 1631 ++++++++++++++++----
> target/i386/sev.h                                  |   13 +-
> target/i386/trace-events                           |    3 +
> 57 files changed, 3272 insertions(+), 1146 deletions(-)
> create mode 100644 linux-headers/asm-x86/setup_data.h
> create mode 100644 linux-headers/linux/bits.h
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state
  2024-03-20  8:39 ` [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state Michael Roth
  2024-03-20 11:44   ` Daniel P. Berrangé
  2024-03-20 11:47   ` Daniel P. Berrangé
@ 2024-04-22 13:06   ` Markus Armbruster
  2 siblings, 0 replies; 110+ messages in thread
From: Markus Armbruster @ 2024-04-22 13:06 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Michael Roth <michael.roth@amd.com> writes:

> Currently all SEV/SEV-ES functionality is managed through a single
> 'sev-guest' QOM type. With upcoming support for SEV-SNP, taking this
> same approach won't work well since some of the properties/state
> managed by 'sev-guest' is not applicable to SEV-SNP, which will instead
> rely on a new QOM type with its own set of properties/state.
>
> To prepare for this, this patch moves common state into an abstract
> 'sev-common' parent type to encapsulate properties/state that are
> common to both SEV/SEV-ES and SEV-SNP, leaving only SEV/SEV-ES-specific
> properties/state in the current 'sev-guest' type. This should not
> affect current behavior or command-line options.

QAPI schema refactoring except for the misleading "since" documentation
pointed out by Daniel
Acked-by: Markus Armbruster <armbru@redhat.com>

[...]


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object
  2024-03-20  8:39 ` [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object Michael Roth
  2024-03-20 11:58   ` Daniel P. Berrangé
@ 2024-04-22 13:52   ` Markus Armbruster
  1 sibling, 0 replies; 110+ messages in thread
From: Markus Armbruster @ 2024-04-22 13:52 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata, Brijesh Singh

Michael Roth <michael.roth@amd.com> writes:

> From: Brijesh Singh <brijesh.singh@amd.com>
>
> SEV-SNP support relies on a different set of properties/state than the
> existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
> object, which can be used to configure an SEV-SNP guest. For example,
> a default-configured SEV-SNP guest with no additional information
> passed in for use with attestation:
>
>   -object sev-snp-guest,id=sev0
>
> or a fully-specified SEV-SNP guest where all spec-defined binary
> blobs are passed in as base64-encoded strings:
>
>   -object sev-snp-guest,id=sev0, \
>     policy=0x30000, \
>     init-flags=0, \
>     id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
>     id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
>     auth-key-enabled=on, \
>     host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
>     guest-visible-workarounds=AA==, \
>
> See the QAPI schema updates included in this patch for more usage
> details.
>
> In some cases these blobs may be up to 4096 characters, but this is
> generally well below the default limit for linux hosts where
> command-line sizes are defined by the sysconf-configurable ARG_MAX
> value, which defaults to 2097152 characters for Ubuntu hosts, for
> example.
>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> Co-developed-by: Michael Roth <michael.roth@amd.com>
> Acked-by: Markus Armbruster <armbru@redhat.com> (for QAPI schema)
> Signed-off-by: Michael Roth <michael.roth@amd.com>

[...]

> diff --git a/qapi/qom.json b/qapi/qom.json
> index 66b5781ca6..b25a3043da 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -920,6 +920,55 @@
>              '*handle': 'uint32',
>              '*kernel-hashes': 'bool' } }
>  
> +##
> +# @SevSnpGuestProperties:
> +#
> +# Properties for sev-snp-guest objects. Most of these are direct arguments
> +# for the KVM_SNP_* interfaces documented in the linux kernel source

"Linux", please.

> +# under Documentation/virt/kvm/amd-memory-encryption.rst, which are in

Does not seem to exist.  Do you mean
Documentation/arch/x86/amd-memory-encryption.rst?

> +# turn closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
> +# documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).

docs/devel/qapi-code-gen.rst:

    For legibility, wrap text paragraphs so every line is at most 70
    characters long.

    Separate sentences with two spaces.

> +#
> +# More usage information is also available in the QEMU source tree under
> +# docs/amd-memory-encryption.
> +#
> +# @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
> +#          defined in the SEV-SNP firmware ABI (default: 0x30000)

docs/devel/qapi-code-gen.rst:

    Descriptions start with '\@name:'.  The description text must be
    indented like this::

     # @name: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
     #     do eiusmod tempor incididunt ut labore et dolore magna aliqua.

> +#
> +# @guest-visible-workarounds: 16-byte, base64-encoded blob to report
> +#                             hypervisor-defined workarounds, corresponding
> +#                             to the 'GOSVW' parameter of the
> +#                             SNP_LAUNCH_START command defined in the
> +#                             SEV-SNP firmware ABI (default: all-zero)
> +#
> +# @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
> +#            structure for the SNP_LAUNCH_FINISH command defined in the
> +#            SEV-SNP firmware ABI (default: all-zero)
> +#
> +# @id-auth: 4096-byte, base64-encoded blob to provide the 'ID Authentication
> +#           Information Structure' for the SNP_LAUNCH_FINISH command defined
> +#           in the SEV-SNP firmware ABI (default: all-zero)
> +#
> +# @auth-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY' field
> +#                    defined SEV-SNP firmware ABI (default: false)
> +#
> +# @host-data: 32-byte, base64-encoded, user-defined blob to provide to the
> +#             guest, as documented for the 'HOST_DATA' parameter of the
> +#             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
> +#             (default: all-zero)
> +#
> +# Since: 7.2

9.1

> +##

Together:

    ##
    # @SevSnpGuestProperties:
    #
    # Properties for sev-snp-guest objects.  Most of these are direct
    # arguments for the KVM_SNP_* interfaces documented in the Linux
    # kernel source under
    # Documentation/arch/x86/amd-memory-encryption.rst, which are in turn
    # closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
    # documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).
    #
    # More usage information is also available in the QEMU source tree
    # under docs/amd-memory-encryption.
    #
    # @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
    #     defined in the SEV-SNP firmware ABI (default: 0x30000)
    #
    # @guest-visible-workarounds: 16-byte, base64-encoded blob to report
    #     hypervisor-defined workarounds, corresponding to the 'GOSVW'
    #     parameter of the SNP_LAUNCH_START command defined in the SEV-SNP
    #     firmware ABI (default: all-zero)
    #
    # @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
    #     structure for the SNP_LAUNCH_FINISH command defined in the
    #     SEV-SNP firmware ABI (default: all-zero)
    #
    # @id-auth: 4096-byte, base64-encoded blob to provide the 'ID
    #     Authentication Information Structure' for the SNP_LAUNCH_FINISH
    #     command defined in the SEV-SNP firmware ABI (default: all-zero)
    #
    # @auth-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY'
    #     field defined SEV-SNP firmware ABI (default: false)
    #
    # @host-data: 32-byte, base64-encoded, user-defined blob to provide to
    #     the guest, as documented for the 'HOST_DATA' parameter of the
    #     SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI (default:
    #     all-zero)
    #
    # @certs-path: path to certificate data that can be passed to guests
    #     via SNP Extended Guest Requests.  File should be in the format
    #     described in the GHCB specification.  (default: none)
    #
    # Since: 9.1
    ##

We generally prefer symbolic to numeric / binary encoding in QMP.  Can
you explain briefly why you choose numeric and binary here?

> +{ 'struct': 'SevSnpGuestProperties',
> +  'base': 'SevCommonProperties',
> +  'data': {
> +            '*policy': 'uint64',
> +            '*guest-visible-workarounds': 'str',
> +            '*id-block': 'str',
> +            '*id-auth': 'str',
> +            '*auth-key-enabled': 'bool',
> +            '*host-data': 'str' } }
> +
>  ##
>  # @ThreadContextProperties:
>  #
> @@ -998,6 +1047,7 @@
>      { 'name': 'secret_keyring',
>        'if': 'CONFIG_SECRET_KEYRING' },
>      'sev-guest',
> +    'sev-snp-guest',
>      'thread-context',
>      's390-pv-guest',
>      'throttle-group',
> @@ -1068,6 +1118,7 @@
>        'secret_keyring':             { 'type': 'SecretKeyringProperties',
>                                        'if': 'CONFIG_SECRET_KEYRING' },
>        'sev-guest':                  'SevGuestProperties',
> +      'sev-snp-guest':              'SevSnpGuestProperties',
>        'thread-context':             'ThreadContextProperties',
>        'throttle-group':             'ThrottleGroupProperties',
>        'tls-creds-anon':             'TlsCredsAnonProperties',

[...]


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP
  2024-03-20  8:39 ` [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP Michael Roth
  2024-03-20 12:10   ` Daniel P. Berrangé
@ 2024-04-22 15:01   ` Markus Armbruster
  1 sibling, 0 replies; 110+ messages in thread
From: Markus Armbruster @ 2024-04-22 15:01 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Michael Roth <michael.roth@amd.com> writes:

> Most of the current 'query-sev' command is relevant to both legacy
> SEV/SEV-ES guests and SEV-SNP guests, with 2 exceptions:
>
>   - 'policy' is a 64-bit field for SEV-SNP, not 32-bit, and
>     the meaning of the bit positions has changed
>   - 'handle' is not relevant to SEV-SNP
>
> To address this, this patch adds a new 'sev-type' field that can be
> used as a discriminator to select between SEV and SEV-SNP-specific
> fields/formats without breaking compatibility for existing management
> tools (so long as management tools that add support for launching
> SEV-SNP guest update their handling of query-sev appropriately).
>
> The corresponding HMP command has also been fixed up similarly.
>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  qapi/misc-target.json | 71 ++++++++++++++++++++++++++++++++++---------
>  target/i386/sev.c     | 50 ++++++++++++++++++++----------
>  target/i386/sev.h     |  3 ++
>  3 files changed, 94 insertions(+), 30 deletions(-)
>
> diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> index 4e0a6492a9..daceb85d95 100644
> --- a/qapi/misc-target.json
> +++ b/qapi/misc-target.json
> @@ -47,6 +47,49 @@
>             'send-update', 'receive-update' ],
>    'if': 'TARGET_I386' }
>  
> +##
> +# @SevGuestType:
> +#
> +# An enumeration indicating the type of SEV guest being run.
> +#
> +# @sev:     The guest is a legacy SEV or SEV-ES guest.

Single space after ':', please.

Recommend a blank line between argument descriptions.

> +# @sev-snp: The guest is an SEV-SNP guest.
> +#
> +# Since: 6.2

The type is since 9.1, but its members become results of query-sev,
where they are since 2.12.  See also my reply to Daniel's question on
PATCH 21.

> +##
> +{ 'enum': 'SevGuestType',
> +  'data': [ 'sev', 'sev-snp' ],
> +  'if': 'TARGET_I386' }
> +
> +##
> +# @SevGuestInfo:
> +#
> +# Information specific to legacy SEV/SEV-ES guests.
> +#
> +# @policy: SEV policy value

I know you're just moving existing documentation.  Still: this is rather
sparse.  Where would I find what numbers to pass for @policy?

> +#
> +# @handle: SEV firmware handle
> +#
> +# Since: 2.12
> +##
> +{ 'struct': 'SevGuestInfo',
> +  'data': { 'policy': 'uint32',
> +            'handle': 'uint32' },
> +  'if': 'TARGET_I386' }
> +
> +##
> +# @SevSnpGuestInfo:
> +#
> +# Information specific to SEV-SNP guests.
> +#
> +# @snp-policy: SEV-SNP policy value

Same question.

> +#
> +# Since: 6.2

9.1

> +##
> +{ 'struct': 'SevSnpGuestInfo',
> +  'data': { 'snp-policy': 'uint64' },
> +  'if': 'TARGET_I386' }
> +
>  ##
>  # @SevInfo:
>  #
> @@ -60,25 +103,25 @@
>  #
>  # @build-id: SEV FW build id
>  #
> -# @policy: SEV policy value
> -#
>  # @state: SEV guest state
>  #
> -# @handle: SEV firmware handle
> +# @sev-type: Type of SEV guest being run
>  #
>  # Since: 2.12
>  ##
> -{ 'struct': 'SevInfo',
> -    'data': { 'enabled': 'bool',
> -              'api-major': 'uint8',
> -              'api-minor' : 'uint8',
> -              'build-id' : 'uint8',
> -              'policy' : 'uint32',
> -              'state' : 'SevState',
> -              'handle' : 'uint32'
> -            },
> -  'if': 'TARGET_I386'
> -}
> +{ 'union': 'SevInfo',
> +  'base': { 'enabled': 'bool',
> +            'api-major': 'uint8',
> +            'api-minor' : 'uint8',
> +            'build-id' : 'uint8',
> +            'state' : 'SevState',
> +            'sev-type' : 'SevGuestType' },
> +  'discriminator': 'sev-type',
> +  'data': {
> +      'sev': 'SevGuestInfo',
> +      'sev-snp': 'SevSnpGuestInfo' },
> +  'if': 'TARGET_I386' }
> +
>  
>  ##
>  # @query-sev:

[...]


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests
  2024-03-20  8:39 ` [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests Michael Roth
@ 2024-04-22 15:02   ` Markus Armbruster
  0 siblings, 0 replies; 110+ messages in thread
From: Markus Armbruster @ 2024-04-22 15:02 UTC (permalink / raw)
  To: Michael Roth
  Cc: qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P . Berrangé,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata

Michael Roth <michael.roth@amd.com> writes:

> The GHCB specification[1] defines a VMGEXIT-based Guest Request
> hypercall to allow an SNP guest to issue encrypted requests directly to
> SNP firmware to do things like query the attestation report for the
> guest. These are generally handled purely in the kernel.
>
> In some some cases, it's useful for the host to be able to additionally
> supply the certificate chain for the signing key that SNP firmware uses
> to sign these attestation reports. To allow for, the GHCB specification
> defines an Extended Guest Request where this certificate data can be
> provided in a special format described in the GHCB spec. This
> certificate data may be global or guest-specific depending on how the
> guest was configured. Rather than providing interfaces to manage these
> within the kernel, KVM handles this by forward the Extended Guest
> Requests on to userspace so the certificate data can be provided in the
> expected format.
>
> Add a certs-path parameter to the sev-snp-guest object so that it can
> be used to inject any certificate data into these Extended Guest
> Requests.
>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
>  qapi/qom.json     |  7 +++-
>  target/i386/sev.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 91 insertions(+), 1 deletion(-)
>
> diff --git a/qapi/qom.json b/qapi/qom.json
> index b25a3043da..7ba778af91 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -957,6 +957,10 @@
>  #             SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
>  #             (default: all-zero)
>  #
> +# @certs-path: path to certificate data that can be passed to guests via
> +#              SNP Extended Guest Requests. File should be in the format
> +#              described in the GHCB specification. (default: none)

Is this a filename, or is it a search path of sorts?

> +#
>  # Since: 7.2
>  ##
>  { 'struct': 'SevSnpGuestProperties',
> @@ -967,7 +971,8 @@
>              '*id-block': 'str',
>              '*id-auth': 'str',
>              '*auth-key-enabled': 'bool',
> -            '*host-data': 'str' } }
> +            '*host-data': 'str',
> +            '*certs-path': 'str' } }
>  
>  ##
>  # @ThreadContextProperties:

[...]


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties
  2024-03-20 12:20   ` Daniel P. Berrangé
@ 2024-04-22 15:03     ` Markus Armbruster
  0 siblings, 0 replies; 110+ messages in thread
From: Markus Armbruster @ 2024-04-22 15:03 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Michael Roth, qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Pankaj Gupta, Xiaoyao Li, Isaku Yamahata, Dov Murik

Daniel P. Berrangé <berrange@redhat.com> writes:

> On Wed, Mar 20, 2024 at 03:39:39AM -0500, Michael Roth wrote:
>> From: Dov Murik <dovmurik@linux.ibm.com>
>> 
>> In order to enable kernel-hashes for SNP, pull it from
>> SevGuestProperties to its parent SevCommonProperties so
>> it will be available for both SEV and SNP.
>> 
>> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
>> Signed-off-by: Michael Roth <michael.roth@amd.com>
>> ---
>>  qapi/qom.json     | 14 +++++++-------
>>  target/i386/sev.c | 44 ++++++++++++++++++--------------------------
>>  2 files changed, 25 insertions(+), 33 deletions(-)
>
> This change ought to be squashed into the earlier patch
> that introduce sev-guest-common.

Concur.

[...]


^ permalink raw reply	[flat|nested] 110+ messages in thread

* Re: [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs
  2024-03-28  0:45     ` Xiaoyao Li
@ 2024-04-24  0:08       ` Michael Roth
  0 siblings, 0 replies; 110+ messages in thread
From: Michael Roth @ 2024-04-24  0:08 UTC (permalink / raw)
  To: Xiaoyao Li
  Cc: Isaku Yamahata, qemu-devel, kvm, Tom Lendacky, Paolo Bonzini,
	Daniel P. Berrangé,
	Markus Armbruster, Pankaj Gupta, Isaku Yamahata

On Thu, Mar 28, 2024 at 08:45:03AM +0800, Xiaoyao Li wrote:
> On 3/21/2024 2:12 AM, Isaku Yamahata wrote:
> > On Wed, Mar 20, 2024 at 03:39:44AM -0500,
> > Michael Roth <michael.roth@amd.com> wrote:
> > 
> > > TODO: make this SNP-specific if TDX disables legacy ROMs in general
> > 
> > TDX disables pc.rom, not disable isa-bios. IIRC, TDX doesn't need pc pflash.
> 
> Not TDX doesn't need pc pflash, but TDX cannot support pflash.
> 
> Can SNP support the behavior of pflash? That what's got changed will be
> synced back to OVMF file?

For split OVMF files (separate FD for CODE vs. VARS) it can, but it
requires special handling in OVMF to handle MMIO to the VARS area using
direct MMIO hypercalls rather than relying on MMIO emulation. Here's the
relevant OVMF commit:

  commit 437eb3f7a8db7681afe0e6064d3a8edb12abb766
  Author: Tom Lendacky <thomas.lendacky@amd.com>
  Date:   Wed Aug 12 15:21:42 2020 -0500

      OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES

      BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198

For SNP, the plan is to continue to use -bios to handle the actual
CODE/BIOS FD, but to allow the use of pflash,unit=0 to handle the VARS
fd if a separate/persistent store is desired. This allows us to continue
using read-only memslots on the VARS/pflash side without being at odds
with the fact that read-only memslots are no longer supported for private
memslots (since VARS doesn't need to be measured/mapped as private), and
limiting the special handling to -bios where TDX/SNP both need private
memslots.

This is roughly how things will look with v4 of this series:

  https://github.com/AMDESE/qemu/commit/21fff075372ad25b2d09c5e416349c2b353fdb4c

I think (if needed) TDX could in theory take a similar approach with
similar modifications to OVMF and providing an option for a split CODE/VARS
variant.

-Mike

> 
> > Xiaoyao can chime in.
> > 
> > Thanks,
> > 
> > > 
> > > Current SNP guest kernels will attempt to access these regions with
> > > with C-bit set, so guest_memfd is needed to handle that. Otherwise,
> > > kvm_convert_memory() will fail when the guest kernel tries to access it
> > > and QEMU attempts to call KVM_SET_MEMORY_ATTRIBUTES to set these ranges
> > > to private.
> > > 
> > > Whether guests should actually try to access ROM regions in this way (or
> > > need to deal with legacy ROM regions at all), is a separate issue to be
> > > addressed on kernel side, but current SNP guest kernels will exhibit
> > > this behavior and so this handling is needed to allow QEMU to continue
> > > running existing SNP guest kernels.
> > > 
> > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > ---
> > >   hw/i386/pc.c       | 13 +++++++++----
> > >   hw/i386/pc_sysfw.c | 13 ++++++++++---
> > >   2 files changed, 19 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > > index feb7a93083..5feaeb43ee 100644
> > > --- a/hw/i386/pc.c
> > > +++ b/hw/i386/pc.c
> > > @@ -1011,10 +1011,15 @@ void pc_memory_init(PCMachineState *pcms,
> > >       pc_system_firmware_init(pcms, rom_memory);
> > >       option_rom_mr = g_malloc(sizeof(*option_rom_mr));
> > > -    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
> > > -                           &error_fatal);
> > > -    if (pcmc->pci_enabled) {
> > > -        memory_region_set_readonly(option_rom_mr, true);
> > > +    if (machine_require_guest_memfd(machine)) {
> > > +        memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
> > > +                                           PC_ROM_SIZE, &error_fatal);
> > > +    } else {
> > > +        memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
> > > +                               &error_fatal);
> > > +        if (pcmc->pci_enabled) {
> > > +            memory_region_set_readonly(option_rom_mr, true);
> > > +        }
> > >       }
> > >       memory_region_add_subregion_overlap(rom_memory,
> > >                                           PC_ROM_MIN_VGA,
> > > diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
> > > index 9dbb3f7337..850f86edd4 100644
> > > --- a/hw/i386/pc_sysfw.c
> > > +++ b/hw/i386/pc_sysfw.c
> > > @@ -54,8 +54,13 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
> > >       /* map the last 128KB of the BIOS in ISA space */
> > >       isa_bios_size = MIN(flash_size, 128 * KiB);
> > >       isa_bios = g_malloc(sizeof(*isa_bios));
> > > -    memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
> > > -                           &error_fatal);
> > > +    if (machine_require_guest_memfd(current_machine)) {
> > > +        memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
> > > +                                           isa_bios_size, &error_fatal);
> > > +    } else {
> > > +        memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
> > > +                               &error_fatal);
> > > +    }
> > >       memory_region_add_subregion_overlap(rom_memory,
> > >                                           0x100000 - isa_bios_size,
> > >                                           isa_bios,
> > > @@ -68,7 +73,9 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
> > >              ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
> > >              isa_bios_size);
> > > -    memory_region_set_readonly(isa_bios, true);
> > > +    if (!machine_require_guest_memfd(current_machine)) {
> > > +        memory_region_set_readonly(isa_bios, true);
> > > +    }
> > >   }
> > >   static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
> > > -- 
> > > 2.25.1
> > > 
> > > 
> > 
> 
> 

^ permalink raw reply	[flat|nested] 110+ messages in thread

end of thread, other threads:[~2024-04-24  0:09 UTC | newest]

Thread overview: 110+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-20  8:38 [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Michael Roth
2024-03-20  8:38 ` [PATCH v3 01/49] Revert "linux-headers hack" from sevinit2 base tree Michael Roth
2024-03-20  8:38 ` [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list Michael Roth
2024-03-20  9:19   ` Paolo Bonzini
2024-03-20  8:38 ` [PATCH v3 03/49] scripts/update-linux-headers: Add bits.h to file imports Michael Roth
2024-03-20  8:39 ` [PATCH v3 04/49] [HACK] linux-headers: Update headers for 6.8 + kvm-coco-queue + SNP Michael Roth
2024-03-20  8:39 ` [PATCH v3 05/49] [TEMP] hw/i386: Remove redeclaration of struct setup_data Michael Roth
2024-03-20  8:39 ` [PATCH v3 06/49] RAMBlock: Add support of KVM private guest memfd Michael Roth
2024-03-20 16:38   ` Paolo Bonzini
2024-03-20  8:39 ` [PATCH v3 07/49] HostMem: Add mechanism to opt in kvm guest memfd via MachineState Michael Roth
2024-03-20  8:39 ` [PATCH v3 08/49] trace/kvm: Split address space and slot id in trace_kvm_set_user_memory() Michael Roth
2024-03-20  8:39 ` [PATCH v3 09/49] kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot Michael Roth
2024-03-20 15:56   ` Paolo Bonzini
2024-03-20  8:39 ` [PATCH v3 10/49] kvm: Introduce support for memory_attributes Michael Roth
2024-03-20 16:00   ` Paolo Bonzini
2024-03-20  8:39 ` [PATCH v3 11/49] physmem: Introduce ram_block_discard_guest_memfd_range() Michael Roth
2024-03-20  9:37   ` David Hildenbrand
2024-03-20 12:43     ` Xiaoyao Li
2024-03-20 12:58       ` David Hildenbrand
2024-03-20 17:38     ` Michael Roth
2024-03-20 20:04       ` David Hildenbrand
2024-03-21 20:24         ` Michael Roth
2024-03-20  8:39 ` [PATCH v3 12/49] kvm: handle KVM_EXIT_MEMORY_FAULT Michael Roth
2024-03-20  8:39 ` [PATCH v3 13/49] [FIXUP] "kvm: handle KVM_EXIT_MEMORY_FAULT": drop qemu_host_page_size Michael Roth
2024-03-20 12:46   ` Xiaoyao Li
2024-03-20  8:39 ` [PATCH v3 14/49] trace/kvm: Add trace for page convertion between shared and private Michael Roth
2024-03-20  8:39 ` [PATCH v3 15/49] kvm/memory: Make memory type private by default if it has guest memfd backend Michael Roth
2024-03-20  8:39 ` [PATCH v3 16/49] memory: Introduce memory_region_init_ram_guest_memfd() Michael Roth
2024-03-20  8:39 ` [PATCH v3 17/49] pci-host/q35: Move PAM initialization above SMRAM initialization Michael Roth
2024-03-20  8:39 ` [PATCH v3 18/49] q35: Introduce smm_ranges property for q35-pci-host Michael Roth
2024-03-20  8:39 ` [PATCH v3 19/49] kvm: Make kvm_convert_memory() obey ram_block_discard_is_enabled() Michael Roth
2024-03-20 16:26   ` Paolo Bonzini
2024-03-20 19:47     ` Michael Roth
2024-03-20  8:39 ` [PATCH v3 20/49] trace/kvm: Add trace for KVM_EXIT_MEMORY_FAULT Michael Roth
2024-03-20  8:39 ` [PATCH v3 21/49] i386/sev: Introduce "sev-common" type to encapsulate common SEV state Michael Roth
2024-03-20 11:44   ` Daniel P. Berrangé
2024-03-20 21:36     ` Michael Roth
2024-03-20 21:36       ` Michael Roth via
2024-03-27 15:22     ` Markus Armbruster
2024-03-20 11:47   ` Daniel P. Berrangé
2024-03-20 21:45     ` Michael Roth
2024-03-20 21:45       ` Michael Roth via
2024-04-22 13:06   ` Markus Armbruster
2024-03-20  8:39 ` [PATCH v3 22/49] i386/sev: Introduce 'sev-snp-guest' object Michael Roth
2024-03-20 11:58   ` Daniel P. Berrangé
2024-03-20 22:09     ` Michael Roth
2024-03-20 22:09       ` Michael Roth via
2024-04-22 13:52   ` Markus Armbruster
2024-03-20  8:39 ` [PATCH v3 23/49] i386/sev: Add a sev_snp_enabled() helper Michael Roth
2024-03-20 12:35   ` Daniel P. Berrangé
2024-03-20 22:11     ` Michael Roth
2024-03-20 22:11       ` Michael Roth via
2024-03-20  8:39 ` [PATCH v3 24/49] target/i386: Add handling for KVM_X86_SNP_VM VM type Michael Roth
2024-03-20  9:33   ` Paolo Bonzini
2024-03-20  8:39 ` [PATCH v3 25/49] i386/sev: Skip RAMBlock notifiers for SNP Michael Roth
2024-03-20  9:46   ` Paolo Bonzini
2024-03-20 22:14     ` Michael Roth
2024-03-20  8:39 ` [PATCH v3 26/49] i386/sev: Skip machine-init-done " Michael Roth
2024-03-20  8:39 ` [PATCH v3 27/49] i386/sev: Set ms->require_guest_memfd " Michael Roth
2024-03-20  9:48   ` Paolo Bonzini
2024-03-20  8:39 ` [PATCH v3 28/49] i386/sev: Disable SMM " Michael Roth
2024-03-20 12:32   ` Daniel P. Berrangé
2024-03-20  8:39 ` [PATCH v3 29/49] i386/sev: Don't disable block discarding " Michael Roth
2024-03-20 12:33   ` Daniel P. Berrangé
2024-03-20  8:39 ` [PATCH v3 30/49] i386/cpu: Set SEV-SNP CPUID bit when SNP enabled Michael Roth
2024-03-20  8:39 ` [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP Michael Roth
2024-03-20 12:10   ` Daniel P. Berrangé
2024-03-20 22:23     ` Michael Roth
2024-03-20 22:23       ` Michael Roth via
2024-04-22 15:01   ` Markus Armbruster
2024-03-20  8:39 ` [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests Michael Roth
2024-03-20 12:15   ` Daniel P. Berrangé
2024-03-20 12:27     ` Daniel P. Berrangé
2024-03-20  8:39 ` [PATCH v3 33/49] kvm: Make kvm_convert_memory() non-static Michael Roth
2024-03-20  8:39 ` [PATCH v3 34/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes Michael Roth
2024-03-20  8:39 ` [PATCH v3 35/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based) Michael Roth
2024-03-20  8:39 ` [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests Michael Roth
2024-04-22 15:02   ` Markus Armbruster
2024-03-20  8:39 ` [PATCH v3 37/49] i386/sev: Add the SNP launch start context Michael Roth
2024-03-20  9:58   ` Paolo Bonzini
2024-03-20 22:32     ` Michael Roth
2024-03-21 11:55       ` Paolo Bonzini
2024-03-20  8:39 ` [PATCH v3 38/49] i386/sev: Add handling to encrypt/finalize guest launch data Michael Roth
2024-03-20  8:39 ` [PATCH v3 39/49] i386/sev: Set CPU state to protected once SNP guest payload is finalized Michael Roth
2024-03-20  8:39 ` [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header Michael Roth
2024-03-20 17:55   ` Isaku Yamahata
2024-03-20 22:35     ` Michael Roth
2024-03-20  8:39 ` [PATCH v3 41/49] i386/sev: Add support for populating OVMF metadata pages Michael Roth
2024-03-20  8:39 ` [PATCH v3 42/49] i386/sev: Add support for SNP CPUID validation Michael Roth
2024-03-20 12:18   ` Daniel P. Berrangé
2024-03-20  8:39 ` [PATCH v3 43/49] qapi, i386: Move kernel-hashes to SevCommonProperties Michael Roth
2024-03-20 12:20   ` Daniel P. Berrangé
2024-04-22 15:03     ` Markus Armbruster
2024-03-20  8:39 ` [PATCH v3 44/49] i386/sev: Extract build_kernel_loader_hashes Michael Roth
2024-03-20  8:39 ` [PATCH v3 45/49] i386/sev: Reorder struct declarations Michael Roth
2024-03-20  8:39 ` [PATCH v3 46/49] i386/sev: Allow measured direct kernel boot on SNP Michael Roth
2024-03-20  8:39 ` [PATCH v3 47/49] hw/i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled Michael Roth
2024-03-20 12:22   ` Daniel P. Berrangé
2024-03-21 13:42     ` Michael Roth
2024-03-21 13:42       ` Michael Roth via
2024-03-20  8:39 ` [PATCH v3 48/49] hw/i386/sev: Use guest_memfd for legacy ROMs Michael Roth
2024-03-20 18:12   ` Isaku Yamahata
2024-03-28  0:45     ` Xiaoyao Li
2024-04-24  0:08       ` Michael Roth
2024-03-20  8:39 ` [PATCH v3 49/49] hw/i386: Add support for loading BIOS using guest_memfd Michael Roth
2024-03-20  9:59 ` [PATCH RFC v3 00/49] Add AMD Secure Nested Paging (SEV-SNP) support Paolo Bonzini
2024-03-20 17:08   ` Paolo Bonzini
2024-03-20 20:54     ` Xiaoyao Li
2024-03-21 20:26 ` Michael Roth
2024-04-18 11:37 ` Ani Sinha

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.