The OS kernels navigate between HEST, error source struct
and CPER by the usage of some pointers. Double-check if such
pointers were properly initializing, ensuring that they match
the right address for CPER.

Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org>
---
 hw/acpi/ghes.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c
index a822a5eafaa0..51e2e40e5a9c 100644
--- a/hw/acpi/ghes.c
+++ b/hw/acpi/ghes.c
@@ -85,6 +85,9 @@ enum AcpiHestSourceId {
 #define HEST_GHES_V2_TABLE_SIZE  92
 #define GHES_ACK_OFFSET          (64 + GAS_ADDR_OFFSET + ACPI_HEST_HEADER_SIZE)
 
+/* ACPI 6.2: 18.3.2.7: Generic Hardware Error Source */
+#define GHES_ERR_ST_ADDR_OFFSET  (20 + GAS_ADDR_OFFSET + ACPI_HEST_HEADER_SIZE)
+
 /*
  * Values for error_severity field
  */
@@ -425,7 +428,10 @@ NotifierList acpi_generic_error_notifiers =
 void ghes_record_cper_errors(const void *cper, size_t len,
                              enum AcpiGhesNotifyType notify, Error **errp)
 {
-    uint64_t cper_addr, read_ack_start_addr;
+    uint64_t hest_read_ack_start_addr, read_ack_start_addr;
+    uint64_t read_ack_start_addr_2, err_source_struct;
+    uint64_t hest_err_block_addr, error_block_addr;
+    uint64_t cper_addr, cper_addr_2;
     enum AcpiHestSourceId source;
     AcpiGedState *acpi_ged_state;
     AcpiGhesState *ags;
@@ -450,6 +456,28 @@ void ghes_record_cper_errors(const void *cper, size_t len,
     cper_addr += ACPI_HEST_SRC_ID_COUNT * sizeof(uint64_t);
     cper_addr += source * ACPI_GHES_MAX_RAW_DATA_LENGTH;
 
+    err_source_struct = le64_to_cpu(ags->hest_addr_le) +
+                        source * HEST_GHES_V2_TABLE_SIZE;
+
+    /* Check if BIOS addr pointers were properly generated */
+
+    hest_err_block_addr = err_source_struct + GHES_ERR_ST_ADDR_OFFSET;
+    hest_read_ack_start_addr = err_source_struct + GHES_ACK_OFFSET;
+
+    cpu_physical_memory_read(hest_err_block_addr, &error_block_addr,
+                             sizeof(error_block_addr));
+
+    cpu_physical_memory_read(error_block_addr, &cper_addr_2,
+                             sizeof(error_block_addr));
+
+    cpu_physical_memory_read(hest_read_ack_start_addr, &read_ack_start_addr_2,
+                            sizeof(read_ack_start_addr_2));
+
+    assert(cper_addr == cper_addr_2);
+    assert(read_ack_start_addr == read_ack_start_addr_2);
+
+    /* Update ACK offset to notify about a new error */
+
     cpu_physical_memory_read(read_ack_start_addr,
                              &read_ack, sizeof(uint64_t));
 
-- 
2.46.0


Reply via email to