[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v3 1/2] pc: add parser for OVMF reset block
From: |
Dr. David Alan Gilbert |
Subject: |
Re: [PATCH v3 1/2] pc: add parser for OVMF reset block |
Date: |
Thu, 4 Feb 2021 19:58:26 +0000 |
User-agent: |
Mutt/1.14.6 (2020-07-11) |
* James Bottomley (jejb@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 <jejb@linux.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@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 / dgilbert@redhat.com / Manchester, UK
- [PATCH v3 0/2] sev: enable secret injection to a self described area in OVMF, James Bottomley, 2021/02/04
- [PATCH v3 1/2] pc: add parser for OVMF reset block, James Bottomley, 2021/02/04
- Re: [PATCH v3 1/2] pc: add parser for OVMF reset block,
Dr. David Alan Gilbert <=
- [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, James Bottomley, 2021/02/04
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Dr. David Alan Gilbert, 2021/02/04
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Daniel P . Berrangé, 2021/02/05
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Paolo Bonzini, 2021/02/05
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Daniel P . Berrangé, 2021/02/05
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Paolo Bonzini, 2021/02/05
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Daniel P . Berrangé, 2021/02/05
- Re: [PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional, Dr. David Alan Gilbert, 2021/02/08
Re: [PATCH v3 0/2] sev: enable secret injection to a self described area in OVMF, Paolo Bonzini, 2021/02/05