mirror of
https://github.com/qemu/qemu.git
synced 2026-02-04 02:24:51 +00:00
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
268
backends/igvm.c
268
backends/igvm.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
82
include/system/igvm-internal.h
Normal file
82
include/system/igvm-internal.h
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user