/* * Support for generating APEI tables and recording CPER for Guests * * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD. * * Author: Dongjiu Geng * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ #include "qemu/osdep.h" #include "qemu/units.h" #include "hw/acpi/ghes.h" #include "hw/acpi/aml-build.h" #define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors" #define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" /* 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 /* * Build table for the hardware error fw_cfg blob. * Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs. * See docs/specs/acpi_hest_ghes.rst for blobs format. */ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker) { int i, error_status_block_offset; /* Build error_block_address */ for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { build_append_int_noprefix(hardware_errors, 0, sizeof(uint64_t)); } /* Build read_ack_register */ for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { /* * Initialize the value of read_ack_register to 1, so GHES can be * writeable after (re)boot. * ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2 * (GHESv2 - Type 10) */ build_append_int_noprefix(hardware_errors, 1, sizeof(uint64_t)); } /* Generic Error Status Block offset in the hardware error fw_cfg blob */ error_status_block_offset = hardware_errors->len; /* Reserve space for Error Status Data Block */ acpi_data_push(hardware_errors, ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT); /* Tell guest firmware to place hardware_errors blob into RAM */ bios_linker_loader_alloc(linker, ACPI_GHES_ERRORS_FW_CFG_FILE, hardware_errors, sizeof(uint64_t), false); for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { /* * Tell firmware to patch error_block_address entries to point to * corresponding "Generic Error Status Block" */ bios_linker_loader_add_pointer(linker, ACPI_GHES_ERRORS_FW_CFG_FILE, sizeof(uint64_t) * i, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, error_status_block_offset + i * ACPI_GHES_MAX_RAW_DATA_LENGTH); } /* * tell firmware to write hardware_errors GPA into * hardware_errors_addr fw_cfg, once the former has been initialized. */ bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, 0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0); }