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 "qemu/error-report.h" 28 #include "hw/i386/pc.h" 29 #include "exec/target_page.h" 30 #include "cpu.h" 31 32 #define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" 33 34 static const int bytes_after_table_footer = 32; 35 36 static bool ovmf_flash_parsed; 37 static uint8_t *ovmf_table; 38 static int ovmf_table_len; 39 40 void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) 41 { 42 uint8_t *ptr; 43 QemuUUID guid; 44 int tot_len; 45 46 /* should only be called once */ 47 if (ovmf_flash_parsed) { 48 return; 49 } 50 51 ovmf_flash_parsed = true; 52 53 if (flash_size < TARGET_PAGE_SIZE) { 54 return; 55 } 56 57 /* 58 * if this is OVMF there will be a table footer 59 * guid 48 bytes before the end of the flash file 60 * (= 32 bytes after the table + 16 bytes the GUID itself). 61 * If it's not found, silently abort the flash parsing. 62 */ 63 qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid); 64 guid = qemu_uuid_bswap(guid); /* guids are LE */ 65 ptr = flash_ptr + flash_size - (bytes_after_table_footer + sizeof(guid)); 66 if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) { 67 return; 68 } 69 70 /* if found, just before is two byte table length */ 71 ptr -= sizeof(uint16_t); 72 tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t); 73 74 if (tot_len < 0 || tot_len > (ptr - flash_ptr)) { 75 error_report("OVMF table has invalid size %d", tot_len); 76 return; 77 } 78 79 if (tot_len == 0) { 80 /* no entries in the OVMF table */ 81 return; 82 } 83 84 ovmf_table = g_malloc(tot_len); 85 ovmf_table_len = tot_len; 86 87 /* 88 * ptr is the foot of the table, so copy it all to the newly 89 * allocated ovmf_table and then set the ovmf_table pointer 90 * to the table foot 91 */ 92 memcpy(ovmf_table, ptr - tot_len, tot_len); 93 ovmf_table += tot_len; 94 } 95 96 /** 97 * pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's 98 * reset vector GUIDed table. 99 * 100 * @entry: GUID string of the entry to lookup 101 * @data: Filled with a pointer to the entry's value (if not NULL) 102 * @data_len: Filled with the length of the entry's value (if not NULL). Pass 103 * NULL here if the length of data is known. 104 * 105 * Return: true if the entry was found in the OVMF table; false otherwise. 106 */ 107 bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, 108 int *data_len) 109 { 110 uint8_t *ptr = ovmf_table; 111 int tot_len = ovmf_table_len; 112 QemuUUID entry_guid; 113 114 assert(ovmf_flash_parsed); 115 116 if (qemu_uuid_parse(entry, &entry_guid) < 0) { 117 return false; 118 } 119 120 if (!ptr) { 121 return false; 122 } 123 124 entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */ 125 while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) { 126 int len; 127 QemuUUID *guid; 128 129 /* 130 * The data structure is 131 * arbitrary length data 132 * 2 byte length of entire entry 133 * 16 byte guid 134 */ 135 guid = (QemuUUID *)(ptr - sizeof(QemuUUID)); 136 len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) - 137 sizeof(uint16_t))); 138 139 /* 140 * just in case the table is corrupt, wouldn't want to spin in 141 * the zero case 142 */ 143 if (len < sizeof(QemuUUID) + sizeof(uint16_t)) { 144 return false; 145 } else if (len > tot_len) { 146 return false; 147 } 148 149 ptr -= len; 150 tot_len -= len; 151 if (qemu_uuid_is_equal(guid, &entry_guid)) { 152 if (data) { 153 *data = ptr; 154 } 155 if (data_len) { 156 *data_len = len - sizeof(QemuUUID) - sizeof(uint16_t); 157 } 158 return true; 159 } 160 } 161 return false; 162 } 163