@@ -364,10 +364,37 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s,
ags->present = true;
}
+static void get_hw_error_offsets(uint64_t ghes_addr,
+ uint64_t *cper_addr,
+ uint64_t *read_ack_register_addr)
+{
+ if (!ghes_addr) {
+ return;
+ }
+
+ /*
+ * non-HEST version supports only one source, so no need to change
+ * the start offset based on the source ID. Also, we can't validate
+ * the source ID, as it is stored inside the HEST table.
+ */
+
+ cpu_physical_memory_read(ghes_addr, cper_addr,
+ sizeof(*cper_addr));
+
+ *cper_addr = le64_to_cpu(*cper_addr);
+
+ /*
+ * As the current version supports only one source, the ack offset is
+ * just sizeof(uint64_t).
+ */
+ *read_ack_register_addr = ghes_addr +
+ ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t);
+}
+
void ghes_record_cper_errors(const void *cper, size_t len,
uint16_t source_id, Error **errp)
{
- uint64_t error_block_addr, read_ack_register_addr, read_ack_register = 0;
+ uint64_t cper_addr = 0, read_ack_register_addr = 0, read_ack_register;
uint64_t start_addr;
AcpiGedState *acpi_ged_state;
AcpiGhesState *ags;
@@ -389,18 +416,14 @@ void ghes_record_cper_errors(const void *cper, size_t len,
start_addr += source_id * sizeof(uint64_t);
- cpu_physical_memory_read(start_addr, &error_block_addr,
- sizeof(error_block_addr));
+ get_hw_error_offsets(start_addr, &cper_addr, &read_ack_register_addr);
- error_block_addr = le64_to_cpu(error_block_addr);
- if (!error_block_addr) {
+ cper_addr = le64_to_cpu(cper_addr);
+ if (!cper_addr) {
error_setg(errp, "can not find Generic Error Status Block");
return;
}
- read_ack_register_addr = start_addr +
- ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t);
-
cpu_physical_memory_read(read_ack_register_addr,
&read_ack_register, sizeof(read_ack_register));
@@ -421,7 +444,7 @@ void ghes_record_cper_errors(const void *cper, size_t len,
&read_ack_register, sizeof(uint64_t));
/* Write the generic error data entry into guest memory */
- cpu_physical_memory_write(error_block_addr, cper, len);
+ cpu_physical_memory_write(cper_addr, cper, len);
return;
}