Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

virtio,pc,pci: features, fixes, cleanups

The big thing here are:
stage-1 translation in vtd
internal migration in vhost-user
ghes driver preparation for error injection
new resource uuid feature in virtio gpu
new vmclock device

And as usual, fixes and cleanups.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmeIOiIPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRpORgIAL0clwZxQL7PIPJ91FwXc1bo6Do/HYquAzvH
# eA+ryCG5S5ewh/e2R8SdIUG7nYesEMWJGVL1gb3BFu7wgGh1aLaaTxQ1LIo5HpRF
# P0Ak3QO7TKIsSEcZIz9h3eMEpg6X9d8i2h7llp7H3qqXBbduO+cGfeNH/fZD5IEl
# 7DFvXuJUgUtZb38I+qtcO+9EQFKGHjgdQAN5P/I4vawWJdxN9sBfT4YVEgpVhiq/
# ALxdSeaEiXA4EXexdHVZhXiQzEBsCQ78RZIIDiRE8I34cVY7rolTodKRfr4bip3P
# 6Llu11yvzNi1gppOzkny3QFsRza3hV0RisWYjAMTwLhNCdi/mHQ=
# =GjDq
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 15 Jan 2025 17:43:46 EST
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (49 commits)
  hw/acpi: Add vmclock device
  virtio-net: vhost-user: Implement internal migration
  vhost: Add stubs for the migration state transfer interface
  hw/cxl: Fix msix_notify: Assertion `vector < dev->msix_entries_nr`
  tests: acpi: update expected blobs
  pci: acpi: Windows 'PCI Label Id' bug workaround
  tests: acpi: whitelist expected blobs
  docs: acpi_hest_ghes: fix documentation for CPER size
  acpi/ghes: Change ghes fill logic to work with only one source
  acpi/ghes: move offset calculus to a separate function
  acpi/ghes: better name the offset of the hardware error firmware
  acpi/ghes: rename etc/hardware_error file macros
  acpi/ghes: don't crash QEMU if ghes GED is not found
  acpi/ghes: better name GHES memory error function
  acpi/ghes: make the GHES record generation more generic
  acpi/ghes: don't check if physical_address is not zero
  acpi/ghes: Change the type for source_id
  acpi/ghes: Remove a duplicated out of bounds check
  acpi/ghes: Fix acpi_ghes_record_errors() argument
  acpi/ghes: better handle source_id and notification
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2025-01-16 09:02:18 -05:00
74 changed files with 1544 additions and 334 deletions
+1
View File
@@ -3711,6 +3711,7 @@ F: hw/i386/intel_iommu.c
F: hw/i386/intel_iommu_internal.h
F: include/hw/i386/intel_iommu.h
F: tests/functional/test_intel_iommu.py
F: tests/qtest/intel-iommu-test.c
AMD-Vi Emulation
S: Orphan
+4 -2
View File
@@ -67,8 +67,10 @@ Design Details
(3) The address registers table contains N Error Block Address entries
and N Read Ack Register entries. The size for each entry is 8-byte.
The Error Status Data Block table contains N Error Status Data Block
entries. The size for each entry is 4096(0x1000) bytes. The total size
for the "etc/hardware_errors" fw_cfg blob is (N * 8 * 2 + N * 4096) bytes.
entries. The size for each entry is defined at the source code as
ACPI_GHES_MAX_RAW_DATA_LENGTH (currently 1024 bytes). The total size
for the "etc/hardware_errors" fw_cfg blob is
(N * 8 * 2 + N * ACPI_GHES_MAX_RAW_DATA_LENGTH) bytes.
N is the number of the kinds of hardware error sources.
(4) QEMU generates the ACPI linker/loader script for the firmware. The
+5
View File
@@ -60,6 +60,11 @@ config ACPI_VMGENID
default y
depends on PC
config ACPI_VMCLOCK
bool
default y
depends on PC
config ACPI_VIOT
bool
depends on ACPI
+34 -9
View File
@@ -327,6 +327,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
#define CPU_EJECT_METHOD "CEJ0"
#define CPU_OST_METHOD "COST"
#define CPU_ADDED_LIST "CNEW"
#define CPU_EJ_LIST "CEJL"
#define CPU_ENABLED "CPEN"
#define CPU_SELECTOR "CSEL"
@@ -488,7 +489,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED);
{
const uint8_t max_cpus_per_pass = 255;
Aml *else_ctx;
Aml *while_ctx, *while_ctx2;
Aml *has_event = aml_local(0);
Aml *dev_chk = aml_int(1);
@@ -499,6 +499,8 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
Aml *uid = aml_local(3);
Aml *has_job = aml_local(4);
Aml *new_cpus = aml_name(CPU_ADDED_LIST);
Aml *ej_cpus = aml_name(CPU_EJ_LIST);
Aml *num_ej_cpus = aml_local(5);
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
@@ -513,6 +515,8 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
*/
aml_append(method, aml_name_decl(CPU_ADDED_LIST,
aml_package(max_cpus_per_pass)));
aml_append(method, aml_name_decl(CPU_EJ_LIST,
aml_package(max_cpus_per_pass)));
aml_append(method, aml_store(zero, uid));
aml_append(method, aml_store(one, has_job));
@@ -527,6 +531,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(while_ctx2, aml_store(one, has_event));
aml_append(while_ctx2, aml_store(zero, num_added_cpus));
aml_append(while_ctx2, aml_store(zero, num_ej_cpus));
/*
* Scan CPUs, till there are CPUs with events or
@@ -559,8 +564,10 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
* if CPU_ADDED_LIST is full, exit inner loop and process
* collected CPUs
*/
ifctx = aml_if(
aml_equal(num_added_cpus, aml_int(max_cpus_per_pass)));
ifctx = aml_if(aml_lor(
aml_equal(num_added_cpus, aml_int(max_cpus_per_pass)),
aml_equal(num_ej_cpus, aml_int(max_cpus_per_pass))
));
{
aml_append(ifctx, aml_store(one, has_job));
aml_append(ifctx, aml_break());
@@ -577,16 +584,16 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(ifctx, aml_store(one, has_event));
}
aml_append(while_ctx, ifctx);
else_ctx = aml_else();
ifctx = aml_if(aml_equal(rm_evt, one));
{
aml_append(ifctx,
aml_call2(CPU_NOTIFY_METHOD, uid, eject_req));
aml_append(ifctx, aml_store(one, rm_evt));
/* cache to be removed CPUs to Notify later */
aml_append(ifctx, aml_store(uid,
aml_index(ej_cpus, num_ej_cpus)));
aml_append(ifctx, aml_increment(num_ej_cpus));
aml_append(ifctx, aml_store(one, has_event));
}
aml_append(else_ctx, ifctx);
aml_append(while_ctx, else_ctx);
aml_append(while_ctx, ifctx);
aml_append(while_ctx, aml_increment(uid));
}
aml_append(while_ctx2, while_ctx);
@@ -620,6 +627,24 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(while_ctx, aml_increment(cpu_idx));
}
aml_append(while_ctx2, while_ctx);
/*
* Notify OSPM about to be removed CPUs and clear remove flag
*/
aml_append(while_ctx2, aml_store(zero, cpu_idx));
while_ctx = aml_while(aml_lless(cpu_idx, num_ej_cpus));
{
aml_append(while_ctx,
aml_store(aml_derefof(aml_index(ej_cpus, cpu_idx)),
uid));
aml_append(while_ctx,
aml_call2(CPU_NOTIFY_METHOD, uid, eject_req));
aml_append(while_ctx, aml_store(uid, cpu_selector));
aml_append(while_ctx, aml_store(one, rm_evt));
aml_append(while_ctx, aml_increment(cpu_idx));
}
aml_append(while_ctx2, while_ctx);
/*
* If another batch is needed, then it will resume scanning
* exactly at -- and not after -- the last CPU that's currently
+2 -2
View File
@@ -363,7 +363,7 @@ static const VMStateDescription vmstate_ghes = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT64(ghes_addr_le, AcpiGhesState),
VMSTATE_UINT64(hw_error_le, AcpiGhesState),
VMSTATE_END_OF_LIST()
},
};
@@ -371,7 +371,7 @@ static const VMStateDescription vmstate_ghes = {
static bool ghes_needed(void *opaque)
{
AcpiGedState *s = opaque;
return s->ghes_state.ghes_addr_le;
return s->ghes_state.hw_error_le;
}
static const VMStateDescription vmstate_ghes_state = {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "hw/acpi/ghes.h"
int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
int acpi_ghes_memory_errors(uint16_t source_id, uint64_t physical_address)
{
return -1;
}
+147 -109
View File
@@ -28,15 +28,12 @@
#include "hw/nvram/fw_cfg.h"
#include "qemu/uuid.h"
#define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors"
#define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr"
#define ACPI_HW_ERROR_FW_CFG_FILE "etc/hardware_errors"
#define ACPI_HW_ERROR_ADDR_FW_CFG_FILE "etc/hardware_errors_addr"
/* The max size in bytes for one error block */
#define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB)
/* Now only support ARMv8 SEA notification type error source */
#define ACPI_GHES_ERROR_SOURCE_COUNT 1
/* Generic Hardware Error Source version 2 */
#define ACPI_GHES_SOURCE_GENERIC_ERROR_V2 10
@@ -184,51 +181,24 @@ static void acpi_ghes_build_append_mem_cper(GArray *table,
build_append_int_noprefix(table, 0, 7);
}
static int acpi_ghes_record_mem_error(uint64_t error_block_address,
uint64_t error_physical_addr)
static void
ghes_gen_err_data_uncorrectable_recoverable(GArray *block,
const uint8_t *section_type,
int data_length)
{
GArray *block;
/* Memory Error Section Type */
const uint8_t uefi_cper_mem_sec[] =
UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
0xED, 0x7C, 0x83, 0xB1);
/* invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data,
* Table 17-13 Generic Error Data Entry
*/
QemuUUID fru_id = {};
uint32_t data_length;
block = g_array_new(false, true /* clear */, 1);
/* This is the length if adding a new generic error data entry*/
data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH;
/*
* It should not run out of the preallocated memory if adding a new generic
* error data entry
*/
assert((data_length + ACPI_GHES_GESB_SIZE) <=
ACPI_GHES_MAX_RAW_DATA_LENGTH);
/* Build the new generic error status block header */
acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE,
0, 0, data_length, ACPI_CPER_SEV_RECOVERABLE);
/* Build this new generic error data entry header */
acpi_ghes_generic_error_data(block, uefi_cper_mem_sec,
acpi_ghes_generic_error_data(block, section_type,
ACPI_CPER_SEV_RECOVERABLE, 0, 0,
ACPI_GHES_MEM_CPER_LENGTH, fru_id, 0);
/* Build the memory section CPER for above new generic error data entry */
acpi_ghes_build_append_mem_cper(block, error_physical_addr);
/* Write the generic error data entry into guest memory */
cpu_physical_memory_write(error_block_address, block->data, block->len);
g_array_free(block, true);
return 0;
}
/*
@@ -236,7 +206,7 @@ static int acpi_ghes_record_mem_error(uint64_t error_block_address,
* Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs.
* See docs/specs/acpi_hest_ghes.rst for blobs format.
*/
void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
static void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
{
int i, error_status_block_offset;
@@ -264,7 +234,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT);
/* Tell guest firmware to place hardware_errors blob into RAM */
bios_linker_loader_alloc(linker, ACPI_GHES_ERRORS_FW_CFG_FILE,
bios_linker_loader_alloc(linker, ACPI_HW_ERROR_FW_CFG_FILE,
hardware_errors, sizeof(uint64_t), false);
for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) {
@@ -273,23 +243,31 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
* corresponding "Generic Error Status Block"
*/
bios_linker_loader_add_pointer(linker,
ACPI_GHES_ERRORS_FW_CFG_FILE, sizeof(uint64_t) * i,
sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE,
error_status_block_offset + i * ACPI_GHES_MAX_RAW_DATA_LENGTH);
ACPI_HW_ERROR_FW_CFG_FILE,
sizeof(uint64_t) * i,
sizeof(uint64_t),
ACPI_HW_ERROR_FW_CFG_FILE,
error_status_block_offset +
i * ACPI_GHES_MAX_RAW_DATA_LENGTH);
}
/*
* tell firmware to write hardware_errors GPA into
* hardware_errors_addr fw_cfg, once the former has been initialized.
*/
bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE,
0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0);
bios_linker_loader_write_pointer(linker, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, 0,
sizeof(uint64_t),
ACPI_HW_ERROR_FW_CFG_FILE, 0);
}
/* Build Generic Hardware Error Source version 2 (GHESv2) */
static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
static void build_ghes_v2(GArray *table_data,
BIOSLinker *linker,
enum AcpiGhesNotifyType notify,
uint16_t source_id)
{
uint64_t address_offset;
/*
* Type:
* Generic Hardware Error Source version 2(GHESv2 - Type 10)
@@ -316,21 +294,13 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0,
4 /* QWord access */, 0);
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t),
ACPI_GHES_ERRORS_FW_CFG_FILE, source_id * sizeof(uint64_t));
address_offset + GAS_ADDR_OFFSET,
sizeof(uint64_t),
ACPI_HW_ERROR_FW_CFG_FILE,
source_id * sizeof(uint64_t));
switch (source_id) {
case ACPI_HEST_SRC_ID_SEA:
/*
* Notification Structure
* Now only enable ARMv8 SEA notification type
*/
build_ghes_hw_error_notification(table_data, ACPI_GHES_NOTIFY_SEA);
break;
default:
error_report("Not support this error source");
abort();
}
/* Notification Structure */
build_ghes_hw_error_notification(table_data, notify);
/* Error Status Block Length */
build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4);
@@ -344,9 +314,11 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0,
4 /* QWord access */, 0);
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
address_offset + GAS_ADDR_OFFSET,
sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE,
(ACPI_GHES_ERROR_SOURCE_COUNT + source_id) * sizeof(uint64_t));
address_offset + GAS_ADDR_OFFSET,
sizeof(uint64_t),
ACPI_HW_ERROR_FW_CFG_FILE,
(ACPI_GHES_ERROR_SOURCE_COUNT + source_id)
* sizeof(uint64_t));
/*
* Read Ack Preserve field
@@ -359,17 +331,21 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
}
/* Build Hardware Error Source Table */
void acpi_build_hest(GArray *table_data, BIOSLinker *linker,
void acpi_build_hest(GArray *table_data, GArray *hardware_errors,
BIOSLinker *linker,
const char *oem_id, const char *oem_table_id)
{
AcpiTable table = { .sig = "HEST", .rev = 1,
.oem_id = oem_id, .oem_table_id = oem_table_id };
build_ghes_error_table(hardware_errors, linker);
acpi_table_begin(&table, table_data);
/* Error Source Count */
build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4);
build_ghes_v2(table_data, ACPI_HEST_SRC_ID_SEA, linker);
build_ghes_v2(table_data, linker,
ACPI_GHES_NOTIFY_SEA, ACPI_HEST_SRC_ID_SEA);
acpi_table_end(linker, &table);
}
@@ -378,70 +354,132 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s,
GArray *hardware_error)
{
/* Create a read-only fw_cfg file for GHES */
fw_cfg_add_file(s, ACPI_GHES_ERRORS_FW_CFG_FILE, hardware_error->data,
fw_cfg_add_file(s, ACPI_HW_ERROR_FW_CFG_FILE, hardware_error->data,
hardware_error->len);
/* Create a read-write fw_cfg file for Address */
fw_cfg_add_file_callback(s, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, NULL, NULL,
NULL, &(ags->ghes_addr_le), sizeof(ags->ghes_addr_le), false);
fw_cfg_add_file_callback(s, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, NULL, NULL,
NULL, &(ags->hw_error_le), sizeof(ags->hw_error_le), false);
ags->present = true;
}
int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
static void get_hw_error_offsets(uint64_t ghes_addr,
uint64_t *cper_addr,
uint64_t *read_ack_register_addr)
{
uint64_t error_block_addr, read_ack_register_addr, read_ack_register = 0;
uint64_t start_addr;
bool ret = -1;
if (!ghes_addr) {
return;
}
/*
* non-HEST version supports only one source, so no need to change
* the start offset based on the source ID. Also, we can't validate
* the source ID, as it is stored inside the HEST table.
*/
cpu_physical_memory_read(ghes_addr, cper_addr,
sizeof(*cper_addr));
*cper_addr = le64_to_cpu(*cper_addr);
/*
* As the current version supports only one source, the ack offset is
* just sizeof(uint64_t).
*/
*read_ack_register_addr = ghes_addr + sizeof(uint64_t);
}
void ghes_record_cper_errors(const void *cper, size_t len,
uint16_t source_id, Error **errp)
{
uint64_t cper_addr = 0, read_ack_register_addr = 0, read_ack_register;
AcpiGedState *acpi_ged_state;
AcpiGhesState *ags;
assert(source_id < ACPI_HEST_SRC_ID_RESERVED);
if (len > ACPI_GHES_MAX_RAW_DATA_LENGTH) {
error_setg(errp, "GHES CPER record is too big: %zd", len);
return;
}
acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED,
NULL));
g_assert(acpi_ged_state);
if (!acpi_ged_state) {
error_setg(errp, "Can't find ACPI_GED object");
return;
}
ags = &acpi_ged_state->ghes_state;
start_addr = le64_to_cpu(ags->ghes_addr_le);
assert(ACPI_GHES_ERROR_SOURCE_COUNT == 1);
get_hw_error_offsets(le64_to_cpu(ags->hw_error_le),
&cper_addr, &read_ack_register_addr);
if (physical_address) {
if (source_id < ACPI_HEST_SRC_ID_RESERVED) {
start_addr += source_id * sizeof(uint64_t);
}
cpu_physical_memory_read(start_addr, &error_block_addr,
sizeof(error_block_addr));
error_block_addr = le64_to_cpu(error_block_addr);
read_ack_register_addr = start_addr +
ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t);
cpu_physical_memory_read(read_ack_register_addr,
&read_ack_register, sizeof(read_ack_register));
/* zero means OSPM does not acknowledge the error */
if (!read_ack_register) {
error_report("OSPM does not acknowledge previous error,"
" so can not record CPER for current error anymore");
} else if (error_block_addr) {
read_ack_register = cpu_to_le64(0);
/*
* Clear the Read Ack Register, OSPM will write it to 1 when
* it acknowledges this error.
*/
cpu_physical_memory_write(read_ack_register_addr,
&read_ack_register, sizeof(uint64_t));
ret = acpi_ghes_record_mem_error(error_block_addr,
physical_address);
} else
error_report("can not find Generic Error Status Block");
if (!cper_addr) {
error_setg(errp, "can not find Generic Error Status Block");
return;
}
return ret;
cpu_physical_memory_read(read_ack_register_addr,
&read_ack_register, sizeof(read_ack_register));
/* zero means OSPM does not acknowledge the error */
if (!read_ack_register) {
error_setg(errp,
"OSPM does not acknowledge previous error,"
" so can not record CPER for current error anymore");
return;
}
read_ack_register = cpu_to_le64(0);
/*
* Clear the Read Ack Register, OSPM will write 1 to this register when
* it acknowledges the error.
*/
cpu_physical_memory_write(read_ack_register_addr,
&read_ack_register, sizeof(uint64_t));
/* Write the generic error data entry into guest memory */
cpu_physical_memory_write(cper_addr, cper, len);
return;
}
int acpi_ghes_memory_errors(uint16_t source_id, uint64_t physical_address)
{
/* Memory Error Section Type */
const uint8_t guid[] =
UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
0xED, 0x7C, 0x83, 0xB1);
Error *errp = NULL;
int data_length;
GArray *block;
block = g_array_new(false, true /* clear */, 1);
data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH;
/*
* It should not run out of the preallocated memory if adding a new generic
* error data entry
*/
assert((data_length + ACPI_GHES_GESB_SIZE) <=
ACPI_GHES_MAX_RAW_DATA_LENGTH);
ghes_gen_err_data_uncorrectable_recoverable(block, guid, data_length);
/* Build the memory section CPER for above new generic error data entry */
acpi_ghes_build_append_mem_cper(block, physical_address);
/* Report the error */
ghes_record_cper_errors(block->data, block->len, source_id, &errp);
g_array_free(block, true);
if (errp) {
error_report_err(errp);
return -1;
}
return 0;
}
bool acpi_ghes_present(void)
+1
View File
@@ -15,6 +15,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_false: files('acpi-nvdimm-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c'))
acpi_ss.add(when: 'CONFIG_ACPI_CXL', if_true: files('cxl.c'), if_false: files('cxl-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VMCLOCK', if_true: files('vmclock.c'))
acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device.c'))
acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c'))
acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c'))
+179
View File
@@ -0,0 +1,179 @@
/*
* Virtual Machine Clock Device
*
* Copyright © 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Authors: David Woodhouse <dwmw2@infradead.org>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/i386/e820_memory_layout.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/vmclock.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "migration/vmstate.h"
#include "system/reset.h"
#include "standard-headers/linux/vmclock-abi.h"
void vmclock_build_acpi(VmclockState *vms, GArray *table_data,
BIOSLinker *linker, const char *oem_id)
{
Aml *ssdt, *dev, *scope, *crs;
AcpiTable table = { .sig = "SSDT", .rev = 1,
.oem_id = oem_id, .oem_table_id = "VMCLOCK" };
/* Put VMCLOCK into a separate SSDT table */
acpi_table_begin(&table, table_data);
ssdt = init_aml_allocator();
scope = aml_scope("\\_SB");
dev = aml_device("VCLK");
aml_append(dev, aml_name_decl("_HID", aml_string("AMZNC10C")));
aml_append(dev, aml_name_decl("_CID", aml_string("VMCLOCK")));
aml_append(dev, aml_name_decl("_DDN", aml_string("VMCLOCK")));
/* Simple status method */
aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
crs = aml_resource_template();
aml_append(crs, aml_qword_memory(AML_POS_DECODE,
AML_MIN_FIXED, AML_MAX_FIXED,
AML_CACHEABLE, AML_READ_ONLY,
0xffffffffffffffffULL,
vms->physaddr,
vms->physaddr + VMCLOCK_SIZE - 1,
0, VMCLOCK_SIZE));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
aml_append(ssdt, scope);
g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
acpi_table_end(linker, &table);
free_aml_allocator();
}
static void vmclock_update_guest(VmclockState *vms)
{
uint64_t disruption_marker;
uint32_t seq_count;
if (!vms->clk) {
return;
}
seq_count = le32_to_cpu(vms->clk->seq_count) | 1;
vms->clk->seq_count = cpu_to_le32(seq_count);
/* These barriers pair with read barriers in the guest */
smp_wmb();
disruption_marker = le64_to_cpu(vms->clk->disruption_marker);
disruption_marker++;
vms->clk->disruption_marker = cpu_to_le64(disruption_marker);
/* These barriers pair with read barriers in the guest */
smp_wmb();
vms->clk->seq_count = cpu_to_le32(seq_count + 1);
}
/*
* After restoring an image, we need to update the guest memory to notify
* it of clock disruption.
*/
static int vmclock_post_load(void *opaque, int version_id)
{
VmclockState *vms = opaque;
vmclock_update_guest(vms);
return 0;
}
static const VMStateDescription vmstate_vmclock = {
.name = "vmclock",
.version_id = 1,
.minimum_version_id = 1,
.post_load = vmclock_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT64(physaddr, VmclockState),
VMSTATE_END_OF_LIST()
},
};
static void vmclock_handle_reset(void *opaque)
{
VmclockState *vms = VMCLOCK(opaque);
if (!memory_region_is_mapped(&vms->clk_page)) {
memory_region_add_subregion_overlap(get_system_memory(),
vms->physaddr,
&vms->clk_page, 0);
}
}
static void vmclock_realize(DeviceState *dev, Error **errp)
{
VmclockState *vms = VMCLOCK(dev);
/*
* Given that this function is executing, there is at least one VMCLOCK
* device. Check if there are several.
*/
if (!find_vmclock_dev()) {
error_setg(errp, "at most one %s device is permitted", TYPE_VMCLOCK);
return;
}
vms->physaddr = VMCLOCK_ADDR;
e820_add_entry(vms->physaddr, VMCLOCK_SIZE, E820_RESERVED);
memory_region_init_ram(&vms->clk_page, OBJECT(dev), "vmclock_page",
VMCLOCK_SIZE, &error_abort);
memory_region_set_enabled(&vms->clk_page, true);
vms->clk = memory_region_get_ram_ptr(&vms->clk_page);
memset(vms->clk, 0, VMCLOCK_SIZE);
vms->clk->magic = cpu_to_le32(VMCLOCK_MAGIC);
vms->clk->size = cpu_to_le16(VMCLOCK_SIZE);
vms->clk->version = cpu_to_le16(1);
/* These are all zero and thus default, but be explicit */
vms->clk->clock_status = VMCLOCK_STATUS_UNKNOWN;
vms->clk->counter_id = VMCLOCK_COUNTER_INVALID;
qemu_register_reset(vmclock_handle_reset, vms);
vmclock_update_guest(vms);
}
static void vmclock_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_vmclock;
dc->realize = vmclock_realize;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo vmclock_device_info = {
.name = TYPE_VMCLOCK,
.parent = TYPE_DEVICE,
.instance_size = sizeof(VmclockState),
.class_init = vmclock_device_class_init,
};
static void vmclock_register_types(void)
{
type_register_static(&vmclock_device_info);
}
type_init(vmclock_register_types)
+2 -3
View File
@@ -946,10 +946,9 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
build_dbg2(tables_blob, tables->linker, vms);
if (vms->ras) {
build_ghes_error_table(tables->hardware_errors, tables->linker);
acpi_add_table(table_offsets, tables_blob);
acpi_build_hest(tables_blob, tables->linker, vms->oem_id,
vms->oem_table_id);
acpi_build_hest(tables_blob, tables->hardware_errors, tables->linker,
vms->oem_id, vms->oem_table_id);
}
if (ms->numa_state->num_nodes > 0) {
+8
View File
@@ -631,6 +631,14 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
error_report("EDID requested but the backend doesn't support it.");
g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
}
if (virtio_has_feature(g->vhost->dev.features,
VIRTIO_GPU_F_RESOURCE_UUID)) {
g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
}
if (virtio_has_feature(g->vhost->dev.features,
VIRTIO_GPU_F_RESOURCE_UUID)) {
g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
}
if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
return;
+3
View File
@@ -235,6 +235,9 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features,
if (virtio_gpu_context_init_enabled(g->conf)) {
features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT);
}
if (virtio_gpu_resource_uuid_enabled(g->conf)) {
features |= (1 << VIRTIO_GPU_F_RESOURCE_UUID);
}
return features;
}
+1
View File
@@ -43,6 +43,7 @@ config PC
select SERIAL_ISA
select ACPI_PCI
select ACPI_VMGENID
select ACPI_VMCLOCK
select VIRTIO_PMEM_SUPPORTED
select VIRTIO_MEM_SUPPORTED
select HV_BALLOON_SUPPORTED
+32 -11
View File
@@ -43,6 +43,7 @@
#include "system/tpm.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/vmgenid.h"
#include "hw/acpi/vmclock.h"
#include "hw/acpi/erst.h"
#include "hw/acpi/piix4.h"
#include "system/tpm_backend.h"
@@ -654,6 +655,7 @@ static Aml *aml_pci_pdsm(void)
Aml *acpi_index = aml_local(2);
Aml *zero = aml_int(0);
Aml *one = aml_int(1);
Aml *not_supp = aml_int(0xFFFFFFFF);
Aml *func = aml_arg(2);
Aml *params = aml_arg(4);
Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
@@ -678,7 +680,7 @@ static Aml *aml_pci_pdsm(void)
*/
ifctx1 = aml_if(aml_lnot(
aml_or(aml_equal(acpi_index, zero),
aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
aml_equal(acpi_index, not_supp), NULL)
));
{
/* have supported functions */
@@ -704,18 +706,30 @@ static Aml *aml_pci_pdsm(void)
{
Aml *pkg = aml_package(2);
aml_append(pkg, zero);
/*
* optional, if not impl. should return null string
*/
aml_append(pkg, aml_string("%s", ""));
aml_append(ifctx, aml_store(pkg, ret));
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
aml_append(ifctx, aml_store(pkg, ret));
/*
* update acpi-index to actual value
* Windows calls func=7 without checking if it's available,
* as workaround Microsoft has suggested to return invalid for func7
* Package, so return 2 elements package but only initialize elements
* when acpi_index is supported and leave them uninitialized, which
* leads elements to being Uninitialized ObjectType and should trip
* Windows into discarding result as an unexpected and prevent setting
* bogus 'PCI Label' on the device.
*/
aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero)));
ifctx1 = aml_if(aml_lnot(aml_lor(
aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp)
)));
{
aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
/*
* optional, if not impl. should return null string
*/
aml_append(ifctx1, aml_store(aml_string("%s", ""),
aml_index(ret, one)));
}
aml_append(ifctx, ifctx1);
aml_append(ifctx, aml_return(ret));
}
@@ -2432,7 +2446,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
uint8_t *u;
GArray *tables_blob = tables->table_data;
AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
Object *vmgenid_dev;
Object *vmgenid_dev, *vmclock_dev;
char *oem_id;
char *oem_table_id;
@@ -2505,6 +2519,13 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
tables->vmgenid, tables->linker, x86ms->oem_id);
}
vmclock_dev = find_vmclock_dev();
if (vmclock_dev) {
acpi_add_table(table_offsets, tables_blob);
vmclock_build_acpi(VMCLOCK(vmclock_dev), tables_blob, tables->linker,
x86ms->oem_id);
}
if (misc.has_hpet) {
acpi_add_table(table_offsets, tables_blob);
build_hpet(tables_blob, tables->linker, x86ms->oem_id,
+593 -141
View File
File diff suppressed because it is too large Load Diff
+83 -18
View File
@@ -195,6 +195,7 @@
#define VTD_ECAP_PASID (1ULL << 40)
#define VTD_ECAP_SMTS (1ULL << 43)
#define VTD_ECAP_SLTS (1ULL << 46)
#define VTD_ECAP_FLTS (1ULL << 47)
/* CAP_REG */
/* (offset >> 4) << 24 */
@@ -211,6 +212,7 @@
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
#define VTD_CAP_DRAIN_WRITE (1ULL << 54)
#define VTD_CAP_DRAIN_READ (1ULL << 55)
#define VTD_CAP_FS1GP (1ULL << 56)
#define VTD_CAP_DRAIN (VTD_CAP_DRAIN_READ | VTD_CAP_DRAIN_WRITE)
#define VTD_CAP_CM (1ULL << 7)
#define VTD_PASID_ID_SHIFT 20
@@ -311,10 +313,28 @@ typedef enum VTDFaultReason {
* request while disabled */
VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */
VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */
/* PASID directory entry access failure */
VTD_FR_PASID_DIR_ACCESS_ERR = 0x50,
/* The Present(P) field of pasid directory entry is 0 */
VTD_FR_PASID_DIR_ENTRY_P = 0x51,
VTD_FR_PASID_TABLE_ACCESS_ERR = 0x58, /* PASID table entry access failure */
/* The Present(P) field of pasid table entry is 0 */
VTD_FR_PASID_ENTRY_P = 0x59,
VTD_FR_PASID_TABLE_ENTRY_INV = 0x5b, /*Invalid PASID table entry */
/* Fail to access a first-level paging entry (not FS_PML4E) */
VTD_FR_FS_PAGING_ENTRY_INV = 0x70,
VTD_FR_FS_PAGING_ENTRY_P = 0x71,
/* Non-zero reserved field in present first-stage paging entry */
VTD_FR_FS_PAGING_ENTRY_RSVD = 0x72,
VTD_FR_PASID_ENTRY_FSPTPTR_INV = 0x73, /* Invalid FSPTPTR in PASID entry */
VTD_FR_FS_NON_CANONICAL = 0x80, /* SNG.1 : Address for FS not canonical.*/
VTD_FR_FS_PAGING_ENTRY_US = 0x81, /* Privilege violation */
VTD_FR_SM_WRITE = 0x85, /* No write permission */
/* Output address in the interrupt address range for scalable mode */
VTD_FR_SM_INTERRUPT_ADDR = 0x87,
VTD_FR_FS_BIT_UPDATE_FAILED = 0x91, /* SFS.10 */
VTD_FR_MAX, /* Guard */
} VTDFaultReason;
@@ -367,6 +387,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
#define VTD_INV_DESC_PIOTLB 0x6 /* PASID-IOTLB Invalidate Desc */
#define VTD_INV_DESC_PC 0x7 /* PASID-cache Invalidate Desc */
#define VTD_INV_DESC_DEV_PIOTLB 0x8 /* PASID-based-DIOTLB inv_desc*/
#define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */
/* Masks for Invalidation Wait Descriptor*/
@@ -397,11 +418,6 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
#define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4)
#define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4)
#define VTD_INV_DESC_IOTLB_PASID(val) (((val) >> 32) & VTD_PASID_ID_MASK)
#define VTD_INV_DESC_IOTLB_PASID_RSVD_LO 0xfff00000000001c0ULL
#define VTD_INV_DESC_IOTLB_PASID_RSVD_HI 0xf80ULL
/* Mask for Device IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL)
@@ -413,6 +429,16 @@ typedef union VTDInvDesc VTDInvDesc;
/* Masks for Interrupt Entry Invalidate Descriptor */
#define VTD_INV_DESC_IEC_RSVD 0xffff000007fff1e0ULL
/* Masks for PASID based Device IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_ADDR(val) ((val) & \
0xfffffffffffff000ULL)
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_SIZE(val) ((val >> 11) & 0x1)
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_GLOBAL(val) ((val) & 0x1)
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_SID(val) (((val) >> 16) & 0xffffULL)
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_PASID(val) ((val >> 32) & 0xfffffULL)
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_RSVD_VAL0 0xfff000000000f000ULL
#define VTD_INV_DESC_PASID_DEVICE_IOTLB_RSVD_VAL1 0x7feULL
/* Rsvd field masks for spte */
#define VTD_SPTE_SNP 0x800ULL
@@ -436,6 +462,34 @@ typedef union VTDInvDesc VTDInvDesc;
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
/* Rsvd field masks for fpte */
#define VTD_FS_UPPER_IGNORED 0xfff0000000000000ULL
#define VTD_FPTE_PAGE_L1_RSVD_MASK(aw) \
(~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
#define VTD_FPTE_PAGE_L2_RSVD_MASK(aw) \
(~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
#define VTD_FPTE_PAGE_L3_RSVD_MASK(aw) \
(~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
#define VTD_FPTE_PAGE_L4_RSVD_MASK(aw) \
(0x80ULL | ~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
#define VTD_FPTE_LPAGE_L2_RSVD_MASK(aw) \
(0x1fe000ULL | ~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
#define VTD_FPTE_LPAGE_L3_RSVD_MASK(aw) \
(0x3fffe000ULL | ~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
/* Masks for PIOTLB Invalidate Descriptor */
#define VTD_INV_DESC_PIOTLB_G (3ULL << 4)
#define VTD_INV_DESC_PIOTLB_ALL_IN_PASID (2ULL << 4)
#define VTD_INV_DESC_PIOTLB_PSI_IN_PASID (3ULL << 4)
#define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL)
#define VTD_INV_DESC_PIOTLB_AM(val) ((val) & 0x3fULL)
#define VTD_INV_DESC_PIOTLB_IH(val) (((val) >> 6) & 0x1)
#define VTD_INV_DESC_PIOTLB_ADDR(val) ((val) & ~0xfffULL)
#define VTD_INV_DESC_PIOTLB_RSVD_VAL0 0xfff000000000f1c0ULL
#define VTD_INV_DESC_PIOTLB_RSVD_VAL1 0xf80ULL
/* Information about page-selective IOTLB invalidate */
struct VTDIOTLBPageInvInfo {
uint16_t domain_id;
@@ -519,27 +573,38 @@ typedef struct VTDRootEntry VTDRootEntry;
#define VTD_SM_PASID_ENTRY_AW 7ULL /* Adjusted guest-address-width */
#define VTD_SM_PASID_ENTRY_DID(val) ((val) & VTD_DOMAIN_ID_MASK)
#define VTD_SM_PASID_ENTRY_FLPM 3ULL
#define VTD_SM_PASID_ENTRY_FLPTPTR (~0xfffULL)
/* First Level Paging Structure */
/* Masks for First Level Paging Entry */
#define VTD_FL_P 1ULL
#define VTD_FL_RW (1ULL << 1)
#define VTD_FL_US (1ULL << 2)
#define VTD_FL_A (1ULL << 5)
#define VTD_FL_D (1ULL << 6)
/* Second Level Page Translation Pointer*/
#define VTD_SM_PASID_ENTRY_SLPTPTR (~0xfffULL)
/* Paging Structure common */
#define VTD_SL_PT_PAGE_SIZE_MASK (1ULL << 7)
/* Bits to decide the offset for each level */
#define VTD_SL_LEVEL_BITS 9
/* Second Level Paging Structure */
#define VTD_SL_PML4_LEVEL 4
#define VTD_SL_PDP_LEVEL 3
#define VTD_SL_PD_LEVEL 2
#define VTD_SL_PT_LEVEL 1
#define VTD_SL_PT_ENTRY_NR 512
/* Masks for Second Level Paging Entry */
#define VTD_SL_RW_MASK 3ULL
#define VTD_SL_R 1ULL
#define VTD_SL_W (1ULL << 1)
#define VTD_SL_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
#define VTD_SL_IGN_COM 0xbff0000000000000ULL
#define VTD_SL_TM (1ULL << 62)
/* Common for both First Level and Second Level */
#define VTD_PML4_LEVEL 4
#define VTD_PDP_LEVEL 3
#define VTD_PD_LEVEL 2
#define VTD_PT_LEVEL 1
#define VTD_PT_ENTRY_NR 512
#define VTD_PT_PAGE_SIZE_MASK (1ULL << 7)
#define VTD_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
/* Bits to decide the offset for each level */
#define VTD_LEVEL_BITS 9
#endif
+1
View File
@@ -86,6 +86,7 @@ GlobalProperty pc_compat_9_1[] = {
{ "ICH9-LPC", "x-smi-swsmi-timer", "off" },
{ "ICH9-LPC", "x-smi-periodic-timer", "off" },
{ TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" },
{ TYPE_INTEL_IOMMU_DEVICE, "aw-bits", "39" },
};
const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
+1 -1
View File
@@ -843,7 +843,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
ComponentRegisters *regs = &cxl_cstate->crb;
MemoryRegion *mr = &regs->component_registers;
uint8_t *pci_conf = pci_dev->config;
unsigned short msix_num = 6;
unsigned short msix_num = 10;
int i, rc;
uint16_t count;
+112 -23
View File
@@ -3337,6 +3337,117 @@ static const VMStateDescription vmstate_virtio_net_rss = {
},
};
static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc;
struct vhost_net *net;
if (!n->nic) {
return NULL;
}
nc = qemu_get_queue(n->nic);
if (!nc) {
return NULL;
}
net = get_vhost_net(nc->peer);
if (!net) {
return NULL;
}
return &net->dev;
}
static int vhost_user_net_save_state(QEMUFile *f, void *pv, size_t size,
const VMStateField *field,
JSONWriter *vmdesc)
{
VirtIONet *n = pv;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct vhost_dev *vhdev;
Error *local_error = NULL;
int ret;
vhdev = virtio_net_get_vhost(vdev);
if (vhdev == NULL) {
error_reportf_err(local_error,
"Error getting vhost back-end of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return -1;
}
ret = vhost_save_backend_state(vhdev, f, &local_error);
if (ret < 0) {
error_reportf_err(local_error,
"Error saving back-end state of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return ret;
}
return 0;
}
static int vhost_user_net_load_state(QEMUFile *f, void *pv, size_t size,
const VMStateField *field)
{
VirtIONet *n = pv;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct vhost_dev *vhdev;
Error *local_error = NULL;
int ret;
vhdev = virtio_net_get_vhost(vdev);
if (vhdev == NULL) {
error_reportf_err(local_error,
"Error getting vhost back-end of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return -1;
}
ret = vhost_load_backend_state(vhdev, f, &local_error);
if (ret < 0) {
error_reportf_err(local_error,
"Error loading back-end state of %s device %s: ",
vdev->name, vdev->parent_obj.canonical_path);
return ret;
}
return 0;
}
static bool vhost_user_net_is_internal_migration(void *opaque)
{
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct vhost_dev *vhdev;
vhdev = virtio_net_get_vhost(vdev);
if (vhdev == NULL) {
return false;
}
return vhost_supports_device_state(vhdev);
}
static const VMStateDescription vhost_user_net_backend_state = {
.name = "virtio-net-device/backend",
.version_id = 0,
.needed = vhost_user_net_is_internal_migration,
.fields = (const VMStateField[]) {
{
.name = "backend",
.info = &(const VMStateInfo) {
.name = "virtio-net vhost-user backend state",
.get = vhost_user_net_load_state,
.put = vhost_user_net_save_state,
},
},
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_virtio_net_device = {
.name = "virtio-net-device",
.version_id = VIRTIO_NET_VM_VERSION,
@@ -3389,6 +3500,7 @@ static const VMStateDescription vmstate_virtio_net_device = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_virtio_net_rss,
&vhost_user_net_backend_state,
NULL
}
};
@@ -3950,29 +4062,6 @@ static bool dev_unplug_pending(void *opaque)
return vdc->primary_unplug_pending(dev);
}
static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc;
struct vhost_net *net;
if (!n->nic) {
return NULL;
}
nc = qemu_get_queue(n->nic);
if (!nc) {
return NULL;
}
net = get_vhost_net(nc->peer);
if (!net) {
return NULL;
}
return &net->dev;
}
static const VMStateDescription vmstate_virtio_net = {
.name = "virtio-net",
.minimum_version_id = VIRTIO_NET_VM_VERSION,
+1 -1
View File
@@ -250,7 +250,7 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
PCIDevice *dev = opaque;
if (dev->msix_vector_poll_notifier) {
unsigned vector_start = addr * 8;
unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr);
unsigned vector_end = MIN((addr + size) * 8, dev->msix_entries_nr);
dev->msix_vector_poll_notifier(dev, vector_start, vector_end);
}

Some files were not shown because too many files have changed in this diff Show More