* [PATCH v5 1/6] hw/acpi: Make BIOS linker optional
2026-01-27 9:59 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
@ 2026-01-27 9:59 ` Oliver Steffen
0 siblings, 0 replies; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 9:59 UTC (permalink / raw)
To: qemu-devel
Cc: Ani Sinha, Eduardo Habkost, Stefano Garzarella, Igor Mammedov,
Richard Henderson, Gerd Hoffmann, Paolo Bonzini, Luigi Leonardi,
Joerg Roedel, Michael S. Tsirkin, Marcelo Tosatti,
Marcel Apfelbaum, Zhao Liu, kvm, Oliver Steffen
Make the BIOS linker optional in acpi_table_end() and calculate the ACPI
table checksum directly if no linker is provided.
This makes it possible to call for example
acpi_build_madt() from outside the ACPI table builder context.
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
hw/acpi/aml-build.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index dad4cfcc7d..6a3650076f 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1730,6 +1730,25 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
build_append_int_noprefix(array, 1, 4); /* Creator Revision */
}
+static uint8_t calculate_acpi_checksum(const gchar *data, size_t len)
+{
+ size_t i;
+ uint8_t sum = 0;
+
+ for (i = 0; i < len; ++i) {
+ sum += (uint8_t)data[i];
+ }
+
+ return sum;
+}
+
+static void update_acpi_checksum(gchar *data, size_t start_offset,
+ size_t table_len, size_t checksum_offset)
+{
+ uint8_t sum = calculate_acpi_checksum(&data[start_offset], table_len);
+ data[checksum_offset] = 0xff - sum + 1;
+}
+
void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
{
/*
@@ -1748,8 +1767,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 {
+ update_acpi_checksum(desc->array->data, desc->table_offset,
+ table_len, desc->table_offset + checksum_offset);
+ }
}
void *acpi_data_push(GArray *table_data, unsigned size)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 1/6] hw/acpi: Make BIOS linker optional
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
0 siblings, 0 replies; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Ani Sinha, Igor Mammedov, Marcelo Tosatti, Eduardo Habkost,
Zhao Liu, Stefano Garzarella, Marcel Apfelbaum, Luigi Leonardi,
Joerg Roedel, kvm, Paolo Bonzini, Michael S. Tsirkin,
Gerd Hoffmann, Richard Henderson, Oliver Steffen
Make the BIOS linker optional in acpi_table_end() and calculate the ACPI
table checksum directly if no linker is provided.
This makes it possible to call for example
acpi_build_madt() from outside the ACPI table builder context.
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
hw/acpi/aml-build.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index dad4cfcc7d..6a3650076f 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1730,6 +1730,25 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
build_append_int_noprefix(array, 1, 4); /* Creator Revision */
}
+static uint8_t calculate_acpi_checksum(const gchar *data, size_t len)
+{
+ size_t i;
+ uint8_t sum = 0;
+
+ for (i = 0; i < len; ++i) {
+ sum += (uint8_t)data[i];
+ }
+
+ return sum;
+}
+
+static void update_acpi_checksum(gchar *data, size_t start_offset,
+ size_t table_len, size_t checksum_offset)
+{
+ uint8_t sum = calculate_acpi_checksum(&data[start_offset], table_len);
+ data[checksum_offset] = 0xff - sum + 1;
+}
+
void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
{
/*
@@ -1748,8 +1767,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 {
+ update_acpi_checksum(desc->array->data, desc->table_offset,
+ table_len, desc->table_offset + checksum_offset);
+ }
}
void *acpi_data_push(GArray *table_data, unsigned size)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter
@ 2026-01-27 10:02 Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
When launching using an IGVM file, supply a copy of the MADT (part of the ACPI
tables) via an IGVM parameter (IGVM_VHY_MADT) to the guest, in addition to the
regular fw_cfg mechanism.
The IGVM parameter can be consumed by Coconut SVSM [1], instead of relying on
the fw_cfg interface, which has caused problems before due to unexpected access
[2,3]. Using IGVM parameters is the default way for Coconut SVSM; switching
over would allow removing specialized code paths for QEMU in Coconut.
Coconut SVSM needs to know the SMP configuration, but does not look at
any other ACPI data, nor does it interact with the PCI bus settings.
Since the MADT is static and not linked with other ACPI tables, it can
be supplied stand-alone like this.
Generating the MADT twice (IGVM processing and ACPI table building) seems
acceptable, since there is no infrastructure to obtain the MADT out of the ACPI
table memory area during IGVM processing.
In any case OVMF, which runs after SVSM has already been initialized, will
continue reading all ACPI tables via fw_cfg and provide fixed up ACPI data to
the OS as before.
This series makes ACPI table building more generic by making the BIOS linker
optional. This allows the MADT to be generated outside of the ACPI build
context. A new function (acpi_build_madt_standalone()) is added for that. With
that, the IGVM MADT parameter field can be filled with the MADT data during
processing of the IGVM file.
[1] https://github.com/coconut-svsm/svsm/pull/858
[2] https://gitlab.com/qemu-project/qemu/-/issues/2882
[3] https://github.com/coconut-svsm/svsm/issues/646
v5:
- Rebase on latest IGVM rework series from Gerd
- Make qigvm_find_parameter_entry() more generic and use everywhere possible;
It now takes the index as input, instead of the full parameter struct
- Consistently use early returns when looking up parameter entries
- Emit a warning message if no parameter area can be found for a given index
v4:
- Add ACPI table checksum calculation without BIOS linker, used
for the standalone MADT.
- Don't pass ConfidentialGuestState into the IGVM backend anymore.
Not needed, since we already have the full MachineState there now.
- Move the NULL check patch out into a new series (to be posted).
- Address remaining cleanup comments.
v3:
- Pass the machine state into IGVM file processing context instead of MADT data
- Generate MADT from inside the IGVM backend
- Refactor: Extract common code for finding IGVM parameter from IGVM parameter handlers
- Add NULL pointer check for igvm_get_buffer()
v2:
- Provide more context in the message of the main commit
- Document the MADT parameter of IgvmCfgClass::process()
- Document why no MADT data is provided the process call in sev.c
Based-on: <20260126123755.357378-1-kraxel@redhat.com>
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
Oliver Steffen (6):
hw/acpi: Make BIOS linker optional
hw/acpi: Add standalone function to build MADT
igvm: Add common function for finding parameter entries
igvm: Refactor qigvm_parameter_insert
igvm: Pass machine state to IGVM file processing
igvm: Fill MADT IGVM parameter field
backends/igvm-cfg.c | 2 +-
backends/igvm.c | 255 +++++++++++++++++++++++---------------
hw/acpi/aml-build.c | 29 ++++-
hw/i386/acpi-build.c | 9 ++
hw/i386/acpi-build.h | 2 +
include/system/igvm-cfg.h | 3 +-
include/system/igvm.h | 5 +-
target/i386/sev.c | 3 +-
8 files changed, 197 insertions(+), 111 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v5 1/6] hw/acpi: Make BIOS linker optional
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
2026-01-29 10:51 ` Luigi Leonardi
2026-01-27 10:02 ` [PATCH v5 2/6] hw/acpi: Add standalone function to build MADT Oliver Steffen
` (4 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
Make the BIOS linker optional in acpi_table_end() and calculate the ACPI
table checksum directly if no linker is provided.
This makes it possible to call for example
acpi_build_madt() from outside the ACPI table builder context.
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
hw/acpi/aml-build.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index dad4cfcc7d..6a3650076f 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1730,6 +1730,25 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
build_append_int_noprefix(array, 1, 4); /* Creator Revision */
}
+static uint8_t calculate_acpi_checksum(const gchar *data, size_t len)
+{
+ size_t i;
+ uint8_t sum = 0;
+
+ for (i = 0; i < len; ++i) {
+ sum += (uint8_t)data[i];
+ }
+
+ return sum;
+}
+
+static void update_acpi_checksum(gchar *data, size_t start_offset,
+ size_t table_len, size_t checksum_offset)
+{
+ uint8_t sum = calculate_acpi_checksum(&data[start_offset], table_len);
+ data[checksum_offset] = 0xff - sum + 1;
+}
+
void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
{
/*
@@ -1748,8 +1767,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 {
+ update_acpi_checksum(desc->array->data, desc->table_offset,
+ table_len, desc->table_offset + checksum_offset);
+ }
}
void *acpi_data_push(GArray *table_data, unsigned size)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 2/6] hw/acpi: Add standalone function to build MADT
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 3/6] igvm: Add common function for finding parameter entries Oliver Steffen
` (3 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
Add a fuction called `acpi_build_madt_standalone()` that builds a MADT
without the rest of the ACPI table structure.
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
hw/i386/acpi-build.c | 9 +++++++++
hw/i386/acpi-build.h | 2 ++
2 files changed, 11 insertions(+)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 9446a9f862..19c62362e3 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -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;
+}
diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h
index 8ba3c33e48..00e19bbe5e 100644
--- a/hw/i386/acpi-build.h
+++ b/hw/i386/acpi-build.h
@@ -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
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 3/6] igvm: Add common function for finding parameter entries
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 2/6] hw/acpi: Add standalone function to build MADT Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
2026-01-29 11:09 ` Luigi Leonardi
2026-01-27 10:02 ` [PATCH v5 4/6] igvm: Refactor qigvm_parameter_insert Oliver Steffen
` (2 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
Move repeating code for finding the parameter entries in the IGVM
backend out of the parameter handlers into a common function.
A warning message is emitted in case a no parameter entry can be found
for a given index.
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
backends/igvm.c | 143 ++++++++++++++++++++++++++----------------------
1 file changed, 77 insertions(+), 66 deletions(-)
diff --git a/backends/igvm.c b/backends/igvm.c
index 4cf7b57234..213c9d337e 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -12,6 +12,7 @@
#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"
@@ -97,6 +98,20 @@ typedef struct QIgvm {
unsigned region_page_count;
} QIgvm;
+static 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);
static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
@@ -571,58 +586,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;
-
- 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);
+ param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
+ if (param_entry == NULL) {
+ return 0;
+ }
+
+ max_entry_count = param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY);
+ mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data;
+
+ 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;
}
@@ -634,18 +645,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)
+ 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)
{
- 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;
- }
+ (*vp_count)++;
}
+
return 0;
}
@@ -657,15 +668,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;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 4/6] igvm: Refactor qigvm_parameter_insert
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
` (2 preceding siblings ...)
2026-01-27 10:02 ` [PATCH v5 3/6] igvm: Add common function for finding parameter entries Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
2026-01-29 11:10 ` Luigi Leonardi
2026-01-27 10:02 ` [PATCH v5 5/6] igvm: Pass machine state to IGVM file processing Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 6/6] igvm: Fill MADT IGVM parameter field Oliver Steffen
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
Use qigvm_find_param_entry() also in qigvm_parameter_insert().
This changes behavior: Processing now stops after the first parameter
entry found. That is OK, because we expect only one matching entry
anyway.
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
backends/igvm.c | 50 ++++++++++++++++++++++++-------------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/backends/igvm.c b/backends/igvm.c
index 213c9d337e..0a0092fb55 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -513,31 +513,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;
-
- /*
- * 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;
- }
- }
+ param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
+ if (param_entry == NULL) {
+ return 0;
+ }
+
+ 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->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;
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 5/6] igvm: Pass machine state to IGVM file processing
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
` (3 preceding siblings ...)
2026-01-27 10:02 ` [PATCH v5 4/6] igvm: Refactor qigvm_parameter_insert Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 6/6] igvm: Fill MADT IGVM parameter field Oliver Steffen
5 siblings, 0 replies; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
Pass the full MachineState to the IGVM backend during file processing,
instead of just the ConfidentialGuestSupport struct (which is a member
of the MachineState).
This replaces the cgs parameter of qigvm_process_file() with the machine
state to make it available in the IGVM processing context.
We will use it later to generate MADT data there to pass to the guest
as IGVM parameter.
Reviewed-by: Luigi Leonardi <leonardi@redhat.com>
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
backends/igvm-cfg.c | 2 +-
backends/igvm.c | 31 ++++++++++++++++++-------------
include/system/igvm-cfg.h | 3 ++-
include/system/igvm.h | 5 +++--
target/i386/sev.c | 3 +--
5 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/backends/igvm-cfg.c b/backends/igvm-cfg.c
index f236b523df..64589ca34f 100644
--- a/backends/igvm-cfg.c
+++ b/backends/igvm-cfg.c
@@ -52,7 +52,7 @@ static void igvm_reset_hold(Object *obj, ResetType type)
trace_igvm_reset_hold(type);
- qigvm_process_file(igvm, ms->cgs, false, &error_fatal);
+ qigvm_process_file(igvm, ms, false, &error_fatal);
}
static void igvm_reset_exit(Object *obj, ResetType type)
diff --git a/backends/igvm.c b/backends/igvm.c
index 0a0092fb55..f26eb633f8 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -11,6 +11,7 @@
#include "qemu/osdep.h"
+#include "hw/core/boards.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/target-info-qapi.h"
@@ -73,7 +74,7 @@ struct QEMU_PACKED sev_id_authentication {
*/
typedef struct QIgvm {
IgvmHandle file;
- ConfidentialGuestSupport *cgs;
+ MachineState *machine_state;
ConfidentialGuestSupportClass *cgsc;
uint32_t compatibility_mask;
unsigned current_header_index;
@@ -239,7 +240,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;
@@ -359,7 +361,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) {
@@ -461,7 +463,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);
@@ -531,7 +533,7 @@ static int qigvm_directive_parameter_insert(QIgvm *ctx,
* If a confidential guest support object is provided then use it to
* set the guest state.
*/
- if (ctx->cgs) {
+ if (ctx->machine_state->cgs) {
result = ctx->cgsc->set_guest_state(param->gpa, region,
param_entry->size,
CGS_PAGE_TYPE_UNMEASURED, 0,
@@ -572,7 +574,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) {
@@ -698,7 +700,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);
@@ -816,14 +818,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)) {
@@ -831,7 +833,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)) {
@@ -904,7 +906,7 @@ IgvmHandle qigvm_file_init(char *filename, Error **errp)
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;
@@ -920,13 +922,16 @@ int qigvm_process_file(IgvmCfg *cfg, ConfidentialGuestSupport *cgs,
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
diff --git a/include/system/igvm-cfg.h b/include/system/igvm-cfg.h
index 6c07f30840..e06d611f74 100644
--- a/include/system/igvm-cfg.h
+++ b/include/system/igvm-cfg.h
@@ -12,6 +12,7 @@
#ifndef QEMU_IGVM_CFG_H
#define QEMU_IGVM_CFG_H
+#include "hw/core/boards.h"
#include "qemu/typedefs.h"
#include "qom/object.h"
@@ -27,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;
diff --git a/include/system/igvm.h b/include/system/igvm.h
index 8355e54e95..5573a6111a 100644
--- a/include/system/igvm.h
+++ b/include/system/igvm.h
@@ -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 "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,
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 1d70f96ec1..6f86dd710b 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1891,8 +1891,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;
}
/*
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 6/6] igvm: Fill MADT IGVM parameter field
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
` (4 preceding siblings ...)
2026-01-27 10:02 ` [PATCH v5 5/6] igvm: Pass machine state to IGVM file processing Oliver Steffen
@ 2026-01-27 10:02 ` Oliver Steffen
2026-01-27 15:54 ` Gerd Hoffmann
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Steffen @ 2026-01-27 10:02 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel, Oliver Steffen
Use the new acpi_build_madt_standalone() function to fill the MADT
parameter field.
The IGVM parameter can be consumed by Coconut SVSM [1], instead of
relying on the fw_cfg interface, which has caused problems before due to
unexpected access [2,3]. Using IGVM parameters is the default way for
Coconut SVSM across hypervisors; switching over would allow removing
specialized code paths for QEMU in Coconut.
Coconut SVSM needs to know the SMP configuration, but does not look at
any other ACPI data, nor does it interact with the PCI bus settings.
Since the MADT is static and not linked with other ACPI tables, it can
be supplied stand-alone like this.
Generating the MADT twice (during ACPI table building and IGVM processing)
seems acceptable, since there is no infrastructure to obtain the MADT
out of the ACPI table memory area.
In any case OVMF, which runs after SVSM has already been initialized,
will continue reading all ACPI tables via fw_cfg and provide fixed up
ACPI data to the OS as before without any changes.
[1] https://github.com/coconut-svsm/svsm/pull/858
[2] https://gitlab.com/qemu-project/qemu/-/issues/2882
[3] https://github.com/coconut-svsm/svsm/issues/646
Signed-off-by: Oliver Steffen <osteffen@redhat.com>
---
backends/igvm.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/backends/igvm.c b/backends/igvm.c
index f26eb633f8..1d8f807cf6 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -21,6 +21,7 @@
#include "system/memory.h"
#include "system/address-spaces.h"
#include "hw/core/cpu.h"
+#include "hw/i386/acpi-build.h"
#include "trace.h"
@@ -138,6 +139,8 @@ static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
static int qigvm_initialization_guest_policy(QIgvm *ctx,
const uint8_t *header_data,
Error **errp);
+static int qigvm_directive_madt(QIgvm *ctx, const uint8_t *header_data,
+ Error **errp);
struct QIGVMHandler {
uint32_t type;
@@ -166,6 +169,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)
@@ -779,6 +784,34 @@ static int qigvm_initialization_guest_policy(QIgvm *ctx,
return 0;
}
+static 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;
+}
+
static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
{
int32_t header_count;
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v5 6/6] igvm: Fill MADT IGVM parameter field
2026-01-27 10:02 ` [PATCH v5 6/6] igvm: Fill MADT IGVM parameter field Oliver Steffen
@ 2026-01-27 15:54 ` Gerd Hoffmann
0 siblings, 0 replies; 13+ messages in thread
From: Gerd Hoffmann @ 2026-01-27 15:54 UTC (permalink / raw)
To: Oliver Steffen
Cc: qemu-devel, Paolo Bonzini, Eduardo Habkost, Stefano Garzarella,
Zhao Liu, Marcel Apfelbaum, Igor Mammedov, Marcelo Tosatti,
Richard Henderson, Ani Sinha, kvm, Michael S. Tsirkin,
Luigi Leonardi, Joerg Roedel
Hi,
> +static int qigvm_directive_madt(QIgvm *ctx, const uint8_t *header_data,
> + Error **errp)
> +{
[3358/3616] Linking target qemu-system-s390x
FAILED: [code=1] qemu-system-s390x
cc -m64 @qemu-system-s390x.rsp
/usr/bin/ld: libsystem.a.p/backends_igvm.c.o: in function `qigvm_directive_madt':
/home/kraxel/projects/qemu/build/default/../../backends/igvm.c:800:(.text+0x1bdc): undefined reference to `acpi_build_madt_standalone'
collect2: error: ld returned 1 exit status
Moving the function to target/i386/igvm.c and adding a stub version to
stubs/igvm.c should fix that.
take care,
Gerd
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 1/6] hw/acpi: Make BIOS linker optional
2026-01-27 10:02 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
@ 2026-01-29 10:51 ` Luigi Leonardi
0 siblings, 0 replies; 13+ messages in thread
From: Luigi Leonardi @ 2026-01-29 10:51 UTC (permalink / raw)
To: Oliver Steffen
Cc: qemu-devel, Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann,
Stefano Garzarella, Zhao Liu, Marcel Apfelbaum, Igor Mammedov,
Marcelo Tosatti, Richard Henderson, Ani Sinha, kvm,
Michael S. Tsirkin, Joerg Roedel
Hi Oliver,
On Tue, Jan 27, 2026 at 11:02:52AM +0100, Oliver Steffen wrote:
>Make the BIOS linker optional in acpi_table_end() and calculate the ACPI
>table checksum directly if no linker is provided.
>
>This makes it possible to call for example
>acpi_build_madt() from outside the ACPI table builder context.
>
>Signed-off-by: Oliver Steffen <osteffen@redhat.com>
>---
> hw/acpi/aml-build.c | 29 +++++++++++++++++++++++++++--
> 1 file changed, 27 insertions(+), 2 deletions(-)
>
>diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
>index dad4cfcc7d..6a3650076f 100644
>--- a/hw/acpi/aml-build.c
>+++ b/hw/acpi/aml-build.c
>@@ -1730,6 +1730,25 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
> build_append_int_noprefix(array, 1, 4); /* Creator Revision */
> }
>
>+static uint8_t calculate_acpi_checksum(const gchar *data, size_t len)
>+{
>+ size_t i;
>+ uint8_t sum = 0;
>+
>+ for (i = 0; i < len; ++i) {
>+ sum += (uint8_t)data[i];
>+ }
>+
>+ return sum;
>+}
>+
In `hw/acpi/core.c` there is a `acpi_checksum` function that does
exactly this. Can we reuse this to reduce code duplication? Currently
that function is marked as static.
Thanks for all the work so far.
Luigi
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 3/6] igvm: Add common function for finding parameter entries
2026-01-27 10:02 ` [PATCH v5 3/6] igvm: Add common function for finding parameter entries Oliver Steffen
@ 2026-01-29 11:09 ` Luigi Leonardi
0 siblings, 0 replies; 13+ messages in thread
From: Luigi Leonardi @ 2026-01-29 11:09 UTC (permalink / raw)
To: Oliver Steffen
Cc: qemu-devel, Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann,
Stefano Garzarella, Zhao Liu, Marcel Apfelbaum, Igor Mammedov,
Marcelo Tosatti, Richard Henderson, Ani Sinha, kvm,
Michael S. Tsirkin, Joerg Roedel
On Tue, Jan 27, 2026 at 11:02:54AM +0100, Oliver Steffen wrote:
>Move repeating code for finding the parameter entries in the IGVM
>backend out of the parameter handlers into a common function.
>
>A warning message is emitted in case a no parameter entry can be found
>for a given index.
>
>Signed-off-by: Oliver Steffen <osteffen@redhat.com>
>---
> backends/igvm.c | 143 ++++++++++++++++++++++++++----------------------
> 1 file changed, 77 insertions(+), 66 deletions(-)
>
>diff --git a/backends/igvm.c b/backends/igvm.c
>index 4cf7b57234..213c9d337e 100644
>--- a/backends/igvm.c
>+++ b/backends/igvm.c
>@@ -12,6 +12,7 @@
> #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"
>@@ -97,6 +98,20 @@ typedef struct QIgvm {
> unsigned region_page_count;
> } QIgvm;
>
>+static 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);
> static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
>@@ -571,58 +586,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;
>-
>- 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);
>+ param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
>+ if (param_entry == NULL) {
>+ return 0;
>+ }
>+
>+ max_entry_count = param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY);
>+ mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data;
>+
>+ 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;
> }
>
>@@ -634,18 +645,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)
>+ 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)
> {
>- 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;
>- }
>+ (*vp_count)++;
> }
>+
> return 0;
> }
>
>@@ -657,15 +668,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;
> }
>
>--
>2.52.0
>
LGTM!
Reviewed-by: Luigi Leonardi <leonardi@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 4/6] igvm: Refactor qigvm_parameter_insert
2026-01-27 10:02 ` [PATCH v5 4/6] igvm: Refactor qigvm_parameter_insert Oliver Steffen
@ 2026-01-29 11:10 ` Luigi Leonardi
0 siblings, 0 replies; 13+ messages in thread
From: Luigi Leonardi @ 2026-01-29 11:10 UTC (permalink / raw)
To: Oliver Steffen
Cc: qemu-devel, Paolo Bonzini, Eduardo Habkost, Gerd Hoffmann,
Stefano Garzarella, Zhao Liu, Marcel Apfelbaum, Igor Mammedov,
Marcelo Tosatti, Richard Henderson, Ani Sinha, kvm,
Michael S. Tsirkin, Joerg Roedel
On Tue, Jan 27, 2026 at 11:02:55AM +0100, Oliver Steffen wrote:
>Use qigvm_find_param_entry() also in qigvm_parameter_insert().
>This changes behavior: Processing now stops after the first parameter
>entry found. That is OK, because we expect only one matching entry
>anyway.
>
>Signed-off-by: Oliver Steffen <osteffen@redhat.com>
>---
> backends/igvm.c | 50 ++++++++++++++++++++++++-------------------------
> 1 file changed, 25 insertions(+), 25 deletions(-)
>
>diff --git a/backends/igvm.c b/backends/igvm.c
>index 213c9d337e..0a0092fb55 100644
>--- a/backends/igvm.c
>+++ b/backends/igvm.c
>@@ -513,31 +513,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;
>-
>- /*
>- * 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;
>- }
>- }
>+ param_entry = qigvm_find_param_entry(ctx, param->parameter_area_index);
>+ if (param_entry == NULL) {
>+ return 0;
>+ }
>+
>+ 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->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;
>--
>2.52.0
>
LGTM
Reviewed-by: Luigi Leonardi <leonardi@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-01-29 11:10 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
2026-01-29 10:51 ` Luigi Leonardi
2026-01-27 10:02 ` [PATCH v5 2/6] hw/acpi: Add standalone function to build MADT Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 3/6] igvm: Add common function for finding parameter entries Oliver Steffen
2026-01-29 11:09 ` Luigi Leonardi
2026-01-27 10:02 ` [PATCH v5 4/6] igvm: Refactor qigvm_parameter_insert Oliver Steffen
2026-01-29 11:10 ` Luigi Leonardi
2026-01-27 10:02 ` [PATCH v5 5/6] igvm: Pass machine state to IGVM file processing Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 6/6] igvm: Fill MADT IGVM parameter field Oliver Steffen
2026-01-27 15:54 ` Gerd Hoffmann
-- strict thread matches above, loose matches on Subject: below --
2026-01-27 10:02 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
2026-01-27 10:02 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
2026-01-27 9:59 [PATCH v5 0/6] igvm: Supply MADT via IGVM parameter Oliver Steffen
2026-01-27 9:59 ` [PATCH v5 1/6] hw/acpi: Make BIOS linker optional Oliver Steffen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox