pc_sysfw_ovmf.c (5625B)
1/* 2 * QEMU PC System Firmware (OVMF specific) 3 * 4 * Copyright (c) 2003-2004 Fabrice Bellard 5 * Copyright (c) 2011-2012 Intel Corporation 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26#include "qemu/osdep.h" 27#include "hw/i386/pc.h" 28#include "cpu.h" 29 30#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" 31 32static bool ovmf_flash_parsed; 33static uint8_t *ovmf_table; 34static int ovmf_table_len; 35static OvmfSevMetadata *ovmf_sev_metadata_table; 36 37#define OVMF_SEV_META_DATA_GUID "dc886566-984a-4798-A75e-5585a7bf67cc" 38typedef struct __attribute__((__packed__)) OvmfSevMetadataOffset { 39 uint32_t offset; 40} OvmfSevMetadataOffset; 41 42static void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size) 43{ 44 OvmfSevMetadata *metadata; 45 OvmfSevMetadataOffset *data; 46 47 if (!pc_system_ovmf_table_find(OVMF_SEV_META_DATA_GUID, (uint8_t **)&data, 48 NULL)) { 49 return; 50 } 51 52 metadata = (OvmfSevMetadata *)(flash_ptr + flash_size - data->offset); 53 if (memcmp(metadata->signature, "ASEV", 4) != 0) { 54 return; 55 } 56 57 ovmf_sev_metadata_table = g_malloc(metadata->len); 58 memcpy(ovmf_sev_metadata_table, metadata, metadata->len); 59} 60 61void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) 62{ 63 uint8_t *ptr; 64 QemuUUID guid; 65 int tot_len; 66 67 /* should only be called once */ 68 if (ovmf_flash_parsed) { 69 return; 70 } 71 72 ovmf_flash_parsed = true; 73 74 if (flash_size < TARGET_PAGE_SIZE) { 75 return; 76 } 77 78 /* 79 * if this is OVMF there will be a table footer 80 * guid 48 bytes before the end of the flash file. If it's 81 * not found, silently abort the flash parsing. 82 */ 83 qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid); 84 guid = qemu_uuid_bswap(guid); /* guids are LE */ 85 ptr = flash_ptr + flash_size - 48; 86 if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) { 87 return; 88 } 89 90 /* if found, just before is two byte table length */ 91 ptr -= sizeof(uint16_t); 92 tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t); 93 94 if (tot_len <= 0) { 95 return; 96 } 97 98 ovmf_table = g_malloc(tot_len); 99 ovmf_table_len = tot_len; 100 101 /* 102 * ptr is the foot of the table, so copy it all to the newly 103 * allocated ovmf_table and then set the ovmf_table pointer 104 * to the table foot 105 */ 106 memcpy(ovmf_table, ptr - tot_len, tot_len); 107 ovmf_table += tot_len; 108 109 /* Copy the SEV metadata table (if exist) */ 110 pc_system_parse_sev_metadata(flash_ptr, flash_size); 111} 112 113/** 114 * pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's 115 * reset vector GUIDed table. 116 * 117 * @entry: GUID string of the entry to lookup 118 * @data: Filled with a pointer to the entry's value (if not NULL) 119 * @data_len: Filled with the length of the entry's value (if not NULL). Pass 120 * NULL here if the length of data is known. 121 * 122 * Return: true if the entry was found in the OVMF table; false otherwise. 123 */ 124bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, 125 int *data_len) 126{ 127 uint8_t *ptr = ovmf_table; 128 int tot_len = ovmf_table_len; 129 QemuUUID entry_guid; 130 131 assert(ovmf_flash_parsed); 132 133 if (qemu_uuid_parse(entry, &entry_guid) < 0) { 134 return false; 135 } 136 137 if (!ptr) { 138 return false; 139 } 140 141 entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */ 142 while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) { 143 int len; 144 QemuUUID *guid; 145 146 /* 147 * The data structure is 148 * arbitrary length data 149 * 2 byte length of entire entry 150 * 16 byte guid 151 */ 152 guid = (QemuUUID *)(ptr - sizeof(QemuUUID)); 153 len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) - 154 sizeof(uint16_t))); 155 156 /* 157 * just in case the table is corrupt, wouldn't want to spin in 158 * the zero case 159 */ 160 if (len < sizeof(QemuUUID) + sizeof(uint16_t)) { 161 return false; 162 } else if (len > tot_len) { 163 return false; 164 } 165 166 ptr -= len; 167 tot_len -= len; 168 if (qemu_uuid_is_equal(guid, &entry_guid)) { 169 if (data) { 170 *data = ptr; 171 } 172 if (data_len) { 173 *data_len = len - sizeof(QemuUUID) - sizeof(uint16_t); 174 } 175 return true; 176 } 177 } 178 return false; 179} 180 181OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void) 182{ 183 return ovmf_sev_metadata_table; 184}