cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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}