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