Re: [PATCH 2/2] x86: don't append setup_data to cmdline for SEV guests

2023-02-08 Thread Tom Lendacky

On 2/7/23 16:48, Jason A. Donenfeld wrote:

From: Dov Murik 

Modifying the cmdline by appending setup_data breaks measured boot with
SEV and OVMF, and possibly signed boot. Previously this was disabled
when appending to the kernel image, but with eac7a7791bb6 ("x86: don't
let decompressed kernel image clobber setup_data"), this was changed to
the cmdline file instead, with the sev_enabled() check left out.

Fixes: eac7a7791bb6 ("x86: don't let decompressed kernel image clobber 
setup_data")
Reported-by: Tom Lendacky 
Signed-off-by: Dov Murik 
Signed-off-by: Jason A. Donenfeld 
---
  hw/i386/x86.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index c6d7bf6db2..80a1678acd 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -1079,7 +1079,7 @@ void x86_load_linux(X86MachineState *x86ms,
  fclose(f);
  
  /* append dtb to kernel */

-if (dtb_filename) {
+if (dtb_filename && !sev_enabled()) {


Is this change necessary? From an SEV point of view, the DTB file should 
be "constant" and so a guest owner will be able to use that to correctly 
verify the SEV LAUNCH measurement. Additionally, it won't change from the 
time it was measured to the time OVMF validates everything. Of course, I 
don't really anticipate that a DTB file would be used with an SEV guest, 
anyway.


@Dov, does that make sense?

Thanks,
Tom


  if (protocol < 0x209) {
  fprintf(stderr, "qemu: Linux kernel too old to load a dtb\n");
  exit(1);
@@ -1103,7 +1103,7 @@ void x86_load_linux(X86MachineState *x86ms,
  load_image_size(dtb_filename, setup_data->data, dtb_size);
  }
  
-if (!legacy_no_rng_seed && protocol >= 0x209) {

+if (!legacy_no_rng_seed && protocol >= 0x209 && !sev_enabled()) {
  setup_data_offset = cmdline_size;
  cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH;
  kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size);




Re: [PATCH] x86: Don't add RNG seed to Linux cmdline for SEV guests

2023-02-08 Thread Tom Lendacky

On 2/7/23 17:24, Jason A. Donenfeld wrote:

Hi Tom,

On Tue, Feb 7, 2023 at 8:21 PM Tom Lendacky  wrote:


On 2/7/23 15:45, Michael S. Tsirkin wrote:

On Tue, Feb 07, 2023 at 08:41:16AM +, Dov Murik wrote:

Recent feature to supply RNG seed to the guest kernel modifies the
kernel command-line by adding extra data at its end; this breaks
measured boot with SEV and OVMF, and possibly signed boot.

Specifically SEV doesn't miss this feature because it uses UEFI/OVMF
which has its own way of getting random seed (not to mention that
getting the random seed from the untrusted host breaks the confidential
computing trust model).


Nope - getting a random seed from an untrusted source should not break
anything assuming you also have some other randomness source.
If you don't then you have other problems.


Disable the RNG seed feature in SEV guests.

Fixes: eac7a7791bb6 ("x86: don't let decompressed kernel image clobber 
setup_data")
Reported-by: Tom Lendacky 
Signed-off-by: Dov Murik 

---

There might be a need for a wider change to the ways setup_data entries
are handled in x86_load_linux(); here I just try to restore the
situation for SEV guests prior to the addition of the SETUP_RNG_SEED
entry.

Recent discussions on other (safer?) ways to pass this setup_data entry:
[1] 
https://lore.kernel.org/qemu-devel/da39abab9785aea2a2e7652ed6403b6268aeb31f.ca...@linux.ibm.com/

Note that in qemu 7.2.0 this is broken as well -- there the
SETUP_RNG_SEED entry is appended to the Linux kernel data (and therefore
modifies and breaks the measurement of the kernel in SEV measured boot).
A similar fix will be needed there (but I fear this patch cannot be
applied as-is).


So it's not a regression, is it?


SEV kernel hash comparison succeeded with Qemu v7.1.0, but fails with
v7.2.0, so I think that is a regression.


Please let me know if this series fixes it:
https://lore.kernel.org/all/20230207224847.94429-1-ja...@zx2c4.com/


I applied this series and it did fix the problem.

For SEV, there were two problems associated with the RNG seed support:

- The first is that it becomes part of the SEV LAUNCH measurement and 
therefore makes it impossible for the guest owner to be able to validate 
the measurement because the guest owner won't know the value of the RNG 
seed that was included in the LAUNCH measurement.


- The second problem is that the RNG is set and measured as part of the 
kernel-hashes support in x86_load_linux(), but it is changed via 
reset_rng_seed() before actually booting the first time. So the 
measurement taken in x86_load_linux() will never be the same when measured 
by, for example, OVMF.


So the addition of the !sev_enabled() check is definitely appropriate for 
the RNG seed support check for SEV.


However, is the change to the DTB check appropriate? Does the DTB vary / 
get updated before booting? If the DTB file is "constant" then the above 
two problems that face the RNG seed support shouldn't affect SEV. @Dov, 
does that make sense?


In any case, you'll need a version of the patch(es) that can be applied to 
the Qemu v7.2.0 tree to fix the regression.


Thanks,
Tom



Jason




Re: [PATCH] x86: Don't add RNG seed to Linux cmdline for SEV guests

2023-02-07 Thread Tom Lendacky

On 2/7/23 15:45, Michael S. Tsirkin wrote:

On Tue, Feb 07, 2023 at 08:41:16AM +, Dov Murik wrote:

Recent feature to supply RNG seed to the guest kernel modifies the
kernel command-line by adding extra data at its end; this breaks
measured boot with SEV and OVMF, and possibly signed boot.

Specifically SEV doesn't miss this feature because it uses UEFI/OVMF
which has its own way of getting random seed (not to mention that
getting the random seed from the untrusted host breaks the confidential
computing trust model).


Nope - getting a random seed from an untrusted source should not break
anything assuming you also have some other randomness source.
If you don't then you have other problems.


Disable the RNG seed feature in SEV guests.

Fixes: eac7a7791bb6 ("x86: don't let decompressed kernel image clobber 
setup_data")
Reported-by: Tom Lendacky 
Signed-off-by: Dov Murik 

---

There might be a need for a wider change to the ways setup_data entries
are handled in x86_load_linux(); here I just try to restore the
situation for SEV guests prior to the addition of the SETUP_RNG_SEED
entry.

Recent discussions on other (safer?) ways to pass this setup_data entry:
[1] 
https://lore.kernel.org/qemu-devel/da39abab9785aea2a2e7652ed6403b6268aeb31f.ca...@linux.ibm.com/

Note that in qemu 7.2.0 this is broken as well -- there the
SETUP_RNG_SEED entry is appended to the Linux kernel data (and therefore
modifies and breaks the measurement of the kernel in SEV measured boot).
A similar fix will be needed there (but I fear this patch cannot be
applied as-is).


So it's not a regression, is it?


SEV kernel hash comparison succeeded with Qemu v7.1.0, but fails with 
v7.2.0, so I think that is a regression.


Thanks,
Tom




---
  hw/i386/x86.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index eaff4227bd..e65a83f8df 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -1103,7 +1103,7 @@ void x86_load_linux(X86MachineState *x86ms,
  load_image_size(dtb_filename, setup_data->data, dtb_size);
  }
  
-if (!legacy_no_rng_seed && protocol >= 0x209) {

+if (!legacy_no_rng_seed && protocol >= 0x209 && !sev_enabled()) {
  setup_data_offset = cmdline_size;
  cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH;
  kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size);

base-commit: 6661b8c7fe3f8b5687d2d90f7b4f3f23d70e3e8b


I am beginning to think we have been hasty here. no rng seed
should have been then default and requested with a flag.
Then we'd avoid all this heartburn - and SEV might not be the
only workload broken.
Maybe not too late. Jason - objections?


--
2.25.1






Re: [PATCH 0/4] Qemu SEV reduced-phys-bits fixes

2023-01-04 Thread Tom Lendacky

On 9/30/22 10:14, Tom Lendacky wrote:

This patch series fixes up and tries to remove some confusion around the
SEV reduced-phys-bits parameter.

Based on the "AMD64 Architecture Programmer's Manual Volume 2: System
Programming", section "15.34.6 Page Table Support" [1], a guest should
only ever see a maximum of 1 bit of physical address space reduction.

- Update the documentation, to change the default value from 5 to 1.
- Update the validation of the parameter to ensure the parameter value
   is within the range of the CPUID field that it is reported in. To allow
   for backwards compatibility, especially to support the previously
   documented value of 5, allow the full range of values from 1 to 63
   (0 was never allowed).
- Update the setting of CPUID 0x801F_EBX to limit the values to the
   field width that they are setting as an additional safeguard.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf


Ping, any concerns with this series?

Thanks,
Tom



Tom Lendacky (4):
   qapi, i386/sev: Change the reduced-phys-bits value from 5 to 1
   qemu-options.hx: Update the reduced-phys-bits documentation
   i386/sev: Update checks and information related to reduced-phys-bits
   i386/cpu: Update how the EBX register of CPUID 0x801F is set

  qapi/misc-target.json |  2 +-
  qemu-options.hx   |  4 ++--
  target/i386/cpu.c |  4 ++--
  target/i386/sev.c | 17 ++---
  4 files changed, 19 insertions(+), 8 deletions(-)





[PATCH 0/4] Qemu SEV reduced-phys-bits fixes

2022-09-30 Thread Tom Lendacky
This patch series fixes up and tries to remove some confusion around the
SEV reduced-phys-bits parameter.

Based on the "AMD64 Architecture Programmer's Manual Volume 2: System
Programming", section "15.34.6 Page Table Support" [1], a guest should
only ever see a maximum of 1 bit of physical address space reduction.

- Update the documentation, to change the default value from 5 to 1.
- Update the validation of the parameter to ensure the parameter value
  is within the range of the CPUID field that it is reported in. To allow
  for backwards compatibility, especially to support the previously
  documented value of 5, allow the full range of values from 1 to 63
  (0 was never allowed).
- Update the setting of CPUID 0x801F_EBX to limit the values to the
  field width that they are setting as an additional safeguard.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf

Tom Lendacky (4):
  qapi, i386/sev: Change the reduced-phys-bits value from 5 to 1
  qemu-options.hx: Update the reduced-phys-bits documentation
  i386/sev: Update checks and information related to reduced-phys-bits
  i386/cpu: Update how the EBX register of CPUID 0x801F is set

 qapi/misc-target.json |  2 +-
 qemu-options.hx   |  4 ++--
 target/i386/cpu.c |  4 ++--
 target/i386/sev.c | 17 ++---
 4 files changed, 19 insertions(+), 8 deletions(-)

-- 
2.37.3




[PATCH 3/4] i386/sev: Update checks and information related to reduced-phys-bits

2022-09-30 Thread Tom Lendacky
The value of the reduced-phys-bits parameter is propogated to the CPUID
information exposed to the guest. Update the current validation check to
account for the size of the CPUID field (6-bits), ensuring the value is
in the range of 1 to 63.

Maintain backward compatibility, to an extent, by allowing a value greater
than 1 (so that the previously documented value of 5 still works), but not
allowing anything over 63.

Fixes: d8575c6c02 ("sev/i386: add command to initialize the memory encryption 
context")
Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 32f7dbac4e..78c2d37eba 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -932,15 +932,26 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error 
**errp)
 host_cpuid(0x801F, 0, NULL, , NULL, NULL);
 host_cbitpos = ebx & 0x3f;
 
+/*
+ * The cbitpos value will be placed in bit positions 5:0 of the EBX
+ * register of CPUID 0x801F. No need to verify the range as the
+ * comparison against the host value accomplishes that.
+ */
 if (host_cbitpos != sev->cbitpos) {
 error_setg(errp, "%s: cbitpos check failed, host '%d' requested '%d'",
__func__, host_cbitpos, sev->cbitpos);
 goto err;
 }
 
-if (sev->reduced_phys_bits < 1) {
-error_setg(errp, "%s: reduced_phys_bits check failed, it should be 
>=1,"
-   " requested '%d'", __func__, sev->reduced_phys_bits);
+/*
+ * The reduced-phys-bits value will be placed in bit positions 11:6 of
+ * the EBX register of CPUID 0x801F, so verify the supplied value
+ * is in the range of 1 to 63.
+ */
+if (sev->reduced_phys_bits < 1 || sev->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);
 goto err;
 }
 
-- 
2.37.3




[PATCH 4/4] i386/cpu: Update how the EBX register of CPUID 0x8000001F is set

2022-09-30 Thread Tom Lendacky
Update the setting of CPUID 0x801F EBX to clearly document the ranges
associated with fields being set.

Fixes: 6cb8f2a663 ("cpu/i386: populate CPUID 0x8000_001F when SEV is active")
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 1db1278a59..d4b806cfec 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5853,8 +5853,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 if (sev_enabled()) {
 *eax = 0x2;
 *eax |= sev_es_enabled() ? 0x8 : 0;
-*ebx = sev_get_cbit_position();
-*ebx |= sev_get_reduced_phys_bits() << 6;
+*ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
+*ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */
 }
 break;
 default:
-- 
2.37.3




[PATCH 2/4] qemu-options.hx: Update the reduced-phys-bits documentation

2022-09-30 Thread Tom Lendacky
A guest only ever experiences, at most, 1 bit of reduced physical
addressing. Update the documentation to reflect this as well as change
the example value on the reduced-phys-bits option.

Fixes: a9b4942f48 ("target/i386: add Secure Encrypted Virtualization (SEV) 
object")
Signed-off-by: Tom Lendacky 
---
 qemu-options.hx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index 913c71e38f..3396085cf0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -5391,7 +5391,7 @@ SRST
 physical address space. The ``reduced-phys-bits`` is used to
 provide the number of bits we loose in physical address space.
 Similar to C-bit, the value is Host family dependent. On EPYC,
-the value should be 5.
+a guest will lose a maximum of 1 bit, so the value should be 1.
 
 The ``sev-device`` provides the device file to use for
 communicating with the SEV firmware running inside AMD Secure
@@ -5426,7 +5426,7 @@ SRST
 
  # |qemu_system_x86| \\
  .. \\
- -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 \\
+ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1 \\
  -machine ...,memory-encryption=sev0 \\
  .
 
-- 
2.37.3




[PATCH 1/4] qapi, i386/sev: Change the reduced-phys-bits value from 5 to 1

2022-09-30 Thread Tom Lendacky
A guest only ever experiences, at most, 1 bit of reduced physical
addressing. Change the query-sev-capabilities json comment to use 1.

Fixes: 31dd67f684 ("sev/i386: qmp: add query-sev-capabilities command")
Signed-off-by: Tom Lendacky 
---
 qapi/misc-target.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4944c0528f..398fd09f25 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -172,7 +172,7 @@
 # -> { "execute": "query-sev-capabilities" }
 # <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE",
 #  "cpu0-id": "2lvmGwo+...61iEinw==",
-#  "cbitpos": 47, "reduced-phys-bits": 5}}
+#  "cbitpos": 47, "reduced-phys-bits": 1}}
 #
 ##
 { 'command': 'query-sev-capabilities', 'returns': 'SevCapability',
-- 
2.37.3




Re: [PATCH v2] target/i386: Add unaccepted memory configuration

2022-06-30 Thread Tom Lendacky

On 6/30/22 03:14, Daniel P. Berrangé wrote:

On Wed, Jun 29, 2022 at 07:37:01PM +, Dionna Glaze wrote:

For SEV-SNP, an OS is "SEV-SNP capable" without supporting this UEFI
v2.9 memory type. In order for OVMF to be able to avoid pre-validating
potentially hundreds of gibibytes of data before booting, it needs to
know if the guest OS can support its use of the new type of memory in
the memory map.


This talks about something supported for SEV-SNP, but


  static void
  sev_guest_class_init(ObjectClass *oc, void *data)
  {
@@ -376,6 +401,14 @@ sev_guest_class_init(ObjectClass *oc, void *data)
 sev_guest_set_kernel_hashes);
  object_class_property_set_description(oc, "kernel-hashes",
  "add kernel hashes to guest firmware for measured Linux boot");
+object_class_property_add_enum(oc, "accept-all-memory",
+   "MemoryAcceptance",
+   _acceptance_lookup,
+sev_guest_get_accept_all_memory, sev_guest_set_accept_all_memory);
+object_class_property_set_description(
+oc, "accept-all-memory",
+"false: Accept all memory, true: Accept up to 4G and leave the rest 
unaccepted (UEFI"
+" v2.9 memory type), default: default firmware behavior.");
  }


..this is adding a property to the 'sev-guest' object, which only
targets SEV/SEV-ES currently AFAIK.

The most recent patches I recall for SEV-SNP introduced a new
'sev-snp-guest' object instead of overloading the existing
'sev-guest' object:

   https://lists.gnu.org/archive/html/qemu-devel/2021-08/msg04757.html



Correct, the SNP support for Qemu is only RFC at this point until the KVM 
support for SNP is (near) finalized.


Thanks,
Tom




With regards,
Daniel




Re: New "IndustryStandard" fw_cfg?

2022-06-15 Thread Tom Lendacky

On 6/15/22 10:19, Xiaoyao Li wrote:

On 6/15/2022 8:46 AM, Xu, Min M wrote:
I would like to add more engineers (Confidential Computing Reviewers in 
EDK2 community and Intel's QEMU engineers) in this mail thread.



-Original Message-
From: Dionna Amalie Glaze 
Sent: Wednesday, June 15, 2022 2:09 AM
To: qemu-devel@nongnu.org
Cc: Xu, Min M ; Lendacky, Thomas

Subject: New "IndustryStandard" fw_cfg?

Hi y'all, I'm Dionna. I work on Confidential VMs at Google Cloud. I've 
been

keeping up with the TDX and SEV-SNP developments in OVMF and Linux,
and some in Qemu.

There's a new UEFI feature in v2.9 of the specification (March 2021) that
allows for memory ranges to be classified as "unaccepted", since both TDX
and SEV-SNP require that the guest VM accept any host-made changes to
page state. We should expect newer technologies on non-x86 architectures
to require memory acceptance as well. Operating systems are not
necessarily going to support this memory type, however.

This leads to a problem: how does the UEFI know that the OS it's going to
boot will support unaccepted memory? 


Why does UEFI need to know it?

Per my understanding, Unaccepted Memory in UEFI is introduced for 
confidential VMs, i.e., for Intel TDX and AMD SEV-SNP. The only reason 
UEFI/OVMF reports "Unaccepted Memory" to OS, is a confidential VM is 
desired. Thus, the (guset) OS has to be enlightened to know how to handle 
unaccepted memory. And of course, the non-confidential enlightened OS, 
e.g., old linux kernel, fails boot/hits issue if it doesn't support 
unaccepted memory.


As of today, SNP guest support is part of current OVMF and Linux 5.19-rcX, 
but support for unaccepted memory is not. The current OVMF SNP guest 
support will accept all the guest memory and the Linux SNP guest support 
will terminate the SNP guest if a page is accessed that has not been accepted.


Thanks,
Tom







Re: [PATCH 1/3] sev/i386: Allow launching with -kernel if no OVMF hashes table found

2021-11-01 Thread Tom Lendacky

On 11/1/21 5:21 AM, Dov Murik wrote:

Commit cff03145ed3c ("sev/i386: Introduce sev_add_kernel_loader_hashes
for measured linux boot", 2021-09-30) introduced measured direct boot
with -kernel, using an OVMF-designated hashes table which QEMU fills.

However, if OVMF doesn't designate such an area, QEMU would completely
abort the VM launch.  This breaks launching with -kernel using older
OVMF images which don't publish the SEV_HASH_TABLE_RV_GUID.

Instead, just warn the user that -kernel was supplied by OVMF doesn't
specify the GUID for the hashes table.  The following warning will be
displayed during VM launch:

 qemu-system-x86_64: warning: SEV: kernel specified but OVMF has no hash 
table guid

Signed-off-by: Dov Murik 
Reported-by: Tom Lendacky 


Just a few minor comments/questions below, otherwise:

Acked-by: Tom Lendacky 


---
  target/i386/sev.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index eede07f11d..682b8ccf6c 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1204,7 +1204,7 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext 
*ctx, Error **errp)
  int aligned_len;
  
  if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, , NULL)) {

-error_setg(errp, "SEV: kernel specified but OVMF has no hash table 
guid");
+warn_report("SEV: kernel specified but OVMF has no hash table guid");


Not sure if warn or info would be better, either way works for me, though, 
since this allows the guest to boot now.


Unrelated to this change, but do we explicitly want to say OVMF? Can't 
another BIOS/UEFI implementation have this support?


and should guid be GUID?

Thanks,
Tom


  return false;
  }
  area = (SevHashTableDescriptor *)data;





Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot

2021-10-20 Thread Tom Lendacky

On 10/19/21 1:18 AM, Dov Murik wrote:

On 18/10/2021 21:02, Tom Lendacky wrote:

On 9/30/21 12:49 AM, Dov Murik wrote:

...


+/*
+ * 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;
+    SevHashTable *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;
+    int aligned_len;
+
+    if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, ,
NULL)) {
+    error_setg(errp, "SEV: kernel specified but OVMF has no hash
table guid");
+    return false;
+    }


This breaks backwards compatibility with an older OVMF image. Any older
OVMF image with SEV support that doesn't have the hash table GUID will
now fail to boot using -kernel/-initrd/-append, where it used to be able
to boot before.




Thanks Tom for noticing this.

Just so we're on the same page: this patch is already merged.


Right, just not in a release, yet.




We're dealing with a scenario of launching a guest with SEV enabled and
with -kernel.  The behaviours are:


A. With current QEMU:

A1. New AmdSev OVMF build: OVMF will verify the hashes and boot correctly.
A2. New Generic OvmfPkgX64 build: No verification but will boot correctly.

A3. Old AmdSev OVMF build: QEMU aborts the launch because there's no
hash table GUID.
A4. Old Generic OvmfPkgX64 build: QEMU aborts the launch because there's
no hash table GUID.


B. With older QEMU (before this patch was merged):

B1. New AmdSev OVMF build: OVMF will try to verify the hashes but they
are not populated; boot aborted.
B2. New Generic OvmfPkgX64 build: No verification but will boot correctly.

B3. Old AmdSev OVMF build: OVMF aborts the launch because -kernel is not
supported at all.
B4. Old Generic OvmfPkgX64 build: No verification but will boot correctly.


So the problem you are raising is scenario A4 (as opposed to previous
behaviour B4).


Correct, scenario A4.






Is that anything we need to be concerned about?



Possible solutions:

1. Do nothing. For users that encounter this: tell them to upgrade OVMF.
2. Modify the code: remove the line: error_setg(errp, "SEV: kernel
specified but OVMF has no hash table guid")

I think that option 2 will not degrade security *if* the Guest Owner
verifies the measurement (which is mandatory anyway; otherwise the
untrusted host can replace OVMF with a "malicious" version that doesn't
verify the hashes). Skipping silently might make debugging a bit harder.
Maybe we can print a warning and return, and then the guest launch will
continue?


That sounds like it might be the best approach if there are no security 
concerns. I agree with printing a message, either informational or warning 
is ok by me.


Lets see if anyone else has some thoughts/ideas.

Thanks,
Tom



Other ideas?


-Dov





Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot

2021-10-18 Thread Tom Lendacky

On 9/30/21 12:49 AM, Dov Murik wrote:

...


+/*
+ * 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;
+SevHashTable *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;
+int aligned_len;
+
+if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, , NULL)) {
+error_setg(errp, "SEV: kernel specified but OVMF has no hash table 
guid");
+return false;
+}


This breaks backwards compatibility with an older OVMF image. Any older 
OVMF image with SEV support that doesn't have the hash table GUID will now 
fail to boot using -kernel/-initrd/-append, where it used to be able to 
boot before.


Is that anything we need to be concerned about?

Thanks,
Tom




Re: [RFC PATCH 0/6] Add AMD Secure Nested Paging (SEV-SNP) support

2021-07-12 Thread Tom Lendacky
On 7/9/21 4:55 PM, Brijesh Singh wrote:
> SEV-SNP builds upon existing SEV and SEV-ES functionality while adding
> new hardware-based memory protections. SEV-SNP adds strong memory integrity
> protection to help prevent malicious hypervisor-based attacks like data
> replay, memory re-mapping and more in order to create an isolated memory
> encryption environment.
> 
> The patches to support the SEV-SNP in Linux kernel and OVMF are available:
> https://lore.kernel.org/kvm/20210707181506.30489-1-brijesh.si...@amd.com/
> https://lore.kernel.org/kvm/20210707183616.5620-1-brijesh.si...@amd.com/
> https://edk2.groups.io/g/devel/message/77335?p=,,,20,0,0,0::Created,,posterid%3A5969970,20,2,20,83891508
> 
> The Qemu patches uses the command id added by the SEV-SNP hypervisor
> patches to bootstrap the SEV-SNP VMs.
> 
> TODO:
>  * Add support to filter CPUID values through the PSP.
> 
> Additional resources
> -
> SEV-SNP whitepaper
> https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf
> 
> APM 2: https://www.amd.com/system/files/TechDocs/24593.pdf (section 15.36)
> 
> GHCB spec:
> https://developer.amd.com/wp-content/resources/56421.pdf
> 
> SEV-SNP firmware specification:
> https://www.amd.com/system/files/TechDocs/56860.pdf
> 
> Brijesh Singh (6):
>   linux-header: add the SNP specific command
>   i386/sev: extend sev-guest property to include SEV-SNP
>   i386/sev: initialize SNP context
>   i386/sev: add the SNP launch start context
>   i386/sev: add support to encrypt BIOS when SEV-SNP is enabled
>   i386/sev: populate secrets and cpuid page and finalize the SNP launch
> 
>  docs/amd-memory-encryption.txt |  81 +-
>  linux-headers/linux/kvm.h  |  47 
>  qapi/qom.json  |   6 +
>  target/i386/sev.c  | 498 -
>  target/i386/sev_i386.h |   1 +
>  target/i386/trace-events   |   4 +
>  6 files changed, 628 insertions(+), 9 deletions(-)

Don't forget to update target/i386/sev-stub.c as appropriate, too.

Thanks,
Tom

> 



Re: [PATCH v2 1/2] hw/i386/pc: pc_system_ovmf_table_find: Assert that flash was parsed

2021-06-30 Thread Tom Lendacky
On 6/30/21 12:46 AM, Dov Murik wrote:
> Add assertion in pc_system_ovmf_table_find that verifies that the flash
> was indeed previously parsed (looking for the OVMF table) by
> pc_system_parse_ovmf_flash.
> 
> Now pc_system_ovmf_table_find distinguishes between "no one called
> pc_system_parse_ovmf_flash" (which will abort due to assertion failure)
> and "the flash was parsed but no OVMF table was found, or it is invalid"
> (which will return false).
> 
> Suggested-by: Philippe Mathieu-Daudé 
> Signed-off-by: Dov Murik 

Does the qemu coding style prefer not initializing the bool to false since
it will default to that? Otherwise,

Reviewed-by: Tom Lendacky 

> ---
>  hw/i386/pc_sysfw.c | 7 ++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
> index 6ce37a2b05..9eac36b830 100644
> --- a/hw/i386/pc_sysfw.c
> +++ b/hw/i386/pc_sysfw.c
> @@ -126,6 +126,7 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms)
>  
>  #define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
>  
> +static bool ovmf_flash_parsed = false;
>  static uint8_t *ovmf_table;
>  static int ovmf_table_len;
>  
> @@ -136,10 +137,12 @@ static void pc_system_parse_ovmf_flash(uint8_t 
> *flash_ptr, size_t flash_size)
>  int tot_len;
>  
>  /* should only be called once */
> -if (ovmf_table) {
> +if (ovmf_flash_parsed) {
>  return;
>  }
>  
> +ovmf_flash_parsed = true;
> +
>  if (flash_size < TARGET_PAGE_SIZE) {
>  return;
>  }
> @@ -183,6 +186,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t 
> **data,
>  int tot_len = ovmf_table_len;
>  QemuUUID entry_guid;
>  
> +assert(ovmf_flash_parsed);
> +
>  if (qemu_uuid_parse(entry, _guid) < 0) {
>  return false;
>  }
> 



Re: [PATCH] hw/i386/pc: Document pc_system_ovmf_table_find

2021-06-29 Thread Tom Lendacky
On 6/29/21 2:11 AM, Philippe Mathieu-Daudé wrote:
> On 6/29/21 7:56 AM, Dov Murik wrote:
>> On 29/06/2021 1:03, Tom Lendacky wrote:
>>> On 6/22/21 7:58 AM, Dov Murik wrote:
>>

>> (a) add a 'static bool ovmf_table_parsed' which will be set to true at
>> the beginning of pc_system_parse_ovmf_flash(). Then, at the beginning of
>> pc_system_ovmf_table_find add: assert(ovmf_table_parsed).
>>
>> (b) (ab)use our existing ovmf_table_len static variable: initialize it
>> to -1 (meaning that we haven't parsed the OVMF flash yet). When looking
>> for the table set it to 0 (meaning that OVMF table doesn't exist or is
>> invalid). When a proper table is found and copied to ovmf_table, then
>> set it to the real length (>= 0). At the beginning of
>> pc_system_ovmf_table_find add: assert(ovmf_table_len != -1). (this -1
>> can be #define OVMF_FLASH_NOT_PARSED -1).
>>
>>
>> Phil, Tom, James: which do you prefer? other options? Rust enum? ;-)
> 
> Since we are discussing code that should not be called, I don't have
> strong preference as long as we keep the code easy to review :)
> 
> With that in mind, (a) seems simpler.

Yes, to me (a) seems simpler, too.

Thanks,
Tom

> 
> Regards,
> 
> Phil.
> 



Re: [PATCH] hw/i386/pc: Document pc_system_ovmf_table_find

2021-06-28 Thread Tom Lendacky
On 6/22/21 7:58 AM, Dov Murik wrote:
> +cc: Tom Lendacky
> 
> On 22/06/2021 15:47, Philippe Mathieu-Daudé wrote:
>> On 6/22/21 2:44 PM, Dov Murik wrote:
>>> Suggested-by: Philippe Mathieu-Daudé 
>>> Signed-off-by: Dov Murik 
>>> ---
>>>  hw/i386/pc_sysfw.c | 14 ++
>>>  1 file changed, 14 insertions(+)
>>>
>>> diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
>>> index 6ce37a2b05..e8d20cb83f 100644
>>> --- a/hw/i386/pc_sysfw.c
>>> +++ b/hw/i386/pc_sysfw.c
>>> @@ -176,6 +176,20 @@ static void pc_system_parse_ovmf_flash(uint8_t 
>>> *flash_ptr, size_t flash_size)
>>>  ovmf_table += tot_len;
>>>  }
>>>  
>>> +/**
>>> + * pc_system_ovmf_table_find - Find the data associated with an entry in 
>>> OVMF's
>>> + * reset vector GUIDed table.
>>> + *
>>> + * @entry: GUID string of the entry to lookup
>>> + * @data: Filled with a pointer to the entry's value (if not NULL)
>>> + * @data_len: Filled with the length of the entry's value (if not NULL). 
>>> Pass
>>> + *NULL here if the length of data is known.
>>> + *
>>> + * Note that this function must be called after the OVMF table was found 
>>> and
>>> + * copied by pc_system_parse_ovmf_flash().
>>
>> What about replacing this comment by:
>>
>>   assert(ovmf_table && ovmf_table_len);
>>
> 
> I think this will break things: in target/i386/sev.c we have SEV-ES code
> that calls pc_system_ovmf_table_find() and can deal with the case when
> there's no OVMF table.  An assert will break it.

Right, what would be best is to differentiate between an OVMF table that
isn't present in the flash vs the fact that pc_system_parse_ovmf_flash()
wasn't called, asserting only on the latter.

Thanks,
Tom

> 
> 
>> Otherwise,
>>
>> Reviewed-by: Philippe Mathieu-Daudé 
>>
> 
> Thanks!
> 
> -Dov
> 
> 
> 
>> Thanks!
>>
>>> + *
>>> + * Return: true if the entry was found in the OVMF table; false otherwise.
>>> + */
>>>  bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
>>> int *data_len)
>>>  {
>>>
>>



Re: [PATCH v2 1/3] doc: Fix some mistakes in the SEV documentation

2021-06-02 Thread Tom Lendacky
Just a quick ping on this series...

Thanks,
Tom

On 4/23/21 3:08 PM, Tom Lendacky wrote:
> From: Tom Lendacky 
> 
> Fix some spelling and grammar mistakes in the amd-memory-encryption.txt
> file. No new information added.
> 
> Signed-off-by: Tom Lendacky 
> ---
>  docs/amd-memory-encryption.txt | 59 +-
>  1 file changed, 29 insertions(+), 30 deletions(-)
> 
> diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
> index 145896aec7..ed85159ea7 100644
> --- a/docs/amd-memory-encryption.txt
> +++ b/docs/amd-memory-encryption.txt
> @@ -1,38 +1,38 @@
>  Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
>  
>  SEV is an extension to the AMD-V architecture which supports running 
> encrypted
> -virtual machine (VMs) under the control of KVM. Encrypted VMs have their 
> pages
> +virtual machines (VMs) under the control of KVM. Encrypted VMs have their 
> pages
>  (code and data) secured such that only the guest itself has access to the
>  unencrypted version. Each encrypted VM is associated with a unique encryption
> -key; if its data is accessed to a different entity using a different key the
> +key; if its data is accessed by a different entity using a different key the
>  encrypted guests data will be incorrectly decrypted, leading to 
> unintelligible
>  data.
>  
> -The key management of this feature is handled by separate processor known as
> -AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware running
> -inside the AMD-SP provide commands to support common VM lifecycle. This
> +Key management for this feature is handled by a separate processor known as 
> the
> +AMD secure processor (AMD-SP), which is present in AMD SOCs. Firmware running
> +inside the AMD-SP provides commands to support a common VM lifecycle. This
>  includes commands for launching, snapshotting, migrating and debugging the
> -encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
> +encrypted guest. These SEV commands can be issued via KVM_MEMORY_ENCRYPT_OP
>  ioctls.
>  
>  Launching
>  -
> -Boot images (such as bios) must be encrypted before guest can be booted.
> -MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images 
> :LAUNCH_START,
> +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,
>  LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
>  together generate a fresh memory encryption key for the VM, encrypt the boot
> -images and provide a measurement than can be used as an attestation of the
> +images and provide a measurement than can be used as an attestation of a
>  successful launch.
>  
>  LAUNCH_START is called first to create a cryptographic launch context within
> -the firmware. To create this context, guest owner must provides guest policy,
> +the firmware. To create this context, guest owner must provide a guest 
> policy,
>  its public Diffie-Hellman key (PDH) and session parameters. These inputs
> -should be treated as binary blob and must be passed as-is to the SEV 
> firmware.
> +should be treated as a binary blob and must be passed as-is to the SEV 
> firmware.
>  
> -The guest policy is passed as plaintext and hypervisor may able to read it
> +The guest policy is passed as plaintext. A hypervisor may choose to read it,
>  but should not modify it (any modification of the policy bits will result
>  in bad measurement). The guest policy is a 4-byte data structure containing
> -several flags that restricts what can be done on running SEV guest.
> +several flags that restricts what can be done on a running SEV guest.
>  See KM Spec section 3 and 6.2 for more details.
>  
>  The guest policy can be provided via the 'policy' property (see below)
> @@ -40,31 +40,30 @@ The guest policy can be provided via the 'policy' 
> property (see below)
>  # ${QEMU} \
> sev-guest,id=sev0,policy=0x1...\
>  
> -Guest owners provided DH certificate and session parameters will be used to
> +The guest owner provided DH certificate and session parameters will be used 
> to
>  establish a cryptographic session with the guest owner to negotiate keys used
>  for the attestation.
>  
> -The DH certificate and session blob can be provided via 'dh-cert-file' and
> -'session-file' property (see below
> +The DH certificate and session blob can be provided via the 'dh-cert-file' 
> and
> +'session-file' properties (see below)
>  
>  # ${QEMU} \
>   sev-guest,id=sev0,dh-cert-file=,session-file=
>  
>  LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic

Re: [PATCH] docs: Add SEV-ES documentation to amd-memory-encryption.txt

2021-04-23 Thread Tom Lendacky
On 4/22/21 9:09 AM, Laszlo Ersek wrote:
> On 04/21/21 21:31, Tom Lendacky wrote:
>> On 4/21/21 2:12 PM, Tom Lendacky wrote:
>>> From: Tom Lendacky 
>>>
>>> Update the amd-memory-encryption.txt file with information about SEV-ES,
>>> including how to launch an SEV-ES guest and some of the differences
>>> between SEV and SEV-ES guests in regards to launching and measuring the
>>> guest.
>>>
>>
>> Hmm, it occurs to me that I should also mention some of the launch
>> restrictions between SEV and SEV-ES - such as not supporting SMM or reboot
>> in SEV-ES because of the requirements to modify the guest register state.
>>
>> I'll wait for feedback on this version and send out a v2 with the added
>> information.
> 
> I have two comments on v1 (and thanks much for posting it):
> 
> (1) Please split the typo fixes off to an initial patch. I tried to read
> your changes carefully and the typo fixes kept throwing me off.

Ok, will do. Since I'm splitting it I'll go through it in a bit more
detail and there will be additional changes without any new information.

> 
> (2) Since you are already doing great work on this :) , can you tack on
> the patch for "docs/interop/firmware.json"?
> 
> It would mean just duplicating the @amd-sev enum constant as @amd-sev-es
> (documentation paragraph and the actual enum definition).

I'll give that a shot. Let me know if I got it right when you review it :)

Look for a follow-on three patch series.

Thanks,
Tom

> 
> The new (SEV-ES) content in v1 looks plausible to me, but minimally
> Brijesh should review it more closely.
> 
> Thanks!
> Laszlo
> 
>>
>> Thanks,
>> Tom
>>
>>> Signed-off-by: Tom Lendacky 
>>> ---
>>>  docs/amd-memory-encryption.txt | 45 --
>>>  1 file changed, 37 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
>>> index 145896aec7..795b990fab 100644
>>> --- a/docs/amd-memory-encryption.txt
>>> +++ b/docs/amd-memory-encryption.txt
>>> @@ -12,18 +12,28 @@ The key management of this feature is handled by 
>>> separate processor known as
>>>  AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware 
>>> running
>>>  inside the AMD-SP provide commands to support common VM lifecycle. This
>>>  includes commands for launching, snapshotting, migrating and debugging the
>>> -encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
>>> +encrypted guest. Those SEV commands can be issued via KVM_MEMORY_ENCRYPT_OP
>>>  ioctls.
>>>  
>>> +Secure Encrypted Virtualization - Encrypted State (SEV-ES) builds on the 
>>> SEV
>>> +support to additionally protect the guest register state. In order to 
>>> allow a
>>> +hypervisor to perform functions on behalf of a guest, there is 
>>> architectural
>>> +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
>>>  -
>>>  Boot images (such as bios) must be encrypted before guest can be booted.
>>> -MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images 
>>> :LAUNCH_START,
>>> +MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images: 
>>> LAUNCH_START,
>>>  LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
>>>  together generate a fresh memory encryption key for the VM, encrypt the 
>>> boot
>>>  images and provide a measurement than can be used as an attestation of the
>>>  successful launch.
>>>  
>>> +For an SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to 
>>> encrypt the
>>> +guest register state, or VM save area (VMSA), for all of the guest vCPUs.
>>> +
>>>  LAUNCH_START is called first to create a cryptographic launch context 
>>> within
>>>  the firmware. To create this context, guest owner must provides guest 
>>> policy,
>>>  its public Diffie-Hellman key (PDH) and session parameters. These inputs
>>> @@ -40,31 +50,42 @@ The guest policy can be provided via the 'policy' 
>>> property (see below)
>>>  # ${QEMU} \
>>> sev-guest,id=sev0,policy=0x1...\
>>>  
>>> +Setting the "SEV-ES required" policy bit (bit 2) wil

[PATCH v2 2/3] docs: Add SEV-ES documentation to amd-memory-encryption.txt

2021-04-23 Thread Tom Lendacky
From: Tom Lendacky 

Update the amd-memory-encryption.txt file with information about SEV-ES,
including how to launch an SEV-ES guest and some of the differences
between SEV and SEV-ES guests in regards to launching and measuring the
guest.

Signed-off-by: Tom Lendacky 
---
 docs/amd-memory-encryption.txt | 54 +-
 1 file changed, 47 insertions(+), 7 deletions(-)

diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
index ed85159ea7..ffca382b5f 100644
--- a/docs/amd-memory-encryption.txt
+++ b/docs/amd-memory-encryption.txt
@@ -15,6 +15,13 @@ includes commands for launching, snapshotting, migrating and 
debugging the
 encrypted guest. These SEV commands can be issued via KVM_MEMORY_ENCRYPT_OP
 ioctls.
 
+Secure Encrypted Virtualization - Encrypted State (SEV-ES) builds on the SEV
+support to additionally protect the guest register state. In order to allow a
+hypervisor to perform functions on behalf of a guest, there is architectural
+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
 -
 Boot images (such as bios) must be encrypted before a guest can be booted. The
@@ -24,6 +31,9 @@ together generate a fresh memory encryption key for the VM, 
encrypt the boot
 images and provide a measurement than can be used as an attestation of a
 successful launch.
 
+For a SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to encrypt the
+guest register state, or VM save area (VMSA), for all of the guest vCPUs.
+
 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,
 its public Diffie-Hellman key (PDH) and session parameters. These inputs
@@ -40,6 +50,12 @@ The guest policy can be provided via the 'policy' property 
(see below)
 # ${QEMU} \
sev-guest,id=sev0,policy=0x1...\
 
+Setting the "SEV-ES required" policy bit (bit 2) will launch the guest as a
+SEV-ES guest (see below)
+
+# ${QEMU} \
+   sev-guest,id=sev0,policy=0x5...\
+
 The guest owner provided DH certificate and session parameters will be used to
 establish a cryptographic session with the guest owner to negotiate keys used
 for the attestation.
@@ -55,13 +71,19 @@ created via the 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.
 
-LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory.
-This measurement is a signature of the memory contents that can be sent to the
-guest owner as an attestation that the memory was encrypted correctly by the
-firmware. The guest owner may wait to provide the guest confidential 
information
-until it can verify the attestation measurement. Since the guest owner knows 
the
-initial contents of the guest at boot, the attestation measurement can be
-verified by comparing it to what the guest owner expects.
+LAUNCH_UPDATE_VMSA encrypts all the vCPU VMSAs for a SEV-ES guest using the
+cryptographic context created via the LAUNCH_START command. The command also
+calculates the measurement of the VMSAs as it encrypts them.
+
+LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory and,
+for a SEV-ES guest, encrypted VMSAs. This measurement is a signature of the
+memory contents and, for a SEV-ES guest, the VMSA contents, that can be sent
+to the guest owner as an attestation that the memory and VMSAs were encrypted
+correctly by the firmware. The guest owner may wait to provide the guest
+confidential information until it can verify the attestation measurement.
+Since the guest owner knows the initial contents of the guest at boot, the
+attestation measurement can be verified by comparing it to what the guest owner
+expects.
 
 LAUNCH_FINISH finalizes the guest launch and destroys the cryptographic
 context.
@@ -75,6 +97,22 @@ To launch a SEV guest
 -machine ...,confidential-guest-support=sev0 \
 -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
 
+To launch a SEV-ES guest
+
+# ${QEMU} \
+-machine ...,confidential-guest-support=sev0 \
+-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x5
+
+An SEV-ES guest has some restrictions as compared to a SEV guest. Because the
+guest register state is encrypted and cannot be updated by the VMM/hypervisor,
+a SEV-ES guest:
+ - Does not support SMM - SMM support requires updating the guest register
+   state.
+ - Does not support reboot - a system reset requires updating the guest 
register
+   state.
+ - Requires in-kernel irqchip - the burden is placed on the hypervisor to
+   manage booting APs.
+
 Debugging
 ---
 Since the memory contents of a SEV guest are encrypted, hypervisor access to
@@ -101

[PATCH v2 3/3] docs/interop/firmware.json: Add SEV-ES support

2021-04-23 Thread Tom Lendacky
From: Tom Lendacky 

Create an enum definition, '@amd-sev-es', for SEV-ES and add documention
for the new enum. Add an example that shows some of the requirements for
SEV-ES, including not having SMM support and the requirement for an
X64-only build.

Signed-off-by: Tom Lendacky 
---
 docs/interop/firmware.json | 47 +-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 9d94ccafa9..8d8b0be030 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -115,6 +115,12 @@
 #   this feature are documented in
 #   "docs/amd-memory-encryption.txt".
 #
+# @amd-sev-es: The firmware supports running under AMD Secure Encrypted
+#  Virtualization - Encrypted State, as specified in the AMD64
+#  Architecture Programmer's Manual. QEMU command line options
+#  related to this feature are documented in
+#  "docs/amd-memory-encryption.txt".
+#
 # @enrolled-keys: The variable store (NVRAM) template associated with
 # the firmware binary has the UEFI Secure Boot
 # operational mode turned on, with certificates
@@ -179,7 +185,7 @@
 # Since: 3.0
 ##
 { 'enum' : 'FirmwareFeature',
-  'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'enrolled-keys',
+  'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'enrolled-keys',
  'requires-smm', 'secure-boot', 'verbose-dynamic',
  'verbose-static' ] }
 
@@ -504,6 +510,45 @@
 # }
 #
 # {
+# "description": "OVMF with SEV-ES support",
+# "interface-types": [
+# "uefi"
+# ],
+# "mapping": {
+# "device": "flash",
+# "executable": {
+# "filename": "/usr/share/OVMF/OVMF_CODE.fd",
+# "format": "raw"
+# },
+# "nvram-template": {
+# "filename": "/usr/share/OVMF/OVMF_VARS.fd",
+# "format": "raw"
+# }
+# },
+# "targets": [
+# {
+# "architecture": "x86_64",
+# "machines": [
+# "pc-q35-*"
+# ]
+# }
+# ],
+# "features": [
+# "acpi-s3",
+# "amd-sev",
+# "amd-sev-es",
+# "verbose-dynamic"
+# ],
+# "tags": [
+# "-a X64",
+# "-p OvmfPkg/OvmfPkgX64.dsc",
+# "-t GCC48",
+# "-b DEBUG",
+# "-D FD_SIZE_4MB"
+# ]
+# }
+#
+# {
 # "description": "UEFI firmware for ARM64 virtual machines",
 # "interface-types": [
 # "uefi"
-- 
2.31.0




[PATCH v2 1/3] doc: Fix some mistakes in the SEV documentation

2021-04-23 Thread Tom Lendacky
From: Tom Lendacky 

Fix some spelling and grammar mistakes in the amd-memory-encryption.txt
file. No new information added.

Signed-off-by: Tom Lendacky 
---
 docs/amd-memory-encryption.txt | 59 +-
 1 file changed, 29 insertions(+), 30 deletions(-)

diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
index 145896aec7..ed85159ea7 100644
--- a/docs/amd-memory-encryption.txt
+++ b/docs/amd-memory-encryption.txt
@@ -1,38 +1,38 @@
 Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
 
 SEV is an extension to the AMD-V architecture which supports running encrypted
-virtual machine (VMs) under the control of KVM. Encrypted VMs have their pages
+virtual machines (VMs) under the control of KVM. Encrypted VMs have their pages
 (code and data) secured such that only the guest itself has access to the
 unencrypted version. Each encrypted VM is associated with a unique encryption
-key; if its data is accessed to a different entity using a different key the
+key; if its data is accessed by a different entity using a different key the
 encrypted guests data will be incorrectly decrypted, leading to unintelligible
 data.
 
-The key management of this feature is handled by separate processor known as
-AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware running
-inside the AMD-SP provide commands to support common VM lifecycle. This
+Key management for this feature is handled by a separate processor known as the
+AMD secure processor (AMD-SP), which is present in AMD SOCs. Firmware running
+inside the AMD-SP provides commands to support a common VM lifecycle. This
 includes commands for launching, snapshotting, migrating and debugging the
-encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
+encrypted guest. These SEV commands can be issued via KVM_MEMORY_ENCRYPT_OP
 ioctls.
 
 Launching
 -
-Boot images (such as bios) must be encrypted before guest can be booted.
-MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images :LAUNCH_START,
+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,
 LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
 together generate a fresh memory encryption key for the VM, encrypt the boot
-images and provide a measurement than can be used as an attestation of the
+images and provide a measurement than can be used as an attestation of a
 successful launch.
 
 LAUNCH_START is called first to create a cryptographic launch context within
-the firmware. To create this context, guest owner must provides guest policy,
+the firmware. To create this context, guest owner must provide a guest policy,
 its public Diffie-Hellman key (PDH) and session parameters. These inputs
-should be treated as binary blob and must be passed as-is to the SEV firmware.
+should be treated as a binary blob and must be passed as-is to the SEV 
firmware.
 
-The guest policy is passed as plaintext and hypervisor may able to read it
+The guest policy is passed as plaintext. A hypervisor may choose to read it,
 but should not modify it (any modification of the policy bits will result
 in bad measurement). The guest policy is a 4-byte data structure containing
-several flags that restricts what can be done on running SEV guest.
+several flags that restricts what can be done on a running SEV guest.
 See KM Spec section 3 and 6.2 for more details.
 
 The guest policy can be provided via the 'policy' property (see below)
@@ -40,31 +40,30 @@ The guest policy can be provided via the 'policy' property 
(see below)
 # ${QEMU} \
sev-guest,id=sev0,policy=0x1...\
 
-Guest owners provided DH certificate and session parameters will be used to
+The guest owner provided DH certificate and session parameters will be used to
 establish a cryptographic session with the guest owner to negotiate keys used
 for the attestation.
 
-The DH certificate and session blob can be provided via 'dh-cert-file' and
-'session-file' property (see below
+The DH certificate and session blob can be provided via the 'dh-cert-file' and
+'session-file' properties (see below)
 
 # ${QEMU} \
  sev-guest,id=sev0,dh-cert-file=,session-file=
 
 LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
-created via LAUNCH_START command. If required, this command can be called
+created via the 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.
 
-LAUNCH_MEASURE command can be used to retrieve the measurement of encrypted
-memory. This measurement is a signature of the memory contents that can be
-sent to the guest owner as an attestation that the memory was encrypted
-correctly by the firmware. The guest owner may wait to provide the guest

Re: [PATCH] docs: Add SEV-ES documentation to amd-memory-encryption.txt

2021-04-21 Thread Tom Lendacky
On 4/21/21 2:12 PM, Tom Lendacky wrote:
> From: Tom Lendacky 
> 
> Update the amd-memory-encryption.txt file with information about SEV-ES,
> including how to launch an SEV-ES guest and some of the differences
> between SEV and SEV-ES guests in regards to launching and measuring the
> guest.
> 

Hmm, it occurs to me that I should also mention some of the launch
restrictions between SEV and SEV-ES - such as not supporting SMM or reboot
in SEV-ES because of the requirements to modify the guest register state.

I'll wait for feedback on this version and send out a v2 with the added
information.

Thanks,
Tom

> Signed-off-by: Tom Lendacky 
> ---
>  docs/amd-memory-encryption.txt | 45 --
>  1 file changed, 37 insertions(+), 8 deletions(-)
> 
> diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
> index 145896aec7..795b990fab 100644
> --- a/docs/amd-memory-encryption.txt
> +++ b/docs/amd-memory-encryption.txt
> @@ -12,18 +12,28 @@ The key management of this feature is handled by separate 
> processor known as
>  AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware running
>  inside the AMD-SP provide commands to support common VM lifecycle. This
>  includes commands for launching, snapshotting, migrating and debugging the
> -encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
> +encrypted guest. Those SEV commands can be issued via KVM_MEMORY_ENCRYPT_OP
>  ioctls.
>  
> +Secure Encrypted Virtualization - Encrypted State (SEV-ES) builds on the SEV
> +support to additionally protect the guest register state. In order to allow a
> +hypervisor to perform functions on behalf of a guest, there is architectural
> +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
>  -
>  Boot images (such as bios) must be encrypted before guest can be booted.
> -MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images 
> :LAUNCH_START,
> +MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images: 
> LAUNCH_START,
>  LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
>  together generate a fresh memory encryption key for the VM, encrypt the boot
>  images and provide a measurement than can be used as an attestation of the
>  successful launch.
>  
> +For an SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to encrypt 
> the
> +guest register state, or VM save area (VMSA), for all of the guest vCPUs.
> +
>  LAUNCH_START is called first to create a cryptographic launch context within
>  the firmware. To create this context, guest owner must provides guest policy,
>  its public Diffie-Hellman key (PDH) and session parameters. These inputs
> @@ -40,31 +50,42 @@ The guest policy can be provided via the 'policy' 
> property (see below)
>  # ${QEMU} \
> sev-guest,id=sev0,policy=0x1...\
>  
> +Setting the "SEV-ES required" policy bit (bit 2) will launch the guest as an
> +SEV-ES guest (see below)
> +
> +# ${QEMU} \
> +   sev-guest,id=sev0,policy=0x5...\
> +
>  Guest owners provided DH certificate and session parameters will be used to
>  establish a cryptographic session with the guest owner to negotiate keys used
>  for the attestation.
>  
>  The DH certificate and session blob can be provided via 'dh-cert-file' and
> -'session-file' property (see below
> +'session-file' property (see below)
>  
>  # ${QEMU} \
>   sev-guest,id=sev0,dh-cert-file=,session-file=
>  
>  LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
> -created via LAUNCH_START command. If required, this command can be called
> +created via the 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.
>  
> -LAUNCH_MEASURE command can be used to retrieve the measurement of encrypted
> -memory. This measurement is a signature of the memory contents that can be
> -sent to the guest owner as an attestation that the memory was encrypted
> +LAUNCH_UPDATE_VMSA encrypts all the vCPU VMSAs for an SEV-ES guest using the
> +cryptographic context created via the LAUNCH_START command. The command also
> +calculates the measurement of the VMSAs as it encrypts them.
> +
> +LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory 
> and,
> +for an SEV-ES guest, encrypted VMSAs. This measurement is a signature of the
> +memory contents and, for an SEV-ES guest, the VMSA co

[PATCH] docs: Add SEV-ES documentation to amd-memory-encryption.txt

2021-04-21 Thread Tom Lendacky
From: Tom Lendacky 

Update the amd-memory-encryption.txt file with information about SEV-ES,
including how to launch an SEV-ES guest and some of the differences
between SEV and SEV-ES guests in regards to launching and measuring the
guest.

Signed-off-by: Tom Lendacky 
---
 docs/amd-memory-encryption.txt | 45 --
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
index 145896aec7..795b990fab 100644
--- a/docs/amd-memory-encryption.txt
+++ b/docs/amd-memory-encryption.txt
@@ -12,18 +12,28 @@ The key management of this feature is handled by separate 
processor known as
 AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware running
 inside the AMD-SP provide commands to support common VM lifecycle. This
 includes commands for launching, snapshotting, migrating and debugging the
-encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
+encrypted guest. Those SEV commands can be issued via KVM_MEMORY_ENCRYPT_OP
 ioctls.
 
+Secure Encrypted Virtualization - Encrypted State (SEV-ES) builds on the SEV
+support to additionally protect the guest register state. In order to allow a
+hypervisor to perform functions on behalf of a guest, there is architectural
+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
 -
 Boot images (such as bios) must be encrypted before guest can be booted.
-MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images :LAUNCH_START,
+MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images: LAUNCH_START,
 LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
 together generate a fresh memory encryption key for the VM, encrypt the boot
 images and provide a measurement than can be used as an attestation of the
 successful launch.
 
+For an SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to encrypt the
+guest register state, or VM save area (VMSA), for all of the guest vCPUs.
+
 LAUNCH_START is called first to create a cryptographic launch context within
 the firmware. To create this context, guest owner must provides guest policy,
 its public Diffie-Hellman key (PDH) and session parameters. These inputs
@@ -40,31 +50,42 @@ The guest policy can be provided via the 'policy' property 
(see below)
 # ${QEMU} \
sev-guest,id=sev0,policy=0x1...\
 
+Setting the "SEV-ES required" policy bit (bit 2) will launch the guest as an
+SEV-ES guest (see below)
+
+# ${QEMU} \
+   sev-guest,id=sev0,policy=0x5...\
+
 Guest owners provided DH certificate and session parameters will be used to
 establish a cryptographic session with the guest owner to negotiate keys used
 for the attestation.
 
 The DH certificate and session blob can be provided via 'dh-cert-file' and
-'session-file' property (see below
+'session-file' property (see below)
 
 # ${QEMU} \
  sev-guest,id=sev0,dh-cert-file=,session-file=
 
 LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
-created via LAUNCH_START command. If required, this command can be called
+created via the 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.
 
-LAUNCH_MEASURE command can be used to retrieve the measurement of encrypted
-memory. This measurement is a signature of the memory contents that can be
-sent to the guest owner as an attestation that the memory was encrypted
+LAUNCH_UPDATE_VMSA encrypts all the vCPU VMSAs for an SEV-ES guest using the
+cryptographic context created via the LAUNCH_START command. The command also
+calculates the measurement of the VMSAs as it encrypts them.
+
+LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory and,
+for an SEV-ES guest, encrypted VMSAs. This measurement is a signature of the
+memory contents and, for an SEV-ES guest, the VMSA contents, that can be sent
+to the guest owner as an attestation that the memory and VMSAs were encrypted
 correctly by the firmware. The guest owner may wait to provide the guest
 confidential information until it can verify the attestation measurement.
 Since the guest owner knows the initial contents of the guest at boot, the
 attestation measurement can be verified by comparing it to what the guest owner
 expects.
 
-LAUNCH_FINISH command finalizes the guest launch and destroy's the 
cryptographic
+LAUNCH_FINISH command finalizes the guest launch and destroys the cryptographic
 context.
 
 See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
@@ -76,6 +97,12 @@ To launch a SEV guest
 -machine ...,confidential-guest-support=sev0 \
 -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
 
+To la

Re: firmware selection for SEV-ES

2021-04-21 Thread Tom Lendacky
On 4/21/21 4:54 AM, Laszlo Ersek wrote:
> Hi Brijesh, Tom,

Hi Laszlo,

> 
> in QEMU's "docs/interop/firmware.json", the @FirmwareFeature enumeration
> has a constant called @amd-sev. We should introduce an @amd-sev-es
> constant as well, minimally for the following reason:
> 
> AMD document #56421 ("SEV-ES Guest-Hypervisor Communication Block
> Standardization") revision 1.40 says in "4.6 System Management Mode
> (SMM)" that "SMM will not be supported in this version of the
> specification". This is reflected in OVMF, so an OVMF binary that's
> supposed to run in a SEV-ES guest must be built without "-D
> SMM_REQUIRE". (As a consequence, such a binary should be built also
> without "-D SECURE_BOOT_ENABLE".)
> 
> At the level of "docs/interop/firmware.json", this means that management
> applications should be enabled to look for the @amd-sev-es feature (and
> it also means, for OS distributors, that any firmware descriptor
> exposing @amd-sev-es will currently have to lack all three of:
> @requires-smm, @secure-boot, @enrolled-keys).
> 
> I have three questions:
> 
> 
> (1) According to
> ,
>  SEV-ES is
> explicitly requested in the domain XML via setting bit#2 in the "policy"
> element.
> 
> Can this setting be used by libvirt to look for such a firmware
> descriptor that exposes @amd-sev-es?
> 
> 
> (2) "docs/interop/firmware.json" documents @amd-sev as follows:
> 
> # @amd-sev: The firmware supports running under AMD Secure Encrypted
> #   Virtualization, as specified in the AMD64 Architecture
> #   Programmer's Manual. QEMU command line options related to
> #   this feature are documented in
> #   "docs/amd-memory-encryption.txt".
> 
> Documenting the new @amd-sev-es enum constant with very slight
> customizations for the same text should be possible, I reckon. However,
> "docs/amd-memory-encryption.txt" (nor
> "docs/confidential-guest-support.txt") seem to mention SEV-ES.
> 
> Can you guys propose a patch for "docs/amd-memory-encryption.txt"?

Yes, I can submit a patch to update the documentation.

> 
> I guess that would be next to this snippet:
> 
>> # ${QEMU} \
>>sev-guest,id=sev0,policy=0x1...\
> 
> 
> (3) Is the "AMD64 Architecture Programmer's Manual" the specification
> that we should reference under @amd-sev-es as well (i.e., same as with
> @amd-sev), or is there a more specific document?

Yes, the same specification applies to SEV-ES.

Thanks,
Tom

> 
> Thanks,
> Laszlo
> 



Re: [PATCH for-6.0] qapi: qom: do not use target-specific conditionals

2021-03-26 Thread Tom Lendacky
On 3/26/21 5:03 AM, Paolo Bonzini wrote:
> ObjectType and ObjectOptions are defined in a target-independent file,
> therefore they do not have access to target-specific configuration
> symbols such as CONFIG_PSERIES or CONFIG_SEV.  For this reason,
> pef-guest and sev-guest are currently omitted when compiling the
> generated QAPI files.  In addition, this causes ObjectType to have
> different definitions depending on the file that is including
> qapi-types-qom.h (currently this is not causing any issues, but it
> is wrong).
> 
> Define the two enum entries and the SevGuestProperties type
> unconditionally to avoid the issue.  We do not expect to have
> many target-dependent user-creatable classes, so it is not
> particularly problematic.
> 
> Reported-by: Tom Lendacky 
> Signed-off-by: Paolo Bonzini 

I'm once again able to launch SEV guests.

Tested-by: Tom Lendacky 

> ---
>  qapi/qom.json | 10 --
>  1 file changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/qapi/qom.json b/qapi/qom.json
> index 2056edc072..db5ac419b1 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -733,8 +733,7 @@
>  '*policy': 'uint32',
>  '*handle': 'uint32',
>  '*cbitpos': 'uint32',
> -'reduced-phys-bits': 'uint32' },
> -  'if': 'defined(CONFIG_SEV)' }
> +'reduced-phys-bits': 'uint32' } }
>  
>  ##
>  # @ObjectType:
> @@ -768,14 +767,14 @@
>  { 'name': 'memory-backend-memfd',
>'if': 'defined(CONFIG_LINUX)' },
>  'memory-backend-ram',
> -{'name': 'pef-guest', 'if': 'defined(CONFIG_PSERIES)' },
> +'pef-guest',
>  'pr-manager-helper',
>  'rng-builtin',
>  'rng-egd',
>  'rng-random',
>  'secret',
>  'secret_keyring',
> -{'name': 'sev-guest', 'if': 'defined(CONFIG_SEV)' },
> +'sev-guest',
>  's390-pv-guest',
>  'throttle-group',
>  'tls-creds-anon',
> @@ -831,8 +830,7 @@
>'rng-random': 'RngRandomProperties',
>'secret': 'SecretProperties',
>'secret_keyring': 'SecretKeyringProperties',
> -  'sev-guest':  { 'type': 'SevGuestProperties',
> -  'if': 'defined(CONFIG_SEV)' },
> +  'sev-guest':  'SevGuestProperties',
>'throttle-group': 'ThrottleGroupProperties',
>'tls-creds-anon': 'TlsCredsAnonProperties',
>'tls-creds-psk':  'TlsCredsPskProperties',
> 



Re: Fail to create sev-guest object on 6.0.0-rc0

2021-03-25 Thread Tom Lendacky
On 3/25/21 1:51 PM, Brijesh Singh wrote:
> Hi All,
> 
> It seems creating the sev-guest object is broken rc0 tag. The following
> command is no longer able to create the sev-guest object
> 
> $QEMU \
> 
>  -machine ...,confidential-guest-support=sev0 \
> 
>  -object sev-guest,id=sev0,policy=0x1 \
> 
> It fails with "-object sev-guest,id=sev0: Invalid parameter
> 'sev-guest'". I will try to bisect the broken commit but if someone has
> already looked into it then let me know.

I bisected it to:

bc2f4fcb1d ("qom: move user_creatable_add_opts logic to vl.c and QAPIfy it")

> 
> 
> Thanks
> 
> Brijesh
> 



Re: [PATCH v6 0/6] Qemu SEV-ES guest support

2021-02-08 Thread Tom Lendacky

On 2/8/21 10:31 AM, Paolo Bonzini wrote:

On 08/02/21 16:48, Tom Lendacky wrote:




Queued, thanks.


It looks like David Gibson's patches for the memory encryption rework 
went into the main tree before mine. So, I think I'm going to have to 
rework my patches. Let me look into it.


I was going to ask you to check out my own rebase, but it hadn't finished 
CI yet.  Please take a look at branch sev-next at 
https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitlab.com%2Fbonzini%2Fqemudata=04%7C01%7Cthomas.lendacky%40amd.com%7C0fd806ab779a47c04fb508d8cc4eef45%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637483986711396809%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000sdata=kxzVD%2FwGNrU0zIhZjxyA0XCDtyycPW%2FROsvs3BrlkJE%3Dreserved=0 
(commit 15acccb1b769aa3854bfd875d3d17945703e3f2a, ignore the PPC failure).


Everything looked good from a review perspective and AP booting worked 
without a hitch, which was the main area effected.


Thanks for taking care of it!
Tom



Paolo





Re: [PATCH v6 0/6] Qemu SEV-ES guest support

2021-02-08 Thread Tom Lendacky

On 2/5/21 4:59 AM, Paolo Bonzini wrote:

On 26/01/21 18:36, Tom Lendacky wrote:

From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.



...





Queued, thanks.


It looks like David Gibson's patches for the memory encryption rework went 
into the main tree before mine. So, I think I'm going to have to rework my 
patches. Let me look into it.


Thanks,
Tom



Paolo





Re: [PATCH v6 3/6] sev/i386: Allow AP booting under SEV-ES

2021-02-01 Thread Tom Lendacky

On 1/29/21 11:44 AM, Venu Busireddy wrote:

On 2021-01-26 11:36:46 -0600, Tom Lendacky wrote:

From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured. Search the guest firmware for the guest for a
specific GUID that tells Qemu the value of the reset vector to use.

Cc: Paolo Bonzini 
Cc: "Michael S. Tsirkin" 
Cc: Marcel Apfelbaum 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Cc: Marcelo Tosatti 
Signed-off-by: Tom Lendacky 
---

...

+
+/*
+ * SEV info block not found in the Firmware GUID Table (or there isn't
+ * a Firmware GUID Table), fall back to the original implementation.
+ */
+data = flash_ptr + flash_size - 0x20;


Even if the SEV_INFO_BLOCK_GUID is always located at 32 bytes from the end
of the flash, isn't it better to define a constant with a value of 0x20?


A follow-on patch that updates both this and the table parser code from 
James would probably be best.


Thanks,
Tom




+




[PATCH v6 6/6] sev/i386: Enable an SEV-ES guest based on SEV policy

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Reviewed-by: Dr. David Alan Gilbert 
Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index badc141554..62ecc28cf6 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -371,7 +371,7 @@ sev_enabled(void)
 bool
 sev_es_enabled(void)
 {
-return false;
+return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
 }
 
 uint64_t
-- 
2.30.0




[PATCH v6 5/6] kvm/i386: Use a per-VM check for SMM capability

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

SMM is not currently supported for an SEV-ES guest by KVM. Change the SMM
capability check from a KVM-wide check to a per-VM check in order to have
a finer-grained SMM capability check.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Suggested-by: Sean Christopherson 
Signed-off-by: Tom Lendacky 
---
 target/i386/kvm/kvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index bb6bfc19de..37fca43cd9 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -135,7 +135,7 @@ int kvm_has_pit_state2(void)
 
 bool kvm_has_smm(void)
 {
-return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
+return kvm_vm_check_extension(kvm_state, KVM_CAP_X86_SMM);
 }
 
 bool kvm_has_adjust_clock_stable(void)
-- 
2.30.0




[PATCH v6 4/6] sev/i386: Don't allow a system reset under an SEV-ES guest

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When an SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES. Prevent that from occuring by introducing an arch-specific
callback that returns a boolean indicating whether vCPUs are resettable.

Cc: Peter Maydell 
Cc: Aurelien Jarno 
Cc: Jiaxun Yang 
Cc: Aleksandar Rikalo 
Cc: David Gibson 
Cc: David Hildenbrand 
Reviewed-by: Dr. David Alan Gilbert 
Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c   |  5 +
 include/sysemu/cpus.h |  2 ++
 include/sysemu/hw_accel.h |  5 +
 include/sysemu/kvm.h  | 10 ++
 softmmu/cpus.c|  5 +
 softmmu/runstate.c|  3 +++
 target/arm/kvm.c  |  5 +
 target/i386/kvm/kvm.c |  6 ++
 target/mips/kvm.c |  5 +
 target/ppc/kvm.c  |  5 +
 target/s390x/kvm.c|  5 +
 11 files changed, 56 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 410879cf94..6c099a3869 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2414,6 +2414,11 @@ void kvm_flush_coalesced_mmio_buffer(void)
 s->coalesced_flush_in_progress = false;
 }
 
+bool kvm_cpu_check_are_resettable(void)
+{
+return kvm_arch_cpu_check_are_resettable();
+}
+
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
 if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index e8156728c6..1cb4f9dbeb 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -57,6 +57,8 @@ extern int icount_align_option;
 /* Unblock cpu */
 void qemu_cpu_kick_self(void);
 
+bool cpus_are_resettable(void);
+
 void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index ffed6192a3..61672f9b32 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -22,4 +22,9 @@ void cpu_synchronize_post_reset(CPUState *cpu);
 void cpu_synchronize_post_init(CPUState *cpu);
 void cpu_synchronize_pre_loadvm(CPUState *cpu);
 
+static inline bool cpu_check_are_resettable(void)
+{
+return kvm_enabled() ? kvm_cpu_check_are_resettable() : true;
+}
+
 #endif /* QEMU_HW_ACCEL_H */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 875ca101e3..3e265cea3d 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -573,4 +573,14 @@ int kvm_get_max_memslots(void);
 /* Notify resamplefd for EOI of specific interrupts. */
 void kvm_resample_fd_notify(int gsi);
 
+/**
+ * kvm_cpu_check_are_resettable - return whether CPUs can be reset
+ *
+ * Returns: true: CPUs are resettable
+ *  false: CPUs are not resettable
+ */
+bool kvm_cpu_check_are_resettable(void);
+
+bool kvm_arch_cpu_check_are_resettable(void);
+
 #endif
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 1dc20b9dc3..89de46eae0 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -194,6 +194,11 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu)
 }
 }
 
+bool cpus_are_resettable(void)
+{
+return cpu_check_are_resettable();
+}
+
 int64_t cpus_get_virtual_clock(void)
 {
 /*
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index beee050815..1813691898 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -527,6 +527,9 @@ void qemu_system_reset_request(ShutdownCause reason)
 if (reboot_action == REBOOT_ACTION_SHUTDOWN &&
 reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
 shutdown_requested = reason;
+} else if (!cpus_are_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
 } else {
 reset_requested = reason;
 }
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ffe186de8d..00e124c812 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1045,3 +1045,8 @@ int kvm_arch_msi_data_to_gsi(uint32_t data)
 {
 return (data - 32) & 0x;
 }
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+return true;
+}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index aaae79557d..bb6bfc19de 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -27,6 +27,7 @@
 #include "sysemu/kvm_int.h"
 #include "sysemu/runstate.h"
 #include "kvm_i386.h"
+#include "sev_i386.h"
 #include "hyperv.h"
 #include "hyperv-proto.h"
 
@@ -4788,3 +4789,8 @@ bool kvm_has_waitpkg(void)
 {
 return has_msr_umwait;
 }
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+return !sev_es_enabled();
+}
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index 84fb10ea35..123ec1be7e 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -1290,3 +1290,8 @@ int mips_kvm_type(MachineState *machine, const char 
*vm_type)
 
 return -1;
 }
+
+bool kvm_arch_cpu_c

[PATCH v6 3/6] sev/i386: Allow AP booting under SEV-ES

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured. Search the guest firmware for the guest for a
specific GUID that tells Qemu the value of the reset vector to use.

Cc: Paolo Bonzini 
Cc: "Michael S. Tsirkin" 
Cc: Marcel Apfelbaum 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Cc: Marcelo Tosatti 
Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c| 64 
 accel/stubs/kvm-stub.c |  5 +++
 hw/i386/pc_sysfw.c | 10 +-
 include/sysemu/kvm.h   | 16 +
 include/sysemu/sev.h   |  3 ++
 target/i386/kvm/kvm.c  |  2 ++
 target/i386/sev.c  | 74 ++
 7 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 3feb17d965..410879cf94 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
 #include "qemu/main-loop.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sev.h"
 #include "qapi/visitor.h"
 #include "qapi/qapi-types-common.h"
@@ -126,6 +127,12 @@ struct KVMState
 /* memory encryption */
 void *memcrypt_handle;
 int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
+  uint64_t flash_size, uint32_t *addr);
+
+uint32_t reset_cs;
+uint32_t reset_ip;
+bool reset_data_valid;
 
 /* For "info mtree -f" to tell if an MR is registered in KVM */
 int nr_as;
@@ -245,6 +252,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
 return 1;
 }
 
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)
+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_data_valid) {
+return;
+}
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0) {
+return;
+}
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size,
+);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_data_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
@@ -2216,6 +2279,7 @@ static int kvm_init(MachineState *ms)
 }
 
 kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
 }
 
 ret = kvm_arch_init(ms, s);
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 680e099463..162c28429e 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -91,6 +91,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
   return 1;
 }
 
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+return -ENOSYS;
+}
+
 #ifndef CONFIG_USER_ONLY
 int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 436b78c587..edec28842d 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -248,7 +248,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 PFlashCFI01 *system_flash;
 MemoryRegion *flash_mem;
 void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
 
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
@@ -301,6 +302,13 @@ static void pc_system_flash_map(PCMachineState *pcms,
  * search for them
   

[PATCH v6 2/6] sev/i386: Require in-kernel irqchip support for SEV-ES guests

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

In prep for AP booting, require the use of in-kernel irqchip support. This
lessens the Qemu support burden required to boot APs.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Reviewed-by: Dr. David Alan Gilbert 
Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index fce2128c07..ddec7ebaa7 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -776,6 +776,12 @@ sev_guest_init(const char *id)
 sev->api_minor = status.api_minor;
 
 if (sev_es_enabled()) {
+if (!kvm_kernel_irqchip_allowed()) {
+error_report("%s: SEV-ES guests require in-kernel irqchip support",
+ __func__);
+goto err;
+}
+
 if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
 error_report("%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
-- 
2.30.0




[PATCH v6 1/6] sev/i386: Add initial support for SEV-ES

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Reviewed-by: Dr. David Alan Gilbert 
Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c  |  1 +
 target/i386/sev-stub.c |  6 ++
 target/i386/sev.c  | 44 --
 target/i386/sev_i386.h |  1 +
 4 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 72a79e6019..0415d8a99c 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5987,6 +5987,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 break;
 case 0x801F:
 *eax = sev_enabled() ? 0x2 : 0;
+*eax |= sev_es_enabled() ? 0x8 : 0;
 *ebx = sev_get_cbit_position();
 *ebx |= sev_get_reduced_phys_bits() << 6;
 *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index c1fecc2101..229a2ee77b 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,8 +49,14 @@ SevCapability *sev_get_capabilities(Error **errp)
 error_setg(errp, "SEV is not available in this QEMU");
 return NULL;
 }
+
 int sev_inject_launch_secret(const char *hdr, const char *secret,
  uint64_t gpa, Error **errp)
 {
 return 1;
 }
+
+bool sev_es_enabled(void)
+{
+return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 1546606811..fce2128c07 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -360,6 +360,12 @@ sev_enabled(void)
 return !!sev_guest;
 }
 
+bool
+sev_es_enabled(void)
+{
+return false;
+}
+
 uint64_t
 sev_get_me_mask(void)
 {
@@ -580,6 +586,20 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
 return ret;
 }
 
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+int ret, fw_error;
+
+ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, _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));
+}
+
+return ret;
+}
+
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
@@ -592,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 return;
 }
 
+if (sev_es_enabled()) {
+/* measure all the VM save areas before getting launch_measure */
+ret = sev_launch_update_vmsa(sev);
+if (ret) {
+exit(1);
+}
+}
+
 measurement = g_new0(struct kvm_sev_launch_measure, 1);
 
 /* query the measurement blob length */
@@ -686,7 +714,7 @@ sev_guest_init(const char *id)
 {
 SevGuestState *sev;
 char *devname;
-int ret, fw_error;
+int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
@@ -747,8 +775,20 @@ sev_guest_init(const char *id)
 sev->api_major = status.api_major;
 sev->api_minor = status.api_minor;
 
+if (sev_es_enabled()) {
+if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+goto err;
+}
+cmd = KVM_SEV_ES_INIT;
+} else {
+cmd = KVM_SEV_INIT;
+}
+
 trace_kvm_sev_init();
-ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, _error);
+ret = sev_ioctl(sev->sev_fd, cmd, NULL, _error);
 if (ret) {
 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
  __func__, ret, fw_error, fw_error_to_str(fw_error));
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..4f9a5e9b21 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -29,6 +29,7 @@
 #define SEV_POLICY_SEV  0x20
 
 extern bool sev_enabled(void);
+extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
-- 
2.30.0




[PATCH v6 0/6] Qemu SEV-ES guest support

2021-01-26 Thread Tom Lendacky
From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

Cc: Aleksandar Rikalo 
Cc: Aurelien Jarno 
Cc: David Gibson 
Cc: David Hildenbrand 
Cc: Eduardo Habkost 
Cc: Jiaxun Yang 
Cc: Marcel Apfelbaum 
Cc: Marcelo Tosatti 
Cc: "Michael S. Tsirkin" 
Cc: Paolo Bonzini 
Cc: Peter Maydell 
Cc: Richard Henderson 

---

These patches are based on commit:
9cd69f1a27 ("Merge remote-tracking branch 
'remotes/stefanberger/tags/pull-tpm-2021-01-25-1' into staging")

Additionally, these patches pre-req the following patch series that has
not yet been accepted into the Qemu tree:

[PATCH v2 0/2] sev: enable secret injection to a self described area in OVMF
  https://lore.kernel.org/qemu-devel/20201214154429.11023-1-j...@linux.ibm.com/

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v14

Changes since v5:
- Rework the reset prevention patch to not issue the error message if the
  --no-reboot option has been specified for SEV-ES guests.

Changes since v4:
- Add support for an updated Firmware GUID table implementation, that
  is now present in OVMF SEV-ES firmware, when searching for the reset
  vector information. The code will check for the new implementation
  first, followed by the original implementation to maintain backward
  compatibility.

Changes since v3:
- Use the QemuUUID structure for GUID definitions
- Use SEV-ES policy bit definition from target/i386/sev_i386.h
- Update SMM support to a per-VM check in order to check SMM capability
  at the VM level since SEV-ES guests don't currently support SMM
- Make the CPU resettable check an arch-specific check

Changes since v2:
- Add in-kernel irqchip requirement for SEV-ES guests

Changes since v1:
- Fixed checkpatch.pl errors/warnings

Tom Lendacky (6):
  sev/i386: Add initial support for SEV-ES
  sev/i386: Require in-kernel irqchip support for SEV-ES guests
  sev/i386: Allow AP booting under SEV-ES
  sev/i386: Don't allow a system reset under an SEV-ES guest
  kvm/i386: Use a per-VM check for SMM capability
  sev/i386: Enable an SEV-ES guest based on SEV policy

 accel/kvm/kvm-all.c   |  69 ++

Re: [PATCH v4 0/6] Qemu SEV-ES guest support

2021-01-26 Thread Tom Lendacky
On 1/26/21 10:49 AM, Tom Lendacky wrote:
> On 1/26/21 10:21 AM, Paolo Bonzini wrote:
>> On 25/09/20 21:03, Tom Lendacky wrote:
>>> From: Tom Lendacky 
>>>
>>> This patch series provides support for launching an SEV-ES guest.
>>>
> 
> ...
> 
>>>
>>
>> Looks good!  Please fix the nit in patch 4 and rebase, I'll then apply it.
> 
> There's a v5 on the list that was rebased on the latest tree, but still
> has the patch 4 issue. I'm updating that now, so look for the v6 version
> for merging.

Also, the new version will have a prereq against another patch series that
has not been accepted yet:

  [PATCH v2 0/2] sev: enable secret injection to a self described area in OVMF

  https://lore.kernel.org/qemu-devel/20201214154429.11023-1-j...@linux.ibm.com/

Thanks,
Tom

> 
> Thanks,
> Tom
> 
>>
>> Thanks,
>>
>> Paolo
>>



Re: [PATCH v4 0/6] Qemu SEV-ES guest support

2021-01-26 Thread Tom Lendacky
On 1/26/21 10:21 AM, Paolo Bonzini wrote:
> On 25/09/20 21:03, Tom Lendacky wrote:
>> From: Tom Lendacky 
>>
>> This patch series provides support for launching an SEV-ES guest.
>>

...

>>
> 
> Looks good!  Please fix the nit in patch 4 and rebase, I'll then apply it.

There's a v5 on the list that was rebased on the latest tree, but still
has the patch 4 issue. I'm updating that now, so look for the v6 version
for merging.

Thanks,
Tom

> 
> Thanks,
> 
> Paolo
> 



Re: [PATCH v4 4/6] sev/i386: Don't allow a system reset under an SEV-ES guest

2021-01-26 Thread Tom Lendacky
On 1/26/21 10:16 AM, Paolo Bonzini wrote:
> On 25/09/20 21:03, Tom Lendacky wrote:
>>
>>  {
>> -    if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
>> +    if (!cpus_are_resettable()) {
>> +    error_report("cpus are not resettable, terminating");
>> +    shutdown_requested = reason;
>> +    } else if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
> 
> The error should not be emitted if "no_reboot && reason !=
> SHUTDOWN_CAUSE_SUBSYSTEM_RESET" (the condition has changed a bit in latest
> QEMU but the idea is the same).
> 
> This is because whoever invoked QEMU could already know about this SEV-ES
> limitation, and use -no-reboot (aka -action reset=shutdown in 6.0) in
> order to change the forbidden warm reset into a shutdown+restart cold reset.

Ah, right. Let me re-work this to not emit the message when it is not
warranted.

Thanks,
Tom

> 
> Paolo
> 



[PATCH v5 0/6] Qemu SEV-ES guest support

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

Cc: Aleksandar Rikalo 
Cc: Aurelien Jarno 
Cc: David Gibson 
Cc: David Hildenbrand 
Cc: Eduardo Habkost 
Cc: Jiaxun Yang 
Cc: Marcel Apfelbaum 
Cc: Marcelo Tosatti 
Cc: "Michael S. Tsirkin" 
Cc: Paolo Bonzini 
Cc: Peter Maydell 
Cc: Richard Henderson 

---

These patches are based on commit:
7c79721606 ("Merge remote-tracking branch 
'remotes/rth-gitlab/tags/pull-tcg-20210113' into staging")

Additionally, these patches pre-req the following patch series that has
not yet been accepted into the Qemu tree:

[PATCH v2 0/2] sev: enable secret injection to a self described area in OVMF
  https://lore.kernel.org/qemu-devel/20201214154429.11023-1-j...@linux.ibm.com/

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v13

Changes since v4:
- Add support for an updated Firmware GUID table implementation, that
  is now present in OVMF SEV-ES firmware, when searching for the reset
  vector information. The code will check for the new implementation
  first, followed by the original implementation to maintain backward
  compatibility.

Changes since v3:
- Use the QemuUUID structure for GUID definitions
- Use SEV-ES policy bit definition from target/i386/sev_i386.h
- Update SMM support to a per-VM check in order to check SMM capability
  at the VM level since SEV-ES guests don't currently support SMM
- Make the CPU resettable check an arch-specific check

Changes since v2:
- Add in-kernel irqchip requirement for SEV-ES guests

Changes since v1:
- Fixed checkpatch.pl errors/warnings

Tom Lendacky (6):
  sev/i386: Add initial support for SEV-ES
  sev/i386: Require in-kernel irqchip support for SEV-ES guests
  sev/i386: Allow AP booting under SEV-ES
  sev/i386: Don't allow a system reset under an SEV-ES guest
  kvm/i386: Use a per-VM check for SMM capability
  sev/i386: Enable an SEV-ES guest based on SEV policy

 accel/kvm/kvm-all.c   |  69 +
 accel/stubs/kvm-stub.c|   5 ++
 hw/i386/pc_sysfw.c|  10 ++-
 include/sysemu/cpus.h |   2 +
 include/sysemu/hw_accel.h |   5 

[PATCH v5 4/6] sev/i386: Don't allow a system reset under an SEV-ES guest

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When an SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES. Prevent that from occuring by introducing an arch-specific
callback that returns a boolean indicating whether vCPUs are resettable.

Cc: Peter Maydell 
Cc: Aurelien Jarno 
Cc: Jiaxun Yang 
Cc: Aleksandar Rikalo 
Cc: David Gibson 
Cc: David Hildenbrand 
Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c   |  5 +
 include/sysemu/cpus.h |  2 ++
 include/sysemu/hw_accel.h |  5 +
 include/sysemu/kvm.h  | 10 ++
 softmmu/cpus.c|  5 +
 softmmu/runstate.c|  7 +--
 target/arm/kvm.c  |  5 +
 target/i386/kvm/kvm.c |  6 ++
 target/mips/kvm.c |  5 +
 target/ppc/kvm.c  |  5 +
 target/s390x/kvm.c|  5 +
 11 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 9db74b465e..9ac44ad018 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2411,6 +2411,11 @@ void kvm_flush_coalesced_mmio_buffer(void)
 s->coalesced_flush_in_progress = false;
 }
 
+bool kvm_cpu_check_are_resettable(void)
+{
+return kvm_arch_cpu_check_are_resettable();
+}
+
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
 if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index e8156728c6..1cb4f9dbeb 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -57,6 +57,8 @@ extern int icount_align_option;
 /* Unblock cpu */
 void qemu_cpu_kick_self(void);
 
+bool cpus_are_resettable(void);
+
 void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index ffed6192a3..61672f9b32 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -22,4 +22,9 @@ void cpu_synchronize_post_reset(CPUState *cpu);
 void cpu_synchronize_post_init(CPUState *cpu);
 void cpu_synchronize_pre_loadvm(CPUState *cpu);
 
+static inline bool cpu_check_are_resettable(void)
+{
+return kvm_enabled() ? kvm_cpu_check_are_resettable() : true;
+}
+
 #endif /* QEMU_HW_ACCEL_H */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 875ca101e3..3e265cea3d 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -573,4 +573,14 @@ int kvm_get_max_memslots(void);
 /* Notify resamplefd for EOI of specific interrupts. */
 void kvm_resample_fd_notify(int gsi);
 
+/**
+ * kvm_cpu_check_are_resettable - return whether CPUs can be reset
+ *
+ * Returns: true: CPUs are resettable
+ *  false: CPUs are not resettable
+ */
+bool kvm_cpu_check_are_resettable(void);
+
+bool kvm_arch_cpu_check_are_resettable(void);
+
 #endif
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 1dc20b9dc3..89de46eae0 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -194,6 +194,11 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu)
 }
 }
 
+bool cpus_are_resettable(void)
+{
+return cpu_check_are_resettable();
+}
+
 int64_t cpus_get_virtual_clock(void)
 {
 /*
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index 636aab0add..7b4f212d19 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -523,8 +523,11 @@ void qemu_system_guest_crashloaded(GuestPanicInformation 
*info)
 
 void qemu_system_reset_request(ShutdownCause reason)
 {
-if (reboot_action == REBOOT_ACTION_SHUTDOWN &&
-reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+if (!cpus_are_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
+} else if (reboot_action == REBOOT_ACTION_SHUTDOWN &&
+   reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
 shutdown_requested = reason;
 } else {
 reset_requested = reason;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ffe186de8d..00e124c812 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1045,3 +1045,8 @@ int kvm_arch_msi_data_to_gsi(uint32_t data)
 {
 return (data - 32) & 0x;
 }
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+return true;
+}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index aaae79557d..bb6bfc19de 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -27,6 +27,7 @@
 #include "sysemu/kvm_int.h"
 #include "sysemu/runstate.h"
 #include "kvm_i386.h"
+#include "sev_i386.h"
 #include "hyperv.h"
 #include "hyperv-proto.h"
 
@@ -4788,3 +4789,8 @@ bool kvm_has_waitpkg(void)
 {
 return has_msr_umwait;
 }
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+return !sev_es_enabled();
+}
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index 477692566a..a907c59c5e 100644
--- 

[PATCH v5 6/6] sev/i386: Enable an SEV-ES guest based on SEV policy

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Reviewed-by: Dr. David Alan Gilbert 
Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index badc141554..62ecc28cf6 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -371,7 +371,7 @@ sev_enabled(void)
 bool
 sev_es_enabled(void)
 {
-return false;
+return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
 }
 
 uint64_t
-- 
2.30.0




[PATCH v5 5/6] kvm/i386: Use a per-VM check for SMM capability

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

SMM is not currently supported for an SEV-ES guest by KVM. Change the SMM
capability check from a KVM-wide check to a per-VM check in order to have
a finer-grained SMM capability check.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Suggested-by: Sean Christopherson 
Signed-off-by: Tom Lendacky 
---
 target/i386/kvm/kvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index bb6bfc19de..37fca43cd9 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -135,7 +135,7 @@ int kvm_has_pit_state2(void)
 
 bool kvm_has_smm(void)
 {
-return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
+return kvm_vm_check_extension(kvm_state, KVM_CAP_X86_SMM);
 }
 
 bool kvm_has_adjust_clock_stable(void)
-- 
2.30.0




[PATCH v5 3/6] sev/i386: Allow AP booting under SEV-ES

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured. Search the guest firmware for the guest for a
specific GUID that tells Qemu the value of the reset vector to use.

Cc: Paolo Bonzini 
Cc: "Michael S. Tsirkin" 
Cc: Marcel Apfelbaum 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Cc: Marcelo Tosatti 
Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c| 64 
 accel/stubs/kvm-stub.c |  5 +++
 hw/i386/pc_sysfw.c | 10 +-
 include/sysemu/kvm.h   | 16 +
 include/sysemu/sev.h   |  3 ++
 target/i386/kvm/kvm.c  |  2 ++
 target/i386/sev.c  | 74 ++
 7 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 389eaace72..9db74b465e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
 #include "qemu/main-loop.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sev.h"
 #include "qapi/visitor.h"
 #include "qapi/qapi-types-common.h"
@@ -123,6 +124,12 @@ struct KVMState
 /* memory encryption */
 void *memcrypt_handle;
 int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
+  uint64_t flash_size, uint32_t *addr);
+
+uint32_t reset_cs;
+uint32_t reset_ip;
+bool reset_data_valid;
 
 /* For "info mtree -f" to tell if an MR is registered in KVM */
 int nr_as;
@@ -242,6 +249,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
 return 1;
 }
 
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)
+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_data_valid) {
+return;
+}
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0) {
+return;
+}
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size,
+);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_data_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
@@ -2213,6 +2276,7 @@ static int kvm_init(MachineState *ms)
 }
 
 kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
 }
 
 ret = kvm_arch_init(ms, s);
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 680e099463..162c28429e 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -91,6 +91,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
   return 1;
 }
 
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+return -ENOSYS;
+}
+
 #ifndef CONFIG_USER_ONLY
 int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 436b78c587..edec28842d 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -248,7 +248,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 PFlashCFI01 *system_flash;
 MemoryRegion *flash_mem;
 void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
 
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
@@ -301,6 +302,13 @@ static void pc_system_flash_map(PCMachineState *pcms,
  * search for them
   

[PATCH v5 2/6] sev/i386: Require in-kernel irqchip support for SEV-ES guests

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

In prep for AP booting, require the use of in-kernel irqchip support. This
lessens the Qemu support burden required to boot APs.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index fce2128c07..ddec7ebaa7 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -776,6 +776,12 @@ sev_guest_init(const char *id)
 sev->api_minor = status.api_minor;
 
 if (sev_es_enabled()) {
+if (!kvm_kernel_irqchip_allowed()) {
+error_report("%s: SEV-ES guests require in-kernel irqchip support",
+ __func__);
+goto err;
+}
+
 if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
 error_report("%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
-- 
2.30.0




[PATCH v5 1/6] sev/i386: Add initial support for SEV-ES

2021-01-14 Thread Tom Lendacky
From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Cc: Paolo Bonzini 
Cc: Richard Henderson 
Cc: Eduardo Habkost 
Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c  |  1 +
 target/i386/sev-stub.c |  6 ++
 target/i386/sev.c  | 44 --
 target/i386/sev_i386.h |  1 +
 4 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 35459a38bb..9adb34c091 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5986,6 +5986,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 break;
 case 0x801F:
 *eax = sev_enabled() ? 0x2 : 0;
+*eax |= sev_es_enabled() ? 0x8 : 0;
 *ebx = sev_get_cbit_position();
 *ebx |= sev_get_reduced_phys_bits() << 6;
 *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index c1fecc2101..229a2ee77b 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,8 +49,14 @@ SevCapability *sev_get_capabilities(Error **errp)
 error_setg(errp, "SEV is not available in this QEMU");
 return NULL;
 }
+
 int sev_inject_launch_secret(const char *hdr, const char *secret,
  uint64_t gpa, Error **errp)
 {
 return 1;
 }
+
+bool sev_es_enabled(void)
+{
+return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 1546606811..fce2128c07 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -360,6 +360,12 @@ sev_enabled(void)
 return !!sev_guest;
 }
 
+bool
+sev_es_enabled(void)
+{
+return false;
+}
+
 uint64_t
 sev_get_me_mask(void)
 {
@@ -580,6 +586,20 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
 return ret;
 }
 
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+int ret, fw_error;
+
+ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, _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));
+}
+
+return ret;
+}
+
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
@@ -592,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 return;
 }
 
+if (sev_es_enabled()) {
+/* measure all the VM save areas before getting launch_measure */
+ret = sev_launch_update_vmsa(sev);
+if (ret) {
+exit(1);
+}
+}
+
 measurement = g_new0(struct kvm_sev_launch_measure, 1);
 
 /* query the measurement blob length */
@@ -686,7 +714,7 @@ sev_guest_init(const char *id)
 {
 SevGuestState *sev;
 char *devname;
-int ret, fw_error;
+int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
@@ -747,8 +775,20 @@ sev_guest_init(const char *id)
 sev->api_major = status.api_major;
 sev->api_minor = status.api_minor;
 
+if (sev_es_enabled()) {
+if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+goto err;
+}
+cmd = KVM_SEV_ES_INIT;
+} else {
+cmd = KVM_SEV_INIT;
+}
+
 trace_kvm_sev_init();
-ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, _error);
+ret = sev_ioctl(sev->sev_fd, cmd, NULL, _error);
 if (ret) {
 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
  __func__, ret, fw_error, fw_error_to_str(fw_error));
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..4f9a5e9b21 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -29,6 +29,7 @@
 #define SEV_POLICY_SEV  0x20
 
 extern bool sev_enabled(void);
+extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
-- 
2.30.0




Re: [PATCH 3/3] sev: update sev-inject-launch-secret to make gpa optional

2020-12-11 Thread Tom Lendacky

On 12/11/20 4:45 PM, James Bottomley wrote:

On Fri, 2020-12-11 at 16:00 -0600, Tom Lendacky wrote:

On 12/9/20 11:23 AM, James Bottomley wrote:


So for this one I'm not checking the length, which argues it wouldn't
be subject to the added length new data rule and I'd have to use a new
guid for new information.  However, I could also see situations where
you would check the length and thus would have the ability to add
fields (either at the beginning or the end).


I think this paragraph explains it nicely and a slightly expanded comment 
with this information would be enough.


Thanks,
Tom





Whatever we decide should probably be documented in both the OVMF
patches and the Qemu patches.


OK, I can add a comment about my use case and you can add one
documenting your length based use case.

James






Re: [PATCH 3/3] sev: update sev-inject-launch-secret to make gpa optional

2020-12-11 Thread Tom Lendacky

On 12/9/20 11:23 AM, James Bottomley wrote:

If the gpa isn't specified, it's value is extracted from the OVMF
properties table located below the reset vector (and if this doesn't
exist, an error is returned).  OVMF has defined the GUID for the SEV
secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format of
the  is: | where both are uint32_t.  We extract
 and use it as the gpa for the injection.

Note: it is expected that the injected secret will also be GUID
described but since qemu can't interpret it, the format is left
undefined here.

Signed-off-by: James Bottomley 
---
  qapi/misc-target.json |  2 +-
  target/i386/monitor.c | 22 +-
  2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4486a543ae..1ee4e62f85 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -216,7 +216,7 @@
  #
  ##
  { 'command': 'sev-inject-launch-secret',
-  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa': 'uint64' },
+  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' },
'if': 'defined(TARGET_I386)' }
  
  ##

diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 1bc91442b1..a99e3dd2b3 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -34,6 +34,7 @@
  #include "sev_i386.h"
  #include "qapi/qapi-commands-misc-target.h"
  #include "qapi/qapi-commands-misc.h"
+#include "hw/i386/pc.h"
  
  /* Perform linear address sign extension */

  static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
@@ -730,9 +731,28 @@ SevCapability *qmp_query_sev_capabilities(Error **errp)
  return sev_get_capabilities(errp);
  }
  
+#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"

+struct sev_secret_area {
+uint32_t base;
+uint32_t size;
+};
+


Originally, the idea was to allow expanding of these GUID based structures 
by pre-pending data to them, but based on how pc_system_ovmf_table_find() 
returns the pointer to the start of the structure (based on the length 
found in the structure), I believe that expansion could be done by 
appending to the structure, which seems more logical. For example, if this 
structure is ever expanded, it can use the third parameter of 
pc_system_ovmf_table_find() to get the length and compare that to the size 
of the structure to determine if new version of the structure is present 
in the firmware.


Otherwise you can't do the nice easy assignment below:
  area = (struct sev_secret_area *)data;

You actually have to do some math:
  area = (struct sev_secret_area *)(data + data_len -
sizeof(QemuUUID) - sizeof(uint16_t) -
sizeof(*area));

or add the QemuUUID and uint16_t fields to sev_secret_area and:
  area = (struct sev_secret_area *)(data + data_len - sizeof(*area));

Or we make the decision that these GUID structs should never change, just 
add a new one to the table if more info is needed.


Whatever we decide should probably be documented in both the OVMF patches 
and the Qemu patches.


Thanks,
Tom


  void qmp_sev_inject_launch_secret(const char *packet_hdr,
-  const char *secret, uint64_t gpa,
+  const char *secret,
+  bool has_gpa, uint64_t gpa,
Error **errp)
  {
+if (!has_gpa) {
+uint8_t *data;
+struct sev_secret_area *area;
+
+if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, , NULL)) {
+error_setg(errp, "SEV: no secret area found in OVMF, gpa must be 
specified.");
+return;
+}
+area = (struct sev_secret_area *)data;
+gpa = area->base;
+}
+
  sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
  }





Re: [PATCH] kvm/i386: Set proper nested state format for SVM

2020-11-16 Thread Tom Lendacky
On 11/16/20 12:09 PM, Paolo Bonzini wrote:
> On 16/11/20 18:02, Tom Lendacky wrote:
>> From: Tom Lendacky
>>
>> Currently, the nested state format is hardcoded to VMX. This will result
>> in kvm_put_nested_state() returning an error because the KVM SVM support
>> checks for the nested state to be KVM_STATE_NESTED_FORMAT_SVM. As a
>> result, kvm_arch_put_registers() errors out early.
>>
>> Update the setting of the format based on the virtualization feature:
>>    VMX - KVM_STATE_NESTED_FORMAT_VMX
>>    SVM - KVM_STATE_NESTED_FORMAT_SVM
> 
> Looks good, but what are the symptoms of this in practice?

I discovered this while testing my SEV-ES patches. When I specified the
'+svm' feature, the new SEV-ES reset address for the APs wasn't getting
set because kvm_arch_put_registers() erred out before it could call
kvm_getput_regs(). This resulted in the guest crashing when OVMF tried to
start the APs.

For a non-SEV-ES guest, I'm not sure if other updates could be missed,
potentially.

Thanks,
Tom

> 
> Paolo
> 



[PATCH] kvm/i386: Set proper nested state format for SVM

2020-11-16 Thread Tom Lendacky
From: Tom Lendacky 

Currently, the nested state format is hardcoded to VMX. This will result
in kvm_put_nested_state() returning an error because the KVM SVM support
checks for the nested state to be KVM_STATE_NESTED_FORMAT_SVM. As a
result, kvm_arch_put_registers() errors out early.

Update the setting of the format based on the virtualization feature:
  VMX - KVM_STATE_NESTED_FORMAT_VMX
  SVM - KVM_STATE_NESTED_FORMAT_SVM

Also, fix the code formatting while at it.

Fixes: b16c0e20c7 ("KVM: add support for AMD nested live migration")
Cc: Eduardo Habkost 
Cc: Richard Henderson 
Cc: Paolo Bonzini 
Cc: Marcelo Tosatti 
Signed-off-by: Tom Lendacky 
---
 target/i386/kvm.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index cf46259534..a2934dda02 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -1820,12 +1820,14 @@ int kvm_arch_init_vcpu(CPUState *cs)
 
 env->nested_state = g_malloc0(max_nested_state_len);
 env->nested_state->size = max_nested_state_len;
-env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX;
 
 if (cpu_has_vmx(env)) {
-vmx_hdr = >nested_state->hdr.vmx;
-vmx_hdr->vmxon_pa = -1ull;
-vmx_hdr->vmcs12_pa = -1ull;
+env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX;
+vmx_hdr = >nested_state->hdr.vmx;
+vmx_hdr->vmxon_pa = -1ull;
+vmx_hdr->vmcs12_pa = -1ull;
+} else {
+env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM;
 }
 }
 }
-- 
2.28.0




[PATCH v4 0/6] Qemu SEV-ES guest support

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

---

These patches are based on commit:
d0ed6a69d3 ("Update version for v5.1.0 release")

(I tried basing on the latest Qemu commit, but I was having build issues
that level)

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v12

Changes since v3:
- Use the QemuUUID structure for GUID definitions
- Use SEV-ES policy bit definition from target/i386/sev_i386.h
- Update SMM support to a per-VM check in order to check SMM capability
  at the VM level since SEV-ES guests don't currently support SMM
- Make the CPU resettable check an arch-specific check

Changes since v2:
- Add in-kernel irqchip requirement for SEV-ES guests

Changes since v1:
- Fixed checkpatch.pl errors/warnings

Tom Lendacky (6):
  sev/i386: Add initial support for SEV-ES
  sev/i386: Require in-kernel irqchip support for SEV-ES guests
  sev/i386: Allow AP booting under SEV-ES
  sev/i386: Don't allow a system reset under an SEV-ES guest
  kvm/i386: Use a per-VM check for SMM capability
  sev/i386: Enable an SEV-ES guest based on SEV policy

 accel/kvm/kvm-all.c   |  69 
 accel/stubs/kvm-stub.c|   5 ++
 hw/i386/pc_sysfw.c|  10 +++-
 include/sysemu/cpus.h |   2 +
 include/sysemu/hw_accel.h |   5 ++
 include/sysemu/kvm.h  |  26 +
 include/sysemu/sev.h  |   3 ++
 softmmu/cpus.c|   5 ++
 softmmu/vl.c  |   5 +-
 target/arm/kvm.c  |   5 ++
 target/i386/cpu.c |   1 +
 target/i386/kvm.c |  10 +++-
 target/i386/sev-stub.c|   5 ++
 target/i386/sev.c | 109 +-
 target/i386/sev_i386.h|   1 +
 target/mips/kvm.c |   5 ++
 target/ppc/kvm.c  |   5 ++
 target/s390x/kvm.c|   5 ++
 18 files changed, 271 insertions(+), 5 deletions(-)

-- 
2.28.0




Re: [PATCH v4 0/6] Qemu SEV-ES guest support

2020-09-25 Thread Tom Lendacky
On 9/25/20 2:03 PM, Tom Lendacky wrote:
> From: Tom Lendacky 
> 
> This patch series provides support for launching an SEV-ES guest.
> 
> Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
> SEV support to protect the guest register state from the hypervisor. See
> "AMD64 Architecture Programmer's Manual Volume 2: System Programming",
> section "15.35 Encrypted State (SEV-ES)" [1].
> 
> In order to allow a hypervisor to perform functions on behalf of a guest,
> there is architectural 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. The notification is performed using a new exception, the VMM
> Communication exception (#VC). The information is shared through the
> Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
> The GHCB format and the protocol for using it is documented in "SEV-ES
> Guest-Hypervisor Communication Block Standardization" [2].
> 
> The main areas of the Qemu code that are updated to support SEV-ES are
> around the SEV guest launch process and AP booting in order to support
> booting multiple vCPUs.
> 
> There are no new command line switches required. Instead, the desire for
> SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
> object indicates that SEV-ES is required.
> 
> The SEV launch process is updated in two ways. The first is that a the
> KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
> standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
> measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
> each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
> invoked, no direct changes to the guest register state can be made.
> 
> AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
> is typically used to boot the APs. However, the hypervisor is not allowed
> to update the guest registers. For the APs, the reset vector must be known
> in advance. An OVMF method to provide a known reset vector address exists
> by providing an SEV information block, identified by UUID, near the end of
> the firmware [3]. OVMF will program the jump to the actual reset vector in
> this area of memory. Since the memory location is known in advance, an AP
> can be created with the known reset vector address as its starting CS:IP.
> The GHCB document [2] talks about how SMP booting under SEV-ES is
> performed. SEV-ES also requires the use of the in-kernel irqchip support
> in order to minimize the changes required to Qemu to support AP booting.
> 
> [1] https://www.amd.com/system/files/TechDocs/24593.pdf
> [2] https://developer.amd.com/wp-content/resources/56421.pdf
> [3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
> vector")
>  
> https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847
> 
> ---
> 
> These patches are based on commit:
> d0ed6a69d3 ("Update version for v5.1.0 release")
> 
> (I tried basing on the latest Qemu commit, but I was having build issues
> that level)

Sorry, forgot to update this part...

These patches are based on commit:
1bd5556f66 ("Merge remote-tracking branch 
'remotes/kraxel/tags/audio-20200923-pull-request' into staging")

Thanks,
Tom

> 
> A version of the tree can be found at:
> https://github.com/AMDESE/qemu/tree/sev-es-v12
> 
> Changes since v3:
> - Use the QemuUUID structure for GUID definitions
> - Use SEV-ES policy bit definition from target/i386/sev_i386.h
> - Update SMM support to a per-VM check in order to check SMM capability
>at the VM level since SEV-ES guests don't currently support SMM
> - Make the CPU resettable check an arch-specific check
> 
> Changes since v2:
> - Add in-kernel irqchip requirement for SEV-ES guests
> 
> Changes since v1:
> - Fixed checkpatch.pl errors/warnings
> 
> Tom Lendacky (6):
>sev/i386: Add initial support for SEV-ES
>sev/i386: Require in-kernel irqchip support for SEV-ES guests
>sev/i386: Allow AP booting under SEV-ES
>sev/i386: Don't allow a system reset under an SEV-ES guest
>kvm/i386: Use a per-VM check for SMM capability
>sev/i386: Enable an SEV-ES guest based on SEV policy
> 
>   accel/kvm/kvm-all.c   |  69 
>   accel/stubs/kvm-stub.c|   5 ++
>   hw/i386/pc_sysfw.c|  10 +++-
>   include/sysemu/cpus.h |   2 +
>   include/sysemu/hw_accel.h |   5 ++
>   include/sysemu/kvm.h  |  26 +
>   include/sysemu/sev.h  |   3 ++
>   so

[PATCH v4 6/6] sev/i386: Enable an SEV-ES guest based on SEV policy

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Reviewed-by: Dr. David Alan Gilbert 
Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 9c081173db..d3342f5cb2 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -377,7 +377,7 @@ sev_enabled(void)
 bool
 sev_es_enabled(void)
 {
-return false;
+return sev_enabled() && (sev_guest->policy & SEV_POLICY_ES);
 }
 
 uint64_t
-- 
2.28.0




[PATCH v4 2/6] sev/i386: Require in-kernel irqchip support for SEV-ES guests

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

In prep for AP booting, require the use of in-kernel irqchip support. This
lessens the Qemu support burden required to boot APs.

Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index af6b88691f..0d4bd3cd75 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -774,6 +774,12 @@ sev_guest_init(const char *id)
 sev->api_minor = status.api_minor;
 
 if (sev_es_enabled()) {
+if (!kvm_kernel_irqchip_allowed()) {
+error_report("%s: SEV-ES guests require in-kernel irqchip support",
+ __func__);
+goto err;
+}
+
 if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
 error_report("%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
-- 
2.28.0




[PATCH v4 5/6] kvm/i386: Use a per-VM check for SMM capability

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

SMM is not currently supported for an SEV-ES guest by KVM. Change the SMM
capability check from a KVM-wide check to a per-VM check in order to have
a finer-grained SMM capability check.

Suggested-by: Sean Christopherson 
Signed-off-by: Tom Lendacky 
---
 target/i386/kvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index eefd1a11b6..917cdf8055 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -134,7 +134,7 @@ int kvm_has_pit_state2(void)
 
 bool kvm_has_smm(void)
 {
-return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
+return kvm_vm_check_extension(kvm_state, KVM_CAP_X86_SMM);
 }
 
 bool kvm_has_adjust_clock_stable(void)
-- 
2.28.0




[PATCH v4 1/6] sev/i386: Add initial support for SEV-ES

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c  |  1 +
 target/i386/sev-stub.c |  5 +
 target/i386/sev.c  | 44 --
 target/i386/sev_i386.h |  1 +
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 3ffd877dd5..ca0e17ed07 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5940,6 +5940,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 break;
 case 0x801F:
 *eax = sev_enabled() ? 0x2 : 0;
+*eax |= sev_es_enabled() ? 0x8 : 0;
 *ebx = sev_get_cbit_position();
 *ebx |= sev_get_reduced_phys_bits() << 6;
 *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 88e3f39a1e..040ac90563 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,3 +49,8 @@ SevCapability *sev_get_capabilities(Error **errp)
 error_setg(errp, "SEV is not available in this QEMU");
 return NULL;
 }
+
+bool sev_es_enabled(void)
+{
+return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 93c4d60b82..af6b88691f 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -358,6 +358,12 @@ sev_enabled(void)
 return !!sev_guest;
 }
 
+bool
+sev_es_enabled(void)
+{
+return false;
+}
+
 uint64_t
 sev_get_me_mask(void)
 {
@@ -578,6 +584,20 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
 return ret;
 }
 
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+int ret, fw_error;
+
+ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, _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));
+}
+
+return ret;
+}
+
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
@@ -590,6 +610,14 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 return;
 }
 
+if (sev_es_enabled()) {
+/* measure all the VM save areas before getting launch_measure */
+ret = sev_launch_update_vmsa(sev);
+if (ret) {
+exit(1);
+}
+}
+
 measurement = g_new0(struct kvm_sev_launch_measure, 1);
 
 /* query the measurement blob length */
@@ -684,7 +712,7 @@ sev_guest_init(const char *id)
 {
 SevGuestState *sev;
 char *devname;
-int ret, fw_error;
+int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
@@ -745,8 +773,20 @@ sev_guest_init(const char *id)
 sev->api_major = status.api_major;
 sev->api_minor = status.api_minor;
 
+if (sev_es_enabled()) {
+if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+goto err;
+}
+cmd = KVM_SEV_ES_INIT;
+} else {
+cmd = KVM_SEV_INIT;
+}
+
 trace_kvm_sev_init();
-ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, _error);
+ret = sev_ioctl(sev->sev_fd, cmd, NULL, _error);
 if (ret) {
 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
  __func__, ret, fw_error, fw_error_to_str(fw_error));
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..4f9a5e9b21 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -29,6 +29,7 @@
 #define SEV_POLICY_SEV  0x20
 
 extern bool sev_enabled(void);
+extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
-- 
2.28.0




[PATCH v4 3/6] sev/i386: Allow AP booting under SEV-ES

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c| 64 ++
 accel/stubs/kvm-stub.c |  5 
 hw/i386/pc_sysfw.c | 10 ++-
 include/sysemu/kvm.h   | 16 +++
 include/sysemu/sev.h   |  3 ++
 target/i386/kvm.c  |  2 ++
 target/i386/sev.c  | 59 ++
 7 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index ad8b315b35..08b66642dd 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
 #include "qemu/main-loop.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sev.h"
 #include "qapi/visitor.h"
 #include "qapi/qapi-types-common.h"
@@ -120,6 +121,12 @@ struct KVMState
 /* memory encryption */
 void *memcrypt_handle;
 int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
+  uint64_t flash_size, uint32_t *addr);
+
+uint32_t reset_cs;
+uint32_t reset_ip;
+bool reset_data_valid;
 
 /* For "info mtree -f" to tell if an MR is registered in KVM */
 int nr_as;
@@ -239,6 +246,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
 return 1;
 }
 
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)
+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_data_valid) {
+return;
+}
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0) {
+return;
+}
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size,
+);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_data_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
@@ -2193,6 +2256,7 @@ static int kvm_init(MachineState *ms)
 }
 
 kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
 }
 
 ret = kvm_arch_init(ms, s);
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 82f118d2df..3aece9b513 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -114,6 +114,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
   return 1;
 }
 
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+return -ENOSYS;
+}
+
 #ifndef CONFIG_USER_ONLY
 int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index b6c0822fe3..321ff94261 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -156,7 +156,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 PFlashCFI01 *system_flash;
 MemoryRegion *flash_mem;
 void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
 
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
@@ -204,6 +205,13 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (kvm_memcrypt_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
+
+ret = kvm_memcrypt_save_reset_vector(flash_ptr, flash_size);
+if (ret) {
+ 

[PATCH v4 4/6] sev/i386: Don't allow a system reset under an SEV-ES guest

2020-09-25 Thread Tom Lendacky
From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When an SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES. Prevent that from occuring by introducing an arch-specific
callback that returns a boolean indicating whether vCPUs are resettable.

Cc: Peter Maydell 
Cc: Aurelien Jarno 
Cc: Jiaxun Yang 
Cc: Aleksandar Rikalo 
Cc: David Gibson 
Cc: David Hildenbrand 
Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c   |  5 +
 include/sysemu/cpus.h |  2 ++
 include/sysemu/hw_accel.h |  5 +
 include/sysemu/kvm.h  | 10 ++
 softmmu/cpus.c|  5 +
 softmmu/vl.c  |  5 -
 target/arm/kvm.c  |  5 +
 target/i386/kvm.c |  6 ++
 target/mips/kvm.c |  5 +
 target/ppc/kvm.c  |  5 +
 target/s390x/kvm.c|  5 +
 11 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 08b66642dd..a161fff813 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2388,6 +2388,11 @@ void kvm_flush_coalesced_mmio_buffer(void)
 s->coalesced_flush_in_progress = false;
 }
 
+bool kvm_cpu_check_are_resettable(void)
+{
+return kvm_arch_cpu_check_are_resettable();
+}
+
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
 if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index 3c1da6a018..d3e6cdf126 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -24,6 +24,8 @@ void dump_drift_info(void);
 void qemu_cpu_kick_self(void);
 void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
 
+bool cpus_are_resettable(void);
+
 void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index e128f8b06b..6d387226d4 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -17,6 +17,11 @@
 #include "sysemu/hvf.h"
 #include "sysemu/whpx.h"
 
+static inline bool cpu_check_are_resettable(void)
+{
+return kvm_enabled() ? kvm_cpu_check_are_resettable() : true;
+}
+
 static inline void cpu_synchronize_state(CPUState *cpu)
 {
 if (kvm_enabled()) {
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index b7ff481d61..51a12c83ed 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -581,4 +581,14 @@ int kvm_get_max_memslots(void);
 /* Notify resamplefd for EOI of specific interrupts. */
 void kvm_resample_fd_notify(int gsi);
 
+/**
+ * kvm_cpu_check_are_resettable - return whether CPUs can be reset
+ *
+ * Returns: true: CPUs are resettable
+ *  false: CPUs are not resettable
+ */
+bool kvm_cpu_check_are_resettable(void);
+
+bool kvm_arch_cpu_check_are_resettable(void);
+
 #endif
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index e3b98065c9..ee9c46527c 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -927,6 +927,11 @@ void hw_error(const char *fmt, ...)
 abort();
 }
 
+bool cpus_are_resettable(void)
+{
+return cpu_check_are_resettable();
+}
+
 void cpu_synchronize_all_states(void)
 {
 CPUState *cpu;
diff --git a/softmmu/vl.c b/softmmu/vl.c
index f7b103467c..1f54c6b416 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1475,7 +1475,10 @@ void qemu_system_guest_crashloaded(GuestPanicInformation 
*info)
 
 void qemu_system_reset_request(ShutdownCause reason)
 {
-if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+if (!cpus_are_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
+} else if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
 shutdown_requested = reason;
 } else {
 reset_requested = reason;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 0dcb9bfe13..f9584a1425 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1029,3 +1029,8 @@ int kvm_arch_msi_data_to_gsi(uint32_t data)
 {
 return (data - 32) & 0x;
 }
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+return true;
+}
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 7c2a3a123b..eefd1a11b6 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -26,6 +26,7 @@
 #include "sysemu/kvm_int.h"
 #include "sysemu/runstate.h"
 #include "kvm_i386.h"
+#include "sev_i386.h"
 #include "hyperv.h"
 #include "hyperv-proto.h"
 
@@ -4738,3 +4739,8 @@ bool kvm_has_waitpkg(void)
 {
 return has_msr_umwait;
 }
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+return !sev_es_enabled();
+}
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index 72637a1e02..ad612e74c1 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -1296,3 +1296,8 @@ int mips_kvm_type(MachineState

Re: [PATCH v3] SEV: QMP support for Inject-Launch-Secret

2020-09-21 Thread Tom Lendacky
On 9/21/20 3:33 PM, Tobin Feldman-Fitzthum wrote:
> On 2020-09-21 15:16, Dr. David Alan Gilbert wrote:
>> * Tobin Feldman-Fitzthum (to...@linux.vnet.ibm.com) wrote:
>>> AMD SEV allows a guest owner to inject a secret blob
>>> into the memory of a virtual machine. The secret is
>>> encrypted with the SEV Transport Encryption Key and
>>> integrity is guaranteed with the Transport Integrity
>>> Key. Although QEMU faciliates the injection of the
>>> launch secret, it cannot access the secret.
>>>
>>> Signed-off-by: Tobin Feldman-Fitzthum 
>>
>> Hi Tobin,
>>   Did the ovmf stuff for agreeing the GUID for automating this ever
>> happen?
>>
> OVMF patches have not been upstreamed yet. I think we are planning
> to do that relatively soon.

The SEV-ES code was recently accepted and uses a GUID for locating SEV
related information. You can probably build upon that GUID or stack
another GUID above that. The GUID block has a size indicator that can help
determine what information is available or for tracking stacked GUIDs.

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

Thanks,
Tom

> 
> -Tobin
>> Dave
>>
>>> ---
>>>  include/monitor/monitor.h |  3 ++
>>>  include/sysemu/sev.h  |  2 ++
>>>  monitor/misc.c    |  8 ++---
>>>  qapi/misc-target.json | 18 +++
>>>  target/i386/monitor.c |  9 ++
>>>  target/i386/sev-stub.c    |  5 +++
>>>  target/i386/sev.c | 66 +++
>>>  target/i386/trace-events  |  1 +
>>>  8 files changed, 108 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
>>> index 1018d754a6..bf049c5b00 100644
>>> --- a/include/monitor/monitor.h
>>> +++ b/include/monitor/monitor.h
>>> @@ -4,6 +4,7 @@
>>>  #include "block/block.h"
>>>  #include "qapi/qapi-types-misc.h"
>>>  #include "qemu/readline.h"
>>> +#include "include/exec/hwaddr.h"
>>>
>>>  extern __thread Monitor *cur_mon;
>>>  typedef struct MonitorHMP MonitorHMP;
>>> @@ -36,6 +37,8 @@ void monitor_flush(Monitor *mon);
>>>  int monitor_set_cpu(int cpu_index);
>>>  int monitor_get_cpu_index(void);
>>>
>>> +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error
>>> **errp);
>>> +
>>>  void monitor_read_command(MonitorHMP *mon, int show_prompt);
>>>  int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func,
>>>    void *opaque);
>>> diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
>>> index 98c1ec8d38..b279b293e8 100644
>>> --- a/include/sysemu/sev.h
>>> +++ b/include/sysemu/sev.h
>>> @@ -18,4 +18,6 @@
>>>
>>>  void *sev_guest_init(const char *id);
>>>  int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
>>> +int sev_inject_launch_secret(const char *hdr, const char *secret,
>>> + uint64_t gpa);
>>>  #endif
>>> diff --git a/monitor/misc.c b/monitor/misc.c
>>> index 89bb970b00..b9ec8ba410 100644
>>> --- a/monitor/misc.c
>>> +++ b/monitor/misc.c
>>> @@ -674,10 +674,10 @@ static void hmp_physical_memory_dump(Monitor
>>> *mon, const QDict *qdict)
>>>  memory_dump(mon, count, format, size, addr, 1);
>>>  }
>>>
>>> -static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
>>> +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error
>>> **errp)
>>>  {
>>>  MemoryRegionSection mrs = memory_region_find(get_system_memory(),
>>> - addr, 1);
>>> + addr, size);
>>>
>>>  if (!mrs.mr) {
>>>  error_setg(errp, "No memory is mapped at address 0x%"
>>> HWADDR_PRIx, addr);
>>> @@ -701,7 +701,7 @@ static void hmp_gpa2hva(Monitor *mon, const QDict
>>> *qdict)
>>>  MemoryRegion *mr = NULL;
>>>  void *ptr;
>>>
>>> -    ptr = gpa2hva(, addr, _err);
>>> +    ptr = gpa2hva(, addr, 1, _err);
>>>  if (local_err) {
>>>  error_report_err(local_err);
>>>  return;
>>> @@ -777,7 +777,7 @@ static void hmp_gpa2hpa(Monitor *mon, const QDict
>>> *qdict)
>>>  void *ptr;
>>>  uint64_t physaddr;
>>>
>>> -    ptr = gpa2hva(, addr, _err);
>>> +    ptr = gpa2hva(, addr, 1, _err);
>>>  if (local_err) {
>>>  error_report_err(local_err);
>>>  return;
>>> diff --git a/qapi/misc-target.json b/qapi/misc-target.json
>>> index dee3b45930..d145f916b3 100644
>>> --- a/qapi/misc-target.json
>>> +++ b/qapi/misc-target.json
>>> @@ -200,6 +200,24 @@
>>>  { 'command': 'query-sev-capabilities', 'returns': 'SevCapability',
>>>    'if': 'defined(TARGET_I386)' }
>>>
>>> +##
>>> +# @sev-inject-launch-secret:
>>> +#
>>> +# This command injects a secret blob into memory of SEV guest.
>>> +#
>>> +# @packet-header: the launch secret packet header encoded in base64
>>> +#
>>> +# @secret: the launch secret data to be injected encoded in base64
>>> +#
>>> +# @gpa: the guest physical address where secret will be injected.
>>> +#
>>> +# Since: 5.1
>>> +#
>>> +##
>>> +{ 'command': 

Re: [PATCH v3 0/5] Qemu SEV-ES guest support

2020-09-21 Thread Tom Lendacky
On 9/21/20 6:48 AM, Dr. David Alan Gilbert wrote:
> * Tom Lendacky (thomas.lenda...@amd.com) wrote:
>> On 9/18/20 5:00 AM, Dr. David Alan Gilbert wrote:
>>> * Tom Lendacky (thomas.lenda...@amd.com) wrote:
>>>> On 9/17/20 12:28 PM, Dr. David Alan Gilbert wrote:
>>>>> * Tom Lendacky (thomas.lenda...@amd.com) wrote:
>>>>>> From: Tom Lendacky 
>>>>>>
>>>>>> This patch series provides support for launching an SEV-ES guest.
>>>>>>
>>>>>> Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
>>>>>> SEV support to protect the guest register state from the hypervisor. See
>>>>>> "AMD64 Architecture Programmer's Manual Volume 2: System Programming",
>>>>>> section "15.35 Encrypted State (SEV-ES)" [1].
>>>>>>
>>>>>> In order to allow a hypervisor to perform functions on behalf of a guest,
>>>>>> there is architectural 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. The notification is performed using a new exception, the VMM
>>>>>> Communication exception (#VC). The information is shared through the
>>>>>> Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT 
>>>>>> instruction.
>>>>>> The GHCB format and the protocol for using it is documented in "SEV-ES
>>>>>> Guest-Hypervisor Communication Block Standardization" [2].
>>>>>>
>>>>>> The main areas of the Qemu code that are updated to support SEV-ES are
>>>>>> around the SEV guest launch process and AP booting in order to support
>>>>>> booting multiple vCPUs.
>>>>>>
>>>>>> There are no new command line switches required. Instead, the desire for
>>>>>> SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
>>>>>> object indicates that SEV-ES is required.
>>>>>>
>>>>>> The SEV launch process is updated in two ways. The first is that a the
>>>>>> KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
>>>>>> standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
>>>>>> measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
>>>>>> each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
>>>>>> invoked, no direct changes to the guest register state can be made.
>>>>>>
>>>>>> AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
>>>>>> is typically used to boot the APs. However, the hypervisor is not allowed
>>>>>> to update the guest registers. For the APs, the reset vector must be 
>>>>>> known
>>>>>> in advance. An OVMF method to provide a known reset vector address exists
>>>>>> by providing an SEV information block, identified by UUID, near the end 
>>>>>> of
>>>>>> the firmware [3]. OVMF will program the jump to the actual reset vector 
>>>>>> in
>>>>>> this area of memory. Since the memory location is known in advance, an AP
>>>>>> can be created with the known reset vector address as its starting CS:IP.
>>>>>> The GHCB document [2] talks about how SMP booting under SEV-ES is
>>>>>> performed. SEV-ES also requires the use of the in-kernel irqchip support
>>>>>> in order to minimize the changes required to Qemu to support AP booting.
>>>>>
>>>>> Some random thoughts:
>>>>> a) Is there something that explicitly disallows SMM?
>>>>
>>>> There isn't currently. Is there a way to know early on that SMM is enabled?
>>>> Could I just call x86_machine_is_smm_enabled() to check that?
>>>>
>>>>> b) I think all the interfaces you're using are already defined in
>>>>> Linux header files - even if the code to implement them isn't actually
>>>>> upstream in the kernel yet (the launch_update in particular) - we
>>>>> normally wait for the kernel interface to be accepted before taking the
>>>>> QEMU patches,

Re: [PATCH v3 1/5] sev/i386: Add initial support for SEV-ES

2020-09-21 Thread Tom Lendacky
On 9/21/20 1:45 AM, Dov Murik wrote:
> On 16/09/2020 0:29, Tom Lendacky wrote:
>> From: Tom Lendacky 
>>
>> Provide initial support for SEV-ES. This includes creating a function to
>> indicate the guest is an SEV-ES guest (which will return false until all
>> support is in place), performing the proper SEV initialization and
>> ensuring that the guest CPU state is measured as part of the launch.
>>
>> Co-developed-by: Jiri Slaby 
>> Signed-off-by: Jiri Slaby 
>> Signed-off-by: Tom Lendacky 
>> ---
>>   target/i386/cpu.c  |  1 +
>>   target/i386/sev-stub.c |  5 +
>>   target/i386/sev.c  | 46 --
>>   target/i386/sev_i386.h |  1 +
>>   4 files changed, 51 insertions(+), 2 deletions(-)
>>
>> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
>> index 588f32e136..bbbe581d35 100644
>> --- a/target/i386/cpu.c
>> +++ b/target/i386/cpu.c
>> @@ -5969,6 +5969,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t
>> index, uint32_t count,
>>   break;
>>   case 0x801F:
>>   *eax = sev_enabled() ? 0x2 : 0;
>> +    *eax |= sev_es_enabled() ? 0x8 : 0;
>>   *ebx = sev_get_cbit_position();
>>   *ebx |= sev_get_reduced_phys_bits() << 6;
>>   *ecx = 0;
>> diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
>> index 88e3f39a1e..040ac90563 100644
>> --- a/target/i386/sev-stub.c
>> +++ b/target/i386/sev-stub.c
>> @@ -49,3 +49,8 @@ SevCapability *sev_get_capabilities(Error **errp)
>>   error_setg(errp, "SEV is not available in this QEMU");
>>   return NULL;
>>   }
>> +
>> +bool sev_es_enabled(void)
>> +{
>> +    return false;
>> +}
>> diff --git a/target/i386/sev.c b/target/i386/sev.c
>> index c3ecf86704..6c9cd0854b 100644
>> --- a/target/i386/sev.c
>> +++ b/target/i386/sev.c
>> @@ -359,6 +359,12 @@ sev_enabled(void)
>>   return !!sev_guest;
>>   }
>>
>> +bool
>> +sev_es_enabled(void)
>> +{
>> +    return false;
>> +}
>> +
>>   uint64_t
>>   sev_get_me_mask(void)
>>   {
>> @@ -578,6 +584,22 @@ sev_launch_update_data(SevGuestState *sev, uint8_t
>> *addr, uint64_t len)
>>   return ret;
>>   }
>>
>> +static int
>> +sev_launch_update_vmsa(SevGuestState *sev)
>> +{
>> +    int ret, fw_error;
>> +
>> +    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL,
>> _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));
>> +    goto err;
> 
> goto (and the err: label) is not needed.

Yup, will remove both.

> 
>> +    }
>> +
>> +err:
>> +    return ret;
>> +}
>> +
>>   static void
>>   sev_launch_get_measure(Notifier *notifier, void *unused)
>>   {
>> @@ -590,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void
>> *unused)
>>   return;
>>   }
>>
>> +    if (sev_es_enabled()) {
>> +    /* measure all the VM save areas before getting launch_measure */
>> +    ret = sev_launch_update_vmsa(sev);
>> +    if (ret) {
>> +    exit(1);
> 
> Other error cases in this function just return on error. Why quit QEMU here?

This is inside an void return function so an error can't be returned. It
matches what happens if sev_launch_finish() fails. To that end, a
LAUNCH_MEASURE error should probably exit(), also.

Thanks,
Tom

> 
>> +    }
>> +    }
>> +
>>   measurement = g_new0(struct kvm_sev_launch_measure, 1);
>>
>>   /* query the measurement blob length */
>> @@ -684,7 +714,7 @@ sev_guest_init(const char *id)
>>   {
>>   SevGuestState *sev;
>>   char *devname;
>> -    int ret, fw_error;
>> +    int ret, fw_error, cmd;
>>   uint32_t ebx;
>>   uint32_t host_cbitpos;
>>   struct sev_user_data_status status = {};
>> @@ -745,8 +775,20 @@ sev_guest_init(const char *id)
>>   sev->api_major = status.api_major;
>>   sev->api_minor = status.api_minor;
>>
>> +    if (sev_es_enabled()) {
>> +    if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
>> +    error_report("%s: guest policy requires SEV-ES, but "
>> + "host SEV-ES support unavailable",
>> + __func__);
>> +    go

Re: [PATCH v3 0/5] Qemu SEV-ES guest support

2020-09-18 Thread Tom Lendacky

On 9/18/20 5:00 AM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

On 9/17/20 12:28 PM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.


Some random thoughts:
a) Is there something that explicitly disallows SMM?


There isn't currently. Is there a way to know early on that SMM is enabled?
Could I just call x86_machine_is_smm_enabled() to check that?


b) I think all the interfaces you're using are already defined in
Linux header files - even if the code to implement them isn't actually
upstream in the kernel yet (the launch_update in particular) - we
normally wait for the kernel interface to be accepted before taking the
QEMU patches, but if the constants are in the headers already I'm not
sure what the rule is.


Correct, everything was already present from a Linux header perspective.


c) What happens if QEMU reads the register values from the state if
the guest is paused - does it just see junk?  I'm just wondering if you
need to add checks in places it might try to.


I thought about what to do about calls to read the registers once the guest
state has become encrypted. I think it would take a lot of changes to make
Qemu "protected state aware" for what I see as little gain. Qemu is likely
to see a lot of zeroes or actual register values from the GHCB protocol for
previous VMGEXITs that took place.


Yep, that's fair enough - I was curious if we'll hit anything
accidentally still reading it.

How does SEV-ES interact with the 'NODBG' flag of the guest policy - if
that's 0, and 'debugging of the guest' is allowed, what can you actually
do?


The SEV-ES KVM patches will disallow debugging of the guest, or at least 
setting breakpoints using the debug registers. Gdb can still break in, but 
you wont get anything reasonable with register dumps and memory dumps.


The NODBG policy bit enables or disables the DBG_DECRYPT and DBG_ENCRYPT 
APIs. So if the guest has allowed debugging, memory dumps could be done 
using those APIs (for encrypted pages). Registers are a different story 
because you simply can't update from the hypervisor side under SEV-ES.


Under SEV you could do actual debugging if the support was developed and 
in place.


Thanks,
Tom



Dave


Thanks,
Tom



Dave


[1] 
https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.amd

Re: [PATCH v3 0/5] Qemu SEV-ES guest support

2020-09-18 Thread Tom Lendacky

On 9/17/20 10:40 PM, Sean Christopherson wrote:

On Thu, Sep 17, 2020 at 01:56:21PM -0500, Tom Lendacky wrote:

On 9/17/20 12:28 PM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.


Some random thoughts:
a) Is there something that explicitly disallows SMM?


There isn't currently. Is there a way to know early on that SMM is enabled?
Could I just call x86_machine_is_smm_enabled() to check that?


KVM_CAP_X86_SMM is currently checked as a KVM-wide capability.  One option
is to change that to use a per-VM ioctl() and then have KVM return 0 for
SEV-ES VMs.

diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 416c82048a..4d7f84ed1b 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -145,7 +145,7 @@ int kvm_has_pit_state2(void)

  bool kvm_has_smm(void)
  {
-return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
+return kvm_vm_check_extension(kvm_state, KVM_CAP_X86_SMM);
  }


This will work. I'll have to modify the has_emulated_msr() op in the 
kernel as part of the the SEV-ES support to take a struct kvm argument. 
I'll be sure to include a comment that the struct kvm argument could be 
NULL, since that op is also used during KVM module initialization and is 
called before VM initialization (and therefore a struct kvm instance), too.


Thanks,
Tom



  bool kvm_has_adjust_clock_stable(void)


b) I think all the interfaces you're using are already defined in
Linux header files - even if the code to implement them isn't actually
upstream in the kernel yet (the launch_update in particular) - we
normally wait for the kernel interface to be accepted before taking the
QEMU patches, but if the constants are in the headers already I'm not
sure what the rule is.


Correct, everything was already present from a Linux header perspective.


c) What happens if QEMU reads the register values from the state if
the guest is paused - does it just see junk?  I'm just wondering if you
need to add checks in places it might try to.


I thought about what to do about calls to read the registers once the guest
state has become encrypted. I think it would take a lot of changes to make
Qemu "protected state aware" for what I see as little gain. Qemu is likely
to see a lot of zeroes or actual register values from the GHCB protocol for
previous VMGEXITs that took place.


Yeah, we more or less ca

Re: [PATCH v3 0/5] Qemu SEV-ES guest support

2020-09-17 Thread Tom Lendacky

On 9/17/20 12:28 PM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.


Some random thoughts:
   a) Is there something that explicitly disallows SMM?


There isn't currently. Is there a way to know early on that SMM is 
enabled? Could I just call x86_machine_is_smm_enabled() to check that?



   b) I think all the interfaces you're using are already defined in
Linux header files - even if the code to implement them isn't actually
upstream in the kernel yet (the launch_update in particular) - we
normally wait for the kernel interface to be accepted before taking the
QEMU patches, but if the constants are in the headers already I'm not
sure what the rule is.


Correct, everything was already present from a Linux header perspective.


   c) What happens if QEMU reads the register values from the state if
the guest is paused - does it just see junk?  I'm just wondering if you
need to add checks in places it might try to.


I thought about what to do about calls to read the registers once the 
guest state has become encrypted. I think it would take a lot of changes 
to make Qemu "protected state aware" for what I see as little gain. Qemu 
is likely to see a lot of zeroes or actual register values from the GHCB 
protocol for previous VMGEXITs that took place.


Thanks,
Tom



Dave


[1] 
https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.amd.com%2Fsystem%2Ffiles%2FTechDocs%2F24593.pdfdata=02%7C01%7Cthomas.lendacky%40amd.com%7Cb07b788e09054a91143308d85b2f1a89%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637359606292398926sdata=B2naGIEXuhD7a%2Fi4NDsRzeHwvDvNJ%2FP7nf5HmAzk9CU%3Dreserved=0
[2] 
https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdeveloper.amd.com%2Fwp-content%2Fresources%2F56421.pdfdata=02%7C01%7Cthomas.lendacky%40amd.com%7Cb07b788e09054a91143308d85b2f1a89%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637359606292398926sdata=0HrHZxdTEK%2FWM1KxxasMAghpzTNGvuKKSlg6nBgPjJY%3Dreserved=0
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")
 
https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Ftianocore%2Fedk2%2Fcommit%2F30937f2f98c42496f2f143fe8374ae7f7e684847data=02%7C01%7Cthomas.lendacky%40amd.com%7Cb07b788e09054a91143308d85b2f1a89%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63735960629

Re: [PATCH v3 4/5] sev/i386: Don't allow a system reset under an SEV-ES guest

2020-09-17 Thread Tom Lendacky

On 9/17/20 12:01 PM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When a SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES, so prevent that from occurring.

Signed-off-by: Tom Lendacky 
---
  accel/kvm/kvm-all.c   | 9 +
  include/sysemu/cpus.h | 2 ++
  include/sysemu/hw_accel.h | 5 +
  include/sysemu/kvm.h  | 2 ++
  softmmu/cpus.c| 5 +
  softmmu/vl.c  | 5 -
  6 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 20725b0368..63153b6e53 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2388,6 +2388,15 @@ void kvm_flush_coalesced_mmio_buffer(void)
  s->coalesced_flush_in_progress = false;
  }
  
+bool kvm_cpu_check_resettable(void)

+{
+/*
+ * If we have a valid reset vector override, then SEV-ES is active
+ * and the CPU can't be reset.
+ */
+return !kvm_state->reset_valid;


This seems a bit weird since it's in generic rather than x86 specific
code.


I could push it down to arch specific code. Is there a way to do that 
without defining the function for all the other arches?


Thanks,
Tom



Dave


+}
+
  static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
  {
  if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index 3c1da6a018..6d688c757f 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -24,6 +24,8 @@ void dump_drift_info(void);
  void qemu_cpu_kick_self(void);
  void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
  
+bool cpu_is_resettable(void);

+
  void cpu_synchronize_all_states(void);
  void cpu_synchronize_all_post_reset(void);
  void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index e128f8b06b..8b4536e7ae 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -17,6 +17,11 @@
  #include "sysemu/hvf.h"
  #include "sysemu/whpx.h"
  
+static inline bool cpu_check_resettable(void)

+{
+return kvm_enabled() ? kvm_cpu_check_resettable() : true;
+}
+
  static inline void cpu_synchronize_state(CPUState *cpu)
  {
  if (kvm_enabled()) {
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index f74cfa85ab..eb94bbbff9 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -494,6 +494,8 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void 
*ram_addr,
  
  #endif /* NEED_CPU_H */
  
+bool kvm_cpu_check_resettable(void);

+
  void kvm_cpu_synchronize_state(CPUState *cpu);
  void kvm_cpu_synchronize_post_reset(CPUState *cpu);
  void kvm_cpu_synchronize_post_init(CPUState *cpu);
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index a802e899ab..32f286643f 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -927,6 +927,11 @@ void hw_error(const char *fmt, ...)
  abort();
  }
  
+bool cpu_is_resettable(void)

+{
+return cpu_check_resettable();
+}
+
  void cpu_synchronize_all_states(void)
  {
  CPUState *cpu;
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 4eb9d1f7fd..422fbb1650 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1475,7 +1475,10 @@ void qemu_system_guest_crashloaded(GuestPanicInformation 
*info)
  
  void qemu_system_reset_request(ShutdownCause reason)

  {
-if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+if (!cpu_is_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
+} else if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
  shutdown_requested = reason;
  } else {
  reset_requested = reason;
--
2.28.0





Re: [PATCH v3 3/5] sev/i386: Allow AP booting under SEV-ES

2020-09-17 Thread Tom Lendacky

On 9/17/20 11:46 AM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured.

Signed-off-by: Tom Lendacky 
---
  accel/kvm/kvm-all.c| 64 ++
  accel/stubs/kvm-stub.c |  5 
  hw/i386/pc_sysfw.c | 10 ++-
  include/sysemu/kvm.h   | 16 +++
  include/sysemu/sev.h   |  3 ++
  target/i386/kvm.c  |  2 ++
  target/i386/sev.c  | 51 +
  7 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 63ef6af9a1..20725b0368 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
  #include "qemu/main-loop.h"
  #include "trace.h"
  #include "hw/irq.h"
+#include "sysemu/kvm.h"
  #include "sysemu/sev.h"
  #include "qapi/visitor.h"
  #include "qapi/qapi-types-common.h"
@@ -120,6 +121,12 @@ struct KVMState
  /* memory encryption */
  void *memcrypt_handle;
  int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
+  uint64_t flash_size, uint32_t *addr);
+
+unsigned int reset_cs;
+unsigned int reset_ip;


uint32_t's ?


I can change those.




+bool reset_valid;
  
  /* For "info mtree -f" to tell if an MR is registered in KVM */

  int nr_as;
@@ -239,6 +246,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
  return 1;
  }
  
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)

+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_valid) {
+return;
+}
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0) {
+return;
+}
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size,
+);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
  /* Called with KVMMemoryListener.slots_lock held */
  static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
  {
@@ -2193,6 +2256,7 @@ static int kvm_init(MachineState *ms)
  }
  
  kvm_state->memcrypt_encrypt_data = sev_encrypt_data;

+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
  }
  
  ret = kvm_arch_init(ms, s);

diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 82f118d2df..3aece9b513 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -114,6 +114,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
return 1;
  }
  
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)

+{
+return -ENOSYS;
+}
+
  #ifndef CONFIG_USER_ONLY
  int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
  {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index b6c0822fe3..321ff94261 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -156,7 +156,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
  PFlashCFI01 *system_flash;
  MemoryRegion *flash_mem;
  void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
  
  assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
  
@@ -204,6 +205,13 @@ static void pc_system_flash_map(PCMachineState *pcms,

  if (kvm_memcrypt_enabled()) {
  flash_ptr = memory_region_get_ram_ptr(flash_mem)

Re: [PATCH v3 5/5] sev/i386: Enable an SEV-ES guest based on SEV policy

2020-09-17 Thread Tom Lendacky

On 9/17/20 10:34 AM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Signed-off-by: Tom Lendacky 
---
  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 6ddefc65fa..bcaadaa2f9 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -70,6 +70,8 @@ struct SevGuestState {
  #define DEFAULT_GUEST_POLICY0x1 /* disable debug */
  #define DEFAULT_SEV_DEVICE  "/dev/sev"
  
+#define GUEST_POLICY_SEV_ES_BIT (1 << 2)

+


I'm surprised that all the policy bits aren't defined in a header somewhere.


I have another version to be issued with changes to use QemuUUID, so I can 
look at moving the bits to a header.


Thanks,
Tom



But other than that,


Reviewed-by: Dr. David Alan Gilbert 


  /* SEV Information Block GUID = 00f771de-1a7e-4fcb-890e-68c77e2fb44e */
  #define SEV_INFO_BLOCK_GUID \
  "\xde\x71\xf7\x00\x7e\x1a\xcb\x4f\x89\x0e\x68\xc7\x7e\x2f\xb4\x4e"
@@ -375,7 +377,7 @@ sev_enabled(void)
  bool
  sev_es_enabled(void)
  {
-return false;
+return sev_enabled() && (sev_guest->policy & GUEST_POLICY_SEV_ES_BIT);
  }
  
  uint64_t

--
2.28.0





Re: [PATCH v3 5/5] sev/i386: Enable an SEV-ES guest based on SEV policy

2020-09-17 Thread Tom Lendacky

On 9/17/20 11:07 AM, Tom Lendacky wrote:

On 9/17/20 10:34 AM, Dr. David Alan Gilbert wrote:

* Tom Lendacky (thomas.lenda...@amd.com) wrote:

From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Signed-off-by: Tom Lendacky 
---
  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 6ddefc65fa..bcaadaa2f9 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -70,6 +70,8 @@ struct SevGuestState {
  #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
  #define DEFAULT_SEV_DEVICE  "/dev/sev"
+#define GUEST_POLICY_SEV_ES_BIT (1 << 2)
+


I'm surprised that all the policy bits aren't defined in a header 
somewhere.


I have another version to be issued with changes to use QemuUUID, so I can 
look at moving the bits to a header.


Hmmm... and they already are defined in target/i386/sev_i386.h. I guess I 
was looking for sev.h and didn't notice sev_i386.h. So I'll update to use 
the values in sev_i386.h.


Thanks,
Tom



Thanks,
Tom



But other than that,


Reviewed-by: Dr. David Alan Gilbert 


  /* SEV Information Block GUID = 00f771de-1a7e-4fcb-890e-68c77e2fb44e */
  #define SEV_INFO_BLOCK_GUID \
  "\xde\x71\xf7\x00\x7e\x1a\xcb\x4f\x89\x0e\x68\xc7\x7e\x2f\xb4\x4e"
@@ -375,7 +377,7 @@ sev_enabled(void)
  bool
  sev_es_enabled(void)
  {
-    return false;
+    return sev_enabled() && (sev_guest->policy & 
GUEST_POLICY_SEV_ES_BIT);

  }
  uint64_t
--
2.28.0





Re: [PATCH v3 3/5] sev/i386: Allow AP booting under SEV-ES

2020-09-16 Thread Tom Lendacky
On 9/16/20 4:23 AM, Laszlo Ersek wrote:
> Hi Tom,

Hi Laszlo,

> 
> sorry for the random feedback -- I haven't followed (and don't really
> intend to follow) the QEMU side of the feature. Just one style idea:
> 
> On 09/15/20 23:29, Tom Lendacky wrote:
>> From: Tom Lendacky 
>>
>> When SEV-ES is enabled, it is not possible modify the guests register
>> state after it has been initially created, encrypted and measured.
>>
>> Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
>> hypervisor cannot emulate this because it cannot update the AP register
>> state. For the very first boot by an AP, the reset vector CS segment
>> value and the EIP value must be programmed before the register has been
>> encrypted and measured.
>>
>> Signed-off-by: Tom Lendacky 
>> ---
>>  accel/kvm/kvm-all.c| 64 ++
>>  accel/stubs/kvm-stub.c |  5 
>>  hw/i386/pc_sysfw.c | 10 ++-
>>  include/sysemu/kvm.h   | 16 +++
>>  include/sysemu/sev.h   |  3 ++
>>  target/i386/kvm.c  |  2 ++
>>  target/i386/sev.c  | 51 +
>>  7 files changed, 150 insertions(+), 1 deletion(-)
>>
>> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
>> index 63ef6af9a1..20725b0368 100644
>> --- a/accel/kvm/kvm-all.c
>> +++ b/accel/kvm/kvm-all.c
>> @@ -39,6 +39,7 @@
>>  #include "qemu/main-loop.h"
>>  #include "trace.h"
>>  #include "hw/irq.h"
>> +#include "sysemu/kvm.h"
>>  #include "sysemu/sev.h"
>>  #include "qapi/visitor.h"
>>  #include "qapi/qapi-types-common.h"
>> @@ -120,6 +121,12 @@ struct KVMState
>>  /* memory encryption */
>>  void *memcrypt_handle;
>>  int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
>> +int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
>> +  uint64_t flash_size, uint32_t *addr);
>> +
>> +unsigned int reset_cs;
>> +unsigned int reset_ip;
>> +bool reset_valid;
>>  
>>  /* For "info mtree -f" to tell if an MR is registered in KVM */
>>  int nr_as;
>> @@ -239,6 +246,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t 
>> len)
>>  return 1;
>>  }
>>  
>> +void kvm_memcrypt_set_reset_vector(CPUState *cpu)
>> +{
>> +X86CPU *x86;
>> +CPUX86State *env;
>> +
>> +/* Only update if we have valid reset information */
>> +if (!kvm_state->reset_valid) {
>> +return;
>> +}
>> +
>> +/* Do not update the BSP reset state */
>> +if (cpu->cpu_index == 0) {
>> +return;
>> +}
>> +
>> +x86 = X86_CPU(cpu);
>> +env = >env;
>> +
>> +cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
>> +   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
>> +   DESC_R_MASK | DESC_A_MASK);
>> +
>> +env->eip = kvm_state->reset_ip;
>> +}
>> +
>> +int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
>> +{
>> +CPUState *cpu;
>> +uint32_t addr;
>> +int ret;
>> +
>> +if (kvm_memcrypt_enabled() &&
>> +kvm_state->memcrypt_save_reset_vector) {
>> +
>> +addr = 0;
>> +ret = 
>> kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
>> +flash_ptr, flash_size,
>> +);
>> +if (ret) {
>> +return ret;
>> +}
>> +
>> +if (addr) {
>> +kvm_state->reset_cs = addr & 0x;
>> +kvm_state->reset_ip = addr & 0x;
>> +kvm_state->reset_valid = true;
>> +
>> +CPU_FOREACH(cpu) {
>> +kvm_memcrypt_set_reset_vector(cpu);
>> +}
>> +}
>> +}
>> +
>> +return 0;
>> +}
>> +
>>  /* Called with KVMMemoryListener.slots_lock held */
>>  static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
>>  {
>> @@ -2193,6 +2256,7 @@ static int kvm_init(MachineState *ms)
>>  }
>>  
>>  kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
>> +kvm_state->memcrypt_save_res

[PATCH v3 0/5] Qemu SEV-ES guest support

2020-09-15 Thread Tom Lendacky
From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed. SEV-ES also requires the use of the in-kernel irqchip support
in order to minimize the changes required to Qemu to support AP booting.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

---

These patches are based on commit:
d0ed6a69d3 ("Update version for v5.1.0 release")

(I tried basing on the latest Qemu commit, but I was having build issues
that level)

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v11

Changes since v2:
- Add in-kernel irqchip requirement for SEV-ES guests

Changes since v1:
- Fixed checkpatch.pl errors/warnings

Tom Lendacky (5):
  sev/i386: Add initial support for SEV-ES
  sev/i386: Require in-kernel irqchip support for SEV-ES guests
  sev/i386: Allow AP booting under SEV-ES
  sev/i386: Don't allow a system reset under an SEV-ES guest
  sev/i386: Enable an SEV-ES guest based on SEV policy

 accel/kvm/kvm-all.c   |  73 ++
 accel/stubs/kvm-stub.c|   5 ++
 hw/i386/pc_sysfw.c|  10 +++-
 include/sysemu/cpus.h |   2 +
 include/sysemu/hw_accel.h |   5 ++
 include/sysemu/kvm.h  |  18 +++
 include/sysemu/sev.h  |   3 ++
 softmmu/cpus.c|   5 ++
 softmmu/vl.c  |   5 +-
 target/i386/cpu.c |   1 +
 target/i386/kvm.c |   2 +
 target/i386/sev-stub.c|   5 ++
 target/i386/sev.c | 105 +-
 target/i386/sev_i386.h|   1 +
 14 files changed, 236 insertions(+), 4 deletions(-)

-- 
2.28.0




[PATCH v3 5/5] sev/i386: Enable an SEV-ES guest based on SEV policy

2020-09-15 Thread Tom Lendacky
From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Signed-off-by: Tom Lendacky 
---
 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 6ddefc65fa..bcaadaa2f9 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -70,6 +70,8 @@ struct SevGuestState {
 #define DEFAULT_GUEST_POLICY0x1 /* disable debug */
 #define DEFAULT_SEV_DEVICE  "/dev/sev"
 
+#define GUEST_POLICY_SEV_ES_BIT (1 << 2)
+
 /* SEV Information Block GUID = 00f771de-1a7e-4fcb-890e-68c77e2fb44e */
 #define SEV_INFO_BLOCK_GUID \
 "\xde\x71\xf7\x00\x7e\x1a\xcb\x4f\x89\x0e\x68\xc7\x7e\x2f\xb4\x4e"
@@ -375,7 +377,7 @@ sev_enabled(void)
 bool
 sev_es_enabled(void)
 {
-return false;
+return sev_enabled() && (sev_guest->policy & GUEST_POLICY_SEV_ES_BIT);
 }
 
 uint64_t
-- 
2.28.0




[PATCH v3 4/5] sev/i386: Don't allow a system reset under an SEV-ES guest

2020-09-15 Thread Tom Lendacky
From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When a SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES, so prevent that from occurring.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c   | 9 +
 include/sysemu/cpus.h | 2 ++
 include/sysemu/hw_accel.h | 5 +
 include/sysemu/kvm.h  | 2 ++
 softmmu/cpus.c| 5 +
 softmmu/vl.c  | 5 -
 6 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 20725b0368..63153b6e53 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2388,6 +2388,15 @@ void kvm_flush_coalesced_mmio_buffer(void)
 s->coalesced_flush_in_progress = false;
 }
 
+bool kvm_cpu_check_resettable(void)
+{
+/*
+ * If we have a valid reset vector override, then SEV-ES is active
+ * and the CPU can't be reset.
+ */
+return !kvm_state->reset_valid;
+}
+
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
 if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index 3c1da6a018..6d688c757f 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -24,6 +24,8 @@ void dump_drift_info(void);
 void qemu_cpu_kick_self(void);
 void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
 
+bool cpu_is_resettable(void);
+
 void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index e128f8b06b..8b4536e7ae 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -17,6 +17,11 @@
 #include "sysemu/hvf.h"
 #include "sysemu/whpx.h"
 
+static inline bool cpu_check_resettable(void)
+{
+return kvm_enabled() ? kvm_cpu_check_resettable() : true;
+}
+
 static inline void cpu_synchronize_state(CPUState *cpu)
 {
 if (kvm_enabled()) {
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index f74cfa85ab..eb94bbbff9 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -494,6 +494,8 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void 
*ram_addr,
 
 #endif /* NEED_CPU_H */
 
+bool kvm_cpu_check_resettable(void);
+
 void kvm_cpu_synchronize_state(CPUState *cpu);
 void kvm_cpu_synchronize_post_reset(CPUState *cpu);
 void kvm_cpu_synchronize_post_init(CPUState *cpu);
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index a802e899ab..32f286643f 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -927,6 +927,11 @@ void hw_error(const char *fmt, ...)
 abort();
 }
 
+bool cpu_is_resettable(void)
+{
+return cpu_check_resettable();
+}
+
 void cpu_synchronize_all_states(void)
 {
 CPUState *cpu;
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 4eb9d1f7fd..422fbb1650 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1475,7 +1475,10 @@ void qemu_system_guest_crashloaded(GuestPanicInformation 
*info)
 
 void qemu_system_reset_request(ShutdownCause reason)
 {
-if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+if (!cpu_is_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
+} else if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
 shutdown_requested = reason;
 } else {
 reset_requested = reason;
-- 
2.28.0




[PATCH v3 2/5] sev/i386: Require in-kernel irqchip support for SEV-ES guests

2020-09-15 Thread Tom Lendacky
From: Tom Lendacky 

In prep for AP booting, require the use of in-kernel irqchip support. This
lessens the Qemu support burden required to boot APs.

Signed-off-by: Tom Lendacky 
---
 target/i386/sev.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 6c9cd0854b..5055b1fe00 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -776,6 +776,12 @@ sev_guest_init(const char *id)
 sev->api_minor = status.api_minor;
 
 if (sev_es_enabled()) {
+if (!kvm_kernel_irqchip_allowed()) {
+error_report("%s: SEV-ES guests require in-kernel irqchip support",
+ __func__);
+goto err;
+}
+
 if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
 error_report("%s: guest policy requires SEV-ES, but "
  "host SEV-ES support unavailable",
-- 
2.28.0




[PATCH v3 3/5] sev/i386: Allow AP booting under SEV-ES

2020-09-15 Thread Tom Lendacky
From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c| 64 ++
 accel/stubs/kvm-stub.c |  5 
 hw/i386/pc_sysfw.c | 10 ++-
 include/sysemu/kvm.h   | 16 +++
 include/sysemu/sev.h   |  3 ++
 target/i386/kvm.c  |  2 ++
 target/i386/sev.c  | 51 +
 7 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 63ef6af9a1..20725b0368 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
 #include "qemu/main-loop.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sev.h"
 #include "qapi/visitor.h"
 #include "qapi/qapi-types-common.h"
@@ -120,6 +121,12 @@ struct KVMState
 /* memory encryption */
 void *memcrypt_handle;
 int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
+  uint64_t flash_size, uint32_t *addr);
+
+unsigned int reset_cs;
+unsigned int reset_ip;
+bool reset_valid;
 
 /* For "info mtree -f" to tell if an MR is registered in KVM */
 int nr_as;
@@ -239,6 +246,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
 return 1;
 }
 
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)
+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_valid) {
+return;
+}
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0) {
+return;
+}
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size,
+);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
@@ -2193,6 +2256,7 @@ static int kvm_init(MachineState *ms)
 }
 
 kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
 }
 
 ret = kvm_arch_init(ms, s);
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 82f118d2df..3aece9b513 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -114,6 +114,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
   return 1;
 }
 
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+return -ENOSYS;
+}
+
 #ifndef CONFIG_USER_ONLY
 int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index b6c0822fe3..321ff94261 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -156,7 +156,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 PFlashCFI01 *system_flash;
 MemoryRegion *flash_mem;
 void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
 
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
@@ -204,6 +205,13 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (kvm_memcrypt_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
+
+ret = kvm_memcrypt_save_reset_vector(flash_ptr, flash_size);
+if (ret) {
+ 

[PATCH v3 1/5] sev/i386: Add initial support for SEV-ES

2020-09-15 Thread Tom Lendacky
From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c  |  1 +
 target/i386/sev-stub.c |  5 +
 target/i386/sev.c  | 46 --
 target/i386/sev_i386.h |  1 +
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 588f32e136..bbbe581d35 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5969,6 +5969,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 break;
 case 0x801F:
 *eax = sev_enabled() ? 0x2 : 0;
+*eax |= sev_es_enabled() ? 0x8 : 0;
 *ebx = sev_get_cbit_position();
 *ebx |= sev_get_reduced_phys_bits() << 6;
 *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 88e3f39a1e..040ac90563 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,3 +49,8 @@ SevCapability *sev_get_capabilities(Error **errp)
 error_setg(errp, "SEV is not available in this QEMU");
 return NULL;
 }
+
+bool sev_es_enabled(void)
+{
+return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index c3ecf86704..6c9cd0854b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -359,6 +359,12 @@ sev_enabled(void)
 return !!sev_guest;
 }
 
+bool
+sev_es_enabled(void)
+{
+return false;
+}
+
 uint64_t
 sev_get_me_mask(void)
 {
@@ -578,6 +584,22 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
 return ret;
 }
 
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+int ret, fw_error;
+
+ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, _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));
+goto err;
+}
+
+err:
+return ret;
+}
+
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
@@ -590,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 return;
 }
 
+if (sev_es_enabled()) {
+/* measure all the VM save areas before getting launch_measure */
+ret = sev_launch_update_vmsa(sev);
+if (ret) {
+exit(1);
+}
+}
+
 measurement = g_new0(struct kvm_sev_launch_measure, 1);
 
 /* query the measurement blob length */
@@ -684,7 +714,7 @@ sev_guest_init(const char *id)
 {
 SevGuestState *sev;
 char *devname;
-int ret, fw_error;
+int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
@@ -745,8 +775,20 @@ sev_guest_init(const char *id)
 sev->api_major = status.api_major;
 sev->api_minor = status.api_minor;
 
+if (sev_es_enabled()) {
+if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+goto err;
+}
+cmd = KVM_SEV_ES_INIT;
+} else {
+cmd = KVM_SEV_INIT;
+}
+
 trace_kvm_sev_init();
-ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, _error);
+ret = sev_ioctl(sev->sev_fd, cmd, NULL, _error);
 if (ret) {
 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
  __func__, ret, fw_error, fw_error_to_str(fw_error));
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..4f9a5e9b21 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -29,6 +29,7 @@
 #define SEV_POLICY_SEV  0x20
 
 extern bool sev_enabled(void);
+extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
-- 
2.28.0




[PATCH v2 0/4] Qemu SEV-ES guest support

2020-08-31 Thread Tom Lendacky
From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

---

These patches are based on commit:
d0ed6a69d3 ("Update version for v5.1.0 release")

(I tried basing on the latest Qemu commit, but I was having build issues
that level)

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v10

Changes since v1:
- Fixed checkpatch.pl errors/warnings

Tom Lendacky (4):
  sev/i386: Add initial support for SEV-ES
  sev/i386: Allow AP booting under SEV-ES
  sev/i386: Don't allow a system reset under an SEV-ES guest
  sev/i386: Enable an SEV-ES guest based on SEV policy

 accel/kvm/kvm-all.c   | 73 +
 accel/stubs/kvm-stub.c|  5 ++
 hw/i386/pc_sysfw.c| 10 +++-
 include/sysemu/cpus.h |  2 +
 include/sysemu/hw_accel.h |  5 ++
 include/sysemu/kvm.h  | 18 +++
 include/sysemu/sev.h  |  3 ++
 softmmu/cpus.c|  5 ++
 softmmu/vl.c  |  5 +-
 target/i386/cpu.c |  1 +
 target/i386/kvm.c |  2 +
 target/i386/sev-stub.c|  5 ++
 target/i386/sev.c | 99 ++-
 target/i386/sev_i386.h|  1 +
 14 files changed, 230 insertions(+), 4 deletions(-)

-- 
2.28.0




[PATCH v2 3/4] sev/i386: Don't allow a system reset under an SEV-ES guest

2020-08-31 Thread Tom Lendacky
From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When a SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES, so prevent that from occurring.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c   | 9 +
 include/sysemu/cpus.h | 2 ++
 include/sysemu/hw_accel.h | 5 +
 include/sysemu/kvm.h  | 2 ++
 softmmu/cpus.c| 5 +
 softmmu/vl.c  | 5 -
 6 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 20725b0368..63153b6e53 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2388,6 +2388,15 @@ void kvm_flush_coalesced_mmio_buffer(void)
 s->coalesced_flush_in_progress = false;
 }
 
+bool kvm_cpu_check_resettable(void)
+{
+/*
+ * If we have a valid reset vector override, then SEV-ES is active
+ * and the CPU can't be reset.
+ */
+return !kvm_state->reset_valid;
+}
+
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
 if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index 3c1da6a018..6d688c757f 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -24,6 +24,8 @@ void dump_drift_info(void);
 void qemu_cpu_kick_self(void);
 void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
 
+bool cpu_is_resettable(void);
+
 void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index e128f8b06b..8b4536e7ae 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -17,6 +17,11 @@
 #include "sysemu/hvf.h"
 #include "sysemu/whpx.h"
 
+static inline bool cpu_check_resettable(void)
+{
+return kvm_enabled() ? kvm_cpu_check_resettable() : true;
+}
+
 static inline void cpu_synchronize_state(CPUState *cpu)
 {
 if (kvm_enabled()) {
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index f74cfa85ab..eb94bbbff9 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -494,6 +494,8 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void 
*ram_addr,
 
 #endif /* NEED_CPU_H */
 
+bool kvm_cpu_check_resettable(void);
+
 void kvm_cpu_synchronize_state(CPUState *cpu);
 void kvm_cpu_synchronize_post_reset(CPUState *cpu);
 void kvm_cpu_synchronize_post_init(CPUState *cpu);
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index a802e899ab..32f286643f 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -927,6 +927,11 @@ void hw_error(const char *fmt, ...)
 abort();
 }
 
+bool cpu_is_resettable(void)
+{
+return cpu_check_resettable();
+}
+
 void cpu_synchronize_all_states(void)
 {
 CPUState *cpu;
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 4eb9d1f7fd..422fbb1650 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1475,7 +1475,10 @@ void qemu_system_guest_crashloaded(GuestPanicInformation 
*info)
 
 void qemu_system_reset_request(ShutdownCause reason)
 {
-if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+if (!cpu_is_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
+} else if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
 shutdown_requested = reason;
 } else {
 reset_requested = reason;
-- 
2.28.0




[PATCH v2 2/4] sev/i386: Allow AP booting under SEV-ES

2020-08-31 Thread Tom Lendacky
From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c| 64 ++
 accel/stubs/kvm-stub.c |  5 
 hw/i386/pc_sysfw.c | 10 ++-
 include/sysemu/kvm.h   | 16 +++
 include/sysemu/sev.h   |  3 ++
 target/i386/kvm.c  |  2 ++
 target/i386/sev.c  | 51 +
 7 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 63ef6af9a1..20725b0368 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
 #include "qemu/main-loop.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sev.h"
 #include "qapi/visitor.h"
 #include "qapi/qapi-types-common.h"
@@ -120,6 +121,12 @@ struct KVMState
 /* memory encryption */
 void *memcrypt_handle;
 int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr,
+  uint64_t flash_size, uint32_t *addr);
+
+unsigned int reset_cs;
+unsigned int reset_ip;
+bool reset_valid;
 
 /* For "info mtree -f" to tell if an MR is registered in KVM */
 int nr_as;
@@ -239,6 +246,62 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
 return 1;
 }
 
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)
+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_valid) {
+return;
+}
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0) {
+return;
+}
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size,
+);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
@@ -2193,6 +2256,7 @@ static int kvm_init(MachineState *ms)
 }
 
 kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
 }
 
 ret = kvm_arch_init(ms, s);
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 82f118d2df..3aece9b513 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -114,6 +114,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
   return 1;
 }
 
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+return -ENOSYS;
+}
+
 #ifndef CONFIG_USER_ONLY
 int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index b6c0822fe3..321ff94261 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -156,7 +156,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 PFlashCFI01 *system_flash;
 MemoryRegion *flash_mem;
 void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
 
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
@@ -204,6 +205,13 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (kvm_memcrypt_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
+
+ret = kvm_memcrypt_save_reset_vector(flash_ptr, flash_size);
+if (ret) {
+ 

[PATCH v2 1/4] sev/i386: Add initial support for SEV-ES

2020-08-31 Thread Tom Lendacky
From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c  |  1 +
 target/i386/sev-stub.c |  5 +
 target/i386/sev.c  | 46 --
 target/i386/sev_i386.h |  1 +
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 588f32e136..bbbe581d35 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5969,6 +5969,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 break;
 case 0x801F:
 *eax = sev_enabled() ? 0x2 : 0;
+*eax |= sev_es_enabled() ? 0x8 : 0;
 *ebx = sev_get_cbit_position();
 *ebx |= sev_get_reduced_phys_bits() << 6;
 *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 88e3f39a1e..040ac90563 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,3 +49,8 @@ SevCapability *sev_get_capabilities(Error **errp)
 error_setg(errp, "SEV is not available in this QEMU");
 return NULL;
 }
+
+bool sev_es_enabled(void)
+{
+return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index c3ecf86704..6c9cd0854b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -359,6 +359,12 @@ sev_enabled(void)
 return !!sev_guest;
 }
 
+bool
+sev_es_enabled(void)
+{
+return false;
+}
+
 uint64_t
 sev_get_me_mask(void)
 {
@@ -578,6 +584,22 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
 return ret;
 }
 
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+int ret, fw_error;
+
+ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, _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));
+goto err;
+}
+
+err:
+return ret;
+}
+
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
@@ -590,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 return;
 }
 
+if (sev_es_enabled()) {
+/* measure all the VM save areas before getting launch_measure */
+ret = sev_launch_update_vmsa(sev);
+if (ret) {
+exit(1);
+}
+}
+
 measurement = g_new0(struct kvm_sev_launch_measure, 1);
 
 /* query the measurement blob length */
@@ -684,7 +714,7 @@ sev_guest_init(const char *id)
 {
 SevGuestState *sev;
 char *devname;
-int ret, fw_error;
+int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
@@ -745,8 +775,20 @@ sev_guest_init(const char *id)
 sev->api_major = status.api_major;
 sev->api_minor = status.api_minor;
 
+if (sev_es_enabled()) {
+if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+goto err;
+}
+cmd = KVM_SEV_ES_INIT;
+} else {
+cmd = KVM_SEV_INIT;
+}
+
 trace_kvm_sev_init();
-ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, _error);
+ret = sev_ioctl(sev->sev_fd, cmd, NULL, _error);
 if (ret) {
 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
  __func__, ret, fw_error, fw_error_to_str(fw_error));
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..4f9a5e9b21 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -29,6 +29,7 @@
 #define SEV_POLICY_SEV  0x20
 
 extern bool sev_enabled(void);
+extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
-- 
2.28.0




[PATCH v2 4/4] sev/i386: Enable an SEV-ES guest based on SEV policy

2020-08-31 Thread Tom Lendacky
From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Signed-off-by: Tom Lendacky 
---
 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 0bc497379b..0fd142abe9 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -70,6 +70,8 @@ struct SevGuestState {
 #define DEFAULT_GUEST_POLICY0x1 /* disable debug */
 #define DEFAULT_SEV_DEVICE  "/dev/sev"
 
+#define GUEST_POLICY_SEV_ES_BIT (1 << 2)
+
 /* SEV Information Block GUID = 00f771de-1a7e-4fcb-890e-68c77e2fb44e */
 #define SEV_INFO_BLOCK_GUID \
 "\xde\x71\xf7\x00\x7e\x1a\xcb\x4f\x89\x0e\x68\xc7\x7e\x2f\xb4\x4e"
@@ -375,7 +377,7 @@ sev_enabled(void)
 bool
 sev_es_enabled(void)
 {
-return false;
+return sev_enabled() && (sev_guest->policy & GUEST_POLICY_SEV_ES_BIT);
 }
 
 uint64_t
-- 
2.28.0




Re: [PATCH 0/4] SEV-ES guest support

2020-08-27 Thread Tom Lendacky

On 8/25/20 2:05 PM, Tom Lendacky wrote:

From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.


I've made the changes associated with the checkpatch script output. I'll 
wait a few more days for other feedback before submitting a v2.


Sorry about the miss in regards to running checkpatch.

Thanks,
Tom



Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")
 
https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

---

These patches are based on commit:
d0ed6a69d3 ("Update version for v5.1.0 release")

(I tried basing on the latest Qemu commit, but I was having build issues
that level)

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v9

Tom Lendacky (4):
   sev/i386: Add initial support for SEV-ES
   sev/i386: Allow AP booting under SEV-ES
   sev/i386: Don't allow a system reset under an SEV-ES guest
   sev/i386: Enable an SEV-ES guest based on SEV policy

  accel/kvm/kvm-all.c   | 68 
  accel/stubs/kvm-stub.c|  5 +++
  hw/i386/pc_sysfw.c| 10 -
  include/sysemu/cpus.h |  2 +
  include/sysemu/hw_accel.h |  4 ++
  include/sysemu/kvm.h  | 18 
  include/sysemu/sev.h  |  2 +
  softmmu/cpus.c|  5 +++
  softmmu/vl.c  |  5 ++-
  target/i386/cpu.c |  1 +
  target/i386/kvm.c |  2 +
  target/i386/sev-stub.c|  5 +++
  target/i386/sev.c | 95 ++-
  target/i386/sev_i386.h|  1 +
  14 files changed, 219 insertions(+), 4 deletions(-)





Re: [PATCH 1/4] sev/i386: Add initial support for SEV-ES

2020-08-26 Thread Tom Lendacky

On 8/26/20 2:07 PM, Connor Kuehl wrote:

On 8/25/20 2:05 PM, Tom Lendacky wrote:

From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 


Hi Tom!


Hi Connor,



Overall I think the patch set looks good. I mainly just have 1 question 
regarding some error handling and a couple of checkpatch related messages.


Ugh, I was positive I ran checkpatch, but obviously I didn't.




---
  target/i386/cpu.c  |  1 +
  target/i386/sev-stub.c |  5 +
  target/i386/sev.c  | 46 --
  target/i386/sev_i386.h |  1 +
  4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 588f32e136..bbbe581d35 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5969,6 +5969,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t 
index, uint32_t count,

  break;
  case 0x801F:
  *eax = sev_enabled() ? 0x2 : 0;
+    *eax |= sev_es_enabled() ? 0x8 : 0;
  *ebx = sev_get_cbit_position();
  *ebx |= sev_get_reduced_phys_bits() << 6;
  *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 88e3f39a1e..040ac90563 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,3 +49,8 @@ SevCapability *sev_get_capabilities(Error **errp)
  error_setg(errp, "SEV is not available in this QEMU");
  return NULL;
  }
+
+bool sev_es_enabled(void)


I don't think this bothers checkpatch, but it'd be consistent with the 
rest of your series if this function put the return type on the line above.


I was being consistent with the file that it is in where all the other 
functions are defined this way.





+{
+    return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index c3ecf86704..6c9cd0854b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -359,6 +359,12 @@ sev_enabled(void)
  return !!sev_guest;
  }
+bool
+sev_es_enabled(void)
+{
+    return false;
+}
+
  uint64_t
  sev_get_me_mask(void)
  {
@@ -578,6 +584,22 @@ sev_launch_update_data(SevGuestState *sev, uint8_t 
*addr, uint64_t len)

  return ret;
  }
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+    int ret, fw_error;
+
+    ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, 
_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));
+    goto err;
+    }
+
+err:
+    return ret;
+}
+
  static void
  sev_launch_get_measure(Notifier *notifier, void *unused)
  {
@@ -590,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void 
*unused)

  return;
  }
+    if (sev_es_enabled()) {
+    /* measure all the VM save areas before getting launch_measure */
+    ret = sev_launch_update_vmsa(sev);
+    if (ret) {
+    exit(1);


Disclaimer: I'm still learning the QEMU source code, sorry if this comes 
across as naive.


Is exit() what we want here? I was looking around the rest of the source 
code and unfortunately the machine_init_done_notifiers mechanism doesn't 
allow for a return value to indicate an error, so I'm wondering if there's 
a more appropriate place in the initialization code to handle these 
fallible operations and if so, propagate the error down. This way if there 
are other resources that need to be cleaned up on the way out, they can 
be. Thoughts?


I was following the existing method of terminating that is being performed 
in this file. I'll see if others have an idea about how to handle these 
types of errors, which could probably be addressed as a separate patch series.


Thanks,
Tom




+    }
+    }
+
  measurement = g_new0(struct kvm_sev_launch_measure, 1);
  /* query the measurement blob length */
@@ -684,7 +714,7 @@ sev_guest_init(const char *id)
  {
  SevGuestState *sev;
  char *devname;
-    int ret, fw_error;
+    int ret, fw_error, cmd;
  uint32_t ebx;
  uint32_t host_cbitpos;
  struct sev_user_data_status status = {};
@@ -745,8 +775,20 @@ sev_guest_init(const char *id)
  sev->api_major = status.api_major;
  sev->api_minor = status.api_minor;
+    if (sev_es_enabled()) {
+    if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+    error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+    goto err;
+    }
+    cmd = KVM_SEV_ES_INIT;
+    } else {
+    cmd = KVM_SEV_INIT;
+    }
+
  trace_kvm_sev_init();
-    ret = sev_ioctl(sev

Re: [PATCH 2/4] sev/i386: Allow AP booting under SEV-ES

2020-08-26 Thread Tom Lendacky

On 8/26/20 2:07 PM, Connor Kuehl wrote:

On 8/25/20 2:05 PM, Tom Lendacky wrote:

From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured.

Signed-off-by: Tom Lendacky 
---
  accel/kvm/kvm-all.c    | 60 ++
  accel/stubs/kvm-stub.c |  5 
  hw/i386/pc_sysfw.c | 10 ++-
  include/sysemu/kvm.h   | 16 +++
  include/sysemu/sev.h   |  2 ++
  target/i386/kvm.c  |  2 ++
  target/i386/sev.c  | 47 +
  7 files changed, 141 insertions(+), 1 deletion(-)


Just a heads-up: ./scripts/checkpatch.pl does report a couple of style 
errors. I've seen other series go by where maintainers didn't mind the 
line length errors, but there are a couple that have to do with braces 
around if-statement contents that may need to be addressed.


Yup, I'll run checkpatch and make the necessary changes.

Thanks,
Tom







[PATCH 0/4] SEV-ES guest support

2020-08-25 Thread Tom Lendacky
From: Tom Lendacky 

This patch series provides support for launching an SEV-ES guest.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural 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. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the Qemu code that are updated to support SEV-ES are
around the SEV guest launch process and AP booting in order to support
booting multiple vCPUs.

There are no new command line switches required. Instead, the desire for
SEV-ES is presented using the SEV policy object. Bit 2 of the SEV policy
object indicates that SEV-ES is required.

The SEV launch process is updated in two ways. The first is that a the
KVM_SEV_ES_INIT ioctl is used to initialize the guest instead of the
standard KVM_SEV_INIT ioctl. The second is that before the SEV launch
measurement is calculated, the LAUNCH_UPDATE_VMSA SEV API is invoked for
each vCPU that Qemu has created. Once the LAUNCH_UPDATE_VMSA API has been
invoked, no direct changes to the guest register state can be made.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. For the APs, the reset vector must be known
in advance. An OVMF method to provide a known reset vector address exists
by providing an SEV information block, identified by UUID, near the end of
the firmware [3]. OVMF will program the jump to the actual reset vector in
this area of memory. Since the memory location is known in advance, an AP
can be created with the known reset vector address as its starting CS:IP.
The GHCB document [2] talks about how SMP booting under SEV-ES is
performed.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] 30937f2f98c4 ("OvmfPkg: Use the SEV-ES work area for the SEV-ES AP reset 
vector")

https://github.com/tianocore/edk2/commit/30937f2f98c42496f2f143fe8374ae7f7e684847

---

These patches are based on commit:
d0ed6a69d3 ("Update version for v5.1.0 release")

(I tried basing on the latest Qemu commit, but I was having build issues
that level)

A version of the tree can be found at:
https://github.com/AMDESE/qemu/tree/sev-es-v9

Tom Lendacky (4):
  sev/i386: Add initial support for SEV-ES
  sev/i386: Allow AP booting under SEV-ES
  sev/i386: Don't allow a system reset under an SEV-ES guest
  sev/i386: Enable an SEV-ES guest based on SEV policy

 accel/kvm/kvm-all.c   | 68 
 accel/stubs/kvm-stub.c|  5 +++
 hw/i386/pc_sysfw.c| 10 -
 include/sysemu/cpus.h |  2 +
 include/sysemu/hw_accel.h |  4 ++
 include/sysemu/kvm.h  | 18 
 include/sysemu/sev.h  |  2 +
 softmmu/cpus.c|  5 +++
 softmmu/vl.c  |  5 ++-
 target/i386/cpu.c |  1 +
 target/i386/kvm.c |  2 +
 target/i386/sev-stub.c|  5 +++
 target/i386/sev.c | 95 ++-
 target/i386/sev_i386.h|  1 +
 14 files changed, 219 insertions(+), 4 deletions(-)

-- 
2.28.0




[PATCH 2/4] sev/i386: Allow AP booting under SEV-ES

2020-08-25 Thread Tom Lendacky
From: Tom Lendacky 

When SEV-ES is enabled, it is not possible modify the guests register
state after it has been initially created, encrypted and measured.

Normally, an INIT-SIPI-SIPI request is used to boot the AP. However, the
hypervisor cannot emulate this because it cannot update the AP register
state. For the very first boot by an AP, the reset vector CS segment
value and the EIP value must be programmed before the register has been
encrypted and measured.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c| 60 ++
 accel/stubs/kvm-stub.c |  5 
 hw/i386/pc_sysfw.c | 10 ++-
 include/sysemu/kvm.h   | 16 +++
 include/sysemu/sev.h   |  2 ++
 target/i386/kvm.c  |  2 ++
 target/i386/sev.c  | 47 +
 7 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 63ef6af9a1..54e8fd098d 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -39,6 +39,7 @@
 #include "qemu/main-loop.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sev.h"
 #include "qapi/visitor.h"
 #include "qapi/qapi-types-common.h"
@@ -120,6 +121,11 @@ struct KVMState
 /* memory encryption */
 void *memcrypt_handle;
 int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+int (*memcrypt_save_reset_vector)(void *handle, void *flash_ptr, uint64_t 
flash_size, uint32_t *addr);
+
+unsigned int reset_cs;
+unsigned int reset_ip;
+bool reset_valid;
 
 /* For "info mtree -f" to tell if an MR is registered in KVM */
 int nr_as;
@@ -239,6 +245,59 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
 return 1;
 }
 
+void kvm_memcrypt_set_reset_vector(CPUState *cpu)
+{
+X86CPU *x86;
+CPUX86State *env;
+
+/* Only update if we have valid reset information */
+if (!kvm_state->reset_valid)
+return;
+
+/* Do not update the BSP reset state */
+if (cpu->cpu_index == 0)
+return;
+
+x86 = X86_CPU(cpu);
+env = >env;
+
+cpu_x86_load_seg_cache(env, R_CS, 0xf000, kvm_state->reset_cs, 0x,
+   DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+   DESC_R_MASK | DESC_A_MASK);
+
+env->eip = kvm_state->reset_ip;
+}
+
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+CPUState *cpu;
+uint32_t addr;
+int ret;
+
+if (kvm_memcrypt_enabled() &&
+kvm_state->memcrypt_save_reset_vector) {
+
+addr = 0;
+ret = kvm_state->memcrypt_save_reset_vector(kvm_state->memcrypt_handle,
+flash_ptr, flash_size, 
);
+if (ret) {
+return ret;
+}
+
+if (addr) {
+kvm_state->reset_cs = addr & 0x;
+kvm_state->reset_ip = addr & 0x;
+kvm_state->reset_valid = true;
+
+CPU_FOREACH(cpu) {
+kvm_memcrypt_set_reset_vector(cpu);
+}
+}
+}
+
+return 0;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
@@ -2193,6 +2252,7 @@ static int kvm_init(MachineState *ms)
 }
 
 kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+kvm_state->memcrypt_save_reset_vector = sev_es_save_reset_vector;
 }
 
 ret = kvm_arch_init(ms, s);
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 82f118d2df..3aece9b513 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -114,6 +114,11 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
   return 1;
 }
 
+int kvm_memcrypt_save_reset_vector(void *flash_ptr, uint64_t flash_size)
+{
+return -ENOSYS;
+}
+
 #ifndef CONFIG_USER_ONLY
 int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index b6c0822fe3..321ff94261 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -156,7 +156,8 @@ static void pc_system_flash_map(PCMachineState *pcms,
 PFlashCFI01 *system_flash;
 MemoryRegion *flash_mem;
 void *flash_ptr;
-int ret, flash_size;
+uint64_t flash_size;
+int ret;
 
 assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
 
@@ -204,6 +205,13 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (kvm_memcrypt_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
+
+ret = kvm_memcrypt_save_reset_vector(flash_ptr, flash_size);
+if (ret) {
+error_report("failed to locate and/or save reset vector");
+exit(1);
+   

[PATCH 4/4] sev/i386: Enable an SEV-ES guest based on SEV policy

2020-08-25 Thread Tom Lendacky
From: Tom Lendacky 

Update the sev_es_enabled() function return value to be based on the SEV
policy that has been specified. SEV-ES is enabled if SEV is enabled and
the SEV-ES policy bit is set in the policy object.

Signed-off-by: Tom Lendacky 
---
 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 5146b788fb..153c2cba2c 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -70,6 +70,8 @@ struct SevGuestState {
 #define DEFAULT_GUEST_POLICY0x1 /* disable debug */
 #define DEFAULT_SEV_DEVICE  "/dev/sev"
 
+#define GUEST_POLICY_SEV_ES_BIT (1 << 2)
+
 /* SEV Information Block GUID = 00f771de-1a7e-4fcb-890e-68c77e2fb44e */
 #define SEV_INFO_BLOCK_GUID 
"\xde\x71\xf7\x00\x7e\x1a\xcb\x4f\x89\x0e\x68\xc7\x7e\x2f\xb4\x4e"
 
@@ -374,7 +376,7 @@ sev_enabled(void)
 bool
 sev_es_enabled(void)
 {
-return false;
+return (sev_enabled() && (sev_guest->policy & GUEST_POLICY_SEV_ES_BIT));
 }
 
 uint64_t
-- 
2.28.0




[PATCH 3/4] sev/i386: Don't allow a system reset under an SEV-ES guest

2020-08-25 Thread Tom Lendacky
From: Tom Lendacky 

An SEV-ES guest does not allow register state to be altered once it has
been measured. When a SEV-ES guest issues a reboot command, Qemu will
reset the vCPU state and resume the guest. This will cause failures under
SEV-ES, so prevent that from occurring.

Signed-off-by: Tom Lendacky 
---
 accel/kvm/kvm-all.c   | 8 
 include/sysemu/cpus.h | 2 ++
 include/sysemu/hw_accel.h | 4 
 include/sysemu/kvm.h  | 2 ++
 softmmu/cpus.c| 5 +
 softmmu/vl.c  | 5 -
 6 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 54e8fd098d..1d925821b2 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2384,6 +2384,14 @@ void kvm_flush_coalesced_mmio_buffer(void)
 s->coalesced_flush_in_progress = false;
 }
 
+bool kvm_cpu_check_resettable(void)
+{
+/* If we have a valid reset vector override, then SEV-ES is active
+ * and the CPU can't be reset.
+ */
+return !kvm_state->reset_valid;
+}
+
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
 if (!cpu->vcpu_dirty) {
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index 3c1da6a018..6d688c757f 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -24,6 +24,8 @@ void dump_drift_info(void);
 void qemu_cpu_kick_self(void);
 void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
 
+bool cpu_is_resettable(void);
+
 void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h
index e128f8b06b..1fddf4f5e1 100644
--- a/include/sysemu/hw_accel.h
+++ b/include/sysemu/hw_accel.h
@@ -17,6 +17,10 @@
 #include "sysemu/hvf.h"
 #include "sysemu/whpx.h"
 
+static inline bool cpu_check_resettable(void)
+{
+return kvm_enabled() ? kvm_cpu_check_resettable() : true;
+}
 static inline void cpu_synchronize_state(CPUState *cpu)
 {
 if (kvm_enabled()) {
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index f74cfa85ab..eb94bbbff9 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -494,6 +494,8 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void 
*ram_addr,
 
 #endif /* NEED_CPU_H */
 
+bool kvm_cpu_check_resettable(void);
+
 void kvm_cpu_synchronize_state(CPUState *cpu);
 void kvm_cpu_synchronize_post_reset(CPUState *cpu);
 void kvm_cpu_synchronize_post_init(CPUState *cpu);
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index a802e899ab..32f286643f 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -927,6 +927,11 @@ void hw_error(const char *fmt, ...)
 abort();
 }
 
+bool cpu_is_resettable(void)
+{
+return cpu_check_resettable();
+}
+
 void cpu_synchronize_all_states(void)
 {
 CPUState *cpu;
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 4eb9d1f7fd..422fbb1650 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1475,7 +1475,10 @@ void qemu_system_guest_crashloaded(GuestPanicInformation 
*info)
 
 void qemu_system_reset_request(ShutdownCause reason)
 {
-if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+if (!cpu_is_resettable()) {
+error_report("cpus are not resettable, terminating");
+shutdown_requested = reason;
+} else if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
 shutdown_requested = reason;
 } else {
 reset_requested = reason;
-- 
2.28.0




[PATCH 1/4] sev/i386: Add initial support for SEV-ES

2020-08-25 Thread Tom Lendacky
From: Tom Lendacky 

Provide initial support for SEV-ES. This includes creating a function to
indicate the guest is an SEV-ES guest (which will return false until all
support is in place), performing the proper SEV initialization and
ensuring that the guest CPU state is measured as part of the launch.

Co-developed-by: Jiri Slaby 
Signed-off-by: Jiri Slaby 
Signed-off-by: Tom Lendacky 
---
 target/i386/cpu.c  |  1 +
 target/i386/sev-stub.c |  5 +
 target/i386/sev.c  | 46 --
 target/i386/sev_i386.h |  1 +
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 588f32e136..bbbe581d35 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5969,6 +5969,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 break;
 case 0x801F:
 *eax = sev_enabled() ? 0x2 : 0;
+*eax |= sev_es_enabled() ? 0x8 : 0;
 *ebx = sev_get_cbit_position();
 *ebx |= sev_get_reduced_phys_bits() << 6;
 *ecx = 0;
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 88e3f39a1e..040ac90563 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -49,3 +49,8 @@ SevCapability *sev_get_capabilities(Error **errp)
 error_setg(errp, "SEV is not available in this QEMU");
 return NULL;
 }
+
+bool sev_es_enabled(void)
+{
+return false;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index c3ecf86704..6c9cd0854b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -359,6 +359,12 @@ sev_enabled(void)
 return !!sev_guest;
 }
 
+bool
+sev_es_enabled(void)
+{
+return false;
+}
+
 uint64_t
 sev_get_me_mask(void)
 {
@@ -578,6 +584,22 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
 return ret;
 }
 
+static int
+sev_launch_update_vmsa(SevGuestState *sev)
+{
+int ret, fw_error;
+
+ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, _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));
+goto err;
+}
+
+err:
+return ret;
+}
+
 static void
 sev_launch_get_measure(Notifier *notifier, void *unused)
 {
@@ -590,6 +612,14 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 return;
 }
 
+if (sev_es_enabled()) {
+/* measure all the VM save areas before getting launch_measure */
+ret = sev_launch_update_vmsa(sev);
+if (ret) {
+exit(1);
+}
+}
+
 measurement = g_new0(struct kvm_sev_launch_measure, 1);
 
 /* query the measurement blob length */
@@ -684,7 +714,7 @@ sev_guest_init(const char *id)
 {
 SevGuestState *sev;
 char *devname;
-int ret, fw_error;
+int ret, fw_error, cmd;
 uint32_t ebx;
 uint32_t host_cbitpos;
 struct sev_user_data_status status = {};
@@ -745,8 +775,20 @@ sev_guest_init(const char *id)
 sev->api_major = status.api_major;
 sev->api_minor = status.api_minor;
 
+if (sev_es_enabled()) {
+if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
+error_report("%s: guest policy requires SEV-ES, but "
+ "host SEV-ES support unavailable",
+ __func__);
+goto err;
+}
+cmd = KVM_SEV_ES_INIT;
+} else {
+cmd = KVM_SEV_INIT;
+}
+
 trace_kvm_sev_init();
-ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, _error);
+ret = sev_ioctl(sev->sev_fd, cmd, NULL, _error);
 if (ret) {
 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
  __func__, ret, fw_error, fw_error_to_str(fw_error));
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..4f9a5e9b21 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -29,6 +29,7 @@
 #define SEV_POLICY_SEV  0x20
 
 extern bool sev_enabled(void);
+extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
-- 
2.28.0




Re: [PATCH 2/2] sev: scan guest ROM for launch secret address

2020-05-29 Thread Tom Lendacky

On 5/28/20 3:51 PM, Tobin Feldman-Fitzthum wrote:

From: Tobin Feldman-Fitzthum 

In addition to using QMP to provide the guest memory address
that the launch secret blob will be injected into, the
secret address can also be specified in the guest ROM. This
patch adds sev_find_secret_gpa, which scans the ROM page by
page to find a launch secret table identified by a GUID. If
the table is found, the address it contains will be used
in place of any address specified via QMP.


I'm working on something similar for SEV-ES support in OVMF (see 
https://www.mail-archive.com/devel@edk2.groups.io/msg20716.html). The GUID 
is placed at a fixed location from the end of the ROM. One of the OVMF 
maintainers recommended the approach and I think we should work to support 
the guest LAUNCH SECRET GPA using the same GUID. This particular patch 
should be delayed until an OVMF method is accepted, so that it doesn't 
have to be reworked.


Thanks,
Tom



Signed-off-by: Tobin Feldman-Fitzthum 
---
  target/i386/sev.c  | 34 --
  target/i386/sev_i386.h | 16 
  2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 774e47d9d1..4adc56d7e3 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -706,6 +706,8 @@ sev_guest_init(const char *id)
  s->api_major = status.api_major;
  s->api_minor = status.api_minor;
  
+s->secret_gpa = 0;

+
  trace_kvm_sev_init();
  ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, _error);
  if (ret) {
@@ -731,6 +733,28 @@ err:
  return NULL;
  }
  
+static void

+sev_find_secret_gpa(uint8_t *ptr, uint64_t len)
+{
+uint64_t offset;
+
+SevROMSecretTable *secret_table;
+QemuUUID secret_table_guid;
+
+qemu_uuid_parse(SEV_ROM_SECRET_GUID,_table_guid);
+secret_table_guid = qemu_uuid_bswap(secret_table_guid);
+
+offset = len - 0x1000;
+while(offset > 0) {
+secret_table = (SevROMSecretTable *)(ptr + offset);
+if(qemu_uuid_is_equal(_table_guid, (QemuUUID *) secret_table)){
+sev_state->secret_gpa = (long unsigned int) secret_table->base;
+break;
+}
+offset -= 0x1000;
+}
+}
+
  int
  sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
  {
@@ -738,6 +762,9 @@ sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
  
  /* if SEV is in update state then encrypt the data else do nothing */

  if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
+if(!sev_state->secret_gpa) {
+sev_find_secret_gpa(ptr, len);
+   }
  return sev_launch_update_data(ptr, len);
  }
  
@@ -776,8 +803,8 @@ int sev_inject_launch_secret(const char *packet_hdr,
  
  /* secret can be inject only in this state */

  if (!sev_check_state(SEV_STATE_LAUNCH_SECRET)) {
-   error_report("Not in correct state. %x",sev_state->state);
-   return 1;
+error_report("Not in correct state. %x",sev_state->state);
+return 1;
  }
  
  hdr = g_base64_decode(packet_hdr, _sz);

@@ -792,6 +819,9 @@ int sev_inject_launch_secret(const char *packet_hdr,
  goto err;
  }
  
+if(sev_state->secret_gpa)

+gpa = sev_state->secret_gpa;
+
  hva = gpa2hva(gpa, data_sz);
  if (!hva) {
  goto err;
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 8ada9d385d..b1f9ab93bb 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -19,6 +19,7 @@
  #include "sysemu/kvm.h"
  #include "sysemu/sev.h"
  #include "qemu/error-report.h"
+#include "qemu/uuid.h"
  #include "qapi/qapi-types-misc-target.h"
  
  #define SEV_POLICY_NODBG0x1

@@ -28,6 +29,8 @@
  #define SEV_POLICY_DOMAIN   0x10
  #define SEV_POLICY_SEV  0x20
  
+#define SEV_ROM_SECRET_GUID "adf956ad-e98c-484c-ae11-b51c7d336447"

+
  #define TYPE_QSEV_GUEST_INFO "sev-guest"
  #define QSEV_GUEST_INFO(obj)  \
  OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO)
@@ -42,6 +45,18 @@ extern SevCapability *sev_get_capabilities(void);
  
  typedef struct QSevGuestInfo QSevGuestInfo;

  typedef struct QSevGuestInfoClass QSevGuestInfoClass;
+typedef struct SevROMSecretTable SevROMSecretTable;
+
+/**
+ * If guest physical address for the launch secret is
+ * provided in the ROM, it should be in the following
+ * page-aligned structure.
+ */
+struct SevROMSecretTable {
+QemuUUID guid;
+unsigned int base;
+unsigned int size;
+};
  
  /**

   * QSevGuestInfo:
@@ -78,6 +93,7 @@ struct SEVState {
  uint32_t cbitpos;
  uint32_t reduced_phys_bits;
  uint32_t handle;
+uint64_t secret_gpa;
  int sev_fd;
  SevState state;
  gchar *measurement;





Re: [PATCH V2] vhost: correctly turn on VIRTIO_F_IOMMU_PLATFORM

2020-02-27 Thread Tom Lendacky
On 2/27/20 7:02 AM, Halil Pasic wrote:
> On Wed, 26 Feb 2020 11:52:26 -0500
> "Michael S. Tsirkin"  wrote:
> 
>> On Wed, Feb 26, 2020 at 04:36:18PM +0100, Halil Pasic wrote:
>>> On Wed, 26 Feb 2020 08:37:13 -0500
>>> "Michael S. Tsirkin"  wrote:
>>>
 On Wed, Feb 26, 2020 at 02:28:39PM +0100, Halil Pasic wrote:
> On Wed, 26 Feb 2020 17:43:57 +0800
> Jason Wang  wrote:
>
>> We turn on device IOTLB via VIRTIO_F_IOMMU_PLATFORM unconditionally on
>> platform without IOMMU support. This can lead unnecessary IOTLB
>> transactions which will damage the performance.
>>
>> Fixing this by check whether the device is backed by IOMMU and disable
>> device IOTLB.
>>
>> Reported-by: Halil Pasic 
>> Fixes: c471ad0e9bd46 ("vhost_net: device IOTLB support")
>> Cc: qemu-sta...@nongnu.org
>> Signed-off-by: Jason Wang 
>
> Tested-by: Halil Pasic 
> Reviewed-by: Halil Pasic 
>
> Thank you very much for fixing this! BTW as I mentioned before it
> fixes vhost-vsock with iommu_platform=on as well.

 Fixes as in improves performance?
>>>
>>> No, fixes like one does not get something like:
>>> qemu-system-s390x: vhost_set_features failed: Operation not supported (95)
>>> qemu-system-s390x: Error starting vhost: 95
>>> any more.
>>>
>>> Regards,
>>> Halil
>>>
>>> [..]
>>
>> But can commit c471ad0e9bd46 actually boot a secure guest
>> where iommu_platform=on is required?
>>
> 
> No, of course it can not. But I'm not sure about AMD SEV. AFAIU without
> Jason's patch it does not work for AMD SEV. Tom already stated that with
> SEV they don't need the IOVA translation aspect of ACCESS_PLATFORM, but
> I have no idea if the condition vdev->dma_as == _space_memory
> catches them as well or not. They probably have !=.
> 
> CCing Tom. @Tom does vhost-vsock work for you with SEV and current qemu?

Adding Brijesh for this, too.

> 
> Also, one can specify iommu_platform=on on a device that ain't a part of
> a secure-capable VM, just for the fun of it. And that breaks
> vhost-vsock. Or is setting iommu_platform=on only valid if
> qemu-system-s390x is protected virtualization capable?
> 
> BTW, I don't have a strong opinion on the fixes tag. We currently do not
> recommend setting iommu_platform, and thus I don't think we care too
> much about past qemus having problems with it.
> 
> Regards,
> Halil
> 



Re: [Qemu-devel] [PATCH 1/2] i386: define the AMD 'amd-ssbd' CPUID feature bit

2018-06-08 Thread Tom Lendacky
On 6/6/2018 9:20 AM, Daniel P. Berrangé wrote:
> On Tue, Jun 05, 2018 at 08:31:41AM -0500, Tom Lendacky wrote:
>> On 6/4/2018 3:07 PM, Eduardo Habkost wrote:
>>> On Fri, Jun 01, 2018 at 11:38:08AM -0400, Konrad Rzeszutek Wilk wrote:
>>>> AMD future CPUs expose _two_ ways to utilize the Intel equivalant
>>>> of the Speculative Store Bypass Disable. The first is via
>>>> the virtualized VIRT_SPEC CTRL MSR (0xC001_011f) and the second
>>>> is via the SPEC_CTRL MSR (0x48). The document titled:
>>>> 124441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf
>>>>
>>>> gives priority of SPEC CTRL MSR over the VIRT SPEC CTRL MSR.
>>>>
>>>> A copy of this document is available at
>>>>   https://bugzilla.kernel.org/show_bug.cgi?id=199889
>>>>
>>>> Anyhow, this means that on future AMD CPUs there will be  _two_ ways to
>>>> deal with SSBD.
>>>
>>> Does anybody know if there are AMD CPUs where virt-ssbd won't
>>> work and would require amd-ssbd to mitigate vulnerabilities?
>>
>> The idea behind virt-ssbd was to provide an architectural method for
>> a guest to do SSBD when amd-ssbd isn't present.  The amd-ssbd feature
>> will use SPEC_CTRL which is intended to not be intercepted and
>> will be fast.  The use of virt-ssbd will always be intercepted and
>> therefore will not be as fast.  So a guest should be presented with
>> amd-ssbd, if available, in preference to virt-ssbd.
> 
> Can you clarify whether 'amd-ssbd' is also an architectural method

Yes, amd-ssbd is architectural - it is a defined CPUID bit.

Thanks,
Tom

> or not ?  ie is it safe to use 'amd-ssbd' in a guest which can be
> live migrated between different generations/families of AMD CPU,
> or must be use virt-ssbd in that case ?
> 
> 
> Regards,
> Daniel
> 



Re: [Qemu-devel] [PATCH 1/2] i386: define the AMD 'amd-ssbd' CPUID feature bit

2018-06-05 Thread Tom Lendacky
On 6/4/2018 3:07 PM, Eduardo Habkost wrote:
> On Fri, Jun 01, 2018 at 11:38:08AM -0400, Konrad Rzeszutek Wilk wrote:
>> AMD future CPUs expose _two_ ways to utilize the Intel equivalant
>> of the Speculative Store Bypass Disable. The first is via
>> the virtualized VIRT_SPEC CTRL MSR (0xC001_011f) and the second
>> is via the SPEC_CTRL MSR (0x48). The document titled:
>> 124441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf
>>
>> gives priority of SPEC CTRL MSR over the VIRT SPEC CTRL MSR.
>>
>> A copy of this document is available at
>>   https://bugzilla.kernel.org/show_bug.cgi?id=199889
>>
>> Anyhow, this means that on future AMD CPUs there will be  _two_ ways to
>> deal with SSBD.
> 
> Does anybody know if there are AMD CPUs where virt-ssbd won't
> work and would require amd-ssbd to mitigate vulnerabilities?

The idea behind virt-ssbd was to provide an architectural method for
a guest to do SSBD when amd-ssbd isn't present.  The amd-ssbd feature
will use SPEC_CTRL which is intended to not be intercepted and
will be fast.  The use of virt-ssbd will always be intercepted and
therefore will not be as fast.  So a guest should be presented with
amd-ssbd, if available, in preference to virt-ssbd.

Thanks,
Tom

> 
> Also, do we have kernel arch/x86/kvm/cpuid.c patches, already?
> I prefer to add new CPUID flag names only after the flag name is
> already agreed upon on the kernel side.
> 
> 
>>
>> Signed-off-by: Konrad Rzeszutek Wilk 
>> ---
>>  target/i386/cpu.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
>> index 52d334a..f91990c 100644
>> --- a/target/i386/cpu.c
>> +++ b/target/i386/cpu.c
>> @@ -490,7 +490,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] 
>> = {
>>  "ibpb", NULL, NULL, NULL,
>>  NULL, NULL, NULL, NULL,
>>  NULL, NULL, NULL, NULL,
>> -NULL, "virt-ssbd", NULL, NULL,
>> +"amd-ssbd", "virt-ssbd", NULL, NULL,
>>  NULL, NULL, NULL, NULL,
>>  },
>>  .cpuid_eax = 0x8008,
>> -- 
>> 1.8.3.1
>>
>>
> 



[Qemu-devel] Re: Network shutdown under load

2010-02-08 Thread Tom Lendacky

Fix a race condition where qemu finds that there are not enough virtio
ring buffers available and the guest make more buffers available before
qemu can enable notifications.

Signed-off-by: Tom Lendacky t...@us.ibm.com
Signed-off-by: Anthony Liguori aligu...@us.ibm.com

 hw/virtio-net.c |   10 +-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 6e48997..5c0093e 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -379,7 +379,15 @@ static int virtio_net_has_buffers(VirtIONet *n, int 
bufsize)
 (n-mergeable_rx_bufs 
  !virtqueue_avail_bytes(n-rx_vq, bufsize, 0))) {
 virtio_queue_set_notification(n-rx_vq, 1);
-return 0;
+
+/* To avoid a race condition where the guest has made some buffers
+ * available after the above check but before notification was
+ * enabled, check for available buffers again.
+ */
+if (virtio_queue_empty(n-rx_vq) ||
+(n-mergeable_rx_bufs 
+ !virtqueue_avail_bytes(n-rx_vq, bufsize, 0)))
+return 0;
 }
 
 virtio_queue_set_notification(n-rx_vq, 0);

On Friday 29 January 2010 02:06:41 pm Tom Lendacky wrote:
 There's been some discussion of this already in the kvm list, but I want to
 summarize what I've found and also include the qemu-devel list in an effort
  to find a solution to this problem.
 
 Running a netperf test between two kvm guests results in the guest's
  network interface shutting down. I originally found this using kvm guests
  on two different machines that were connected via a 10GbE link.  However,
  I found this problem can be easily reproduced using two guests on the same
  machine.
 
 I am running the 2.6.32 level of the kvm.git tree and the 0.12.1.2 level of
 the qemu-kvm.git tree.
 
 The setup includes two bridges, br0 and br1.
 
 The commands used to start the guests are as follows:
 usr/local/bin/qemu-system-x86_64 -name cape-vm001 -m 1024 -drive
 file=/autobench/var/tmp/cape-vm001-
 raw.img,if=virtio,index=0,media=disk,boot=on -net
 nic,model=virtio,vlan=0,macaddr=00:16:3E:00:62:51,netdev=cape-vm001-eth0 -
 netdev tap,id=cape-vm001-eth0,script=/autobench/var/tmp/ifup-kvm-
 br0,downscript=/autobench/var/tmp/ifdown-kvm-br0 -net
 nic,model=virtio,vlan=1,macaddr=00:16:3E:00:62:D1,netdev=cape-vm001-eth1 -
 netdev tap,id=cape-vm001-eth1,script=/autobench/var/tmp/ifup-kvm-
 br1,downscript=/autobench/var/tmp/ifdown-kvm-br1 -vnc :1 -monitor
 telnet::5701,server,nowait -snapshot -daemonize
 
 usr/local/bin/qemu-system-x86_64 -name cape-vm002 -m 1024 -drive
 file=/autobench/var/tmp/cape-vm002-
 raw.img,if=virtio,index=0,media=disk,boot=on -net
 nic,model=virtio,vlan=0,macaddr=00:16:3E:00:62:61,netdev=cape-vm002-eth0 -
 netdev tap,id=cape-vm002-eth0,script=/autobench/var/tmp/ifup-kvm-
 br0,downscript=/autobench/var/tmp/ifdown-kvm-br0 -net
 nic,model=virtio,vlan=1,macaddr=00:16:3E:00:62:E1,netdev=cape-vm002-eth1 -
 netdev tap,id=cape-vm002-eth1,script=/autobench/var/tmp/ifup-kvm-
 br1,downscript=/autobench/var/tmp/ifdown-kvm-br1 -vnc :2 -monitor
 telnet::5702,server,nowait -snapshot -daemonize
 
 The ifup-kvm-br0 script takes the (first) qemu created tap device and
  brings it up and adds it to bridge br0.  The ifup-kvm-br1 script take the
  (second) qemu created tap device and brings it up and adds it to bridge
  br1.
 
 Each ethernet device within a guest is on it's own subnet.  For example:
   guest 1 eth0 has addr 192.168.100.32 and eth1 has addr 192.168.101.32
   guest 2 eth0 has addr 192.168.100.64 and eth1 has addr 192.168.101.64
 
 On one of the guests run netserver:
   netserver -L 192.168.101.32 -p 12000
 
 On the other guest run netperf:
   netperf -L 192.168.101.64 -H 192.168.101.32 -p 12000 -t TCP_STREAM -l 60
  -c -C -- -m 16K -M 16K
 
 It may take more than one netperf run (I find that my second run almost
  always causes the shutdown) but the network on the eth1 links will stop
  working.
 
 I did some debugging and found that in qemu on the guest running netserver:
  - the receive_disabled variable is set and never gets reset
  - the read_poll event handler for the eth1 tap device is disabled and
  never re-enabled
 These conditions result in no packets being read from the tap device and
  sent to the guest - effectively shutting down the network.  Network
  connectivity can be restored by shutting down the guest interfaces,
  unloading the virtio_net module, re-loading the virtio_net module and
  re-starting the guest interfaces.
 
 I'm continuing to work on debugging this, but would appreciate if some
  folks with more qemu network experience could try to recreate and debug
  this.
 
 If my kernel config matters, I can provide that.
 
 Thanks,
 Tom
 --
 To unsubscribe from this list: send the line unsubscribe kvm in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html
 




[Qemu-devel] Network shutdown under load

2010-01-30 Thread Tom Lendacky

There's been some discussion of this already in the kvm list, but I want to 
summarize what I've found and also include the qemu-devel list in an effort to 
find a solution to this problem.

Running a netperf test between two kvm guests results in the guest's network 
interface shutting down. I originally found this using kvm guests on two 
different machines that were connected via a 10GbE link.  However, I found 
this problem can be easily reproduced using two guests on the same machine.

I am running the 2.6.32 level of the kvm.git tree and the 0.12.1.2 level of 
the qemu-kvm.git tree.

The setup includes two bridges, br0 and br1.

The commands used to start the guests are as follows:
usr/local/bin/qemu-system-x86_64 -name cape-vm001 -m 1024 -drive 
file=/autobench/var/tmp/cape-vm001-
raw.img,if=virtio,index=0,media=disk,boot=on -net 
nic,model=virtio,vlan=0,macaddr=00:16:3E:00:62:51,netdev=cape-vm001-eth0 -
netdev tap,id=cape-vm001-eth0,script=/autobench/var/tmp/ifup-kvm-
br0,downscript=/autobench/var/tmp/ifdown-kvm-br0 -net 
nic,model=virtio,vlan=1,macaddr=00:16:3E:00:62:D1,netdev=cape-vm001-eth1 -
netdev tap,id=cape-vm001-eth1,script=/autobench/var/tmp/ifup-kvm-
br1,downscript=/autobench/var/tmp/ifdown-kvm-br1 -vnc :1 -monitor 
telnet::5701,server,nowait -snapshot -daemonize

usr/local/bin/qemu-system-x86_64 -name cape-vm002 -m 1024 -drive 
file=/autobench/var/tmp/cape-vm002-
raw.img,if=virtio,index=0,media=disk,boot=on -net 
nic,model=virtio,vlan=0,macaddr=00:16:3E:00:62:61,netdev=cape-vm002-eth0 -
netdev tap,id=cape-vm002-eth0,script=/autobench/var/tmp/ifup-kvm-
br0,downscript=/autobench/var/tmp/ifdown-kvm-br0 -net 
nic,model=virtio,vlan=1,macaddr=00:16:3E:00:62:E1,netdev=cape-vm002-eth1 -
netdev tap,id=cape-vm002-eth1,script=/autobench/var/tmp/ifup-kvm-
br1,downscript=/autobench/var/tmp/ifdown-kvm-br1 -vnc :2 -monitor 
telnet::5702,server,nowait -snapshot -daemonize

The ifup-kvm-br0 script takes the (first) qemu created tap device and brings 
it up and adds it to bridge br0.  The ifup-kvm-br1 script take the (second) 
qemu created tap device and brings it up and adds it to bridge br1.

Each ethernet device within a guest is on it's own subnet.  For example:
  guest 1 eth0 has addr 192.168.100.32 and eth1 has addr 192.168.101.32
  guest 2 eth0 has addr 192.168.100.64 and eth1 has addr 192.168.101.64

On one of the guests run netserver:
  netserver -L 192.168.101.32 -p 12000

On the other guest run netperf:
  netperf -L 192.168.101.64 -H 192.168.101.32 -p 12000 -t TCP_STREAM -l 60 -c 
-C -- -m 16K -M 16K

It may take more than one netperf run (I find that my second run almost always 
causes the shutdown) but the network on the eth1 links will stop working.

I did some debugging and found that in qemu on the guest running netserver:
 - the receive_disabled variable is set and never gets reset
 - the read_poll event handler for the eth1 tap device is disabled and never 
re-enabled
These conditions result in no packets being read from the tap device and sent 
to the guest - effectively shutting down the network.  Network connectivity 
can be restored by shutting down the guest interfaces, unloading the 
virtio_net module, re-loading the virtio_net module and re-starting the guest 
interfaces.

I'm continuing to work on debugging this, but would appreciate if some folks 
with more qemu network experience could try to recreate and debug this.

If my kernel config matters, I can provide that.

Thanks,
Tom