1aa16508fSDongjiu Geng /* 2aa16508fSDongjiu Geng * Support for generating APEI tables and recording CPER for Guests 3aa16508fSDongjiu Geng * 4aa16508fSDongjiu Geng * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD. 5aa16508fSDongjiu Geng * 6aa16508fSDongjiu Geng * Author: Dongjiu Geng <gengdongjiu@huawei.com> 7aa16508fSDongjiu Geng * 8aa16508fSDongjiu Geng * This program is free software; you can redistribute it and/or modify 9aa16508fSDongjiu Geng * it under the terms of the GNU General Public License as published by 10aa16508fSDongjiu Geng * the Free Software Foundation; either version 2 of the License, or 11aa16508fSDongjiu Geng * (at your option) any later version. 12aa16508fSDongjiu Geng 13aa16508fSDongjiu Geng * This program is distributed in the hope that it will be useful, 14aa16508fSDongjiu Geng * but WITHOUT ANY WARRANTY; without even the implied warranty of 15aa16508fSDongjiu Geng * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16aa16508fSDongjiu Geng * GNU General Public License for more details. 17aa16508fSDongjiu Geng 18aa16508fSDongjiu Geng * You should have received a copy of the GNU General Public License along 19aa16508fSDongjiu Geng * with this program; if not, see <http://www.gnu.org/licenses/>. 20aa16508fSDongjiu Geng */ 21aa16508fSDongjiu Geng 22aa16508fSDongjiu Geng #include "qemu/osdep.h" 23aa16508fSDongjiu Geng #include "qemu/units.h" 24aa16508fSDongjiu Geng #include "hw/acpi/ghes.h" 25aa16508fSDongjiu Geng #include "hw/acpi/aml-build.h" 26*205cc75dSDongjiu Geng #include "qemu/error-report.h" 27aa16508fSDongjiu Geng 28aa16508fSDongjiu Geng #define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors" 29aa16508fSDongjiu Geng #define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" 30aa16508fSDongjiu Geng 31aa16508fSDongjiu Geng /* The max size in bytes for one error block */ 32aa16508fSDongjiu Geng #define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB) 33aa16508fSDongjiu Geng 34aa16508fSDongjiu Geng /* Now only support ARMv8 SEA notification type error source */ 35aa16508fSDongjiu Geng #define ACPI_GHES_ERROR_SOURCE_COUNT 1 36aa16508fSDongjiu Geng 37*205cc75dSDongjiu Geng /* Generic Hardware Error Source version 2 */ 38*205cc75dSDongjiu Geng #define ACPI_GHES_SOURCE_GENERIC_ERROR_V2 10 39*205cc75dSDongjiu Geng 40*205cc75dSDongjiu Geng /* Address offset in Generic Address Structure(GAS) */ 41*205cc75dSDongjiu Geng #define GAS_ADDR_OFFSET 4 42*205cc75dSDongjiu Geng 43*205cc75dSDongjiu Geng /* 44*205cc75dSDongjiu Geng * Hardware Error Notification 45*205cc75dSDongjiu Geng * ACPI 4.0: 17.3.2.7 Hardware Error Notification 46*205cc75dSDongjiu Geng * Composes dummy Hardware Error Notification descriptor of specified type 47*205cc75dSDongjiu Geng */ 48*205cc75dSDongjiu Geng static void build_ghes_hw_error_notification(GArray *table, const uint8_t type) 49*205cc75dSDongjiu Geng { 50*205cc75dSDongjiu Geng /* Type */ 51*205cc75dSDongjiu Geng build_append_int_noprefix(table, type, 1); 52*205cc75dSDongjiu Geng /* 53*205cc75dSDongjiu Geng * Length: 54*205cc75dSDongjiu Geng * Total length of the structure in bytes 55*205cc75dSDongjiu Geng */ 56*205cc75dSDongjiu Geng build_append_int_noprefix(table, 28, 1); 57*205cc75dSDongjiu Geng /* Configuration Write Enable */ 58*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 2); 59*205cc75dSDongjiu Geng /* Poll Interval */ 60*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 4); 61*205cc75dSDongjiu Geng /* Vector */ 62*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 4); 63*205cc75dSDongjiu Geng /* Switch To Polling Threshold Value */ 64*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 4); 65*205cc75dSDongjiu Geng /* Switch To Polling Threshold Window */ 66*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 4); 67*205cc75dSDongjiu Geng /* Error Threshold Value */ 68*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 4); 69*205cc75dSDongjiu Geng /* Error Threshold Window */ 70*205cc75dSDongjiu Geng build_append_int_noprefix(table, 0, 4); 71*205cc75dSDongjiu Geng } 72*205cc75dSDongjiu Geng 73aa16508fSDongjiu Geng /* 74aa16508fSDongjiu Geng * Build table for the hardware error fw_cfg blob. 75aa16508fSDongjiu Geng * Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs. 76aa16508fSDongjiu Geng * See docs/specs/acpi_hest_ghes.rst for blobs format. 77aa16508fSDongjiu Geng */ 78aa16508fSDongjiu Geng void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker) 79aa16508fSDongjiu Geng { 80aa16508fSDongjiu Geng int i, error_status_block_offset; 81aa16508fSDongjiu Geng 82aa16508fSDongjiu Geng /* Build error_block_address */ 83aa16508fSDongjiu Geng for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { 84aa16508fSDongjiu Geng build_append_int_noprefix(hardware_errors, 0, sizeof(uint64_t)); 85aa16508fSDongjiu Geng } 86aa16508fSDongjiu Geng 87aa16508fSDongjiu Geng /* Build read_ack_register */ 88aa16508fSDongjiu Geng for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { 89aa16508fSDongjiu Geng /* 90aa16508fSDongjiu Geng * Initialize the value of read_ack_register to 1, so GHES can be 91aa16508fSDongjiu Geng * writeable after (re)boot. 92aa16508fSDongjiu Geng * ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2 93aa16508fSDongjiu Geng * (GHESv2 - Type 10) 94aa16508fSDongjiu Geng */ 95aa16508fSDongjiu Geng build_append_int_noprefix(hardware_errors, 1, sizeof(uint64_t)); 96aa16508fSDongjiu Geng } 97aa16508fSDongjiu Geng 98aa16508fSDongjiu Geng /* Generic Error Status Block offset in the hardware error fw_cfg blob */ 99aa16508fSDongjiu Geng error_status_block_offset = hardware_errors->len; 100aa16508fSDongjiu Geng 101aa16508fSDongjiu Geng /* Reserve space for Error Status Data Block */ 102aa16508fSDongjiu Geng acpi_data_push(hardware_errors, 103aa16508fSDongjiu Geng ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT); 104aa16508fSDongjiu Geng 105aa16508fSDongjiu Geng /* Tell guest firmware to place hardware_errors blob into RAM */ 106aa16508fSDongjiu Geng bios_linker_loader_alloc(linker, ACPI_GHES_ERRORS_FW_CFG_FILE, 107aa16508fSDongjiu Geng hardware_errors, sizeof(uint64_t), false); 108aa16508fSDongjiu Geng 109aa16508fSDongjiu Geng for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { 110aa16508fSDongjiu Geng /* 111aa16508fSDongjiu Geng * Tell firmware to patch error_block_address entries to point to 112aa16508fSDongjiu Geng * corresponding "Generic Error Status Block" 113aa16508fSDongjiu Geng */ 114aa16508fSDongjiu Geng bios_linker_loader_add_pointer(linker, 115aa16508fSDongjiu Geng ACPI_GHES_ERRORS_FW_CFG_FILE, sizeof(uint64_t) * i, 116aa16508fSDongjiu Geng sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 117aa16508fSDongjiu Geng error_status_block_offset + i * ACPI_GHES_MAX_RAW_DATA_LENGTH); 118aa16508fSDongjiu Geng } 119aa16508fSDongjiu Geng 120aa16508fSDongjiu Geng /* 121aa16508fSDongjiu Geng * tell firmware to write hardware_errors GPA into 122aa16508fSDongjiu Geng * hardware_errors_addr fw_cfg, once the former has been initialized. 123aa16508fSDongjiu Geng */ 124aa16508fSDongjiu Geng bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, 125aa16508fSDongjiu Geng 0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0); 126aa16508fSDongjiu Geng } 127*205cc75dSDongjiu Geng 128*205cc75dSDongjiu Geng /* Build Generic Hardware Error Source version 2 (GHESv2) */ 129*205cc75dSDongjiu Geng static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker) 130*205cc75dSDongjiu Geng { 131*205cc75dSDongjiu Geng uint64_t address_offset; 132*205cc75dSDongjiu Geng /* 133*205cc75dSDongjiu Geng * Type: 134*205cc75dSDongjiu Geng * Generic Hardware Error Source version 2(GHESv2 - Type 10) 135*205cc75dSDongjiu Geng */ 136*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, ACPI_GHES_SOURCE_GENERIC_ERROR_V2, 2); 137*205cc75dSDongjiu Geng /* Source Id */ 138*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, source_id, 2); 139*205cc75dSDongjiu Geng /* Related Source Id */ 140*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, 0xffff, 2); 141*205cc75dSDongjiu Geng /* Flags */ 142*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, 0, 1); 143*205cc75dSDongjiu Geng /* Enabled */ 144*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, 1, 1); 145*205cc75dSDongjiu Geng 146*205cc75dSDongjiu Geng /* Number of Records To Pre-allocate */ 147*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, 1, 4); 148*205cc75dSDongjiu Geng /* Max Sections Per Record */ 149*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, 1, 4); 150*205cc75dSDongjiu Geng /* Max Raw Data Length */ 151*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4); 152*205cc75dSDongjiu Geng 153*205cc75dSDongjiu Geng address_offset = table_data->len; 154*205cc75dSDongjiu Geng /* Error Status Address */ 155*205cc75dSDongjiu Geng build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0, 156*205cc75dSDongjiu Geng 4 /* QWord access */, 0); 157*205cc75dSDongjiu Geng bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, 158*205cc75dSDongjiu Geng address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t), 159*205cc75dSDongjiu Geng ACPI_GHES_ERRORS_FW_CFG_FILE, source_id * sizeof(uint64_t)); 160*205cc75dSDongjiu Geng 161*205cc75dSDongjiu Geng switch (source_id) { 162*205cc75dSDongjiu Geng case ACPI_HEST_SRC_ID_SEA: 163*205cc75dSDongjiu Geng /* 164*205cc75dSDongjiu Geng * Notification Structure 165*205cc75dSDongjiu Geng * Now only enable ARMv8 SEA notification type 166*205cc75dSDongjiu Geng */ 167*205cc75dSDongjiu Geng build_ghes_hw_error_notification(table_data, ACPI_GHES_NOTIFY_SEA); 168*205cc75dSDongjiu Geng break; 169*205cc75dSDongjiu Geng default: 170*205cc75dSDongjiu Geng error_report("Not support this error source"); 171*205cc75dSDongjiu Geng abort(); 172*205cc75dSDongjiu Geng } 173*205cc75dSDongjiu Geng 174*205cc75dSDongjiu Geng /* Error Status Block Length */ 175*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4); 176*205cc75dSDongjiu Geng 177*205cc75dSDongjiu Geng /* 178*205cc75dSDongjiu Geng * Read Ack Register 179*205cc75dSDongjiu Geng * ACPI 6.1: 18.3.2.8 Generic Hardware Error Source 180*205cc75dSDongjiu Geng * version 2 (GHESv2 - Type 10) 181*205cc75dSDongjiu Geng */ 182*205cc75dSDongjiu Geng address_offset = table_data->len; 183*205cc75dSDongjiu Geng build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0, 184*205cc75dSDongjiu Geng 4 /* QWord access */, 0); 185*205cc75dSDongjiu Geng bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, 186*205cc75dSDongjiu Geng address_offset + GAS_ADDR_OFFSET, 187*205cc75dSDongjiu Geng sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 188*205cc75dSDongjiu Geng (ACPI_GHES_ERROR_SOURCE_COUNT + source_id) * sizeof(uint64_t)); 189*205cc75dSDongjiu Geng 190*205cc75dSDongjiu Geng /* 191*205cc75dSDongjiu Geng * Read Ack Preserve field 192*205cc75dSDongjiu Geng * We only provide the first bit in Read Ack Register to OSPM to write 193*205cc75dSDongjiu Geng * while the other bits are preserved. 194*205cc75dSDongjiu Geng */ 195*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, ~0x1ULL, 8); 196*205cc75dSDongjiu Geng /* Read Ack Write */ 197*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, 0x1, 8); 198*205cc75dSDongjiu Geng } 199*205cc75dSDongjiu Geng 200*205cc75dSDongjiu Geng /* Build Hardware Error Source Table */ 201*205cc75dSDongjiu Geng void acpi_build_hest(GArray *table_data, BIOSLinker *linker) 202*205cc75dSDongjiu Geng { 203*205cc75dSDongjiu Geng uint64_t hest_start = table_data->len; 204*205cc75dSDongjiu Geng 205*205cc75dSDongjiu Geng /* Hardware Error Source Table header*/ 206*205cc75dSDongjiu Geng acpi_data_push(table_data, sizeof(AcpiTableHeader)); 207*205cc75dSDongjiu Geng 208*205cc75dSDongjiu Geng /* Error Source Count */ 209*205cc75dSDongjiu Geng build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4); 210*205cc75dSDongjiu Geng 211*205cc75dSDongjiu Geng build_ghes_v2(table_data, ACPI_HEST_SRC_ID_SEA, linker); 212*205cc75dSDongjiu Geng 213*205cc75dSDongjiu Geng build_header(linker, table_data, (void *)(table_data->data + hest_start), 214*205cc75dSDongjiu Geng "HEST", table_data->len - hest_start, 1, NULL, NULL); 215*205cc75dSDongjiu Geng } 216