* [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation
@ 2024-08-01 14:47 Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 1/7] arm/virt: place power button pin number on a define Mauro Carvalho Chehab
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab, Ani Sinha,
Dongjiu Geng, Paolo Bonzini, Peter Maydell, Shannon Zhao,
qemu-arm, qemu-devel
Testing OS kernel ACPI APEI CPER support is tricky, as one depends on
having hardware with special-purpose BIOS and/or hardware.
With QEMU, it becomes a lot easier, as it can be done via QMP.
This series add support for injecting CPER records on ARM emulation.
The QEMU side changes add a QAPI able to do CPER error injection
on ARM, with a raw data parameter, making it very flexible.
A script is provided at the final patch implementing support for
ARM Processor CPER error injection according with ACPI 6.x and
UEFI 2.9A/2.10 specs, via QMP.
Injecting such errors can be done using the provided script:
$ ./scripts/ghes_inject.py arm
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 0, "major": 9}, "package": "v9.0.0-2621-g3de6991b870a"}, "capabilities": ["oob"]}}
{ "execute": "qmp_capabilities" }
{"return": {}}
{ "execute": "ghes-cper", "arguments": {"cper": {"notification-type": [22, 61, 158, 225, 17, 188, 228, 17, 156, 170, 194, 5, 29, 93, 70, 176], "raw-data": [0, 0, 0, 0, 1, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 4, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 0, 0, 0, 0, 173, 11, 186, 171, 0, 0, 0, 0]}} }
{"return": {}}
Produces a simple CPER register, properly handled by the Linux
Kernel:
[ 5876.041410] {18}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 1
[ 5876.041775] {18}[Hardware Error]: event severity: recoverable
[ 5876.042023] {18}[Hardware Error]: Error 0, type: recoverable
[ 5876.042280] {18}[Hardware Error]: section_type: ARM processor error
[ 5876.042538] {18}[Hardware Error]: MIDR: 0x0000000000000000
[ 5876.042781] {18}[Hardware Error]: Error info structure 0:
[ 5876.043013] {18}[Hardware Error]: num errors: 2
[ 5876.043222] {18}[Hardware Error]: error_type: 0x02: cache error
[ 5876.043500] {18}[Hardware Error]: error_info: 0x0000000000000000
[ 5876.043800] [Firmware Warn]: GHES: Unhandled processor error type 0x02: cache error
More complex use cases can be done, like:
$ ./scripts/ghes_inject.py arm --mpidr 0x444 --running --affinity 1 --error-info 12345678 --vendor 0x13,123,4,5,1 --ctx-array 0,1,2,3,4,5 -t cache tlb bus vendor tlb,vendor
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 0, "major": 9}, "package": "v9.0.0-2621-g3de6991b870a"}, "capabilities": ["oob"]}}
{ "execute": "qmp_capabilities" }
{"return": {}}
{ "execute": "ghes-cper", "arguments": {"cper": {"notification-type": [22, 61, 158, 225, 17, 188, 228, 17, 156, 170, 194, 5, 29, 93, 70, 176], "raw-data": [7, 0, 0, 0, 5, 0, 1, 0, 13, 1, 0, 0, 1, 0, 0, 0, 68, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 32, 4, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 0, 0, 0, 0, 173, 11, 186, 171, 0, 0, 0, 0, 0, 32, 4, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 0, 0, 0, 0, 173, 11, 186, 171, 0, 0, 0, 0, 0, 32, 4, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 0, 0, 0, 0, 173, 11, 186, 171, 0, 0, 0, 0, 0, 32, 4, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 0, 0, 0, 0, 173, 11, 186, 171, 0, 0, 0, 0, 0, 32, 0, 0, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 0, 0, 0, 0, 173, 11, 186, 171, 0, 0, 0, 0, 0, 0, 5, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 123, 4, 5, 1]}} }
{"return": {}}
964.134325] {19}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 1
[ 5964.134692] {19}[Hardware Error]: event severity: recoverable
[ 5964.134942] {19}[Hardware Error]: Error 0, type: recoverable
[ 5964.135200] {19}[Hardware Error]: section_type: ARM processor error
[ 5964.135466] {19}[Hardware Error]: MIDR: 0x0000000000000000
[ 5964.135700] {19}[Hardware Error]: Multiprocessor Affinity Register (MPIDR): 0x0000000000000444
[ 5964.136025] {19}[Hardware Error]: error affinity level: 1
[ 5964.136255] {19}[Hardware Error]: running state: 0x1
[ 5964.136468] {19}[Hardware Error]: Power State Coordination Interface state: 0
[ 5964.136767] {19}[Hardware Error]: Error info structure 0:
[ 5964.137001] {19}[Hardware Error]: num errors: 2
[ 5964.137210] {19}[Hardware Error]: error_type: 0x02: cache error
[ 5964.137472] {19}[Hardware Error]: error_info: 0x0000000000000000
[ 5964.137737] {19}[Hardware Error]: Error info structure 1:
[ 5964.137976] {19}[Hardware Error]: num errors: 2
[ 5964.138192] {19}[Hardware Error]: error_type: 0x04: TLB error
[ 5964.138459] {19}[Hardware Error]: error_info: 0x0000000000000000
[ 5964.138727] {19}[Hardware Error]: Error info structure 2:
[ 5964.138967] {19}[Hardware Error]: num errors: 2
[ 5964.139185] {19}[Hardware Error]: error_type: 0x08: bus error
[ 5964.139451] {19}[Hardware Error]: error_info: 0x0000000000000000
[ 5964.139751] {19}[Hardware Error]: Error info structure 3:
[ 5964.139993] {19}[Hardware Error]: num errors: 2
[ 5964.140210] {19}[Hardware Error]: error_type: 0x10: micro-architectural error
[ 5964.140522] {19}[Hardware Error]: error_info: 0x0000000000000000
[ 5964.140790] {19}[Hardware Error]: Error info structure 4:
[ 5964.141030] {19}[Hardware Error]: num errors: 2
[ 5964.141261] {19}[Hardware Error]: error_type: 0x14: TLB error|micro-architectural error
[ 5964.141599] {19}[Hardware Error]: Context info structure 0:
[ 5964.141843] {19}[Hardware Error]: register context type: AArch64 EL1 context registers
[ 5964.142195] {19}[Hardware Error]: 00000000: 00000000 00000000 00000001 00000000
[ 5964.142534] {19}[Hardware Error]: 00000010: 00000002 00000000 00000003 00000000
[ 5964.142867] {19}[Hardware Error]: 00000020: 00000004 00000000 00000005 00000000
[ 5964.143193] {19}[Hardware Error]: 00000030: 00000000 00000000
[ 5964.143464] {19}[Hardware Error]: Vendor specific error info has 5 bytes:
[ 5964.143750] {19}[Hardware Error]: 00000000: 13 7b 04 05 01 .{...
[ 5964.144164] [Firmware Warn]: GHES: Unhandled processor error type 0x02: cache error
[ 5964.144483] [Firmware Warn]: GHES: Unhandled processor error type 0x04: TLB error
[ 5964.144793] [Firmware Warn]: GHES: Unhandled processor error type 0x08: bus error
[ 5964.145099] [Firmware Warn]: GHES: Unhandled processor error type 0x10: micro-architectural error
[ 5964.145454] [Firmware Warn]: GHES: Unhandled processor error type 0x14: TLB error|micro-architectural error
---
v4:
- CPER generation moved to happen outside QEMU;
- One patch adding support for mpidr query was removed.
v3:
- patch 1 cleanups with some comment changes and adding another place where
the poweroff GPIO define should be used. No changes on other patches (except
due to conflict resolution).
v2:
- added a new patch using a define for GPIO power pin;
- patch 2 changed to also use a define for generic error GPIO pin;
- a couple cleanups at patch 2 removing uneeded else clauses.
Jonathan Cameron (1):
acpi/ghes: Support GPIO error source
Mauro Carvalho Chehab (6):
arm/virt: place power button pin number on a define
acpi/generic_event_device: add an APEI error device
arm/virt: Wire up GPIO error source for ACPI / GHES
qapi/ghes-cper: add an interface to do generic CPER error injection
acpi/ghes: add support for generic error injection via QAPI
scripts/ghes_inject: add a script to generate GHES error inject
MAINTAINERS | 8 +
hw/acpi/Kconfig | 5 +
hw/acpi/generic_event_device.c | 17 +
hw/acpi/ghes.c | 178 ++++++-
hw/acpi/ghes_cper.c | 53 ++
hw/acpi/meson.build | 2 +
hw/arm/Kconfig | 5 +
hw/arm/virt-acpi-build.c | 25 +-
hw/arm/virt.c | 33 +-
include/hw/acpi/acpi_dev_interface.h | 1 +
include/hw/acpi/generic_event_device.h | 3 +
include/hw/acpi/ghes.h | 14 +-
include/hw/arm/virt.h | 5 +
qapi/ghes-cper.json | 54 ++
qapi/meson.build | 1 +
qapi/qapi-schema.json | 1 +
scripts/ghes_inject.py | 673 +++++++++++++++++++++++++
17 files changed, 1048 insertions(+), 30 deletions(-)
create mode 100644 hw/acpi/ghes_cper.c
create mode 100644 qapi/ghes-cper.json
create mode 100755 scripts/ghes_inject.py
--
2.45.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/7] arm/virt: place power button pin number on a define
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 2/7] acpi/generic_event_device: add an APEI error device Mauro Carvalho Chehab
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab,
Michael S. Tsirkin, Ani Sinha, Igor Mammedov, Peter Maydell,
Shannon Zhao, linux-kernel, qemu-arm, qemu-devel
Having magic numbers inside the code is not a good idea, as it
is error-prone. So, instead, create a macro with the number
definition.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
hw/arm/virt-acpi-build.c | 6 +++---
hw/arm/virt.c | 7 ++++---
include/hw/arm/virt.h | 3 +++
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index e10cad86dd73..f76fb117adff 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -154,10 +154,10 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
aml_append(dev, aml_name_decl("_CRS", crs));
Aml *aei = aml_resource_template();
- /* Pin 3 for power button */
- const uint32_t pin_list[1] = {3};
+
+ const uint32_t pin = GPIO_PIN_POWER_BUTTON;
aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, AML_PULL_UP, 0, pin_list, 1,
+ AML_EXCLUSIVE, AML_PULL_UP, 0, &pin, 1,
"GPO0", NULL, 0));
aml_append(dev, aml_name_decl("_AEI", aei));
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 719e83e6a1e7..687fe0bb8bc9 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1004,7 +1004,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
if (s->acpi_dev) {
acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS);
} else {
- /* use gpio Pin 3 for power button event */
+ /* use gpio Pin for power button event */
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
}
}
@@ -1013,7 +1013,8 @@ static void create_gpio_keys(char *fdt, DeviceState *pl061_dev,
uint32_t phandle)
{
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
- qdev_get_gpio_in(pl061_dev, 3));
+ qdev_get_gpio_in(pl061_dev,
+ GPIO_PIN_POWER_BUTTON));
qemu_fdt_add_subnode(fdt, "/gpio-keys");
qemu_fdt_setprop_string(fdt, "/gpio-keys", "compatible", "gpio-keys");
@@ -1024,7 +1025,7 @@ static void create_gpio_keys(char *fdt, DeviceState *pl061_dev,
qemu_fdt_setprop_cell(fdt, "/gpio-keys/poweroff", "linux,code",
KEY_POWER);
qemu_fdt_setprop_cells(fdt, "/gpio-keys/poweroff",
- "gpios", phandle, 3, 0);
+ "gpios", phandle, GPIO_PIN_POWER_BUTTON, 0);
}
#define SECURE_GPIO_POWEROFF 0
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index ab961bb6a9b8..a4d937ed45ac 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -47,6 +47,9 @@
/* See Linux kernel arch/arm64/include/asm/pvclock-abi.h */
#define PVTIME_SIZE_PER_CPU 64
+/* GPIO pins */
+#define GPIO_PIN_POWER_BUTTON 3
+
enum {
VIRT_FLASH,
VIRT_MEM,
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/7] acpi/generic_event_device: add an APEI error device
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 1/7] arm/virt: place power button pin number on a define Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 3/7] arm/virt: Wire up GPIO error source for ACPI / GHES Mauro Carvalho Chehab
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab,
Michael S. Tsirkin, Ani Sinha, Igor Mammedov, linux-kernel,
qemu-devel
Adds a Generic Event Device to handle generic hardware error
events, supporting General Purpose Event (GPE) as specified at
ACPI 6.5 specification at 18.3.2.7.2:
https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#event-notification-for-generic-error-sources
using HID PNP0C33.
The PNP0C33 device is used to report hardware errors to
the bios via ACPI APEI Generic Hardware Error Source (GHES).
Co-authored-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Co-authored-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
hw/acpi/generic_event_device.c | 17 +++++++++++++++++
include/hw/acpi/acpi_dev_interface.h | 1 +
include/hw/acpi/generic_event_device.h | 3 +++
3 files changed, 21 insertions(+)
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 15b4c3ebbf24..b9ad05e98c05 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -26,6 +26,7 @@ static const uint32_t ged_supported_events[] = {
ACPI_GED_PWR_DOWN_EVT,
ACPI_GED_NVDIMM_HOTPLUG_EVT,
ACPI_GED_CPU_HOTPLUG_EVT,
+ ACPI_GED_ERROR_EVT
};
/*
@@ -116,6 +117,11 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
aml_int(0x80)));
break;
+ case ACPI_GED_ERROR_EVT:
+ aml_append(if_ctx,
+ aml_notify(aml_name(ACPI_APEI_ERROR_DEVICE),
+ aml_int(0x80)));
+ break;
case ACPI_GED_NVDIMM_HOTPLUG_EVT:
aml_append(if_ctx,
aml_notify(aml_name("\\_SB.NVDR"),
@@ -153,6 +159,15 @@ void acpi_dsdt_add_power_button(Aml *scope)
aml_append(scope, dev);
}
+void acpi_dsdt_add_error_device(Aml *scope)
+{
+ Aml *dev = aml_device(ACPI_APEI_ERROR_DEVICE);
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C33")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
+ aml_append(scope, dev);
+}
+
/* Memory read by the GED _EVT AML dynamic method */
static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size)
{
@@ -295,6 +310,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
sel = ACPI_GED_MEM_HOTPLUG_EVT;
} else if (ev & ACPI_POWER_DOWN_STATUS) {
sel = ACPI_GED_PWR_DOWN_EVT;
+ } else if (ev & ACPI_GENERIC_ERROR) {
+ sel = ACPI_GED_ERROR_EVT;
} else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) {
sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
} else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index 68d9d15f50aa..8294f8f0ccca 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -13,6 +13,7 @@ typedef enum {
ACPI_NVDIMM_HOTPLUG_STATUS = 16,
ACPI_VMGENID_CHANGE_STATUS = 32,
ACPI_POWER_DOWN_STATUS = 64,
+ ACPI_GENERIC_ERROR = 128,
} AcpiEventStatusBits;
#define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 40af3550b56d..b8f2f1328e0c 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -66,6 +66,7 @@
#include "qom/object.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
+#define ACPI_APEI_ERROR_DEVICE "GEDD"
#define TYPE_ACPI_GED "acpi-ged"
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
@@ -98,6 +99,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
#define ACPI_GED_PWR_DOWN_EVT 0x2
#define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4
#define ACPI_GED_CPU_HOTPLUG_EVT 0x8
+#define ACPI_GED_ERROR_EVT 0x10
typedef struct GEDState {
MemoryRegion evt;
@@ -120,5 +122,6 @@ struct AcpiGedState {
void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
void acpi_dsdt_add_power_button(Aml *scope);
+void acpi_dsdt_add_error_device(Aml *scope);
#endif
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 3/7] arm/virt: Wire up GPIO error source for ACPI / GHES
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 1/7] arm/virt: place power button pin number on a define Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 2/7] acpi/generic_event_device: add an APEI error device Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 4/7] acpi/ghes: Support GPIO error source Mauro Carvalho Chehab
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab,
Michael S. Tsirkin, Ani Sinha, Dongjiu Geng, Igor Mammedov,
Peter Maydell, Shannon Zhao, linux-kernel, qemu-arm, qemu-devel
Adds support to ARM virtualization to allow handling
a General Purpose Event (GPE) via GED error device.
It is aligned with Linux Kernel patch:
https://lore.kernel.org/lkml/1272350481-27951-8-git-send-email-ying.huang@intel.com/
Co-authored-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Co-authored-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
hw/acpi/ghes.c | 3 +++
hw/arm/virt-acpi-build.c | 21 +++++++++++++++++----
hw/arm/virt.c | 26 +++++++++++++++++++++++---
include/hw/acpi/ghes.h | 3 +++
include/hw/arm/virt.h | 2 ++
5 files changed, 48 insertions(+), 7 deletions(-)
diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c
index e9511d9b8f71..8d0262e6c1aa 100644
--- a/hw/acpi/ghes.c
+++ b/hw/acpi/ghes.c
@@ -444,6 +444,9 @@ int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
return ret;
}
+NotifierList generic_error_notifiers =
+ NOTIFIER_LIST_INITIALIZER(error_device_notifiers);
+
bool acpi_ghes_present(void)
{
AcpiGedState *acpi_ged_state;
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f76fb117adff..cdd1c6d9f1a3 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -142,6 +142,8 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
uint32_t gpio_irq)
{
+ uint32_t pin;
+
Aml *dev = aml_device("GPO0");
aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061")));
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
@@ -155,7 +157,12 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
Aml *aei = aml_resource_template();
- const uint32_t pin = GPIO_PIN_POWER_BUTTON;
+ pin = GPIO_PIN_POWER_BUTTON;
+ aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, AML_PULL_UP, 0, &pin, 1,
+ "GPO0", NULL, 0));
+
+ pin = GPIO_PIN_GENERIC_ERROR;
aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, AML_PULL_UP, 0, &pin, 1,
"GPO0", NULL, 0));
@@ -166,6 +173,12 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
aml_int(0x80)));
aml_append(dev, method);
+
+ method = aml_method("_E06", 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_notify(aml_name(ACPI_APEI_ERROR_DEVICE),
+ aml_int(0x80)));
+ aml_append(dev, method);
+
aml_append(scope, dev);
}
@@ -841,10 +854,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
HOTPLUG_HANDLER(vms->acpi_dev),
irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY,
memmap[VIRT_ACPI_GED].base);
- } else {
- acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
- (irqmap[VIRT_GPIO] + ARM_SPI_BASE));
}
+ acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
+ irqmap[VIRT_GPIO] + ARM_SPI_BASE);
if (vms->acpi_dev) {
uint32_t event = object_property_get_uint(OBJECT(vms->acpi_dev),
@@ -858,6 +870,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
acpi_dsdt_add_power_button(scope);
+ acpi_dsdt_add_error_device(scope);
#ifdef CONFIG_TPM
acpi_dsdt_add_tpm(scope, vms);
#endif
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 687fe0bb8bc9..e76cc9690788 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -73,6 +73,7 @@
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
+#include "hw/acpi/ghes.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/internals.h"
#include "target/arm/multiprocessing.h"
@@ -677,7 +678,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
DeviceState *dev;
MachineState *ms = MACHINE(vms);
int irq = vms->irqmap[VIRT_ACPI_GED];
- uint32_t event = ACPI_GED_PWR_DOWN_EVT;
+ uint32_t event = ACPI_GED_PWR_DOWN_EVT | ACPI_GED_ERROR_EVT;
if (ms->ram_slots) {
event |= ACPI_GED_MEM_HOTPLUG_EVT;
@@ -1009,12 +1010,28 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
}
}
+static DeviceState *gpio_error_dev;
+static void virt_generic_error_req(Notifier *n, void *opaque)
+{
+ VirtMachineState *s = container_of(n, VirtMachineState, generic_error_notifier);
+
+ if (s->acpi_dev) {
+ acpi_send_event(s->acpi_dev, ACPI_GENERIC_ERROR);
+ } else {
+ /* use gpio Pin for power button event */
+ qemu_set_irq(qdev_get_gpio_in(gpio_error_dev, 0), 1);
+ }
+}
+
static void create_gpio_keys(char *fdt, DeviceState *pl061_dev,
uint32_t phandle)
{
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
qdev_get_gpio_in(pl061_dev,
GPIO_PIN_POWER_BUTTON));
+ gpio_error_dev = sysbus_create_simple("gpio-key", -1,
+ qdev_get_gpio_in(pl061_dev,
+ GPIO_PIN_GENERIC_ERROR));
qemu_fdt_add_subnode(fdt, "/gpio-keys");
qemu_fdt_setprop_string(fdt, "/gpio-keys", "compatible", "gpio-keys");
@@ -2385,9 +2402,8 @@ static void machvirt_init(MachineState *machine)
if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) {
vms->acpi_dev = create_acpi_ged(vms);
- } else {
- create_gpio_devices(vms, VIRT_GPIO, sysmem);
}
+ create_gpio_devices(vms, VIRT_GPIO, sysmem);
if (vms->secure && !vmc->no_secure_gpio) {
create_gpio_devices(vms, VIRT_SECURE_GPIO, secure_sysmem);
@@ -2397,6 +2413,10 @@ static void machvirt_init(MachineState *machine)
vms->powerdown_notifier.notify = virt_powerdown_req;
qemu_register_powerdown_notifier(&vms->powerdown_notifier);
+ vms->generic_error_notifier.notify = virt_generic_error_req;
+ notifier_list_add(&generic_error_notifiers,
+ &vms->generic_error_notifier);
+
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h
index 674f6958e905..6891eafff5ab 100644
--- a/include/hw/acpi/ghes.h
+++ b/include/hw/acpi/ghes.h
@@ -23,6 +23,9 @@
#define ACPI_GHES_H
#include "hw/acpi/bios-linker-loader.h"
+#include "qemu/notify.h"
+
+extern NotifierList generic_error_notifiers;
/*
* Values for Hardware Error Notification Type field
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index a4d937ed45ac..0cbe9a05605f 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -49,6 +49,7 @@
/* GPIO pins */
#define GPIO_PIN_POWER_BUTTON 3
+#define GPIO_PIN_GENERIC_ERROR 6
enum {
VIRT_FLASH,
@@ -175,6 +176,7 @@ struct VirtMachineState {
DeviceState *gic;
DeviceState *acpi_dev;
Notifier powerdown_notifier;
+ Notifier generic_error_notifier;
PCIBus *bus;
char *oem_id;
char *oem_table_id;
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 4/7] acpi/ghes: Support GPIO error source
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
` (2 preceding siblings ...)
2024-08-01 14:47 ` [PATCH v4 3/7] arm/virt: Wire up GPIO error source for ACPI / GHES Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 5/7] qapi/ghes-cper: add an interface to do generic CPER error injection Mauro Carvalho Chehab
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Michael S. Tsirkin, Ani Sinha,
Dongjiu Geng, Igor Mammedov, linux-kernel, qemu-arm, qemu-devel,
Mauro Carvalho Chehab
From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Add error notification to GHES v2 using the GPIO source.
[mchehab: do some cleanups at ACPI_HEST_SRC_ID_* checks]
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
hw/acpi/ghes.c | 16 ++++++++++------
include/hw/acpi/ghes.h | 3 ++-
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c
index 8d0262e6c1aa..a745dcc7be5e 100644
--- a/hw/acpi/ghes.c
+++ b/hw/acpi/ghes.c
@@ -34,8 +34,8 @@
/* The max size in bytes for one error block */
#define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB)
-/* Now only support ARMv8 SEA notification type error source */
-#define ACPI_GHES_ERROR_SOURCE_COUNT 1
+/* Support ARMv8 SEA notification type error source and GPIO interrupt. */
+#define ACPI_GHES_ERROR_SOURCE_COUNT 2
/* Generic Hardware Error Source version 2 */
#define ACPI_GHES_SOURCE_GENERIC_ERROR_V2 10
@@ -290,6 +290,9 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
{
uint64_t address_offset;
+
+ assert(source_id < ACPI_HEST_SRC_ID_RESERVED);
+
/*
* Type:
* Generic Hardware Error Source version 2(GHESv2 - Type 10)
@@ -327,6 +330,9 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
*/
build_ghes_hw_error_notification(table_data, ACPI_GHES_NOTIFY_SEA);
break;
+ case ACPI_HEST_SRC_ID_GPIO:
+ build_ghes_hw_error_notification(table_data, ACPI_GHES_NOTIFY_GPIO);
+ break;
default:
error_report("Not support this error source");
abort();
@@ -370,6 +376,7 @@ void acpi_build_hest(GArray *table_data, BIOSLinker *linker,
/* Error Source Count */
build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4);
build_ghes_v2(table_data, ACPI_HEST_SRC_ID_SEA, linker);
+ build_ghes_v2(table_data, ACPI_HEST_SRC_ID_GPIO, linker);
acpi_table_end(linker, &table);
}
@@ -406,10 +413,7 @@ int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
start_addr = le64_to_cpu(ags->ghes_addr_le);
if (physical_address) {
-
- if (source_id < ACPI_HEST_SRC_ID_RESERVED) {
- start_addr += source_id * sizeof(uint64_t);
- }
+ start_addr += source_id * sizeof(uint64_t);
cpu_physical_memory_read(start_addr, &error_block_addr,
sizeof(error_block_addr));
diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h
index 6891eafff5ab..33be1eb5acf4 100644
--- a/include/hw/acpi/ghes.h
+++ b/include/hw/acpi/ghes.h
@@ -59,9 +59,10 @@ enum AcpiGhesNotifyType {
ACPI_GHES_NOTIFY_RESERVED = 12
};
+/* Those are used as table indexes when building GHES tables */
enum {
ACPI_HEST_SRC_ID_SEA = 0,
- /* future ids go here */
+ ACPI_HEST_SRC_ID_GPIO,
ACPI_HEST_SRC_ID_RESERVED,
};
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 5/7] qapi/ghes-cper: add an interface to do generic CPER error injection
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
` (3 preceding siblings ...)
2024-08-01 14:47 ` [PATCH v4 4/7] acpi/ghes: Support GPIO error source Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
2024-08-02 9:44 ` Markus Armbruster
2024-08-01 14:47 ` [PATCH v4 6/7] acpi/ghes: add support for generic error injection via QAPI Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 7/7] scripts/ghes_inject: add a script to generate GHES error inject Mauro Carvalho Chehab
6 siblings, 1 reply; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab,
Michael S. Tsirkin, Ani Sinha, Dongjiu Geng, Eric Blake,
Igor Mammedov, Markus Armbruster, Michael Roth, Paolo Bonzini,
Peter Maydell, linux-kernel, qemu-arm, qemu-devel
Creates a QAPI to be used for generic ACPI APEI hardware error
injection (HEST) via GHESv2.
The actual GHES code will be added at the followup patch.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
MAINTAINERS | 7 ++++++
hw/acpi/Kconfig | 5 ++++
hw/acpi/ghes_cper.c | 53 +++++++++++++++++++++++++++++++++++++++++
hw/acpi/meson.build | 2 ++
hw/arm/Kconfig | 5 ++++
include/hw/acpi/ghes.h | 6 +++++
qapi/ghes-cper.json | 54 ++++++++++++++++++++++++++++++++++++++++++
qapi/meson.build | 1 +
qapi/qapi-schema.json | 1 +
9 files changed, 134 insertions(+)
create mode 100644 hw/acpi/ghes_cper.c
create mode 100644 qapi/ghes-cper.json
diff --git a/MAINTAINERS b/MAINTAINERS
index 98eddf7ae155..655edcb6688c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2075,6 +2075,13 @@ F: hw/acpi/ghes.c
F: include/hw/acpi/ghes.h
F: docs/specs/acpi_hest_ghes.rst
+ACPI/HEST/GHES/ARM processor CPER
+R: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+S: Maintained
+F: hw/arm/ghes_cper.c
+F: hw/acpi/ghes_cper_stub.c
+F: qapi/ghes-cper.json
+
ppc4xx
L: qemu-ppc@nongnu.org
S: Orphan
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index e07d3204eb36..73ffbb82c150 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -51,6 +51,11 @@ config ACPI_APEI
bool
depends on ACPI
+config GHES_CPER
+ bool
+ depends on ACPI_APEI
+ default y
+
config ACPI_PCI
bool
depends on ACPI && PCI
diff --git a/hw/acpi/ghes_cper.c b/hw/acpi/ghes_cper.c
new file mode 100644
index 000000000000..0d32874a84f1
--- /dev/null
+++ b/hw/acpi/ghes_cper.c
@@ -0,0 +1,53 @@
+/*
+ * ARM Processor error injection
+ *
+ * Copyright(C) 2024 Huawei LTD.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-ghes-cper.h"
+#include "hw/acpi/ghes.h"
+
+void qmp_ghes_cper(CommonPlatformErrorRecord *qmp_cper,
+ Error **errp)
+{
+ unsigned int uuid_len = 0, i;
+ uint8List *p;
+ AcpiGhesCper cper;
+
+ for (p = qmp_cper->notification_type; p; p = p->next) {
+ uuid_len++;
+ if (uuid_len > 16) {
+ break;
+ }
+ cper.uuid[uuid_len - 1] = p->value;
+ }
+
+ if (uuid_len != 16) {
+ error_report("GHES CPER record has an invalid UUID size");
+ return;
+ }
+
+ cper.data_len = 0;
+
+ for (p = qmp_cper->raw_data; p; p = p->next) {
+ cper.data_len++;
+ }
+
+ cper.data = g_malloc(cper.data_len);
+
+ p = qmp_cper->raw_data;
+ for (i = 0; i < cper.data_len; i++, p = p->next) {
+ cper.data[i] = p->value;
+ }
+
+ /* TODO: call a function at ghes */
+
+ g_free(cper.data);
+}
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index fa5c07db9068..6cbf430eb66d 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -34,4 +34,6 @@ endif
system_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
system_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c'))
system_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
+system_ss.add(when: 'CONFIG_GHES_CPER', if_true: files('ghes_cper.c'))
+system_ss.add(when: 'CONFIG_GHES_CPER', if_false: files('ghes_cper_stub.c'))
system_ss.add(files('acpi-qmp-cmds.c'))
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 1ad60da7aa2d..bed6ba27d715 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -712,3 +712,8 @@ config ARMSSE
select UNIMP
select SSE_COUNTER
select SSE_TIMER
+
+config GHES_CPER
+ bool
+ depends on ARM
+ default y if AARCH64
diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h
index 33be1eb5acf4..02ea3715f655 100644
--- a/include/hw/acpi/ghes.h
+++ b/include/hw/acpi/ghes.h
@@ -78,6 +78,12 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *vms, FWCfgState *s,
GArray *hardware_errors);
int acpi_ghes_record_errors(uint8_t notify, uint64_t error_physical_addr);
+typedef struct AcpiGhesCper {
+ uint8_t uuid[16];
+ char *data;
+ uint32_t data_len;
+} AcpiGhesCper;
+
/**
* acpi_ghes_present: Report whether ACPI GHES table is present
*
diff --git a/qapi/ghes-cper.json b/qapi/ghes-cper.json
new file mode 100644
index 000000000000..2b0438431054
--- /dev/null
+++ b/qapi/ghes-cper.json
@@ -0,0 +1,54 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+
+##
+# = GHESv2 CPER Error Injection
+#
+# These are defined at
+# ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2
+# (GHESv2 - Type 10)
+##
+
+##
+# @CommonPlatformErrorRecord:
+#
+# Common Platform Error Record - CPER - as defined at the UEFI
+# specification. See
+# https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header
+# for more details.
+#
+# @notification-type: pre-assigned GUID value indicating the record
+# association with an error event notification type, as defined
+# at https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header
+#
+# @raw-data: Contains the payload of the CPER.
+#
+# Since: 9.2
+##
+{ 'struct': 'CommonPlatformErrorRecord',
+ 'data': {
+ 'notification-type': ['uint8'],
+ 'raw-data': ['uint8']
+ }
+}
+
+##
+# @ghes-cper:
+#
+# Inject ARM Processor error with data to be filled according with
+# ACPI 6.2 GHESv2 spec.
+#
+# @cper: a single CPER record to be sent to the guest OS.
+#
+# Features:
+#
+# @unstable: This command is experimental.
+#
+# Since: 9.2
+##
+{ 'command': 'ghes-cper',
+ 'data': {
+ 'cper': 'CommonPlatformErrorRecord'
+ },
+ 'features': [ 'unstable' ]
+}
diff --git a/qapi/meson.build b/qapi/meson.build
index e7bc54e5d047..bd13cd7d40c9 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -35,6 +35,7 @@ qapi_all_modules = [
'dump',
'ebpf',
'error',
+ 'ghes-cper',
'introspect',
'job',
'machine-common',
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index b1581988e4eb..54165c8d6655 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -81,3 +81,4 @@
{ 'include': 'vfio.json' }
{ 'include': 'cryptodev.json' }
{ 'include': 'cxl.json' }
+{ 'include': 'ghes-cper.json' }
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 6/7] acpi/ghes: add support for generic error injection via QAPI
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
` (4 preceding siblings ...)
2024-08-01 14:47 ` [PATCH v4 5/7] qapi/ghes-cper: add an interface to do generic CPER error injection Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 7/7] scripts/ghes_inject: add a script to generate GHES error inject Mauro Carvalho Chehab
6 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab,
Michael S. Tsirkin, Ani Sinha, Dongjiu Geng, Igor Mammedov,
linux-kernel, qemu-arm, qemu-devel
Provide a generic interface for error injection via GHESv2.
This patch is co-authored:
- original ghes logic to inject a simple ARM record by Shiju Jose;
- generic logic to handle block addresses by Jonathan Cameron;
- generic GHESv2 error inject by Mauro Carvalho Chehab;
Co-authored-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Co-authored-by: Shiju Jose <shiju.jose@huawei.com>
Co-authored-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Shiju Jose <shiju.jose@huawei.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
hw/acpi/ghes.c | 159 ++++++++++++++++++++++++++++++++++++++---
hw/acpi/ghes_cper.c | 2 +-
include/hw/acpi/ghes.h | 2 +
3 files changed, 151 insertions(+), 12 deletions(-)
diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c
index a745dcc7be5e..f5a05f4cb81d 100644
--- a/hw/acpi/ghes.c
+++ b/hw/acpi/ghes.c
@@ -395,23 +395,22 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s,
ags->present = true;
}
+static uint64_t ghes_get_state_start_address(void)
+{
+ AcpiGedState *acpi_ged_state =
+ ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, NULL));
+ AcpiGhesState *ags = &acpi_ged_state->ghes_state;
+
+ return le64_to_cpu(ags->ghes_addr_le);
+}
+
int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
{
uint64_t error_block_addr, read_ack_register_addr, read_ack_register = 0;
- uint64_t start_addr;
+ uint64_t start_addr = ghes_get_state_start_address();
bool ret = -1;
- AcpiGedState *acpi_ged_state;
- AcpiGhesState *ags;
-
assert(source_id < ACPI_HEST_SRC_ID_RESERVED);
- acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED,
- NULL));
- g_assert(acpi_ged_state);
- ags = &acpi_ged_state->ghes_state;
-
- start_addr = le64_to_cpu(ags->ghes_addr_le);
-
if (physical_address) {
start_addr += source_id * sizeof(uint64_t);
@@ -448,9 +447,147 @@ int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
return ret;
}
+/*
+ * Error register block data layout
+ *
+ * | +---------------------+ ges.ghes_addr_le
+ * | |error_block_address0 |
+ * | +---------------------+
+ * | |error_block_address1 |
+ * | +---------------------+ --+--
+ * | | ............. | GHES_ADDRESS_SIZE
+ * | +---------------------+ --+--
+ * | |error_block_addressN |
+ * | +---------------------+
+ * | | read_ack0 |
+ * | +---------------------+ --+--
+ * | | read_ack1 | GHES_ADDRESS_SIZE
+ * | +---------------------+ --+--
+ * | | ............. |
+ * | +---------------------+
+ * | | read_ackN |
+ * | +---------------------+ --+--
+ * | | CPER | |
+ * | | .... | GHES_MAX_RAW_DATA_LENGT
+ * | | CPER | |
+ * | +---------------------+ --+--
+ * | | .......... |
+ * | +---------------------+
+ * | | CPER |
+ * | | .... |
+ * | | CPER |
+ * | +---------------------+
+ */
+
+/* Map from uint32_t notify to entry offset in GHES */
+static const uint8_t error_source_to_index[] = { 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 1, 0};
+
+static bool ghes_get_addr(uint32_t notify, uint64_t *error_block_addr,
+ uint64_t *read_ack_addr)
+{
+ uint64_t base;
+
+ if (notify >= ACPI_GHES_NOTIFY_RESERVED) {
+ return false;
+ }
+
+ /* Find and check the source id for this new CPER */
+ if (error_source_to_index[notify] == 0xff) {
+ return false;
+ }
+
+ base = ghes_get_state_start_address();
+
+ *read_ack_addr = base +
+ ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t) +
+ error_source_to_index[notify] * sizeof(uint64_t);
+
+ /* Could also be read back from the error_block_address register */
+ *error_block_addr = base +
+ ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t) +
+ ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t) +
+ error_source_to_index[notify] * ACPI_GHES_MAX_RAW_DATA_LENGTH;
+
+ return true;
+}
+
NotifierList generic_error_notifiers =
NOTIFIER_LIST_INITIALIZER(error_device_notifiers);
+void ghes_record_cper_errors(AcpiGhesCper *cper, uint32_t notify)
+{
+ int read_ack = 0;
+ uint32_t i;
+ uint64_t read_ack_addr = 0;
+ uint64_t error_block_addr = 0;
+ uint32_t data_length;
+ GArray *block;
+
+ if (!ghes_get_addr(notify, &error_block_addr, &read_ack_addr)) {
+ error_report("GHES: Invalid error block/ack address(es)");
+ return;
+ }
+
+ cpu_physical_memory_read(read_ack_addr,
+ &read_ack, sizeof(uint64_t));
+
+ /* zero means OSPM does not acknowledge the error */
+ if (!read_ack) {
+ error_report("Last time OSPM does not acknowledge the error,"
+ " record CPER failed this time, set the ack value to"
+ " avoid blocking next time CPER record! exit");
+ read_ack = 1;
+ cpu_physical_memory_write(read_ack_addr,
+ &read_ack, sizeof(uint64_t));
+ return;
+ }
+
+ read_ack = cpu_to_le64(0);
+ cpu_physical_memory_write(read_ack_addr,
+ &read_ack, sizeof(uint64_t));
+
+ /* Build CPER record */
+
+ /*
+ * Invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data,
+ * Table 17-13 Generic Error Data Entry
+ */
+ QemuUUID fru_id = {};
+
+ block = g_array_new(false, true /* clear */, 1);
+ data_length = ACPI_GHES_DATA_LENGTH + cper->data_len;
+
+ /*
+ * It should not run out of the preallocated memory if
+ * adding a new generic error data entry
+ */
+ assert((data_length + ACPI_GHES_GESB_SIZE) <=
+ ACPI_GHES_MAX_RAW_DATA_LENGTH);
+
+ /* Build the new generic error status block header */
+ acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE,
+ 0, 0, data_length,
+ ACPI_CPER_SEV_RECOVERABLE);
+
+ /* Build this new generic error data entry header */
+ acpi_ghes_generic_error_data(block, cper->uuid,
+ ACPI_CPER_SEV_RECOVERABLE, 0, 0,
+ cper->data_len, fru_id, 0);
+
+ /* Add CPER data */
+ for (i = 0; i < cper->data_len; i++) {
+ build_append_int_noprefix(block, cper->data[i], 1);
+ }
+
+ /* Write the generic error data entry into guest memory */
+ cpu_physical_memory_write(error_block_addr, block->data, block->len);
+
+ g_array_free(block, true);
+
+ notifier_list_notify(&generic_error_notifiers, NULL);
+}
+
bool acpi_ghes_present(void)
{
AcpiGedState *acpi_ged_state;
diff --git a/hw/acpi/ghes_cper.c b/hw/acpi/ghes_cper.c
index 0d32874a84f1..504ba43ad0cc 100644
--- a/hw/acpi/ghes_cper.c
+++ b/hw/acpi/ghes_cper.c
@@ -47,7 +47,7 @@ void qmp_ghes_cper(CommonPlatformErrorRecord *qmp_cper,
cper.data[i] = p->value;
}
- /* TODO: call a function at ghes */
+ ghes_record_cper_errors(&cper, ACPI_GHES_NOTIFY_GPIO);
g_free(cper.data);
}
diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h
index 02ea3715f655..a426c47f2b96 100644
--- a/include/hw/acpi/ghes.h
+++ b/include/hw/acpi/ghes.h
@@ -84,6 +84,8 @@ typedef struct AcpiGhesCper {
uint32_t data_len;
} AcpiGhesCper;
+void ghes_record_cper_errors(AcpiGhesCper *cper, uint32_t notify);
+
/**
* acpi_ghes_present: Report whether ACPI GHES table is present
*
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 7/7] scripts/ghes_inject: add a script to generate GHES error inject
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
` (5 preceding siblings ...)
2024-08-01 14:47 ` [PATCH v4 6/7] acpi/ghes: add support for generic error injection via QAPI Mauro Carvalho Chehab
@ 2024-08-01 14:47 ` Mauro Carvalho Chehab
6 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2024-08-01 14:47 UTC (permalink / raw)
Cc: Jonathan Cameron, Shiju Jose, Mauro Carvalho Chehab, Cleber Rosa,
John Snow, linux-kernel, qemu-devel
Using the QMP GHESv2 API requires preparing a raw data array
containing a CPER record.
Add a helper script with subcommands to prepare such data.
Currently, only ARM Processor error CPER record is supported.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
MAINTAINERS | 1 +
scripts/ghes_inject.py | 673 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 674 insertions(+)
create mode 100755 scripts/ghes_inject.py
diff --git a/MAINTAINERS b/MAINTAINERS
index 655edcb6688c..9e4874bb552d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2081,6 +2081,7 @@ S: Maintained
F: hw/arm/ghes_cper.c
F: hw/acpi/ghes_cper_stub.c
F: qapi/ghes-cper.json
+F: scripts/ghes_inject.py
ppc4xx
L: qemu-ppc@nongnu.org
diff --git a/scripts/ghes_inject.py b/scripts/ghes_inject.py
new file mode 100755
index 000000000000..99ee93bc2f34
--- /dev/null
+++ b/scripts/ghes_inject.py
@@ -0,0 +1,673 @@
+#!/usr/bin/env python3
+#
+# pylint: disable=C0301, C0114, R0912, R0913, R0915, W0511
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2024 Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+
+# TODO: current implementation has dummy defaults.
+#
+# For a better implementation, a QMP addition/call is needed to
+# retrieve some data for ARM Processor Error injection:
+#
+# - machine emulation architecture, as ARM current default is
+# for AArch64;
+# - ARM registers: power_state, midr, mpidr.
+
+import argparse
+import json
+import socket
+import sys
+
+EINJ_DESCRIPTION = """
+Handle ACPI GHESv2 error injection logic QEMU QMP interface.\n
+
+It allows using UEFI BIOS EINJ features to generate GHES records.
+
+It helps testing Linux CPER and GHES drivers and to test rasdaemon
+error handling logic.
+
+Currently, it support ARM processor error injection for ARM processor
+events, being compatible with UEFI 2.9A Errata.
+
+This small utility works together with those QEMU additions:
+- https://gitlab.com/mchehab_kernel/qemu/-/tree/arm-error-inject-v2
+"""
+
+
+#
+# Socket QMP send command
+#
+def qmp_command(host, port, commands):
+ """Send commands to QEMU though QMP TCP socket"""
+
+ # Needed to negotiate QMP and for QEMU to accept the command
+ commands.insert(0, '{ "execute": "qmp_capabilities" } ')
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((host, port))
+
+ data = s.recv(1024)
+
+ print("\t", data.decode("utf-8"), end="")
+
+ for command in commands:
+ print(command)
+
+ s.sendall(command.encode("utf-8"))
+ data = s.recv(1024)
+ print("\t", data.decode("utf-8"), end="")
+
+ s.shutdown(socket.SHUT_WR)
+ while 1:
+ data = s.recv(1024)
+ if data == b"":
+ break
+ print("\t", data.decode("utf-8"))
+
+ s.close()
+
+
+#
+# Helper routines to handle multiple choice arguments
+#
+def get_choice(name, value, choices, suffixes=None):
+ """Produce a list from multiple choice argument"""
+
+ new_values = []
+
+ if not value:
+ return new_values
+
+ for val in value.split(","):
+ val = val.lower()
+
+ if suffixes:
+ for suffix in suffixes:
+ val = val.removesuffix(suffix)
+
+ if val not in choices.keys():
+ sys.exit(f"Error on '{name}': choice {val} is invalid.")
+
+ val = choices[val]
+
+ new_values.append(val)
+
+ return new_values
+
+
+def get_mult_array(mult, name, values, allow_zero=False, max_val=None):
+ """Add numbered hashes from integer lists"""
+
+ if not allow_zero:
+ if not values:
+ return
+ else:
+ if values is None:
+ return
+
+ if not values:
+ i = 0
+ if i not in mult:
+ mult[i] = {}
+
+ mult[i][name] = []
+ return
+
+ i = 0
+ for value in values:
+ for val in value.split(","):
+ try:
+ val = int(val, 0)
+ except ValueError:
+ sys.exit(f"Error on '{name}': {val} is not an integer")
+
+ if val < 0:
+ sys.exit(f"Error on '{name}': {val} is not unsigned")
+
+ if max_val and val > max_val:
+ sys.exit(f"Error on '{name}': {val} is too little")
+
+ if i not in mult:
+ mult[i] = {}
+
+ if name not in mult[i]:
+ mult[i][name] = []
+
+ mult[i][name].append(val)
+
+ i += 1
+
+
+def get_mult_choices(mult, name, values, choices,
+ suffixes=None, allow_zero=False):
+ """Add numbered hashes from multiple choice arguments"""
+
+ if not allow_zero:
+ if not values:
+ return
+ else:
+ if values is None:
+ return
+
+ i = 0
+ for val in values:
+ new_values = get_choice(name, val, choices, suffixes)
+
+ if i not in mult:
+ mult[i] = {}
+
+ mult[i][name] = new_values
+ i += 1
+
+
+def get_mult_int(mult, name, values, allow_zero=False):
+ """Add numbered hashes from integer arguments"""
+ if not allow_zero:
+ if not values:
+ return
+ else:
+ if values is None:
+ return
+
+ i = 0
+ for val in values:
+ try:
+ val = int(val, 0)
+ except ValueError:
+ sys.exit(f"Error on '{name}': {val} is not an integer")
+
+ if val < 0:
+ sys.exit(f"Error on '{name}': {val} is not unsigned")
+
+ if i not in mult:
+ mult[i] = {}
+
+ mult[i][name] = val
+ i += 1
+
+
+#
+# Data encode helper functions
+#
+def bit(b):
+ """Simple macro to define a bit on a bitmask"""
+ return 1 << b
+
+
+def data_add(data, value, num_bytes):
+ """
+ Adds bytes from value inside a bitarray.
+ If the value is a list, assume it to be a bitmap, where each
+ bit is on a different element inside a list. Such list is
+ converted to a single bitmap integer.
+ """
+
+ if isinstance(value, list):
+ bits = 0
+ for b in value:
+ bits |= b
+
+ value = bits
+
+ data.extend(value.to_bytes(num_bytes, byteorder="little"))
+
+
+def to_uuid(time_low, time_mid, time_high, nodes):
+ """Create an integer array with elements from an UUID"""
+
+ values = bytearray()
+
+ data_add(values, time_low, 4)
+ data_add(values, time_mid, 2)
+ data_add(values, time_high, 2)
+
+ for i in nodes:
+ data_add(values, i, 1)
+
+ return list(values)
+
+
+#
+# Arm processor EINJ logic
+#
+ACPI_GHES_ARM_CPER_LENGTH = 40
+ACPI_GHES_ARM_CPER_PEI_LENGTH = 32
+
+# TODO: query it from emulation. Current default valid only for Aarch64
+CONTEXT_AARCH64_EL1 = 5
+
+CPER_ARM_PROCESSOR_ERROR = to_uuid(0xE19E3D16, 0xBC11, 0x11E4,
+ [0x9C, 0xAA, 0xC2, 0x05,
+ 0x1D, 0x5D, 0x46, 0xB0])
+
+
+class ArmProcessorEinj:
+ """
+ Implements ARM Processor Error injection via GHES
+ """
+
+ def __init__(self, args=None):
+ """
+ Initialize the error injection class. There are two possible
+ ways to initialize it:
+ 1. passing a set of arguments;
+ 2. passing a dict with error inject command parameters. Each
+ column is handled in separate.
+ """
+
+ # Valid choice values
+ self.arm_valid_bits = {
+ "mpidr": bit(0),
+ "affinity": bit(1),
+ "running": bit(2),
+ "vendor": bit(3),
+ }
+
+ self.pei_flags = {
+ "first": bit(0),
+ "last": bit(1),
+ "propagated": bit(2),
+ "overflow": bit(3),
+ }
+
+ self.pei_error_types = {
+ "cache": bit(1),
+ "tlb": bit(2),
+ "bus": bit(3),
+
+ "micro-arch": bit(4),
+ "vendor": bit(4),
+ }
+
+ self.pei_valid_bits = {
+ "multiple-error": bit(0),
+ "flags": bit(1),
+
+ "error": bit(2),
+ "error-info": bit(2),
+
+ "virt": bit(3),
+ "virtual": bit(3),
+
+ "phy": bit(4),
+ "physical": bit(4),
+ }
+
+ self.arm = {}
+
+ if not args:
+ self.args = args
+ return
+
+ pei = {}
+ ctx = {}
+ vendor = {}
+
+ # Handle global parameters
+ if args.arm:
+ arm_validation_init = False
+ self.arm["validation"] = get_choice(name="validation",
+ value=args.arm,
+ choices=self.arm_valid_bits,
+ suffixes=["-error", "-err"])
+ else:
+ self.arm["validation"] = []
+ arm_validation_init = True
+
+ if args.affinity:
+ self.arm["affinity-level"] = args.affinity
+ if arm_validation_init:
+ self.arm["validation"].append(self.arm_valid_bits["affinity"])
+ else:
+ self.arm["affinity-level"] = 0
+
+ if args.mpidr:
+ self.arm["mpidr-el1"] = args.mpidr
+ if arm_validation_init:
+ self.arm["validation"].append(self.arm_valid_bits["mpidr"])
+ else:
+ # TODO: query it from emulation
+ self.arm["mpidr-el1"] = 0
+
+ if args.midr:
+ self.arm["midr-el1"] = args.midr
+ else:
+ # TODO: query it from emulation
+ self.arm["midr-el1"] = 0
+
+ if args.running is not None:
+ if args.running:
+ self.arm["running-state"] = bit(0)
+ else:
+ self.arm["running-state"] = 0
+ if arm_validation_init:
+ self.arm["validation"].append(self.arm_valid_bits["running"])
+ else:
+ # TODO: query it from emulation
+ self.arm["running-state"] = 0
+
+ if args.psci:
+ self.arm["psci-state"] = args.psci
+ if arm_validation_init:
+ self.arm["validation"].append(self.arm_valid_bits["running"])
+ else:
+ # TODO: query it from emulation
+ self.arm["psci-state"] = 0
+
+ # Handle PEI
+ if not args.type:
+ args.type = ["cache-error"]
+
+ get_mult_choices(
+ pei,
+ name="validation",
+ values=args.pei_valid,
+ choices=self.pei_valid_bits,
+ suffixes=["-valid", "-info", "--information", "--addr"],
+ )
+ get_mult_choices(
+ pei,
+ name="type",
+ values=args.type,
+ choices=self.pei_error_types,
+ suffixes=["-error", "-err"],
+ )
+ get_mult_choices(
+ pei,
+ name="flags",
+ values=args.flags,
+ choices=self.pei_flags,
+ suffixes=["-error", "-cap"],
+ )
+ get_mult_int(pei, "error-info", args.error_info)
+ get_mult_int(pei, "multiple-error", args.multiple_error)
+ get_mult_int(pei, "phy-addr", args.physical_address)
+ get_mult_int(pei, "virt-addr", args.virtual_address)
+
+ for i, p in pei.items(): # pylint: disable=W0612
+ # UEFI 2.10 doesn't define how to encode error information
+ # when multiple types are raised. So, provide a default only
+ # if a single type is there
+ if "error-info" not in p:
+ if len(p["type"]) == 1:
+ if p["type"][0] == bit(1):
+ p["error-info"] = 0x0091000F
+ if p["type"][0] == bit(2):
+ p["error-info"] = 0x0054007F
+ if p["type"][0] == bit(3):
+ p["error-info"] = 0x80D6460FFF
+ if p["type"][0] == bit(4):
+ p["error-info"] = 0x78DA03FF
+
+ if "validation" not in p:
+ p["validation"] = []
+ if "multiple-error" in p:
+ p["validation"].append(self.pei_valid_bits["multiple-error"])
+
+ if "flags" in p:
+ p["validation"].append(self.pei_valid_bits["flags"])
+
+ if "error-info" in p:
+ p["validation"].append(self.pei_valid_bits["error-info"])
+
+ if "phy-addr" in p:
+ p["validation"].append(self.pei_valid_bits["phy-addr"])
+
+ if "virt-addr" in p:
+ p["validation"].append(self.pei_valid_bits["virt-addr"])
+
+ # Handle context
+ get_mult_int(ctx, "type", args.ctx_type, allow_zero=True)
+ get_mult_int(ctx, "minimal-size", args.ctx_size, allow_zero=True)
+ get_mult_array(ctx, "register", args.ctx_array, allow_zero=True)
+
+ get_mult_array(vendor, "bytes", args.vendor, max_val=255)
+
+ # Store PEI
+ self.arm["error"] = []
+ for k in sorted(pei.keys()):
+ self.arm["error"].append(pei[k])
+
+ # Store Context
+ self.arm["context"] = []
+ if ctx:
+ for k in sorted(ctx.keys()):
+ self.arm["context"].append(ctx[k])
+
+ # Vendor-specific bytes are not grouped
+ self.arm["vendor-specific"] = []
+ if vendor:
+ for k in sorted(vendor.keys()):
+ self.arm["vendor-specific"] += vendor[k]["bytes"]
+
+ def encode_pei(self):
+ """Encode bytes at the PEI table"""
+
+ data = bytearray()
+
+ for pei in self.arm["error"]:
+ # Version
+ data_add(data, 0, 1)
+
+ data_add(data, ACPI_GHES_ARM_CPER_PEI_LENGTH, 1)
+
+ data_add(data, pei["validation"], 2)
+ data_add(data, pei["type"], 1)
+ data_add(data, pei.get("multiple-error", 1), 2)
+ data_add(data, pei.get("flags", 0), 1)
+ data_add(data, pei.get("error_info", 0), 8)
+ data_add(data, pei.get("virt_addr", 0xDEADBEEF), 8)
+ data_add(data, pei.get("phy_addr", 0xABBA0BAD), 8)
+
+ return data
+
+ def encode_vendor(self):
+ """Encode bytes at the vendor data"""
+
+ data = bytearray()
+
+ for i in self.arm.get("vendor-specific", []):
+ data_add(data, i, 1)
+
+ return data
+
+ def encode_context(self):
+ """Encode bytes for the register context"""
+
+ data = bytearray()
+
+ if "context" not in self.arm:
+ return data
+
+ for ctx in self.arm["context"]:
+ if "type" not in ctx:
+ ctx["type"] = CONTEXT_AARCH64_EL1
+
+ reg_size = len(ctx["register"])
+ size = 0
+
+ if "minimal-size" in ctx:
+ size = ctx["minimal-size"]
+
+ size = max(size, reg_size)
+
+ size = (size + 1) % 0xFFFE
+
+ # Version
+ data_add(data, 0, 2)
+
+ data_add(data, ctx["type"], 2)
+
+ data_add(data, 8 * size, 4)
+
+ for r in ctx["register"]:
+ data_add(data, r, 8)
+
+ for i in range(reg_size, size): # pylint: disable=W0612
+ data_add(data, 0, 8)
+
+ return data
+
+ def encode(self):
+ """Encode bytes for the ARM processor Error record"""
+
+ pei_data = self.encode_pei()
+ vendor_data = self.encode_vendor()
+ context_data = self.encode_context()
+
+ data = bytearray()
+
+ data_add(data, self.arm["validation"], 4)
+
+ error_info_num = len(self.arm["error"])
+ data_add(data, error_info_num, 2)
+
+ context_info_num = len(self.arm["context"])
+ data_add(data, context_info_num, 2)
+
+ # Calculate the length of the CPER data
+ cper_length = ACPI_GHES_ARM_CPER_LENGTH
+ cper_length += len(pei_data)
+ cper_length += len(vendor_data)
+ cper_length += len(context_data)
+ data_add(data, cper_length, 4)
+
+ data_add(data, self.arm["affinity-level"], 1)
+
+ # Reserved
+ data_add(data, 0, 3)
+
+ data_add(data, self.arm["mpidr-el1"], 8)
+ data_add(data, self.arm["midr-el1"], 8)
+ data_add(data, self.arm["running-state"], 4)
+ data_add(data, self.arm["psci-state"], 4)
+
+ # Add PEI
+ data.extend(pei_data)
+ data.extend(context_data)
+ data.extend(vendor_data)
+
+ return list(data)
+
+ def run(self, host, port):
+ """Execute the QMP commands"""
+
+ # Fill the commands to be sent
+ commands = []
+
+ cmd_arg = {
+ 'cper': {
+ 'notification-type': CPER_ARM_PROCESSOR_ERROR,
+ "raw-data": ""
+ }
+ }
+
+ cmd_arg["cper"]["raw-data"] = self.encode()
+
+ command = '{ "execute": "ghes-cper", '
+ command += '"arguments": ' + json.dumps(cmd_arg) + " }"
+
+ commands.append(command)
+
+ qmp_command(host, port, commands)
+
+
+#
+# Argument parser for ARM Processor CPER
+#
+
+
+def arm_handle_args(subparsers):
+ """Add a subparser for ARM-specific arguments"""
+
+ parser = subparsers.add_parser("arm", help="Generate an ARM processor CPER")
+
+ # UEFI N.16 ARM Validation bits
+ g_arm = parser.add_argument_group("ARM processor")
+ g_arm.add_argument("--arm", "--arm-valid",
+ help="ARM validation bits: mpidr,affinity,running,vendor")
+ g_arm.add_argument("-a", "--affinity", "--level", "--affinity-level",
+ type=lambda x: int(x, 0),
+ help="Affinity level (when multiple levels apply)")
+ g_arm.add_argument("-l", "--mpidr", type=lambda x: int(x, 0),
+ help="Multiprocessor Affinity Register")
+ g_arm.add_argument("-i", "--midr", type=lambda x: int(x, 0),
+ help="Main ID Register")
+ g_arm.add_argument("-r", "--running",
+ action=argparse.BooleanOptionalAction, default=None,
+ help="Indicates if the processor is running or not")
+ g_arm.add_argument("--psci", "--psci-state", type=lambda x: int(x, 0),
+ help="Power State Coordination Interface - PSCI state")
+
+ # TODO: Add vendor-specific support
+
+ # UEFI N.17 bitmaps (type and flags)
+ g_pei = parser.add_argument_group("ARM Processor Error Info (PEI)")
+ g_pei.add_argument("-t", "--type", nargs="+",
+ help="one or more error types: cache,tlb,bus,vendor")
+ g_pei.add_argument("-f", "--flags", nargs="*",
+ help="zero or more error flags: first-error,last-error,propagated,overflow")
+ g_arm.add_argument("-V", "--pei-valid", "--error-valid", nargs="*",
+ help="zero or more PEI validation bits: multiple-error,flags,error-info,virt,phy")
+
+ # UEFI N.17 Integer values
+ g_pei.add_argument("-m", "--multiple-error", nargs="+",
+ help="Number of errors: 0: Single error, 1: Multiple errors, 2-65535: Error count if known")
+ g_pei.add_argument("-e", "--error-info", nargs="+",
+ help="Error information (UEFI 2.10 tables N.18 to N.20)")
+ g_pei.add_argument("-p", "--physical-address", nargs="+",
+ help="Physical address")
+ g_pei.add_argument("-v", "--virtual-address", nargs="+",
+ help="Virtual address")
+
+ # UEFI N.21 Context
+ g_pei.add_argument("--ctx-type", "--context-type", nargs="*",
+ help="Type of the context (0=ARM32 GPR, 5=ARM64 EL1, other values supported)")
+ g_pei.add_argument("--ctx-size", "--context-size", nargs="*",
+ help="Minimal size of the context")
+ g_pei.add_argument("--ctx-array", "--context-array", nargs="*",
+ help="Comma-separated arrays for each context")
+
+ # Vendor-specific data
+ g_pei.add_argument("--vendor", "--vendor-specific", nargs="+",
+ help="Vendor-specific byte arrays of data")
+
+
+#
+# Main Program. Each error injection logic is handled by a separate subparser
+#
+
+
+def main():
+ """Main program"""
+
+ # Main parser - handle generic args like QEMU QMP TCP socket options
+ parser = argparse.ArgumentParser(prog="einj.py",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ usage="%(prog)s [options]",
+ description=EINJ_DESCRIPTION,
+ epilog="If a field is not defined, a default value will be applied by QEMU.")
+
+ g_options = parser.add_argument_group("QEMU QMP socket options")
+ g_options.add_argument("-H", "--host", default="localhost", type=str,
+ help="host name")
+ g_options.add_argument("-P", "--port", default=4445, type=int,
+ help="TCP port number")
+
+ # Call subparsers
+ subparsers = parser.add_subparsers()
+ arm_handle_args(subparsers)
+
+ args = parser.parse_args()
+
+ # Handle subparser commands
+ if "arm" in args:
+ einj = ArmProcessorEinj(args)
+ einj.run(args.host, args.port)
+ else:
+ sys.exit("Error: type of error injection missing.")
+
+
+if __name__ == "__main__":
+ main()
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 5/7] qapi/ghes-cper: add an interface to do generic CPER error injection
2024-08-01 14:47 ` [PATCH v4 5/7] qapi/ghes-cper: add an interface to do generic CPER error injection Mauro Carvalho Chehab
@ 2024-08-02 9:44 ` Markus Armbruster
0 siblings, 0 replies; 9+ messages in thread
From: Markus Armbruster @ 2024-08-02 9:44 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Jonathan Cameron, Shiju Jose, Michael S. Tsirkin, Ani Sinha,
Dongjiu Geng, Eric Blake, Igor Mammedov, Michael Roth,
Paolo Bonzini, Peter Maydell, linux-kernel, qemu-arm, qemu-devel
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> Creates a QAPI to be used for generic ACPI APEI hardware error
> injection (HEST) via GHESv2.
Creates a QMP command
> The actual GHES code will be added at the followup patch.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
> MAINTAINERS | 7 ++++++
> hw/acpi/Kconfig | 5 ++++
> hw/acpi/ghes_cper.c | 53 +++++++++++++++++++++++++++++++++++++++++
> hw/acpi/meson.build | 2 ++
> hw/arm/Kconfig | 5 ++++
> include/hw/acpi/ghes.h | 6 +++++
> qapi/ghes-cper.json | 54 ++++++++++++++++++++++++++++++++++++++++++
> qapi/meson.build | 1 +
> qapi/qapi-schema.json | 1 +
> 9 files changed, 134 insertions(+)
> create mode 100644 hw/acpi/ghes_cper.c
> create mode 100644 qapi/ghes-cper.json
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 98eddf7ae155..655edcb6688c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2075,6 +2075,13 @@ F: hw/acpi/ghes.c
> F: include/hw/acpi/ghes.h
> F: docs/specs/acpi_hest_ghes.rst
>
> +ACPI/HEST/GHES/ARM processor CPER
> +R: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +S: Maintained
> +F: hw/arm/ghes_cper.c
> +F: hw/acpi/ghes_cper_stub.c
> +F: qapi/ghes-cper.json
> +
> ppc4xx
> L: qemu-ppc@nongnu.org
> S: Orphan
[...]
> diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
> index fa5c07db9068..6cbf430eb66d 100644
> --- a/hw/acpi/meson.build
> +++ b/hw/acpi/meson.build
> @@ -34,4 +34,6 @@ endif
> system_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
> system_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c'))
> system_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
> +system_ss.add(when: 'CONFIG_GHES_CPER', if_true: files('ghes_cper.c'))
> +system_ss.add(when: 'CONFIG_GHES_CPER', if_false: files('ghes_cper_stub.c'))
../hw/acpi/meson.build:38:50: ERROR: File ghes_cper_stub.c does not exist.
> system_ss.add(files('acpi-qmp-cmds.c'))
[...]
> diff --git a/qapi/ghes-cper.json b/qapi/ghes-cper.json
> new file mode 100644
> index 000000000000..2b0438431054
> --- /dev/null
> +++ b/qapi/ghes-cper.json
Would this fit into acpi.json?
If yes: would the maintainers of acpi.json be happy to take it?
Michael, Igor?
> @@ -0,0 +1,54 @@
> +# -*- Mode: Python -*-
> +# vim: filetype=python
> +
> +##
> +# = GHESv2 CPER Error Injection
> +#
> +# These are defined at
> +# ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2
> +# (GHESv2 - Type 10)
> +##
> +
> +##
> +# @CommonPlatformErrorRecord:
> +#
> +# Common Platform Error Record - CPER - as defined at the UEFI
> +# specification. See
Separate sentences with two spaces for consistency, please.
> +# https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header
> +# for more details.
> +#
> +# @notification-type: pre-assigned GUID value indicating the record
> +# association with an error event notification type, as defined
> +# at https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header
> +#
> +# @raw-data: Contains the payload of the CPER.
> +#
> +# Since: 9.2
> +##
> +{ 'struct': 'CommonPlatformErrorRecord',
> + 'data': {
> + 'notification-type': ['uint8'],
> + 'raw-data': ['uint8']
> + }
> +}
You use ['uint8'] for binary. We commonly represent binary as
base64-encoded strings in QAPI.
If @notification-type is a UUID, we should use the usual text
representation. qemu/uuid.h has functions to convert between binary and
text.
> +
> +##
> +# @ghes-cper:
> +#
> +# Inject ARM Processor error with data to be filled according with
> +# ACPI 6.2 GHESv2 spec.
> +#
> +# @cper: a single CPER record to be sent to the guest OS.
> +#
> +# Features:
> +#
> +# @unstable: This command is experimental.
> +#
> +# Since: 9.2
> +##
> +{ 'command': 'ghes-cper',
> + 'data': {
> + 'cper': 'CommonPlatformErrorRecord'
> + },
> + 'features': [ 'unstable' ]
> +}
> diff --git a/qapi/meson.build b/qapi/meson.build
> index e7bc54e5d047..bd13cd7d40c9 100644
> --- a/qapi/meson.build
> +++ b/qapi/meson.build
> @@ -35,6 +35,7 @@ qapi_all_modules = [
> 'dump',
> 'ebpf',
> 'error',
> + 'ghes-cper',
> 'introspect',
> 'job',
> 'machine-common',
> diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
> index b1581988e4eb..54165c8d6655 100644
> --- a/qapi/qapi-schema.json
> +++ b/qapi/qapi-schema.json
> @@ -81,3 +81,4 @@
> { 'include': 'vfio.json' }
> { 'include': 'cryptodev.json' }
> { 'include': 'cxl.json' }
> +{ 'include': 'ghes-cper.json' }
Put it next to acpi.json, perhaps?
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-08-02 9:44 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-01 14:47 [PATCH v4 0/7] Add ACPI CPER firmware first error injection on ARM emulation Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 1/7] arm/virt: place power button pin number on a define Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 2/7] acpi/generic_event_device: add an APEI error device Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 3/7] arm/virt: Wire up GPIO error source for ACPI / GHES Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 4/7] acpi/ghes: Support GPIO error source Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 5/7] qapi/ghes-cper: add an interface to do generic CPER error injection Mauro Carvalho Chehab
2024-08-02 9:44 ` Markus Armbruster
2024-08-01 14:47 ` [PATCH v4 6/7] acpi/ghes: add support for generic error injection via QAPI Mauro Carvalho Chehab
2024-08-01 14:47 ` [PATCH v4 7/7] scripts/ghes_inject: add a script to generate GHES error inject Mauro Carvalho Chehab
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.