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----- 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:
commit
0e3327b690
@ -3711,6 +3711,7 @@ F: hw/i386/intel_iommu.c
|
|||||||
F: hw/i386/intel_iommu_internal.h
|
F: hw/i386/intel_iommu_internal.h
|
||||||
F: include/hw/i386/intel_iommu.h
|
F: include/hw/i386/intel_iommu.h
|
||||||
F: tests/functional/test_intel_iommu.py
|
F: tests/functional/test_intel_iommu.py
|
||||||
|
F: tests/qtest/intel-iommu-test.c
|
||||||
|
|
||||||
AMD-Vi Emulation
|
AMD-Vi Emulation
|
||||||
S: Orphan
|
S: Orphan
|
||||||
|
@ -67,8 +67,10 @@ Design Details
|
|||||||
(3) The address registers table contains N Error Block Address entries
|
(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.
|
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
|
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
|
entries. The size for each entry is defined at the source code as
|
||||||
for the "etc/hardware_errors" fw_cfg blob is (N * 8 * 2 + N * 4096) bytes.
|
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.
|
N is the number of the kinds of hardware error sources.
|
||||||
|
|
||||||
(4) QEMU generates the ACPI linker/loader script for the firmware. The
|
(4) QEMU generates the ACPI linker/loader script for the firmware. The
|
||||||
|
@ -60,6 +60,11 @@ config ACPI_VMGENID
|
|||||||
default y
|
default y
|
||||||
depends on PC
|
depends on PC
|
||||||
|
|
||||||
|
config ACPI_VMCLOCK
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on PC
|
||||||
|
|
||||||
config ACPI_VIOT
|
config ACPI_VIOT
|
||||||
bool
|
bool
|
||||||
depends on ACPI
|
depends on ACPI
|
||||||
|
@ -327,6 +327,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
|
|||||||
#define CPU_EJECT_METHOD "CEJ0"
|
#define CPU_EJECT_METHOD "CEJ0"
|
||||||
#define CPU_OST_METHOD "COST"
|
#define CPU_OST_METHOD "COST"
|
||||||
#define CPU_ADDED_LIST "CNEW"
|
#define CPU_ADDED_LIST "CNEW"
|
||||||
|
#define CPU_EJ_LIST "CEJL"
|
||||||
|
|
||||||
#define CPU_ENABLED "CPEN"
|
#define CPU_ENABLED "CPEN"
|
||||||
#define CPU_SELECTOR "CSEL"
|
#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);
|
method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED);
|
||||||
{
|
{
|
||||||
const uint8_t max_cpus_per_pass = 255;
|
const uint8_t max_cpus_per_pass = 255;
|
||||||
Aml *else_ctx;
|
|
||||||
Aml *while_ctx, *while_ctx2;
|
Aml *while_ctx, *while_ctx2;
|
||||||
Aml *has_event = aml_local(0);
|
Aml *has_event = aml_local(0);
|
||||||
Aml *dev_chk = aml_int(1);
|
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 *uid = aml_local(3);
|
||||||
Aml *has_job = aml_local(4);
|
Aml *has_job = aml_local(4);
|
||||||
Aml *new_cpus = aml_name(CPU_ADDED_LIST);
|
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));
|
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_append(method, aml_name_decl(CPU_ADDED_LIST,
|
||||||
aml_package(max_cpus_per_pass)));
|
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(zero, uid));
|
||||||
aml_append(method, aml_store(one, has_job));
|
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(one, has_event));
|
||||||
aml_append(while_ctx2, aml_store(zero, num_added_cpus));
|
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
|
* 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
|
* if CPU_ADDED_LIST is full, exit inner loop and process
|
||||||
* collected CPUs
|
* collected CPUs
|
||||||
*/
|
*/
|
||||||
ifctx = aml_if(
|
ifctx = aml_if(aml_lor(
|
||||||
aml_equal(num_added_cpus, aml_int(max_cpus_per_pass)));
|
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_store(one, has_job));
|
||||||
aml_append(ifctx, aml_break());
|
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(ifctx, aml_store(one, has_event));
|
||||||
}
|
}
|
||||||
aml_append(while_ctx, ifctx);
|
aml_append(while_ctx, ifctx);
|
||||||
else_ctx = aml_else();
|
|
||||||
ifctx = aml_if(aml_equal(rm_evt, one));
|
ifctx = aml_if(aml_equal(rm_evt, one));
|
||||||
{
|
{
|
||||||
aml_append(ifctx,
|
/* cache to be removed CPUs to Notify later */
|
||||||
aml_call2(CPU_NOTIFY_METHOD, uid, eject_req));
|
aml_append(ifctx, aml_store(uid,
|
||||||
aml_append(ifctx, aml_store(one, rm_evt));
|
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(ifctx, aml_store(one, has_event));
|
||||||
}
|
}
|
||||||
aml_append(else_ctx, ifctx);
|
aml_append(while_ctx, ifctx);
|
||||||
aml_append(while_ctx, else_ctx);
|
|
||||||
aml_append(while_ctx, aml_increment(uid));
|
aml_append(while_ctx, aml_increment(uid));
|
||||||
}
|
}
|
||||||
aml_append(while_ctx2, while_ctx);
|
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_ctx, aml_increment(cpu_idx));
|
||||||
}
|
}
|
||||||
aml_append(while_ctx2, while_ctx);
|
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
|
* If another batch is needed, then it will resume scanning
|
||||||
* exactly at -- and not after -- the last CPU that's currently
|
* exactly at -- and not after -- the last CPU that's currently
|
||||||
|
@ -363,7 +363,7 @@ static const VMStateDescription vmstate_ghes = {
|
|||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.fields = (const VMStateField[]) {
|
.fields = (const VMStateField[]) {
|
||||||
VMSTATE_UINT64(ghes_addr_le, AcpiGhesState),
|
VMSTATE_UINT64(hw_error_le, AcpiGhesState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -371,7 +371,7 @@ static const VMStateDescription vmstate_ghes = {
|
|||||||
static bool ghes_needed(void *opaque)
|
static bool ghes_needed(void *opaque)
|
||||||
{
|
{
|
||||||
AcpiGedState *s = opaque;
|
AcpiGedState *s = opaque;
|
||||||
return s->ghes_state.ghes_addr_le;
|
return s->ghes_state.hw_error_le;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_ghes_state = {
|
static const VMStateDescription vmstate_ghes_state = {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "hw/acpi/ghes.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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
226
hw/acpi/ghes.c
226
hw/acpi/ghes.c
@ -28,15 +28,12 @@
|
|||||||
#include "hw/nvram/fw_cfg.h"
|
#include "hw/nvram/fw_cfg.h"
|
||||||
#include "qemu/uuid.h"
|
#include "qemu/uuid.h"
|
||||||
|
|
||||||
#define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors"
|
#define ACPI_HW_ERROR_FW_CFG_FILE "etc/hardware_errors"
|
||||||
#define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr"
|
#define ACPI_HW_ERROR_ADDR_FW_CFG_FILE "etc/hardware_errors_addr"
|
||||||
|
|
||||||
/* The max size in bytes for one error block */
|
/* The max size in bytes for one error block */
|
||||||
#define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB)
|
#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 */
|
/* Generic Hardware Error Source version 2 */
|
||||||
#define ACPI_GHES_SOURCE_GENERIC_ERROR_V2 10
|
#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);
|
build_append_int_noprefix(table, 0, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acpi_ghes_record_mem_error(uint64_t error_block_address,
|
static void
|
||||||
uint64_t error_physical_addr)
|
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,
|
/* invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data,
|
||||||
* Table 17-13 Generic Error Data Entry
|
* Table 17-13 Generic Error Data Entry
|
||||||
*/
|
*/
|
||||||
QemuUUID fru_id = {};
|
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 */
|
/* Build the new generic error status block header */
|
||||||
acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE,
|
acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE,
|
||||||
0, 0, data_length, ACPI_CPER_SEV_RECOVERABLE);
|
0, 0, data_length, ACPI_CPER_SEV_RECOVERABLE);
|
||||||
|
|
||||||
/* Build this new generic error data entry header */
|
/* 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_CPER_SEV_RECOVERABLE, 0, 0,
|
||||||
ACPI_GHES_MEM_CPER_LENGTH, fru_id, 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.
|
* Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs.
|
||||||
* See docs/specs/acpi_hest_ghes.rst for blobs format.
|
* 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;
|
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);
|
ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT);
|
||||||
|
|
||||||
/* Tell guest firmware to place hardware_errors blob into RAM */
|
/* 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);
|
hardware_errors, sizeof(uint64_t), false);
|
||||||
|
|
||||||
for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) {
|
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"
|
* corresponding "Generic Error Status Block"
|
||||||
*/
|
*/
|
||||||
bios_linker_loader_add_pointer(linker,
|
bios_linker_loader_add_pointer(linker,
|
||||||
ACPI_GHES_ERRORS_FW_CFG_FILE, sizeof(uint64_t) * i,
|
ACPI_HW_ERROR_FW_CFG_FILE,
|
||||||
sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE,
|
sizeof(uint64_t) * i,
|
||||||
error_status_block_offset + i * ACPI_GHES_MAX_RAW_DATA_LENGTH);
|
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
|
* tell firmware to write hardware_errors GPA into
|
||||||
* hardware_errors_addr fw_cfg, once the former has been initialized.
|
* hardware_errors_addr fw_cfg, once the former has been initialized.
|
||||||
*/
|
*/
|
||||||
bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE,
|
bios_linker_loader_write_pointer(linker, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, 0,
|
||||||
0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0);
|
sizeof(uint64_t),
|
||||||
|
ACPI_HW_ERROR_FW_CFG_FILE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build Generic Hardware Error Source version 2 (GHESv2) */
|
/* 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;
|
uint64_t address_offset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type:
|
* Type:
|
||||||
* Generic Hardware Error Source version 2(GHESv2 - Type 10)
|
* 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,
|
build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0,
|
||||||
4 /* QWord access */, 0);
|
4 /* QWord access */, 0);
|
||||||
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
||||||
address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t),
|
address_offset + GAS_ADDR_OFFSET,
|
||||||
ACPI_GHES_ERRORS_FW_CFG_FILE, source_id * sizeof(uint64_t));
|
sizeof(uint64_t),
|
||||||
|
ACPI_HW_ERROR_FW_CFG_FILE,
|
||||||
|
source_id * sizeof(uint64_t));
|
||||||
|
|
||||||
switch (source_id) {
|
/* Notification Structure */
|
||||||
case ACPI_HEST_SRC_ID_SEA:
|
build_ghes_hw_error_notification(table_data, notify);
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Error Status Block Length */
|
/* Error Status Block Length */
|
||||||
build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4);
|
build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4);
|
||||||
@ -345,8 +315,10 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
|
|||||||
4 /* QWord access */, 0);
|
4 /* QWord access */, 0);
|
||||||
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
||||||
address_offset + GAS_ADDR_OFFSET,
|
address_offset + GAS_ADDR_OFFSET,
|
||||||
sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE,
|
sizeof(uint64_t),
|
||||||
(ACPI_GHES_ERROR_SOURCE_COUNT + source_id) * sizeof(uint64_t));
|
ACPI_HW_ERROR_FW_CFG_FILE,
|
||||||
|
(ACPI_GHES_ERROR_SOURCE_COUNT + source_id)
|
||||||
|
* sizeof(uint64_t));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read Ack Preserve field
|
* 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 */
|
/* 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)
|
const char *oem_id, const char *oem_table_id)
|
||||||
{
|
{
|
||||||
AcpiTable table = { .sig = "HEST", .rev = 1,
|
AcpiTable table = { .sig = "HEST", .rev = 1,
|
||||||
.oem_id = oem_id, .oem_table_id = oem_table_id };
|
.oem_id = oem_id, .oem_table_id = oem_table_id };
|
||||||
|
|
||||||
|
build_ghes_error_table(hardware_errors, linker);
|
||||||
|
|
||||||
acpi_table_begin(&table, table_data);
|
acpi_table_begin(&table, table_data);
|
||||||
|
|
||||||
/* Error Source Count */
|
/* Error Source Count */
|
||||||
build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4);
|
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);
|
acpi_table_end(linker, &table);
|
||||||
}
|
}
|
||||||
@ -378,70 +354,132 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s,
|
|||||||
GArray *hardware_error)
|
GArray *hardware_error)
|
||||||
{
|
{
|
||||||
/* Create a read-only fw_cfg file for GHES */
|
/* 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);
|
hardware_error->len);
|
||||||
|
|
||||||
/* Create a read-write fw_cfg file for Address */
|
/* Create a read-write fw_cfg file for Address */
|
||||||
fw_cfg_add_file_callback(s, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, NULL, NULL,
|
fw_cfg_add_file_callback(s, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, NULL, NULL,
|
||||||
NULL, &(ags->ghes_addr_le), sizeof(ags->ghes_addr_le), false);
|
NULL, &(ags->hw_error_le), sizeof(ags->hw_error_le), false);
|
||||||
|
|
||||||
ags->present = true;
|
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;
|
if (!ghes_addr) {
|
||||||
uint64_t start_addr;
|
return;
|
||||||
bool ret = -1;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
AcpiGedState *acpi_ged_state;
|
||||||
AcpiGhesState *ags;
|
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,
|
acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED,
|
||||||
NULL));
|
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;
|
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 (!cper_addr) {
|
||||||
|
error_setg(errp, "can not find Generic Error Status Block");
|
||||||
if (source_id < ACPI_HEST_SRC_ID_RESERVED) {
|
return;
|
||||||
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,
|
cpu_physical_memory_read(read_ack_register_addr,
|
||||||
&read_ack_register, sizeof(read_ack_register));
|
&read_ack_register, sizeof(read_ack_register));
|
||||||
|
|
||||||
/* zero means OSPM does not acknowledge the error */
|
/* zero means OSPM does not acknowledge the error */
|
||||||
if (!read_ack_register) {
|
if (!read_ack_register) {
|
||||||
error_report("OSPM does not acknowledge previous error,"
|
error_setg(errp,
|
||||||
|
"OSPM does not acknowledge previous error,"
|
||||||
" so can not record CPER for current error anymore");
|
" so can not record CPER for current error anymore");
|
||||||
} else if (error_block_addr) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
read_ack_register = cpu_to_le64(0);
|
read_ack_register = cpu_to_le64(0);
|
||||||
/*
|
/*
|
||||||
* Clear the Read Ack Register, OSPM will write it to 1 when
|
* Clear the Read Ack Register, OSPM will write 1 to this register when
|
||||||
* it acknowledges this error.
|
* it acknowledges the error.
|
||||||
*/
|
*/
|
||||||
cpu_physical_memory_write(read_ack_register_addr,
|
cpu_physical_memory_write(read_ack_register_addr,
|
||||||
&read_ack_register, sizeof(uint64_t));
|
&read_ack_register, sizeof(uint64_t));
|
||||||
|
|
||||||
ret = acpi_ghes_record_mem_error(error_block_addr,
|
/* Write the generic error data entry into guest memory */
|
||||||
physical_address);
|
cpu_physical_memory_write(cper_addr, cper, len);
|
||||||
} else
|
|
||||||
error_report("can not find Generic Error Status Block");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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)
|
bool acpi_ghes_present(void)
|
||||||
|
@ -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_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_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_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_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_HMAT', if_true: files('hmat.c'))
|
||||||
acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c'))
|
acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c'))
|
||||||
|
179
hw/acpi/vmclock.c
Normal file
179
hw/acpi/vmclock.c
Normal 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)
|
@ -946,10 +946,9 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
|||||||
build_dbg2(tables_blob, tables->linker, vms);
|
build_dbg2(tables_blob, tables->linker, vms);
|
||||||
|
|
||||||
if (vms->ras) {
|
if (vms->ras) {
|
||||||
build_ghes_error_table(tables->hardware_errors, tables->linker);
|
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
acpi_build_hest(tables_blob, tables->linker, vms->oem_id,
|
acpi_build_hest(tables_blob, tables->hardware_errors, tables->linker,
|
||||||
vms->oem_table_id);
|
vms->oem_id, vms->oem_table_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ms->numa_state->num_nodes > 0) {
|
if (ms->numa_state->num_nodes > 0) {
|
||||||
|
@ -631,6 +631,14 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
|
|||||||
error_report("EDID requested but the backend doesn't support it.");
|
error_report("EDID requested but the backend doesn't support it.");
|
||||||
g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
|
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)) {
|
if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
|
||||||
return;
|
return;
|
||||||
|
@ -235,6 +235,9 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features,
|
|||||||
if (virtio_gpu_context_init_enabled(g->conf)) {
|
if (virtio_gpu_context_init_enabled(g->conf)) {
|
||||||
features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT);
|
features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT);
|
||||||
}
|
}
|
||||||
|
if (virtio_gpu_resource_uuid_enabled(g->conf)) {
|
||||||
|
features |= (1 << VIRTIO_GPU_F_RESOURCE_UUID);
|
||||||
|
}
|
||||||
|
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ config PC
|
|||||||
select SERIAL_ISA
|
select SERIAL_ISA
|
||||||
select ACPI_PCI
|
select ACPI_PCI
|
||||||
select ACPI_VMGENID
|
select ACPI_VMGENID
|
||||||
|
select ACPI_VMCLOCK
|
||||||
select VIRTIO_PMEM_SUPPORTED
|
select VIRTIO_PMEM_SUPPORTED
|
||||||
select VIRTIO_MEM_SUPPORTED
|
select VIRTIO_MEM_SUPPORTED
|
||||||
select HV_BALLOON_SUPPORTED
|
select HV_BALLOON_SUPPORTED
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "system/tpm.h"
|
#include "system/tpm.h"
|
||||||
#include "hw/acpi/tpm.h"
|
#include "hw/acpi/tpm.h"
|
||||||
#include "hw/acpi/vmgenid.h"
|
#include "hw/acpi/vmgenid.h"
|
||||||
|
#include "hw/acpi/vmclock.h"
|
||||||
#include "hw/acpi/erst.h"
|
#include "hw/acpi/erst.h"
|
||||||
#include "hw/acpi/piix4.h"
|
#include "hw/acpi/piix4.h"
|
||||||
#include "system/tpm_backend.h"
|
#include "system/tpm_backend.h"
|
||||||
@ -654,6 +655,7 @@ static Aml *aml_pci_pdsm(void)
|
|||||||
Aml *acpi_index = aml_local(2);
|
Aml *acpi_index = aml_local(2);
|
||||||
Aml *zero = aml_int(0);
|
Aml *zero = aml_int(0);
|
||||||
Aml *one = aml_int(1);
|
Aml *one = aml_int(1);
|
||||||
|
Aml *not_supp = aml_int(0xFFFFFFFF);
|
||||||
Aml *func = aml_arg(2);
|
Aml *func = aml_arg(2);
|
||||||
Aml *params = aml_arg(4);
|
Aml *params = aml_arg(4);
|
||||||
Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
|
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(
|
ifctx1 = aml_if(aml_lnot(
|
||||||
aml_or(aml_equal(acpi_index, zero),
|
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 */
|
/* have supported functions */
|
||||||
@ -704,18 +706,30 @@ static Aml *aml_pci_pdsm(void)
|
|||||||
{
|
{
|
||||||
Aml *pkg = aml_package(2);
|
Aml *pkg = aml_package(2);
|
||||||
|
|
||||||
aml_append(pkg, zero);
|
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
|
||||||
|
aml_append(ifctx, aml_store(pkg, ret));
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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
|
* optional, if not impl. should return null string
|
||||||
*/
|
*/
|
||||||
aml_append(pkg, aml_string("%s", ""));
|
aml_append(ifctx1, aml_store(aml_string("%s", ""),
|
||||||
aml_append(ifctx, aml_store(pkg, ret));
|
aml_index(ret, one)));
|
||||||
|
}
|
||||||
|
aml_append(ifctx, ifctx1);
|
||||||
|
|
||||||
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
|
|
||||||
/*
|
|
||||||
* update acpi-index to actual value
|
|
||||||
*/
|
|
||||||
aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero)));
|
|
||||||
aml_append(ifctx, aml_return(ret));
|
aml_append(ifctx, aml_return(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2432,7 +2446,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
|||||||
uint8_t *u;
|
uint8_t *u;
|
||||||
GArray *tables_blob = tables->table_data;
|
GArray *tables_blob = tables->table_data;
|
||||||
AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
|
AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
|
||||||
Object *vmgenid_dev;
|
Object *vmgenid_dev, *vmclock_dev;
|
||||||
char *oem_id;
|
char *oem_id;
|
||||||
char *oem_table_id;
|
char *oem_table_id;
|
||||||
|
|
||||||
@ -2505,6 +2519,13 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
|||||||
tables->vmgenid, tables->linker, x86ms->oem_id);
|
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) {
|
if (misc.has_hpet) {
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
build_hpet(tables_blob, tables->linker, x86ms->oem_id,
|
build_hpet(tables_blob, tables->linker, x86ms->oem_id,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -195,6 +195,7 @@
|
|||||||
#define VTD_ECAP_PASID (1ULL << 40)
|
#define VTD_ECAP_PASID (1ULL << 40)
|
||||||
#define VTD_ECAP_SMTS (1ULL << 43)
|
#define VTD_ECAP_SMTS (1ULL << 43)
|
||||||
#define VTD_ECAP_SLTS (1ULL << 46)
|
#define VTD_ECAP_SLTS (1ULL << 46)
|
||||||
|
#define VTD_ECAP_FLTS (1ULL << 47)
|
||||||
|
|
||||||
/* CAP_REG */
|
/* CAP_REG */
|
||||||
/* (offset >> 4) << 24 */
|
/* (offset >> 4) << 24 */
|
||||||
@ -211,6 +212,7 @@
|
|||||||
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
|
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
|
||||||
#define VTD_CAP_DRAIN_WRITE (1ULL << 54)
|
#define VTD_CAP_DRAIN_WRITE (1ULL << 54)
|
||||||
#define VTD_CAP_DRAIN_READ (1ULL << 55)
|
#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_DRAIN (VTD_CAP_DRAIN_READ | VTD_CAP_DRAIN_WRITE)
|
||||||
#define VTD_CAP_CM (1ULL << 7)
|
#define VTD_CAP_CM (1ULL << 7)
|
||||||
#define VTD_PASID_ID_SHIFT 20
|
#define VTD_PASID_ID_SHIFT 20
|
||||||
@ -311,10 +313,28 @@ typedef enum VTDFaultReason {
|
|||||||
* request while disabled */
|
* request while disabled */
|
||||||
VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */
|
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 */
|
/* Output address in the interrupt address range for scalable mode */
|
||||||
VTD_FR_SM_INTERRUPT_ADDR = 0x87,
|
VTD_FR_SM_INTERRUPT_ADDR = 0x87,
|
||||||
|
VTD_FR_FS_BIT_UPDATE_FAILED = 0x91, /* SFS.10 */
|
||||||
VTD_FR_MAX, /* Guard */
|
VTD_FR_MAX, /* Guard */
|
||||||
} VTDFaultReason;
|
} VTDFaultReason;
|
||||||
|
|
||||||
@ -367,6 +387,7 @@ typedef union VTDInvDesc VTDInvDesc;
|
|||||||
#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
|
#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
|
||||||
#define VTD_INV_DESC_PIOTLB 0x6 /* PASID-IOTLB Invalidate Desc */
|
#define VTD_INV_DESC_PIOTLB 0x6 /* PASID-IOTLB Invalidate Desc */
|
||||||
#define VTD_INV_DESC_PC 0x7 /* PASID-cache 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 */
|
#define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */
|
||||||
|
|
||||||
/* Masks for Invalidation Wait 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_AM(val) ((val) & 0x3fULL)
|
||||||
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
|
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
|
||||||
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
|
#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 */
|
/* Mask for Device IOTLB Invalidate Descriptor */
|
||||||
#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL)
|
#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL)
|
||||||
@ -413,6 +429,16 @@ typedef union VTDInvDesc VTDInvDesc;
|
|||||||
/* Masks for Interrupt Entry Invalidate Descriptor */
|
/* Masks for Interrupt Entry Invalidate Descriptor */
|
||||||
#define VTD_INV_DESC_IEC_RSVD 0xffff000007fff1e0ULL
|
#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 */
|
/* Rsvd field masks for spte */
|
||||||
#define VTD_SPTE_SNP 0x800ULL
|
#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 | VTD_SL_TM)) : \
|
||||||
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
(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 */
|
/* Information about page-selective IOTLB invalidate */
|
||||||
struct VTDIOTLBPageInvInfo {
|
struct VTDIOTLBPageInvInfo {
|
||||||
uint16_t domain_id;
|
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_AW 7ULL /* Adjusted guest-address-width */
|
||||||
#define VTD_SM_PASID_ENTRY_DID(val) ((val) & VTD_DOMAIN_ID_MASK)
|
#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*/
|
/* Second Level Page Translation Pointer*/
|
||||||
#define VTD_SM_PASID_ENTRY_SLPTPTR (~0xfffULL)
|
#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 */
|
/* 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 */
|
/* Masks for Second Level Paging Entry */
|
||||||
#define VTD_SL_RW_MASK 3ULL
|
#define VTD_SL_RW_MASK 3ULL
|
||||||
#define VTD_SL_R 1ULL
|
#define VTD_SL_R 1ULL
|
||||||
#define VTD_SL_W (1ULL << 1)
|
#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_IGN_COM 0xbff0000000000000ULL
|
||||||
#define VTD_SL_TM (1ULL << 62)
|
#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
|
#endif
|
||||||
|
@ -86,6 +86,7 @@ GlobalProperty pc_compat_9_1[] = {
|
|||||||
{ "ICH9-LPC", "x-smi-swsmi-timer", "off" },
|
{ "ICH9-LPC", "x-smi-swsmi-timer", "off" },
|
||||||
{ "ICH9-LPC", "x-smi-periodic-timer", "off" },
|
{ "ICH9-LPC", "x-smi-periodic-timer", "off" },
|
||||||
{ TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" },
|
{ 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);
|
const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
|
|||||||
ComponentRegisters *regs = &cxl_cstate->crb;
|
ComponentRegisters *regs = &cxl_cstate->crb;
|
||||||
MemoryRegion *mr = ®s->component_registers;
|
MemoryRegion *mr = ®s->component_registers;
|
||||||
uint8_t *pci_conf = pci_dev->config;
|
uint8_t *pci_conf = pci_dev->config;
|
||||||
unsigned short msix_num = 6;
|
unsigned short msix_num = 10;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
|
|
||||||
|
@ -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 = {
|
static const VMStateDescription vmstate_virtio_net_device = {
|
||||||
.name = "virtio-net-device",
|
.name = "virtio-net-device",
|
||||||
.version_id = VIRTIO_NET_VM_VERSION,
|
.version_id = VIRTIO_NET_VM_VERSION,
|
||||||
@ -3389,6 +3500,7 @@ static const VMStateDescription vmstate_virtio_net_device = {
|
|||||||
},
|
},
|
||||||
.subsections = (const VMStateDescription * const []) {
|
.subsections = (const VMStateDescription * const []) {
|
||||||
&vmstate_virtio_net_rss,
|
&vmstate_virtio_net_rss,
|
||||||
|
&vhost_user_net_backend_state,
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3950,29 +4062,6 @@ static bool dev_unplug_pending(void *opaque)
|
|||||||
return vdc->primary_unplug_pending(dev);
|
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 = {
|
static const VMStateDescription vmstate_virtio_net = {
|
||||||
.name = "virtio-net",
|
.name = "virtio-net",
|
||||||
.minimum_version_id = VIRTIO_NET_VM_VERSION,
|
.minimum_version_id = VIRTIO_NET_VM_VERSION,
|
||||||
|
@ -250,7 +250,7 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
|
|||||||
PCIDevice *dev = opaque;
|
PCIDevice *dev = opaque;
|
||||||
if (dev->msix_vector_poll_notifier) {
|
if (dev->msix_vector_poll_notifier) {
|
||||||
unsigned vector_start = addr * 8;
|
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);
|
dev->msix_vector_poll_notifier(dev, vector_start, vector_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1113,18 +1113,22 @@ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
|
|||||||
if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
|
if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
|
||||||
lnksta &= ~PCI_EXP_LNKSTA_NLW;
|
lnksta &= ~PCI_EXP_LNKSTA_NLW;
|
||||||
lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
|
lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
|
||||||
} else if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
|
|
||||||
lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
|
if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
|
||||||
lnksta &= ~PCI_EXP_LNKSTA_CLS;
|
lnksta &= ~PCI_EXP_LNKSTA_CLS;
|
||||||
lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
|
lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
|
||||||
} else if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
|
|
||||||
lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
|
||||||
|
lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
|
||||||
|
lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
|
||||||
|
}
|
||||||
|
|
||||||
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
|
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
|
||||||
PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
|
PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
|
||||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
|
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define ACPI_GHES_H
|
#define ACPI_GHES_H
|
||||||
|
|
||||||
#include "hw/acpi/bios-linker-loader.h"
|
#include "hw/acpi/bios-linker-loader.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Values for Hardware Error Notification Type field
|
* Values for Hardware Error Notification Type field
|
||||||
@ -59,26 +60,29 @@ enum AcpiGhesNotifyType {
|
|||||||
enum {
|
enum {
|
||||||
ACPI_HEST_SRC_ID_SEA = 0,
|
ACPI_HEST_SRC_ID_SEA = 0,
|
||||||
/* future ids go here */
|
/* future ids go here */
|
||||||
ACPI_HEST_SRC_ID_RESERVED,
|
|
||||||
|
ACPI_GHES_ERROR_SOURCE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct AcpiGhesState {
|
typedef struct AcpiGhesState {
|
||||||
uint64_t ghes_addr_le;
|
uint64_t hw_error_le;
|
||||||
bool present; /* True if GHES is present at all on this board */
|
bool present; /* True if GHES is present at all on this board */
|
||||||
} AcpiGhesState;
|
} AcpiGhesState;
|
||||||
|
|
||||||
void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker);
|
void acpi_build_hest(GArray *table_data, GArray *hardware_errors,
|
||||||
void acpi_build_hest(GArray *table_data, BIOSLinker *linker,
|
BIOSLinker *linker,
|
||||||
const char *oem_id, const char *oem_table_id);
|
const char *oem_id, const char *oem_table_id);
|
||||||
void acpi_ghes_add_fw_cfg(AcpiGhesState *vms, FWCfgState *s,
|
void acpi_ghes_add_fw_cfg(AcpiGhesState *vms, FWCfgState *s,
|
||||||
GArray *hardware_errors);
|
GArray *hardware_errors);
|
||||||
int acpi_ghes_record_errors(uint8_t notify, uint64_t error_physical_addr);
|
int acpi_ghes_memory_errors(uint16_t source_id, uint64_t error_physical_addr);
|
||||||
|
void ghes_record_cper_errors(const void *cper, size_t len,
|
||||||
|
uint16_t source_id, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_ghes_present: Report whether ACPI GHES table is present
|
* acpi_ghes_present: Report whether ACPI GHES table is present
|
||||||
*
|
*
|
||||||
* Returns: true if the system has an ACPI GHES table and it is
|
* Returns: true if the system has an ACPI GHES table and it is
|
||||||
* safe to call acpi_ghes_record_errors() to record a memory error.
|
* safe to call acpi_ghes_memory_errors() to record a memory error.
|
||||||
*/
|
*/
|
||||||
bool acpi_ghes_present(void);
|
bool acpi_ghes_present(void);
|
||||||
#endif
|
#endif
|
||||||
|
34
include/hw/acpi/vmclock.h
Normal file
34
include/hw/acpi/vmclock.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef ACPI_VMCLOCK_H
|
||||||
|
#define ACPI_VMCLOCK_H
|
||||||
|
|
||||||
|
#include "hw/acpi/bios-linker-loader.h"
|
||||||
|
#include "hw/qdev-core.h"
|
||||||
|
#include "qemu/uuid.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
|
#define TYPE_VMCLOCK "vmclock"
|
||||||
|
|
||||||
|
#define VMCLOCK_ADDR 0xfeffb000
|
||||||
|
#define VMCLOCK_SIZE 0x1000
|
||||||
|
|
||||||
|
OBJECT_DECLARE_SIMPLE_TYPE(VmclockState, VMCLOCK)
|
||||||
|
|
||||||
|
struct vmclock_abi;
|
||||||
|
|
||||||
|
struct VmclockState {
|
||||||
|
DeviceState parent_obj;
|
||||||
|
MemoryRegion clk_page;
|
||||||
|
uint64_t physaddr;
|
||||||
|
struct vmclock_abi *clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* returns NULL unless there is exactly one device */
|
||||||
|
static inline Object *find_vmclock_dev(void)
|
||||||
|
{
|
||||||
|
return object_resolve_path_type("", TYPE_VMCLOCK, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmclock_build_acpi(VmclockState *vms, GArray *table_data,
|
||||||
|
BIOSLinker *linker, const char *oem_id);
|
||||||
|
|
||||||
|
#endif
|
@ -45,8 +45,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(IntelIOMMUState, INTEL_IOMMU_DEVICE)
|
|||||||
#define DMAR_REG_SIZE 0x230
|
#define DMAR_REG_SIZE 0x230
|
||||||
#define VTD_HOST_AW_39BIT 39
|
#define VTD_HOST_AW_39BIT 39
|
||||||
#define VTD_HOST_AW_48BIT 48
|
#define VTD_HOST_AW_48BIT 48
|
||||||
#define VTD_HOST_ADDRESS_WIDTH VTD_HOST_AW_39BIT
|
#define VTD_HOST_ADDRESS_WIDTH VTD_HOST_AW_48BIT
|
||||||
#define VTD_HAW_MASK(aw) ((1ULL << (aw)) - 1)
|
#define VTD_HAW_MASK(aw) ((1ULL << (aw)) - 1)
|
||||||
|
#define VTD_MGAW_FROM_CAP(cap) ((cap >> 16) & 0x3fULL)
|
||||||
|
|
||||||
#define DMAR_REPORT_F_INTR (1)
|
#define DMAR_REPORT_F_INTR (1)
|
||||||
|
|
||||||
@ -152,9 +153,10 @@ struct VTDIOTLBEntry {
|
|||||||
uint64_t gfn;
|
uint64_t gfn;
|
||||||
uint16_t domain_id;
|
uint16_t domain_id;
|
||||||
uint32_t pasid;
|
uint32_t pasid;
|
||||||
uint64_t slpte;
|
uint64_t pte;
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
uint8_t access_flags;
|
uint8_t access_flags;
|
||||||
|
uint8_t pgtt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* VT-d Source-ID Qualifier types */
|
/* VT-d Source-ID Qualifier types */
|
||||||
@ -262,6 +264,7 @@ struct IntelIOMMUState {
|
|||||||
|
|
||||||
bool caching_mode; /* RO - is cap CM enabled? */
|
bool caching_mode; /* RO - is cap CM enabled? */
|
||||||
bool scalable_mode; /* RO - is Scalable Mode supported? */
|
bool scalable_mode; /* RO - is Scalable Mode supported? */
|
||||||
|
bool flts; /* RO - is stage-1 translation supported? */
|
||||||
bool snoop_control; /* RO - is SNP filed supported? */
|
bool snoop_control; /* RO - is SNP filed supported? */
|
||||||
|
|
||||||
dma_addr_t root; /* Current root table pointer */
|
dma_addr_t root; /* Current root table pointer */
|
||||||
@ -305,6 +308,7 @@ struct IntelIOMMUState {
|
|||||||
bool dma_drain; /* Whether DMA r/w draining enabled */
|
bool dma_drain; /* Whether DMA r/w draining enabled */
|
||||||
bool dma_translation; /* Whether DMA translation supported */
|
bool dma_translation; /* Whether DMA translation supported */
|
||||||
bool pasid; /* Whether to support PASID */
|
bool pasid; /* Whether to support PASID */
|
||||||
|
bool fs1gp; /* First Stage 1-GByte Page Support */
|
||||||
|
|
||||||
/* Transient Mapping, Reserved(0) since VTD spec revision 3.2 */
|
/* Transient Mapping, Reserved(0) since VTD spec revision 3.2 */
|
||||||
bool stale_tm;
|
bool stale_tm;
|
||||||
|
@ -365,7 +365,14 @@ static inline int vhost_reset_device(struct vhost_dev *hdev)
|
|||||||
* Returns true if the device supports these commands, and false if it
|
* Returns true if the device supports these commands, and false if it
|
||||||
* does not.
|
* does not.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_VHOST
|
||||||
bool vhost_supports_device_state(struct vhost_dev *dev);
|
bool vhost_supports_device_state(struct vhost_dev *dev);
|
||||||
|
#else
|
||||||
|
static inline bool vhost_supports_device_state(struct vhost_dev *dev)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vhost_set_device_state_fd(): Begin transfer of internal state from/to
|
* vhost_set_device_state_fd(): Begin transfer of internal state from/to
|
||||||
@ -448,7 +455,15 @@ int vhost_check_device_state(struct vhost_dev *dev, Error **errp);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, and -errno otherwise.
|
* Returns 0 on success, and -errno otherwise.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_VHOST
|
||||||
int vhost_save_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
int vhost_save_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
||||||
|
#else
|
||||||
|
static inline int vhost_save_backend_state(struct vhost_dev *dev, QEMUFile *f,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vhost_load_backend_state(): High-level function to load a vhost
|
* vhost_load_backend_state(): High-level function to load a vhost
|
||||||
@ -465,6 +480,14 @@ int vhost_save_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, and -errno otherwise.
|
* Returns 0 on success, and -errno otherwise.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_VHOST
|
||||||
int vhost_load_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
int vhost_load_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
||||||
|
#else
|
||||||
|
static inline int vhost_load_backend_state(struct vhost_dev *dev, QEMUFile *f,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,6 +98,7 @@ enum virtio_gpu_base_conf_flags {
|
|||||||
VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED,
|
VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED,
|
||||||
VIRTIO_GPU_FLAG_RUTABAGA_ENABLED,
|
VIRTIO_GPU_FLAG_RUTABAGA_ENABLED,
|
||||||
VIRTIO_GPU_FLAG_VENUS_ENABLED,
|
VIRTIO_GPU_FLAG_VENUS_ENABLED,
|
||||||
|
VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define virtio_gpu_virgl_enabled(_cfg) \
|
#define virtio_gpu_virgl_enabled(_cfg) \
|
||||||
@ -114,6 +115,8 @@ enum virtio_gpu_base_conf_flags {
|
|||||||
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED))
|
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED))
|
||||||
#define virtio_gpu_rutabaga_enabled(_cfg) \
|
#define virtio_gpu_rutabaga_enabled(_cfg) \
|
||||||
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED))
|
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED))
|
||||||
|
#define virtio_gpu_resource_uuid_enabled(_cfg) \
|
||||||
|
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED))
|
||||||
#define virtio_gpu_hostmem_enabled(_cfg) \
|
#define virtio_gpu_hostmem_enabled(_cfg) \
|
||||||
(_cfg.hostmem > 0)
|
(_cfg.hostmem > 0)
|
||||||
#define virtio_gpu_venus_enabled(_cfg) \
|
#define virtio_gpu_venus_enabled(_cfg) \
|
||||||
|
182
include/standard-headers/linux/vmclock-abi.h
Normal file
182
include/standard-headers/linux/vmclock-abi.h
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This structure provides a vDSO-style clock to VM guests, exposing the
|
||||||
|
* relationship (or lack thereof) between the CPU clock (TSC, timebase, arch
|
||||||
|
* counter, etc.) and real time. It is designed to address the problem of
|
||||||
|
* live migration, which other clock enlightenments do not.
|
||||||
|
*
|
||||||
|
* When a guest is live migrated, this affects the clock in two ways.
|
||||||
|
*
|
||||||
|
* First, even between identical hosts the actual frequency of the underlying
|
||||||
|
* counter will change within the tolerances of its specification (typically
|
||||||
|
* ±50PPM, or 4 seconds a day). This frequency also varies over time on the
|
||||||
|
* same host, but can be tracked by NTP as it generally varies slowly. With
|
||||||
|
* live migration there is a step change in the frequency, with no warning.
|
||||||
|
*
|
||||||
|
* Second, there may be a step change in the value of the counter itself, as
|
||||||
|
* its accuracy is limited by the precision of the NTP synchronization on the
|
||||||
|
* source and destination hosts.
|
||||||
|
*
|
||||||
|
* So any calibration (NTP, PTP, etc.) which the guest has done on the source
|
||||||
|
* host before migration is invalid, and needs to be redone on the new host.
|
||||||
|
*
|
||||||
|
* In its most basic mode, this structure provides only an indication to the
|
||||||
|
* guest that live migration has occurred. This allows the guest to know that
|
||||||
|
* its clock is invalid and take remedial action. For applications that need
|
||||||
|
* reliable accurate timestamps (e.g. distributed databases), the structure
|
||||||
|
* can be mapped all the way to userspace. This allows the application to see
|
||||||
|
* directly for itself that the clock is disrupted and take appropriate
|
||||||
|
* action, even when using a vDSO-style method to get the time instead of a
|
||||||
|
* system call.
|
||||||
|
*
|
||||||
|
* In its more advanced mode. this structure can also be used to expose the
|
||||||
|
* precise relationship of the CPU counter to real time, as calibrated by the
|
||||||
|
* host. This means that userspace applications can have accurate time
|
||||||
|
* immediately after live migration, rather than having to pause operations
|
||||||
|
* and wait for NTP to recover. This mode does, of course, rely on the
|
||||||
|
* counter being reliable and consistent across CPUs.
|
||||||
|
*
|
||||||
|
* Note that this must be true UTC, never with smeared leap seconds. If a
|
||||||
|
* guest wishes to construct a smeared clock, it can do so. Presenting a
|
||||||
|
* smeared clock through this interface would be problematic because it
|
||||||
|
* actually messes with the apparent counter *period*. A linear smearing
|
||||||
|
* of 1 ms per second would effectively tweak the counter period by 1000PPM
|
||||||
|
* at the start/end of the smearing period, while a sinusoidal smear would
|
||||||
|
* basically be impossible to represent.
|
||||||
|
*
|
||||||
|
* This structure is offered with the intent that it be adopted into the
|
||||||
|
* nascent virtio-rtc standard, as a virtio-rtc that does not address the live
|
||||||
|
* migration problem seems a little less than fit for purpose. For that
|
||||||
|
* reason, certain fields use precisely the same numeric definitions as in
|
||||||
|
* the virtio-rtc proposal. The structure can also be exposed through an ACPI
|
||||||
|
* device with the CID "VMCLOCK", modelled on the "VMGENID" device except for
|
||||||
|
* the fact that it uses a real _CRS to convey the address of the structure
|
||||||
|
* (which should be a full page, to allow for mapping directly to userspace).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VMCLOCK_ABI_H__
|
||||||
|
#define __VMCLOCK_ABI_H__
|
||||||
|
|
||||||
|
#include "standard-headers/linux/types.h"
|
||||||
|
|
||||||
|
struct vmclock_abi {
|
||||||
|
/* CONSTANT FIELDS */
|
||||||
|
uint32_t magic;
|
||||||
|
#define VMCLOCK_MAGIC 0x4b4c4356 /* "VCLK" */
|
||||||
|
uint32_t size; /* Size of region containing this structure */
|
||||||
|
uint16_t version; /* 1 */
|
||||||
|
uint8_t counter_id; /* Matches VIRTIO_RTC_COUNTER_xxx except INVALID */
|
||||||
|
#define VMCLOCK_COUNTER_ARM_VCNT 0
|
||||||
|
#define VMCLOCK_COUNTER_X86_TSC 1
|
||||||
|
#define VMCLOCK_COUNTER_INVALID 0xff
|
||||||
|
uint8_t time_type; /* Matches VIRTIO_RTC_TYPE_xxx */
|
||||||
|
#define VMCLOCK_TIME_UTC 0 /* Since 1970-01-01 00:00:00z */
|
||||||
|
#define VMCLOCK_TIME_TAI 1 /* Since 1970-01-01 00:00:00z */
|
||||||
|
#define VMCLOCK_TIME_MONOTONIC 2 /* Since undefined epoch */
|
||||||
|
#define VMCLOCK_TIME_INVALID_SMEARED 3 /* Not supported */
|
||||||
|
#define VMCLOCK_TIME_INVALID_MAYBE_SMEARED 4 /* Not supported */
|
||||||
|
|
||||||
|
/* NON-CONSTANT FIELDS PROTECTED BY SEQCOUNT LOCK */
|
||||||
|
uint32_t seq_count; /* Low bit means an update is in progress */
|
||||||
|
/*
|
||||||
|
* This field changes to another non-repeating value when the CPU
|
||||||
|
* counter is disrupted, for example on live migration. This lets
|
||||||
|
* the guest know that it should discard any calibration it has
|
||||||
|
* performed of the counter against external sources (NTP/PTP/etc.).
|
||||||
|
*/
|
||||||
|
uint64_t disruption_marker;
|
||||||
|
uint64_t flags;
|
||||||
|
/* Indicates that the tai_offset_sec field is valid */
|
||||||
|
#define VMCLOCK_FLAG_TAI_OFFSET_VALID (1 << 0)
|
||||||
|
/*
|
||||||
|
* Optionally used to notify guests of pending maintenance events.
|
||||||
|
* A guest which provides latency-sensitive services may wish to
|
||||||
|
* remove itself from service if an event is coming up. Two flags
|
||||||
|
* indicate the approximate imminence of the event.
|
||||||
|
*/
|
||||||
|
#define VMCLOCK_FLAG_DISRUPTION_SOON (1 << 1) /* About a day */
|
||||||
|
#define VMCLOCK_FLAG_DISRUPTION_IMMINENT (1 << 2) /* About an hour */
|
||||||
|
#define VMCLOCK_FLAG_PERIOD_ESTERROR_VALID (1 << 3)
|
||||||
|
#define VMCLOCK_FLAG_PERIOD_MAXERROR_VALID (1 << 4)
|
||||||
|
#define VMCLOCK_FLAG_TIME_ESTERROR_VALID (1 << 5)
|
||||||
|
#define VMCLOCK_FLAG_TIME_MAXERROR_VALID (1 << 6)
|
||||||
|
/*
|
||||||
|
* If the MONOTONIC flag is set then (other than leap seconds) it is
|
||||||
|
* guaranteed that the time calculated according this structure at
|
||||||
|
* any given moment shall never appear to be later than the time
|
||||||
|
* calculated via the structure at any *later* moment.
|
||||||
|
*
|
||||||
|
* In particular, a timestamp based on a counter reading taken
|
||||||
|
* immediately after setting the low bit of seq_count (and the
|
||||||
|
* associated memory barrier), using the previously-valid time and
|
||||||
|
* period fields, shall never be later than a timestamp based on
|
||||||
|
* a counter reading taken immediately before *clearing* the low
|
||||||
|
* bit again after the update, using the about-to-be-valid fields.
|
||||||
|
*/
|
||||||
|
#define VMCLOCK_FLAG_TIME_MONOTONIC (1 << 7)
|
||||||
|
|
||||||
|
uint8_t pad[2];
|
||||||
|
uint8_t clock_status;
|
||||||
|
#define VMCLOCK_STATUS_UNKNOWN 0
|
||||||
|
#define VMCLOCK_STATUS_INITIALIZING 1
|
||||||
|
#define VMCLOCK_STATUS_SYNCHRONIZED 2
|
||||||
|
#define VMCLOCK_STATUS_FREERUNNING 3
|
||||||
|
#define VMCLOCK_STATUS_UNRELIABLE 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The time exposed through this device is never smeared. This field
|
||||||
|
* corresponds to the 'subtype' field in virtio-rtc, which indicates
|
||||||
|
* the smearing method. However in this case it provides a *hint* to
|
||||||
|
* the guest operating system, such that *if* the guest OS wants to
|
||||||
|
* provide its users with an alternative clock which does not follow
|
||||||
|
* UTC, it may do so in a fashion consistent with the other systems
|
||||||
|
* in the nearby environment.
|
||||||
|
*/
|
||||||
|
uint8_t leap_second_smearing_hint; /* Matches VIRTIO_RTC_SUBTYPE_xxx */
|
||||||
|
#define VMCLOCK_SMEARING_STRICT 0
|
||||||
|
#define VMCLOCK_SMEARING_NOON_LINEAR 1
|
||||||
|
#define VMCLOCK_SMEARING_UTC_SLS 2
|
||||||
|
uint16_t tai_offset_sec; /* Actually two's complement signed */
|
||||||
|
uint8_t leap_indicator;
|
||||||
|
/*
|
||||||
|
* This field is based on the VIRTIO_RTC_LEAP_xxx values as defined
|
||||||
|
* in the current draft of virtio-rtc, but since smearing cannot be
|
||||||
|
* used with the shared memory device, some values are not used.
|
||||||
|
*
|
||||||
|
* The _POST_POS and _POST_NEG values allow the guest to perform
|
||||||
|
* its own smearing during the day or so after a leap second when
|
||||||
|
* such smearing may need to continue being applied for a leap
|
||||||
|
* second which is now theoretically "historical".
|
||||||
|
*/
|
||||||
|
#define VMCLOCK_LEAP_NONE 0x00 /* No known nearby leap second */
|
||||||
|
#define VMCLOCK_LEAP_PRE_POS 0x01 /* Positive leap second at EOM */
|
||||||
|
#define VMCLOCK_LEAP_PRE_NEG 0x02 /* Negative leap second at EOM */
|
||||||
|
#define VMCLOCK_LEAP_POS 0x03 /* Set during 23:59:60 second */
|
||||||
|
#define VMCLOCK_LEAP_POST_POS 0x04
|
||||||
|
#define VMCLOCK_LEAP_POST_NEG 0x05
|
||||||
|
|
||||||
|
/* Bit shift for counter_period_frac_sec and its error rate */
|
||||||
|
uint8_t counter_period_shift;
|
||||||
|
/*
|
||||||
|
* Paired values of counter and UTC at a given point in time.
|
||||||
|
*/
|
||||||
|
uint64_t counter_value;
|
||||||
|
/*
|
||||||
|
* Counter period, and error margin of same. The unit of these
|
||||||
|
* fields is 1/2^(64 + counter_period_shift) of a second.
|
||||||
|
*/
|
||||||
|
uint64_t counter_period_frac_sec;
|
||||||
|
uint64_t counter_period_esterror_rate_frac_sec;
|
||||||
|
uint64_t counter_period_maxerror_rate_frac_sec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time according to time_type field above.
|
||||||
|
*/
|
||||||
|
uint64_t time_sec; /* Seconds since time_type epoch */
|
||||||
|
uint64_t time_frac_sec; /* Units of 1/2^64 of a second */
|
||||||
|
uint64_t time_esterror_nanosec;
|
||||||
|
uint64_t time_maxerror_nanosec;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __VMCLOCK_ABI_H__ */
|
@ -258,6 +258,7 @@ for i in "$hdrdir"/include/linux/*virtio*.h \
|
|||||||
"$hdrdir/include/linux/kernel.h" \
|
"$hdrdir/include/linux/kernel.h" \
|
||||||
"$hdrdir/include/linux/kvm_para.h" \
|
"$hdrdir/include/linux/kvm_para.h" \
|
||||||
"$hdrdir/include/linux/vhost_types.h" \
|
"$hdrdir/include/linux/vhost_types.h" \
|
||||||
|
"$hdrdir/include/linux/vmclock-abi.h" \
|
||||||
"$hdrdir/include/linux/sysinfo.h"; do
|
"$hdrdir/include/linux/sysinfo.h"; do
|
||||||
cp_portable "$i" "$output/include/standard-headers/linux"
|
cp_portable "$i" "$output/include/standard-headers/linux"
|
||||||
done
|
done
|
||||||
|
@ -2387,7 +2387,7 @@ void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
|
|||||||
*/
|
*/
|
||||||
if (code == BUS_MCEERR_AR) {
|
if (code == BUS_MCEERR_AR) {
|
||||||
kvm_cpu_synchronize_state(c);
|
kvm_cpu_synchronize_state(c);
|
||||||
if (!acpi_ghes_record_errors(ACPI_HEST_SRC_ID_SEA, paddr)) {
|
if (!acpi_ghes_memory_errors(ACPI_HEST_SRC_ID_SEA, paddr)) {
|
||||||
kvm_inject_arm_sea(c);
|
kvm_inject_arm_sea(c);
|
||||||
} else {
|
} else {
|
||||||
error_report("failed to record the error");
|
error_report("failed to record the error");
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
64
tests/qtest/intel-iommu-test.c
Normal file
64
tests/qtest/intel-iommu-test.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* QTest testcase for intel-iommu
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Intel, Inc.
|
||||||
|
*
|
||||||
|
* Author: Zhenzhong Duan <zhenzhong.duan@intel.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "libqtest.h"
|
||||||
|
#include "hw/i386/intel_iommu_internal.h"
|
||||||
|
|
||||||
|
#define CAP_STAGE_1_FIXED1 (VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | \
|
||||||
|
VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS)
|
||||||
|
#define ECAP_STAGE_1_FIXED1 (VTD_ECAP_QI | VTD_ECAP_IR | VTD_ECAP_IRO | \
|
||||||
|
VTD_ECAP_MHMV | VTD_ECAP_SMTS | VTD_ECAP_FLTS)
|
||||||
|
|
||||||
|
static inline uint64_t vtd_reg_readq(QTestState *s, uint64_t offset)
|
||||||
|
{
|
||||||
|
return qtest_readq(s, Q35_HOST_BRIDGE_IOMMU_ADDR + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_intel_iommu_stage_1(void)
|
||||||
|
{
|
||||||
|
uint8_t init_csr[DMAR_REG_SIZE]; /* register values */
|
||||||
|
uint8_t post_reset_csr[DMAR_REG_SIZE]; /* register values */
|
||||||
|
uint64_t cap, ecap, tmp;
|
||||||
|
QTestState *s;
|
||||||
|
|
||||||
|
s = qtest_init("-M q35 -device intel-iommu,x-scalable-mode=on,x-flts=on");
|
||||||
|
|
||||||
|
cap = vtd_reg_readq(s, DMAR_CAP_REG);
|
||||||
|
g_assert((cap & CAP_STAGE_1_FIXED1) == CAP_STAGE_1_FIXED1);
|
||||||
|
|
||||||
|
tmp = cap & VTD_CAP_SAGAW_MASK;
|
||||||
|
g_assert(tmp == (VTD_CAP_SAGAW_39bit | VTD_CAP_SAGAW_48bit));
|
||||||
|
|
||||||
|
tmp = VTD_MGAW_FROM_CAP(cap);
|
||||||
|
g_assert(tmp == VTD_HOST_AW_48BIT - 1);
|
||||||
|
|
||||||
|
ecap = vtd_reg_readq(s, DMAR_ECAP_REG);
|
||||||
|
g_assert((ecap & ECAP_STAGE_1_FIXED1) == ECAP_STAGE_1_FIXED1);
|
||||||
|
|
||||||
|
qtest_memread(s, Q35_HOST_BRIDGE_IOMMU_ADDR, init_csr, DMAR_REG_SIZE);
|
||||||
|
|
||||||
|
qobject_unref(qtest_qmp(s, "{ 'execute': 'system_reset' }"));
|
||||||
|
qtest_qmp_eventwait(s, "RESET");
|
||||||
|
|
||||||
|
qtest_memread(s, Q35_HOST_BRIDGE_IOMMU_ADDR, post_reset_csr, DMAR_REG_SIZE);
|
||||||
|
/* Ensure registers are consistent after hard reset */
|
||||||
|
g_assert(!memcmp(init_csr, post_reset_csr, DMAR_REG_SIZE));
|
||||||
|
|
||||||
|
qtest_quit(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
qtest_add_func("/q35/intel-iommu/stage-1", test_intel_iommu_stage_1);
|
||||||
|
|
||||||
|
return g_test_run();
|
||||||
|
}
|
@ -93,6 +93,7 @@ qtests_i386 = \
|
|||||||
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
|
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
|
||||||
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
|
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
|
||||||
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
|
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
|
||||||
|
(config_all_devices.has_key('CONFIG_VTD') ? ['intel-iommu-test'] : []) + \
|
||||||
(host_os != 'windows' and \
|
(host_os != 'windows' and \
|
||||||
config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \
|
config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \
|
||||||
(config_all_devices.has_key('CONFIG_PCIE_PORT') and \
|
(config_all_devices.has_key('CONFIG_PCIE_PORT') and \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user