summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hw/i386/pc_sysfw.c122
-rw-r--r--include/hw/i386/pc.h4
-rw-r--r--include/sysemu/sev.h1
-rw-r--r--target/i386/sev_i386.h1
4 files changed, 123 insertions, 5 deletions
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 11172214f1..6404b5a86f 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -125,6 +125,113 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms)
}
}
+#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
+
+static uint8_t *ovmf_table;
+static int ovmf_table_len;
+
+static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
+{
+ uint8_t *ptr;
+ QemuUUID guid;
+ int tot_len;
+
+ /* should only be called once */
+ if (ovmf_table) {
+ return;
+ }
+
+ if (flash_size < TARGET_PAGE_SIZE) {
+ return;
+ }
+
+ /*
+ * if this is OVMF there will be a table footer
+ * guid 48 bytes before the end of the flash file. If it's
+ * not found, silently abort the flash parsing.
+ */
+ qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid);
+ guid = qemu_uuid_bswap(guid); /* guids are LE */
+ ptr = flash_ptr + flash_size - 48;
+ if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) {
+ return;
+ }
+
+ /* if found, just before is two byte table length */
+ ptr -= sizeof(uint16_t);
+ tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t);
+
+ if (tot_len <= 0) {
+ return;
+ }
+
+ ovmf_table = g_malloc(tot_len);
+ ovmf_table_len = tot_len;
+
+ /*
+ * ptr is the foot of the table, so copy it all to the newly
+ * allocated ovmf_table and then set the ovmf_table pointer
+ * to the table foot
+ */
+ memcpy(ovmf_table, ptr - tot_len, tot_len);
+ ovmf_table += tot_len;
+}
+
+bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
+ int *data_len)
+{
+ uint8_t *ptr = ovmf_table;
+ int tot_len = ovmf_table_len;
+ QemuUUID entry_guid;
+
+ if (qemu_uuid_parse(entry, &entry_guid) < 0) {
+ return false;
+ }
+
+ if (!ptr) {
+ return false;
+ }
+
+ entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */
+ while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) {
+ int len;
+ QemuUUID *guid;
+
+ /*
+ * The data structure is
+ * arbitrary length data
+ * 2 byte length of entire entry
+ * 16 byte guid
+ */
+ guid = (QemuUUID *)(ptr - sizeof(QemuUUID));
+ len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) -
+ sizeof(uint16_t)));
+
+ /*
+ * just in case the table is corrupt, wouldn't want to spin in
+ * the zero case
+ */
+ if (len < sizeof(QemuUUID) + sizeof(uint16_t)) {
+ return false;
+ } else if (len > tot_len) {
+ return false;
+ }
+
+ ptr -= len;
+ tot_len -= len;
+ if (qemu_uuid_is_equal(guid, &entry_guid)) {
+ if (data) {
+ *data = ptr;
+ }
+ if (data_len) {
+ *data_len = len - sizeof(QemuUUID) - sizeof(uint16_t);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* Map the pcms->flash[] from 4GiB downward, and realize.
* Map them in descending order, i.e. pcms->flash[0] at the top,
@@ -192,10 +299,17 @@ static void pc_system_flash_map(PCMachineState *pcms,
flash_mem = pflash_cfi01_get_memory(system_flash);
pc_isa_bios_init(rom_memory, flash_mem, size);
- /* Encrypt the pflash boot ROM, if necessary */
- flash_ptr = memory_region_get_ram_ptr(flash_mem);
- flash_size = memory_region_size(flash_mem);
- sev_encrypt_flash(flash_ptr, flash_size, &error_fatal);
+ /* Encrypt the pflash boot ROM */
+ if (sev_enabled()) {
+ flash_ptr = memory_region_get_ram_ptr(flash_mem);
+ flash_size = memory_region_size(flash_mem);
+ /*
+ * OVMF places a GUIDed structures in the flash, so
+ * search for them
+ */
+ pc_system_parse_ovmf_flash(flash_ptr, flash_size);
+ sev_encrypt_flash(flash_ptr, flash_size, &error_fatal);
+ }
}
}
}
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 5f93540a43..c9d194a5e7 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -3,6 +3,7 @@
#include "qemu/notify.h"
#include "qapi/qapi-types-common.h"
+#include "qemu/uuid.h"
#include "hw/boards.h"
#include "hw/block/fdc.h"
#include "hw/block/flash.h"
@@ -191,6 +192,9 @@ ISADevice *pc_find_fdc0(void);
void pc_system_flash_create(PCMachineState *pcms);
void pc_system_flash_cleanup_unused(PCMachineState *pcms);
void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory);
+bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
+ int *data_len);
+
/* acpi-build.c */
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
index 5c5a13c6ca..882e8a4fb1 100644
--- a/include/sysemu/sev.h
+++ b/include/sysemu/sev.h
@@ -16,6 +16,7 @@
#include "sysemu/kvm.h"
+bool sev_enabled(void);
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp);
int sev_inject_launch_secret(const char *hdr, const char *secret,
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 4db6960f60..bd9f00a908 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -28,7 +28,6 @@
#define SEV_POLICY_DOMAIN 0x10
#define SEV_POLICY_SEV 0x20
-extern bool sev_enabled(void);
extern uint64_t sev_get_me_mask(void);
extern SevInfo *sev_get_info(void);
extern uint32_t sev_get_cbit_position(void);