Can be tested by setting machine to: q35,ras=on E.g.:
qemu-system-x86_64 --enable-kvm -cpu host -m 4g,maxmem=8G,slots=8 \ -M q35,nvdimm=on,ras=on \ -monitor stdio -no-reboot -drive if=pflash,file=OVMF_CODE.fd,format=raw \ -kernel ../linux/arch/x86_64/boot/bzImage \ -device pcie-root-port,id=root_port1 -device virtio-blk-pci,drive=hd \ -device virtio-net-pci,netdev=mynet,id=bob \ -drive if=none,file=debian.qcow2,format=qcow2,id=hd \ -object memory-backend-ram,size=4G,id=mem0 \ -netdev type=user,id=mynet,hostfwd=tcp::5555-:22 \ -qmp tcp:localhost:4445,server=on,wait=off \ -append 'earlycon nomodeset root=/dev/vda1 fsck.mode=skip tp_printk maxcpus=4 console=ttyS0 console=tty0' TODO: add a notifier logic. Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org> --- hw/i386/Kconfig | 1 + hw/i386/acpi-build.c | 33 +++++++++++++++++++++++++++++++++ hw/i386/pc.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 5 +++++ 4 files changed, 81 insertions(+) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index d34ce07b215d..a07d5aa1a138 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -60,6 +60,7 @@ config PC_ACPI select ACPI_CPU_HOTPLUG select ACPI_MEMORY_HOTPLUG select ACPI_PCI_BRIDGE + select ACPI_APEI select ACPI_VIOT select SMBUS_EEPROM select PFLASH_CFI01 diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 3fffa4a33280..cf11231b5fe6 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -38,6 +38,7 @@ #include "hw/nvram/fw_cfg.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/acpi_aml_interface.h" +#include "hw/acpi/generic_event_device.h" #include "hw/input/i8042.h" #include "hw/acpi/memory_hotplug.h" #include "system/tpm.h" @@ -69,6 +70,7 @@ #include "hw/acpi/utils.h" #include "hw/acpi/pci.h" #include "hw/acpi/cxl.h" +#include "hw/acpi/ghes.h" #include "qom/qom-qobject.h" #include "hw/i386/amd_iommu.h" @@ -2431,6 +2433,10 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } +static const AcpiNotificationSourceId hest_ghes_notify[] = { + {ACPI_HEST_SRC_ID_QMP, ACPI_GHES_NOTIFY_GPIO}, +}; + static void acpi_build(AcpiBuildTables *tables, MachineState *machine) { @@ -2587,6 +2593,15 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) cxl_build_cedt(table_offsets, tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id, &pcms->cxl_devices_state); } + if (pcms->ras) { + printf("ADD HEST\n"); + acpi_add_table(table_offsets, tables_blob); + acpi_build_hest(tables_blob, true, tables->hardware_errors, + tables->linker, hest_ghes_notify, + ARRAY_SIZE(hest_ghes_notify), + x86ms->oem_id, x86ms->oem_table_id); + printf("ADD HEST: added\n"); + } acpi_add_table(table_offsets, tables_blob); build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id); @@ -2742,6 +2757,24 @@ void acpi_setup(void) } #endif + if (pcms->ras) { + AcpiGhesState *ags; + AcpiGedState *acpi_ged_state; + + acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, + NULL)); + if (acpi_ged_state) { + printf("GHES FW_CFG: %p\n", acpi_ged_state); + + ags = &acpi_ged_state->ghes_state; + + acpi_ghes_add_fw_cfg(ags, x86ms->fw_cfg, true, + tables.hardware_errors); + + printf("GHES FW_CFG: end\n"); + } + } + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), x86ms->fw_cfg, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 63a96cd23f84..b9c32dbdbcd8 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -47,6 +47,7 @@ #include "qobject/qlist.h" #include "qemu/error-report.h" #include "hw/acpi/cpu_hotplug.h" +#include "hw/acpi/ghes.h" #include "acpi-build.h" #include "hw/mem/nvdimm.h" #include "hw/cxl/cxl_host.h" @@ -1683,6 +1684,37 @@ static void pc_machine_set_max_fw_size(Object *obj, Visitor *v, pcms->max_fw_size = value; } +static bool virt_get_ras(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->ras; +} + +static void virt_set_ras(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->ras = value; +} + +static void pc_sci_error(Notifier *n, void *opaque) +{ + uint16_t *source_id = opaque; + + fprintf(stderr, "GHES error for source ID: %d\n", *source_id); + + /* Currently, only QMP injection is supported */ + if (*source_id != ACPI_HEST_SRC_ID_QMP) + return; + + fprintf(stderr, "GHES error notified for QMP\n"); + + // TODO: add something equivalent to: + // PCMachineState *s = container_of(n, PCMachineState, ghes_sci_notifier); + // acpi_send_event(s->acpi_dev, ACPI_GENERIC_ERROR); + // by calling acpi_update_sci(); +} static void pc_machine_initfn(Object *obj) { @@ -1717,6 +1749,10 @@ static void pc_machine_initfn(Object *obj) if (pcmc->pci_enabled) { cxl_machine_init(obj, &pcms->cxl_devices_state); } + + pcms->ghes_sci_notifier.notify = pc_sci_error; + notifier_list_add(&acpi_generic_error_notifiers, + &pcms->ghes_sci_notifier); } static void pc_machine_reset(MachineState *machine, ResetType type) @@ -1853,6 +1889,12 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP, "SMBIOS Entry Point type [32, 64]"); + object_class_property_add_bool(oc, "ras", virt_get_ras, + virt_set_ras); + object_class_property_set_description(oc, "ras", + "Set on/off to enable/disable reporting host memory errors " + "to a KVM guest using ACPI and guest external abort exceptions"); + object_class_property_add_bool(oc, "fd-bootchk", pc_machine_get_fd_bootchk, pc_machine_set_fd_bootchk); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 103b54301f82..105b087e7af6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -30,6 +30,9 @@ typedef struct PCMachineState { /* State for other subsystems/APIs: */ Notifier machine_done; + /* Triggered when a new SCI GHES error raises */ + Notifier ghes_sci_notifier; + /* Pointers to devices and objects: */ PCIBus *pcibus; I2CBus *smbus; @@ -51,6 +54,8 @@ typedef struct PCMachineState { bool i8042_enabled; bool default_bus_bypass_iommu; bool fd_bootchk; + bool ras; + uint64_t max_fw_size; /* ACPI Memory hotplug IO base address */ -- 2.48.1