Skip to content

Commit

Permalink
hw/i386: Introduce X86_FW_OVMF Kconfig symbol
Browse files Browse the repository at this point in the history
Introduce the X86_FW_OVMF Kconfig symbol for OVMF-specific code.
Move the OVMF-specific code from pc_sysfw.c to pc_sysfw_ovmf.c,
adding a pair of stubs.
Update MAINTAINERS to reach OVMF maintainers when these new
files are modified.

This fixes when building the microvm machine standalone:

  /usr/bin/ld: libqemu-i386-softmmu.fa.p/target_i386_monitor.c.o: in
  function `qmp_sev_inject_launch_secret':
  target/i386/monitor.c:749: undefined reference to `pc_system_ovmf_table_find'

Fixes: f522cef ("sev: update sev-inject-launch-secret to make gpa optional")
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20210616204328.2611406-22-philmd@redhat.com>
  • Loading branch information
philmd committed Jul 14, 2021
1 parent 2165542 commit b5b3186
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 123 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Expand Up @@ -2945,6 +2945,7 @@ EDK2 Firmware
M: Laszlo Ersek <lersek@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com>
S: Supported
F: hw/i386/*ovmf*
F: pc-bios/descriptors/??-edk2-*.json
F: pc-bios/edk2-*
F: roms/Makefile.edk2
Expand Down
4 changes: 4 additions & 0 deletions hw/i386/Kconfig
@@ -1,5 +1,9 @@
config X86_FW_OVMF
bool

config SEV
bool
select X86_FW_OVMF
depends on KVM

config PC
Expand Down
2 changes: 2 additions & 0 deletions hw/i386/meson.build
Expand Up @@ -24,6 +24,8 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files(
'pc_sysfw.c',
'acpi-build.c',
'port92.c'))
i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
if_false: files('pc_sysfw_ovmf-stubs.c'))

subdir('kvm')
subdir('xen')
Expand Down
123 changes: 0 additions & 123 deletions hw/i386/pc_sysfw.c
Expand Up @@ -124,129 +124,6 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms)
}
}

#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"

static bool ovmf_flash_parsed;
static uint8_t *ovmf_table;
static int ovmf_table_len;

static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
{
uint8_t *ptr;
QemuUUID guid;
int tot_len;

/* should only be called once */
if (ovmf_flash_parsed) {
return;
}

ovmf_flash_parsed = true;

if (flash_size < TARGET_PAGE_SIZE) {
return;
}

/*
* if this is OVMF there will be a table footer
* guid 48 bytes before the end of the flash file. If it's
* not found, silently abort the flash parsing.
*/
qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid);
guid = qemu_uuid_bswap(guid); /* guids are LE */
ptr = flash_ptr + flash_size - 48;
if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) {
return;
}

/* if found, just before is two byte table length */
ptr -= sizeof(uint16_t);
tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t);

if (tot_len <= 0) {
return;
}

ovmf_table = g_malloc(tot_len);
ovmf_table_len = tot_len;

/*
* ptr is the foot of the table, so copy it all to the newly
* allocated ovmf_table and then set the ovmf_table pointer
* to the table foot
*/
memcpy(ovmf_table, ptr - tot_len, tot_len);
ovmf_table += tot_len;
}

/**
* pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's
* reset vector GUIDed table.
*
* @entry: GUID string of the entry to lookup
* @data: Filled with a pointer to the entry's value (if not NULL)
* @data_len: Filled with the length of the entry's value (if not NULL). Pass
* NULL here if the length of data is known.
*
* Return: true if the entry was found in the OVMF table; false otherwise.
*/
bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
int *data_len)
{
uint8_t *ptr = ovmf_table;
int tot_len = ovmf_table_len;
QemuUUID entry_guid;

assert(ovmf_flash_parsed);

if (qemu_uuid_parse(entry, &entry_guid) < 0) {
return false;
}

if (!ptr) {
return false;
}

entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */
while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) {
int len;
QemuUUID *guid;

/*
* The data structure is
* arbitrary length data
* 2 byte length of entire entry
* 16 byte guid
*/
guid = (QemuUUID *)(ptr - sizeof(QemuUUID));
len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) -
sizeof(uint16_t)));

/*
* just in case the table is corrupt, wouldn't want to spin in
* the zero case
*/
if (len < sizeof(QemuUUID) + sizeof(uint16_t)) {
return false;
} else if (len > tot_len) {
return false;
}

ptr -= len;
tot_len -= len;
if (qemu_uuid_is_equal(guid, &entry_guid)) {
if (data) {
*data = ptr;
}
if (data_len) {
*data_len = len - sizeof(QemuUUID) - sizeof(uint16_t);
}
return true;
}
}
return false;
}

/*
* Map the pcms->flash[] from 4GiB downward, and realize.
* Map them in descending order, i.e. pcms->flash[0] at the top,
Expand Down
26 changes: 26 additions & 0 deletions hw/i386/pc_sysfw_ovmf-stubs.c
@@ -0,0 +1,26 @@
/*
* QEMU PC System Firmware (OVMF stubs)
*
* Copyright (c) 2021 Red Hat, Inc.
*
* Author:
* Philippe Mathieu-Daudé <philmd@redhat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/

#include "qemu/osdep.h"
#include "hw/i386/pc.h"

bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, int *data_len)
{
g_assert_not_reached();
}

void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
{
g_assert_not_reached();
}
151 changes: 151 additions & 0 deletions hw/i386/pc_sysfw_ovmf.c
@@ -0,0 +1,151 @@
/*
* QEMU PC System Firmware (OVMF specific)
*
* Copyright (c) 2003-2004 Fabrice Bellard
* Copyright (c) 2011-2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "cpu.h"

#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"

static bool ovmf_flash_parsed;
static uint8_t *ovmf_table;
static int ovmf_table_len;

void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
{
uint8_t *ptr;
QemuUUID guid;
int tot_len;

/* should only be called once */
if (ovmf_flash_parsed) {
return;
}

ovmf_flash_parsed = true;

if (flash_size < TARGET_PAGE_SIZE) {
return;
}

/*
* if this is OVMF there will be a table footer
* guid 48 bytes before the end of the flash file. If it's
* not found, silently abort the flash parsing.
*/
qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid);
guid = qemu_uuid_bswap(guid); /* guids are LE */
ptr = flash_ptr + flash_size - 48;
if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) {
return;
}

/* if found, just before is two byte table length */
ptr -= sizeof(uint16_t);
tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t);

if (tot_len <= 0) {
return;
}

ovmf_table = g_malloc(tot_len);
ovmf_table_len = tot_len;

/*
* ptr is the foot of the table, so copy it all to the newly
* allocated ovmf_table and then set the ovmf_table pointer
* to the table foot
*/
memcpy(ovmf_table, ptr - tot_len, tot_len);
ovmf_table += tot_len;
}

/**
* pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's
* reset vector GUIDed table.
*
* @entry: GUID string of the entry to lookup
* @data: Filled with a pointer to the entry's value (if not NULL)
* @data_len: Filled with the length of the entry's value (if not NULL). Pass
* NULL here if the length of data is known.
*
* Return: true if the entry was found in the OVMF table; false otherwise.
*/
bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
int *data_len)
{
uint8_t *ptr = ovmf_table;
int tot_len = ovmf_table_len;
QemuUUID entry_guid;

assert(ovmf_flash_parsed);

if (qemu_uuid_parse(entry, &entry_guid) < 0) {
return false;
}

if (!ptr) {
return false;
}

entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */
while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) {
int len;
QemuUUID *guid;

/*
* The data structure is
* arbitrary length data
* 2 byte length of entire entry
* 16 byte guid
*/
guid = (QemuUUID *)(ptr - sizeof(QemuUUID));
len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) -
sizeof(uint16_t)));

/*
* just in case the table is corrupt, wouldn't want to spin in
* the zero case
*/
if (len < sizeof(QemuUUID) + sizeof(uint16_t)) {
return false;
} else if (len > tot_len) {
return false;
}

ptr -= len;
tot_len -= len;
if (qemu_uuid_is_equal(guid, &entry_guid)) {
if (data) {
*data = ptr;
}
if (data_len) {
*data_len = len - sizeof(QemuUUID) - sizeof(uint16_t);
}
return true;
}
}
return false;
}
1 change: 1 addition & 0 deletions include/hw/i386/pc.h
Expand Up @@ -188,6 +188,7 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms);
void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory);
bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
int *data_len);
void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size);


/* acpi-build.c */
Expand Down

0 comments on commit b5b3186

Please sign in to comment.