* James Bottomley (j...@linux.ibm.com) wrote: > OVMF is developing a mechanism for depositing a GUIDed table just > below the known location of the reset vector. The table goes > backwards in memory so all entries are of the form > > <data>|len|<GUID> > > Where <data> is arbtrary size and type, <len> is a uint16_t and > describes the entire length of the entry from the beginning of the > data to the end of the guid. > > The foot of the table is of this form and <len> for this case > describes the entire size of the table. The table foot GUID is > defined by OVMF as 96b582de-1fb2-45f7-baea-a366c55a082d and if the > table is present this GUID is just below the reset vector, 48 bytes > before the end of the firmware file. > > Add a parser for the ovmf reset block which takes a copy of the block, > if the table foot guid is found, minus the footer and a function for > later traversal to return the data area of any specified GUIDs. > > Signed-off-by: James Bottomley <j...@linux.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilb...@redhat.com> > > --- > > v2: fix brace warnings and return values > v3: add bounds checking for flash tables > --- > hw/i386/pc_sysfw.c | 112 +++++++++++++++++++++++++++++++++++++++++++ > include/hw/i386/pc.h | 4 ++ > 2 files changed, 116 insertions(+) > > diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c > index 92e90ff013..8ef73dbc3a 100644 > --- a/hw/i386/pc_sysfw.c > +++ b/hw/i386/pc_sysfw.c > @@ -124,6 +124,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, > @@ -195,6 +302,11 @@ 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); > + /* > + * OVMF places a GUIDed structures in the flash, so > + * search for them > + */ > + pc_system_parse_ovmf_flash(flash_ptr, flash_size); > ret = kvm_memcrypt_encrypt_data(flash_ptr, flash_size); > if (ret) { > error_report("failed to encrypt pflash rom"); > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h > index 2aa8797c6e..19a53f745f 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" > @@ -188,6 +189,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, > -- > 2.26.2 > -- Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK