Merge tag 'firmware-20260203-pull-request' of https://gitlab.com/kraxel/qemu into staging

firmware updates for 11.0
- igvm: rework reset handling.
- igvm: add MADT parameter support.
- uefi: variable store fixes.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmmB5AYACgkQTLbY7tPo
# cThR7Q//d5Z9cIQEOn7hqAgsqyz4llvyLpZk+pWuyQmJ7iBtF7geP0p61iICi5vP
# +jyKJChHtPQzAQLqKwgHLWAuYSW82EZPh74YvL4MBNe7WX8LouHvCoTsOE28Nxqx
# EWDtucSwwwQpx/r1iSSHEHqjlV2MudlGFMaOb0+by57j2ZsAGEe/0J+yF07hhXLQ
# OxQY1l8gHC+PK6BnRLnwIlBVBe+o2E9hJeV0GA/zd1UufTxsan/r06T1JRsdNhPe
# vkBFedwPz+4+jKbOVWBp2pY5FSxmIEe+sOqRdhFvyvz+KBziAyisCNtv/eABrd9h
# Jk/yfvrDIZEJk7GtwMAC/un+zz/iQfu9BK3EAtT5OnUCEbj7HNaEjuStB2AnfBnw
# 4clhjPA+qwej1771zAuKC5HOc+2mMxbON/roD4nGcEY3WKq7JvjUrIopesJcgCCu
# TjV1UXAxyG6CRvsiUc3uesdleumAqt3I4+OryfnPY5SloYjlg+bEW8fpKvXmI82l
# uZsI1SL3yqXJMVQEh0cS7awquKKkjzNR0CGR+a9KBMl3kCiuAPPkevEhERpd1J6V
# W6zZrNI9IHczBKrZEJ42apXutGmADDZUdREjktc4gUBvTzC317bfSTGk/tvQQe7N
# lRr9KV+56bSVrnLiqcCzfVj8U2YTecsvO98Xp28W3nwwvIls3mQ=
# =npQG
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 03 Feb 2026 10:03:18 PM AEST
# gpg:                using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [unknown]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [unknown]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* tag 'firmware-20260203-pull-request' of https://gitlab.com/kraxel/qemu:
  igvm: Fill MADT IGVM parameter field on x86_64
  igvm: Only build stubs if igvm is enabled
  igvm: Pass machine state to IGVM file processing
  igvm: Refactor qigvm_parameter_insert
  igvm: Add common function for finding parameter entries
  igvm: Move structs to internal header
  hw/acpi: Add standalone function to build MADT
  hw/acpi: Make BIOS linker optional
  hw/acpi: Make acpi_checksum() public
  igvm: move igvm file processing to reset callbacks
  igvm: add trace points for igvm file loading and processing
  igvm: move file load to complete callback
  igvm: make igvm-cfg object resettable
  igvm: reorganize headers
  hw/uefi: fix size negotiation
  hw/uefi: skip time check for append-write updates.
  docs/system/igvm.rst: Update external links

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2026-02-04 01:56:55 +10:00
20 changed files with 362 additions and 189 deletions

View File

@@ -11,9 +11,15 @@
#include "qemu/osdep.h"
#include "system/igvm-cfg.h"
#include "system/igvm.h"
#include "system/igvm-cfg.h"
#include "system/igvm-internal.h"
#include "system/reset.h"
#include "qom/object_interfaces.h"
#include "hw/core/qdev.h"
#include "hw/core/boards.h"
#include "trace.h"
static char *get_igvm(Object *obj, Error **errp)
{
@@ -28,24 +34,78 @@ static void set_igvm(Object *obj, const char *value, Error **errp)
igvm->filename = g_strdup(value);
}
static ResettableState *igvm_reset_state(Object *obj)
{
IgvmCfg *igvm = IGVM_CFG(obj);
return &igvm->reset_state;
}
static void igvm_reset_enter(Object *obj, ResetType type)
{
trace_igvm_reset_enter(type);
}
static void igvm_reset_hold(Object *obj, ResetType type)
{
MachineState *ms = MACHINE(qdev_get_machine());
IgvmCfg *igvm = IGVM_CFG(obj);
trace_igvm_reset_hold(type);
qigvm_process_file(igvm, ms, false, &error_fatal);
}
static void igvm_reset_exit(Object *obj, ResetType type)
{
trace_igvm_reset_exit(type);
}
static void igvm_complete(UserCreatable *uc, Error **errp)
{
IgvmCfg *igvm = IGVM_CFG(uc);
igvm->file = qigvm_file_init(igvm->filename, errp);
}
OBJECT_DEFINE_TYPE_WITH_INTERFACES(IgvmCfg, igvm_cfg, IGVM_CFG, OBJECT,
{ TYPE_USER_CREATABLE }, { NULL })
{ TYPE_USER_CREATABLE },
{ TYPE_RESETTABLE_INTERFACE },
{ NULL })
static void igvm_cfg_class_init(ObjectClass *oc, const void *data)
{
IgvmCfgClass *igvmc = IGVM_CFG_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
UserCreatableClass *uc = USER_CREATABLE_CLASS(oc);
object_class_property_add_str(oc, "file", get_igvm, set_igvm);
object_class_property_set_description(oc, "file",
"Set the IGVM filename to use");
igvmc->process = qigvm_process_file;
rc->get_state = igvm_reset_state;
rc->phases.enter = igvm_reset_enter;
rc->phases.hold = igvm_reset_hold;
rc->phases.exit = igvm_reset_exit;
uc->complete = igvm_complete;
}
static void igvm_cfg_init(Object *obj)
{
IgvmCfg *igvm = IGVM_CFG(obj);
igvm->file = -1;
qemu_register_resettable(obj);
}
static void igvm_cfg_finalize(Object *obj)
{
IgvmCfg *igvm = IGVM_CFG(obj);
qemu_unregister_resettable(obj);
if (igvm->file >= 0) {
igvm_free(igvm->file);
}
}

View File

@@ -12,21 +12,20 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/target-info-qapi.h"
#include "system/igvm.h"
#include "system/igvm-cfg.h"
#include "system/igvm-internal.h"
#include "system/memory.h"
#include "system/address-spaces.h"
#include "hw/core/cpu.h"
#include "trace.h"
#include <igvm/igvm.h>
#include <igvm/igvm_defs.h>
typedef struct QIgvmParameterData {
QTAILQ_ENTRY(QIgvmParameterData) next;
uint8_t *data;
uint32_t size;
uint32_t index;
} QIgvmParameterData;
/*
* Some directives are specific to particular confidential computing platforms.
@@ -62,36 +61,19 @@ struct QEMU_PACKED sev_id_authentication {
#define IGVM_SEV_ID_BLOCK_VERSION 1
/*
* QIgvm contains the information required during processing
* of a single IGVM file.
*/
typedef struct QIgvm {
IgvmHandle file;
ConfidentialGuestSupport *cgs;
ConfidentialGuestSupportClass *cgsc;
uint32_t compatibility_mask;
unsigned current_header_index;
QTAILQ_HEAD(, QIgvmParameterData) parameter_data;
IgvmPlatformType platform_type;
/*
* SEV-SNP platforms can contain an ID block and authentication
* that should be verified by the guest.
*/
struct sev_id_block *id_block;
struct sev_id_authentication *id_auth;
/* Define the guest policy for SEV guests */
uint64_t sev_policy;
/* These variables keep track of contiguous page regions */
IGVM_VHS_PAGE_DATA region_prev_page_data;
uint64_t region_start;
unsigned region_start_index;
unsigned region_last_index;
unsigned region_page_count;
} QIgvm;
QIgvmParameterData*
qigvm_find_param_entry(QIgvm *igvm, uint32_t parameter_area_index)
{
QIgvmParameterData *param_entry;
QTAILQ_FOREACH(param_entry, &igvm->parameter_data, next)
{
if (param_entry->index == parameter_area_index) {
return param_entry;
}
}
warn_report("IGVM: No parameter area for index %u", parameter_area_index);
return NULL;
}
static int qigvm_directive_page_data(QIgvm *ctx, const uint8_t *header_data,
Error **errp);
@@ -146,6 +128,8 @@ static struct QIGVMHandler handlers[] = {
qigvm_directive_snp_id_block },
{ IGVM_VHT_GUEST_POLICY, IGVM_HEADER_SECTION_INITIALIZATION,
qigvm_initialization_guest_policy },
{ IGVM_VHT_MADT, IGVM_HEADER_SECTION_DIRECTIVE,
qigvm_directive_madt },
};
static int qigvm_handler(QIgvm *ctx, uint32_t type, Error **errp)
@@ -220,7 +204,8 @@ static void *qigvm_prepare_memory(QIgvm *ctx, uint64_t addr, uint64_t size,
g_autofree char *region_name =
g_strdup_printf("igvm.%X", region_identifier);
igvm_pages = g_new0(MemoryRegion, 1);
if (ctx->cgs && ctx->cgs->require_guest_memfd) {
if (ctx->machine_state->cgs &&
ctx->machine_state->cgs->require_guest_memfd) {
if (!memory_region_init_ram_guest_memfd(igvm_pages, NULL,
region_name, size, errp)) {
return NULL;
@@ -340,7 +325,7 @@ static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index,
* If a confidential guest support object is provided then use it to set the
* guest state.
*/
if (ctx->cgs) {
if (ctx->machine_state->cgs) {
cgs_page_type =
qigvm_type_to_cgs_type(page_type, flags->unmeasured, zero);
if (cgs_page_type < 0) {
@@ -442,7 +427,7 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
data = (uint8_t *)igvm_get_buffer(ctx->file, data_handle);
if (ctx->cgs) {
if (ctx->machine_state->cgs) {
result = ctx->cgsc->set_guest_state(
vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle),
CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp);
@@ -494,31 +479,31 @@ static int qigvm_directive_parameter_insert(QIgvm *ctx,
return 0;
}
QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
{
if (param_entry->index == param->parameter_area_index) {
region = qigvm_prepare_memory(ctx, param->gpa, param_entry->size,
ctx->current_header_index, errp);
if (!region) {
return -1;
}
memcpy(region, param_entry->data, param_entry->size);
g_free(param_entry->data);
param_entry->data = NULL;
param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
if (param_entry == NULL) {
return 0;
}
/*
* If a confidential guest support object is provided then use it to
* set the guest state.
*/
if (ctx->cgs) {
result = ctx->cgsc->set_guest_state(param->gpa, region,
param_entry->size,
CGS_PAGE_TYPE_UNMEASURED, 0,
errp);
if (result < 0) {
return -1;
}
}
region = qigvm_prepare_memory(ctx, param->gpa, param_entry->size,
ctx->current_header_index, errp);
if (!region) {
return -1;
}
memcpy(region, param_entry->data, param_entry->size);
g_free(param_entry->data);
param_entry->data = NULL;
/*
* If a confidential guest support object is provided then use it to
* set the guest state.
*/
if (ctx->machine_state->cgs) {
result = ctx->cgsc->set_guest_state(param->gpa, region,
param_entry->size,
CGS_PAGE_TYPE_UNMEASURED, 0,
errp);
if (result < 0) {
return -1;
}
}
return 0;
@@ -553,7 +538,7 @@ static int qigvm_directive_memory_map(QIgvm *ctx, const uint8_t *header_data,
ConfidentialGuestMemoryMapEntry cgmm_entry;
int retval = 0;
if (ctx->cgs && ctx->cgsc->get_mem_map_entry) {
if (ctx->machine_state->cgs && ctx->cgsc->get_mem_map_entry) {
get_mem_map_entry = ctx->cgsc->get_mem_map_entry;
} else if (target_arch() == SYS_EMU_TARGET_X86_64) {
@@ -567,58 +552,54 @@ static int qigvm_directive_memory_map(QIgvm *ctx, const uint8_t *header_data,
}
/* Find the parameter area that should hold the memory map */
QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
{
if (param_entry->index == param->parameter_area_index) {
max_entry_count =
param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY);
mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data;
param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
if (param_entry == NULL) {
return 0;
}
retval = get_mem_map_entry(entry, &cgmm_entry, errp);
while (retval == 0) {
if (entry >= max_entry_count) {
error_setg(
errp,
"IGVM: guest memory map size exceeds parameter area defined in IGVM file");
return -1;
}
mm_entry[entry].starting_gpa_page_number = cgmm_entry.gpa >> 12;
mm_entry[entry].number_of_pages = cgmm_entry.size >> 12;
max_entry_count = param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY);
mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data;
switch (cgmm_entry.type) {
case CGS_MEM_RAM:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_MEMORY;
break;
case CGS_MEM_RESERVED:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
break;
case CGS_MEM_ACPI:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
break;
case CGS_MEM_NVS:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PERSISTENT;
break;
case CGS_MEM_UNUSABLE:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
break;
}
retval = get_mem_map_entry(++entry, &cgmm_entry, errp);
}
if (retval < 0) {
return retval;
}
/* The entries need to be sorted */
qsort(mm_entry, entry, sizeof(IGVM_VHS_MEMORY_MAP_ENTRY),
qigvm_cmp_mm_entry);
retval = get_mem_map_entry(entry, &cgmm_entry, errp);
while (retval == 0) {
if (entry >= max_entry_count) {
error_setg(
errp,
"IGVM: guest memory map size exceeds parameter area defined "
"in IGVM file");
return -1;
}
mm_entry[entry].starting_gpa_page_number = cgmm_entry.gpa >> 12;
mm_entry[entry].number_of_pages = cgmm_entry.size >> 12;
switch (cgmm_entry.type) {
case CGS_MEM_RAM:
mm_entry[entry].entry_type = IGVM_MEMORY_MAP_ENTRY_TYPE_MEMORY;
break;
case CGS_MEM_RESERVED:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
break;
case CGS_MEM_ACPI:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
break;
case CGS_MEM_NVS:
mm_entry[entry].entry_type = IGVM_MEMORY_MAP_ENTRY_TYPE_PERSISTENT;
break;
case CGS_MEM_UNUSABLE:
mm_entry[entry].entry_type =
IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
break;
}
retval = get_mem_map_entry(++entry, &cgmm_entry, errp);
}
if (retval < 0) {
return retval;
}
/* The entries need to be sorted */
qsort(mm_entry, entry, sizeof(IGVM_VHS_MEMORY_MAP_ENTRY),
qigvm_cmp_mm_entry);
return 0;
}
@@ -630,18 +611,18 @@ static int qigvm_directive_vp_count(QIgvm *ctx, const uint8_t *header_data,
uint32_t *vp_count;
CPUState *cpu;
QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
{
if (param_entry->index == param->parameter_area_index) {
vp_count = (uint32_t *)(param_entry->data + param->byte_offset);
*vp_count = 0;
CPU_FOREACH(cpu)
{
(*vp_count)++;
}
break;
}
param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
if (param_entry == NULL) {
return 0;
}
vp_count = (uint32_t *)(param_entry->data + param->byte_offset);
*vp_count = 0;
CPU_FOREACH(cpu)
{
(*vp_count)++;
}
return 0;
}
@@ -653,15 +634,15 @@ static int qigvm_directive_environment_info(QIgvm *ctx,
QIgvmParameterData *param_entry;
IgvmEnvironmentInfo *environmental_state;
QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
{
if (param_entry->index == param->parameter_area_index) {
environmental_state =
(IgvmEnvironmentInfo *)(param_entry->data + param->byte_offset);
environmental_state->memory_is_shared = 1;
break;
}
param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
if (param_entry == NULL) {
return 0;
}
environmental_state =
(IgvmEnvironmentInfo *)(param_entry->data + param->byte_offset);
environmental_state->memory_is_shared = 1;
return 0;
}
@@ -683,7 +664,7 @@ static int qigvm_directive_required_memory(QIgvm *ctx,
if (!region) {
return -1;
}
if (ctx->cgs) {
if (ctx->machine_state->cgs) {
result =
ctx->cgsc->set_guest_state(mem->gpa, region, mem->number_of_bytes,
CGS_PAGE_TYPE_REQUIRED_MEMORY, 0, errp);
@@ -801,14 +782,14 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
sizeof(
IGVM_VHS_VARIABLE_HEADER));
if ((platform->platform_type == IGVM_PLATFORM_TYPE_SEV_ES) &&
ctx->cgs) {
ctx->machine_state->cgs) {
if (ctx->cgsc->check_support(
CGS_PLATFORM_SEV_ES, platform->platform_version,
platform->highest_vtl, platform->shared_gpa_boundary)) {
compatibility_mask_sev_es = platform->compatibility_mask;
}
} else if ((platform->platform_type == IGVM_PLATFORM_TYPE_SEV) &&
ctx->cgs) {
ctx->machine_state->cgs) {
if (ctx->cgsc->check_support(
CGS_PLATFORM_SEV, platform->platform_version,
platform->highest_vtl, platform->shared_gpa_boundary)) {
@@ -816,7 +797,7 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
}
} else if ((platform->platform_type ==
IGVM_PLATFORM_TYPE_SEV_SNP) &&
ctx->cgs) {
ctx->machine_state->cgs) {
if (ctx->cgsc->check_support(
CGS_PLATFORM_SEV_SNP, platform->platform_version,
platform->highest_vtl, platform->shared_gpa_boundary)) {
@@ -867,7 +848,7 @@ static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
return 0;
}
static IgvmHandle qigvm_file_init(char *filename, Error **errp)
IgvmHandle qigvm_file_init(char *filename, Error **errp)
{
IgvmHandle igvm;
g_autofree uint8_t *buf = NULL;
@@ -884,10 +865,12 @@ static IgvmHandle qigvm_file_init(char *filename, Error **errp)
error_setg(errp, "Unable to parse IGVM file %s: %d", filename, igvm);
return -1;
}
trace_igvm_file_loaded(filename, igvm);
return igvm;
}
int qigvm_process_file(IgvmCfg *cfg, ConfidentialGuestSupport *cgs,
int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state,
bool onlyVpContext, Error **errp)
{
int32_t header_count;
@@ -896,18 +879,23 @@ int qigvm_process_file(IgvmCfg *cfg, ConfidentialGuestSupport *cgs,
QIgvm ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.file = qigvm_file_init(cfg->filename, errp);
if (ctx.file < 0) {
if (cfg->file < 0) {
error_setg(errp, "No IGVM file loaded.");
return -1;
}
ctx.file = cfg->file;
trace_igvm_process_file(cfg->file, onlyVpContext);
ctx.machine_state = machine_state;
/*
* The ConfidentialGuestSupport object is optional and allows a confidential
* guest platform to perform extra processing, such as page measurement, on
* IGVM directives.
*/
ctx.cgs = cgs;
ctx.cgsc = cgs ? CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs) : NULL;
ctx.cgsc = machine_state->cgs ?
CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(machine_state->cgs) :
NULL;
/*
* Check that the IGVM file provides configuration for the current
@@ -990,7 +978,5 @@ cleanup_parameters:
g_free(ctx.id_auth);
cleanup:
igvm_free(ctx.file);
return retval;
}

View File

@@ -23,3 +23,10 @@ iommufd_backend_get_dirty_bitmap(int iommufd, uint32_t hwpt_id, uint64_t iova, u
iommufd_backend_invalidate_cache(int iommufd, uint32_t id, uint32_t data_type, uint32_t entry_len, uint32_t entry_num, uint32_t done_num, uint64_t data_ptr, int ret) " iommufd=%d id=%u data_type=%u entry_len=%u entry_num=%u done_num=%u data_ptr=0x%"PRIx64" (%d)"
iommufd_backend_alloc_viommu(int iommufd, uint32_t dev_id, uint32_t type, uint32_t hwpt_id, uint32_t viommu_id, int ret) " iommufd=%d type=%u dev_id=%u hwpt_id=%u viommu_id=%u (%d)"
iommufd_backend_alloc_vdev(int iommufd, uint32_t dev_id, uint32_t viommu_id, uint64_t virt_id, uint32_t vdev_id, int ret) " iommufd=%d dev_id=%u viommu_id=%u virt_id=0x%"PRIx64" vdev_id=%u (%d)"
# igvm-cfg.c
igvm_reset_enter(int type) "type=%u"
igvm_reset_hold(int type) "type=%u"
igvm_reset_exit(int type) "type=%u"
igvm_file_loaded(const char *fn, int32_t handle) "fn=%s, handle=0x%x"
igvm_process_file(int32_t handle, bool context_only) "handle=0x%x context-only=%d"

View File

@@ -166,8 +166,8 @@ References
----------
[1] AMD64 Architecture Programmer's Manual, Volume 2: System Programming
Rev 3.41
https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24593.pdf
Rev 3.43
https://docs.amd.com/v/u/en-US/24593_3.43
[2] ``buildigvm`` - A tool to build example IGVM files containing OVMF firmware
https://github.com/roy-hopkins/buildigvm
https://gitlab.com/qemu-project/buildigvm

View File

@@ -22,6 +22,7 @@
#include "qemu/osdep.h"
#include <glib/gprintf.h>
#include "hw/acpi/aml-build.h"
#include "hw/acpi/acpi.h"
#include "qemu/bswap.h"
#include "qemu/bitops.h"
#include "system/numa.h"
@@ -1741,6 +1742,7 @@ void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
uint32_t table_len = desc->array->len - desc->table_offset;
uint32_t table_len_le = cpu_to_le32(table_len);
gchar *len_ptr = &desc->array->data[desc->table_offset + 4];
uint8_t *table;
/* patch "Length" field that has been reserved by acpi_table_begin()
* to the actual length, i.e. accumulated table length from
@@ -1748,8 +1750,14 @@ void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
*/
memcpy(len_ptr, &table_len_le, sizeof table_len_le);
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
desc->table_offset, table_len, desc->table_offset + checksum_offset);
if (linker != NULL) {
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
desc->table_offset, table_len,
desc->table_offset + checksum_offset);
} else {
table = (uint8_t *) &desc->array->data[desc->table_offset];
table[checksum_offset] = acpi_checksum(table, table_len);
}
}
void *acpi_data_push(GArray *table_data, unsigned size)

View File

@@ -83,7 +83,10 @@ bool acpi_builtin(void)
return true;
}
static int acpi_checksum(const uint8_t *data, int len)
/* Calculate the ACPI checksum value so that if used in the corresponding
* header field, the ACPI checksum verification will be successful.
*/
int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;
sum = 0;

View File

@@ -2249,3 +2249,12 @@ void acpi_setup(void)
*/
acpi_build_tables_cleanup(&tables, false);
}
GArray *acpi_build_madt_standalone(MachineState *machine)
{
X86MachineState *x86ms = X86_MACHINE(machine);
GArray *table = g_array_new(false, true, 1);
acpi_build_madt(table, NULL, x86ms, x86ms->oem_id,
x86ms->oem_table_id);
return table;
}

View File

@@ -8,4 +8,6 @@ extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio;
void acpi_setup(void);
Object *acpi_get_i386_pci_host(void);
GArray *acpi_build_madt_standalone(MachineState *machine);
#endif

View File

@@ -320,16 +320,6 @@ static void pc_init1(MachineState *machine, const char *pci_type)
x86_nvdimm_acpi_dsmio,
x86ms->fw_cfg, OBJECT(pcms));
}
#if defined(CONFIG_IGVM)
/* Apply guest state from IGVM if supplied */
if (x86ms->igvm) {
if (IGVM_CFG_GET_CLASS(x86ms->igvm)
->process(x86ms->igvm, machine->cgs, false, &error_fatal) < 0) {
g_assert_not_reached();
}
}
#endif
}
typedef enum PCSouthBridgeOption {

View File

@@ -328,16 +328,6 @@ static void pc_q35_init(MachineState *machine)
x86_nvdimm_acpi_dsmio,
x86ms->fw_cfg, OBJECT(pcms));
}
#if defined(CONFIG_IGVM)
/* Apply guest state from IGVM if supplied */
if (x86ms->igvm) {
if (IGVM_CFG_GET_CLASS(x86ms->igvm)
->process(x86ms->igvm, machine->cgs, false, &error_fatal) < 0) {
g_assert_not_reached();
}
}
#endif
}
#define DEFINE_Q35_MACHINE(major, minor) \

View File

@@ -475,7 +475,8 @@ static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr,
goto rollback;
}
if (old_var && new_var) {
if (uefi_time_compare(&old_var->time, &new_var->time) > 0) {
if ((va->attributes & EFI_VARIABLE_APPEND_WRITE) == 0 &&
uefi_time_compare(&old_var->time, &new_var->time) > 0) {
trace_uefi_vars_security_violation("time check failed");
mvar->status = EFI_SECURITY_VIOLATION;
goto rollback;
@@ -592,7 +593,7 @@ uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr,
return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
}
ps->payload_size = uv->buf_size;
ps->payload_size = uv->buf_size - sizeof(*mhdr) - sizeof(*mvar);
mvar->status = EFI_SUCCESS;
return length;
}

View File

@@ -203,4 +203,7 @@ struct AcpiSlicOem {
};
int acpi_get_slic_oem(AcpiSlicOem *oem);
/* core.c */
int acpi_checksum(const uint8_t *data, int len);
#endif /* QEMU_HW_ACPI_H */

View File

@@ -55,6 +55,7 @@ typedef struct FWCfgState FWCfgState;
typedef struct HostMemoryBackend HostMemoryBackend;
typedef struct I2CBus I2CBus;
typedef struct I2SCodec I2SCodec;
typedef struct IgvmCfg IgvmCfg;
typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
typedef struct ISABus ISABus;
typedef struct ISADevice ISADevice;

View File

@@ -12,19 +12,10 @@
#ifndef QEMU_IGVM_CFG_H
#define QEMU_IGVM_CFG_H
#include "hw/core/boards.h"
#include "qemu/typedefs.h"
#include "qom/object.h"
typedef struct IgvmCfg {
ObjectClass parent_class;
/*
* filename: Filename that specifies a file that contains the configuration
* of the guest in Independent Guest Virtual Machine (IGVM)
* format.
*/
char *filename;
} IgvmCfg;
typedef struct IgvmCfgClass {
ObjectClass parent_class;
@@ -37,7 +28,7 @@ typedef struct IgvmCfgClass {
*
* Returns 0 for ok and -1 on error.
*/
int (*process)(IgvmCfg *cfg, ConfidentialGuestSupport *cgs,
int (*process)(IgvmCfg *cfg, MachineState *machine_state,
bool onlyVpContext, Error **errp);
} IgvmCfgClass;

View File

@@ -0,0 +1,82 @@
/*
* QEMU IGVM private data structures
*
* Everything which depends on igvm library headers goes here.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef QEMU_IGVM_INTERNAL_H
#define QEMU_IGVM_INTERNAL_H
#include "qemu/queue.h"
#include "qemu/typedefs.h"
#include "qom/object.h"
#include "hw/core/boards.h"
#include "hw/core/resettable.h"
#include "system/confidential-guest-support.h"
#include <igvm/igvm.h>
struct IgvmCfg {
ObjectClass parent_class;
/*
* filename: Filename that specifies a file that contains the configuration
* of the guest in Independent Guest Virtual Machine (IGVM)
* format.
*/
char *filename;
IgvmHandle file;
ResettableState reset_state;
};
typedef struct QIgvmParameterData {
QTAILQ_ENTRY(QIgvmParameterData) next;
uint8_t *data;
uint32_t size;
uint32_t index;
} QIgvmParameterData;
/*
* QIgvm contains the information required during processing of a single IGVM
* file.
*/
typedef struct QIgvm {
IgvmHandle file;
MachineState *machine_state;
ConfidentialGuestSupportClass *cgsc;
uint32_t compatibility_mask;
unsigned current_header_index;
QTAILQ_HEAD(, QIgvmParameterData) parameter_data;
IgvmPlatformType platform_type;
/*
* SEV-SNP platforms can contain an ID block and authentication
* that should be verified by the guest.
*/
struct sev_id_block *id_block;
struct sev_id_authentication *id_auth;
/* Define the guest policy for SEV guests */
uint64_t sev_policy;
/* These variables keep track of contiguous page regions */
IGVM_VHS_PAGE_DATA region_prev_page_data;
uint64_t region_start;
unsigned region_start_index;
unsigned region_last_index;
unsigned region_page_count;
} QIgvm;
IgvmHandle qigvm_file_init(char *filename, Error **errp);
QIgvmParameterData*
qigvm_find_param_entry(QIgvm *igvm, uint32_t parameter_area_index);
/*
* IGVM parameter handlers
*/
int qigvm_directive_madt(QIgvm *ctx, const uint8_t *header_data, Error **errp);
#endif

View File

@@ -12,12 +12,13 @@
#ifndef BACKENDS_IGVM_H
#define BACKENDS_IGVM_H
#include "hw/core/boards.h"
#include "qemu/typedefs.h"
#include "system/confidential-guest-support.h"
#include "system/igvm-cfg.h"
#include "qapi/error.h"
int qigvm_process_file(IgvmCfg *igvm, ConfidentialGuestSupport *cgs,
bool onlyVpContext, Error **errp);
int qigvm_process_file(IgvmCfg *igvm, MachineState *machine_state,
bool onlyVpContext, Error **errp);
/* x86 native */
int qigvm_x86_get_mem_map_entry(int index,

View File

@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "system/igvm.h"
#include "system/igvm-internal.h"
int qigvm_x86_get_mem_map_entry(int index,
ConfidentialGuestMemoryMapEntry *entry,
@@ -24,3 +25,8 @@ int qigvm_x86_set_vp_context(void *data, int index, Error **errp)
{
return -1;
}
int qigvm_directive_madt(QIgvm *ctx, const uint8_t *header_data, Error **errp)
{
return -1;
}

View File

@@ -71,7 +71,9 @@ if have_system
stub_ss.add(files('dump.c'))
stub_ss.add(files('cmos.c'))
stub_ss.add(files('fw_cfg.c'))
stub_ss.add(files('igvm.c'))
if igvm.found()
stub_ss.add(files('igvm.c'))
endif
stub_ss.add(files('target-get-monitor-def.c'))
stub_ss.add(files('target-monitor-defs.c'))
stub_ss.add(files('win32-kbd-hook.c'))

View File

@@ -13,7 +13,9 @@
#include "cpu.h"
#include "hw/i386/e820_memory_layout.h"
#include "hw/i386/acpi-build.h"
#include "system/igvm.h"
#include "system/igvm-internal.h"
struct IgvmNativeVpContextX64 {
uint64_t rax;
@@ -178,3 +180,33 @@ void qigvm_x86_bsp_reset(CPUX86State *env)
qigvm_x86_load_context(bsp_context, env);
}
/*
* Process MADT IGVM parameter
*/
int qigvm_directive_madt(QIgvm *ctx, const uint8_t *header_data, Error **errp)
{
const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
QIgvmParameterData *param_entry;
int result = 0;
/* Find the parameter area that should hold the MADT data */
param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
if (param_entry == NULL) {
return 0;
}
GArray *madt = acpi_build_madt_standalone(ctx->machine_state);
if (madt->len <= param_entry->size) {
memcpy(param_entry->data, madt->data, madt->len);
} else {
error_setg(
errp,
"IGVM: MADT size exceeds parameter area defined in IGVM file");
result = -1;
}
g_array_free(madt, true);
return result;
}

View File

@@ -1892,8 +1892,7 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
*/
if (x86machine->igvm) {
if (IGVM_CFG_GET_CLASS(x86machine->igvm)
->process(x86machine->igvm, machine->cgs, true, errp) ==
-1) {
->process(x86machine->igvm, machine, true, errp) == -1) {
return -1;
}
/*