qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

pc_sysfw_ovmf.c (4979B)


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