1*f7e26ffaSEric DeVolder /* 2*f7e26ffaSEric DeVolder * ACPI Error Record Serialization Table, ERST, Implementation 3*f7e26ffaSEric DeVolder * 4*f7e26ffaSEric DeVolder * ACPI ERST introduced in ACPI 4.0, June 16, 2009. 5*f7e26ffaSEric DeVolder * ACPI Platform Error Interfaces : Error Serialization 6*f7e26ffaSEric DeVolder * 7*f7e26ffaSEric DeVolder * Copyright (c) 2021 Oracle and/or its affiliates. 8*f7e26ffaSEric DeVolder * 9*f7e26ffaSEric DeVolder * SPDX-License-Identifier: GPL-2.0-or-later 10*f7e26ffaSEric DeVolder */ 11*f7e26ffaSEric DeVolder 12*f7e26ffaSEric DeVolder #include "qemu/osdep.h" 13*f7e26ffaSEric DeVolder #include "qapi/error.h" 14*f7e26ffaSEric DeVolder #include "hw/qdev-core.h" 15*f7e26ffaSEric DeVolder #include "exec/memory.h" 16*f7e26ffaSEric DeVolder #include "qom/object.h" 17*f7e26ffaSEric DeVolder #include "hw/pci/pci.h" 18*f7e26ffaSEric DeVolder #include "qom/object_interfaces.h" 19*f7e26ffaSEric DeVolder #include "qemu/error-report.h" 20*f7e26ffaSEric DeVolder #include "migration/vmstate.h" 21*f7e26ffaSEric DeVolder #include "hw/qdev-properties.h" 22*f7e26ffaSEric DeVolder #include "hw/acpi/acpi.h" 23*f7e26ffaSEric DeVolder #include "hw/acpi/acpi-defs.h" 24*f7e26ffaSEric DeVolder #include "hw/acpi/aml-build.h" 25*f7e26ffaSEric DeVolder #include "hw/acpi/bios-linker-loader.h" 26*f7e26ffaSEric DeVolder #include "exec/address-spaces.h" 27*f7e26ffaSEric DeVolder #include "sysemu/hostmem.h" 28*f7e26ffaSEric DeVolder #include "hw/acpi/erst.h" 29*f7e26ffaSEric DeVolder #include "trace.h" 30*f7e26ffaSEric DeVolder 31*f7e26ffaSEric DeVolder /* ACPI 4.0: Table 17-16 Serialization Actions */ 32*f7e26ffaSEric DeVolder #define ACTION_BEGIN_WRITE_OPERATION 0x0 33*f7e26ffaSEric DeVolder #define ACTION_BEGIN_READ_OPERATION 0x1 34*f7e26ffaSEric DeVolder #define ACTION_BEGIN_CLEAR_OPERATION 0x2 35*f7e26ffaSEric DeVolder #define ACTION_END_OPERATION 0x3 36*f7e26ffaSEric DeVolder #define ACTION_SET_RECORD_OFFSET 0x4 37*f7e26ffaSEric DeVolder #define ACTION_EXECUTE_OPERATION 0x5 38*f7e26ffaSEric DeVolder #define ACTION_CHECK_BUSY_STATUS 0x6 39*f7e26ffaSEric DeVolder #define ACTION_GET_COMMAND_STATUS 0x7 40*f7e26ffaSEric DeVolder #define ACTION_GET_RECORD_IDENTIFIER 0x8 41*f7e26ffaSEric DeVolder #define ACTION_SET_RECORD_IDENTIFIER 0x9 42*f7e26ffaSEric DeVolder #define ACTION_GET_RECORD_COUNT 0xA 43*f7e26ffaSEric DeVolder #define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB 44*f7e26ffaSEric DeVolder #define ACTION_RESERVED 0xC 45*f7e26ffaSEric DeVolder #define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD 46*f7e26ffaSEric DeVolder #define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE 47*f7e26ffaSEric DeVolder #define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF 48*f7e26ffaSEric DeVolder #define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */ 49*f7e26ffaSEric DeVolder 50*f7e26ffaSEric DeVolder /* ACPI 4.0: Table 17-17 Command Status Definitions */ 51*f7e26ffaSEric DeVolder #define STATUS_SUCCESS 0x00 52*f7e26ffaSEric DeVolder #define STATUS_NOT_ENOUGH_SPACE 0x01 53*f7e26ffaSEric DeVolder #define STATUS_HARDWARE_NOT_AVAILABLE 0x02 54*f7e26ffaSEric DeVolder #define STATUS_FAILED 0x03 55*f7e26ffaSEric DeVolder #define STATUS_RECORD_STORE_EMPTY 0x04 56*f7e26ffaSEric DeVolder #define STATUS_RECORD_NOT_FOUND 0x05 57*f7e26ffaSEric DeVolder 58*f7e26ffaSEric DeVolder /* UEFI 2.1: Appendix N Common Platform Error Record */ 59*f7e26ffaSEric DeVolder #define UEFI_CPER_RECORD_MIN_SIZE 128U 60*f7e26ffaSEric DeVolder #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U 61*f7e26ffaSEric DeVolder #define UEFI_CPER_RECORD_ID_OFFSET 96U 62*f7e26ffaSEric DeVolder #define IS_UEFI_CPER_RECORD(ptr) \ 63*f7e26ffaSEric DeVolder (((ptr)[0] == 'C') && \ 64*f7e26ffaSEric DeVolder ((ptr)[1] == 'P') && \ 65*f7e26ffaSEric DeVolder ((ptr)[2] == 'E') && \ 66*f7e26ffaSEric DeVolder ((ptr)[3] == 'R')) 67*f7e26ffaSEric DeVolder 68*f7e26ffaSEric DeVolder /* 69*f7e26ffaSEric DeVolder * NOTE that when accessing CPER fields within a record, memcpy() 70*f7e26ffaSEric DeVolder * is utilized to avoid a possible misaligned access on the host. 71*f7e26ffaSEric DeVolder */ 72*f7e26ffaSEric DeVolder 73*f7e26ffaSEric DeVolder /* 74*f7e26ffaSEric DeVolder * This implementation is an ACTION (cmd) and VALUE (data) 75*f7e26ffaSEric DeVolder * interface consisting of just two 64-bit registers. 76*f7e26ffaSEric DeVolder */ 77*f7e26ffaSEric DeVolder #define ERST_REG_SIZE (16UL) 78*f7e26ffaSEric DeVolder #define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ 79*f7e26ffaSEric DeVolder #define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ 80*f7e26ffaSEric DeVolder 81*f7e26ffaSEric DeVolder /* 82*f7e26ffaSEric DeVolder * ERST_RECORD_SIZE is the buffer size for exchanging ERST 83*f7e26ffaSEric DeVolder * record contents. Thus, it defines the maximum record size. 84*f7e26ffaSEric DeVolder * As this is mapped through a PCI BAR, it must be a power of 85*f7e26ffaSEric DeVolder * two and larger than UEFI_CPER_RECORD_MIN_SIZE. 86*f7e26ffaSEric DeVolder * The backing storage is divided into fixed size "slots", 87*f7e26ffaSEric DeVolder * each ERST_RECORD_SIZE in length, and each "slot" 88*f7e26ffaSEric DeVolder * storing a single record. No attempt at optimizing storage 89*f7e26ffaSEric DeVolder * through compression, compaction, etc is attempted. 90*f7e26ffaSEric DeVolder * NOTE that slot 0 is reserved for the backing storage header. 91*f7e26ffaSEric DeVolder * Depending upon the size of the backing storage, additional 92*f7e26ffaSEric DeVolder * slots will be part of the slot 0 header in order to account 93*f7e26ffaSEric DeVolder * for a record_id for each available remaining slot. 94*f7e26ffaSEric DeVolder */ 95*f7e26ffaSEric DeVolder /* 8KiB records, not too small, not too big */ 96*f7e26ffaSEric DeVolder #define ERST_RECORD_SIZE (8192UL) 97*f7e26ffaSEric DeVolder 98*f7e26ffaSEric DeVolder #define ACPI_ERST_MEMDEV_PROP "memdev" 99*f7e26ffaSEric DeVolder #define ACPI_ERST_RECORD_SIZE_PROP "record_size" 100*f7e26ffaSEric DeVolder 101*f7e26ffaSEric DeVolder /* 102*f7e26ffaSEric DeVolder * From the ACPI ERST spec sections: 103*f7e26ffaSEric DeVolder * A record id of all 0s is used to indicate 'unspecified' record id. 104*f7e26ffaSEric DeVolder * A record id of all 1s is used to indicate empty or end. 105*f7e26ffaSEric DeVolder */ 106*f7e26ffaSEric DeVolder #define ERST_UNSPECIFIED_RECORD_ID (0UL) 107*f7e26ffaSEric DeVolder #define ERST_EMPTY_END_RECORD_ID (~0UL) 108*f7e26ffaSEric DeVolder 109*f7e26ffaSEric DeVolder #define ERST_IS_VALID_RECORD_ID(rid) \ 110*f7e26ffaSEric DeVolder ((rid != ERST_UNSPECIFIED_RECORD_ID) && \ 111*f7e26ffaSEric DeVolder (rid != ERST_EMPTY_END_RECORD_ID)) 112*f7e26ffaSEric DeVolder 113*f7e26ffaSEric DeVolder /* 114*f7e26ffaSEric DeVolder * Implementation-specific definitions and types. 115*f7e26ffaSEric DeVolder * Values are arbitrary and chosen for this implementation. 116*f7e26ffaSEric DeVolder * See erst.rst documentation for details. 117*f7e26ffaSEric DeVolder */ 118*f7e26ffaSEric DeVolder #define ERST_EXECUTE_OPERATION_MAGIC 0x9CUL 119*f7e26ffaSEric DeVolder #define ERST_STORE_MAGIC 0x524F545354535245UL /* ERSTSTOR */ 120*f7e26ffaSEric DeVolder typedef struct { 121*f7e26ffaSEric DeVolder uint64_t magic; 122*f7e26ffaSEric DeVolder uint32_t record_size; 123*f7e26ffaSEric DeVolder uint32_t storage_offset; /* offset to record storage beyond header */ 124*f7e26ffaSEric DeVolder uint16_t version; 125*f7e26ffaSEric DeVolder uint16_t reserved; 126*f7e26ffaSEric DeVolder uint32_t record_count; 127*f7e26ffaSEric DeVolder uint64_t map[]; /* contains record_ids, and position indicates index */ 128*f7e26ffaSEric DeVolder } __attribute__((packed)) ERSTStorageHeader; 129*f7e26ffaSEric DeVolder 130*f7e26ffaSEric DeVolder /* 131*f7e26ffaSEric DeVolder * Object cast macro 132*f7e26ffaSEric DeVolder */ 133*f7e26ffaSEric DeVolder #define ACPIERST(obj) \ 134*f7e26ffaSEric DeVolder OBJECT_CHECK(ERSTDeviceState, (obj), TYPE_ACPI_ERST) 135*f7e26ffaSEric DeVolder 136*f7e26ffaSEric DeVolder /* 137*f7e26ffaSEric DeVolder * Main ERST device state structure 138*f7e26ffaSEric DeVolder */ 139*f7e26ffaSEric DeVolder typedef struct { 140*f7e26ffaSEric DeVolder PCIDevice parent_obj; 141*f7e26ffaSEric DeVolder 142*f7e26ffaSEric DeVolder /* Backend storage */ 143*f7e26ffaSEric DeVolder HostMemoryBackend *hostmem; 144*f7e26ffaSEric DeVolder MemoryRegion *hostmem_mr; 145*f7e26ffaSEric DeVolder uint32_t storage_size; 146*f7e26ffaSEric DeVolder uint32_t default_record_size; 147*f7e26ffaSEric DeVolder 148*f7e26ffaSEric DeVolder /* Programming registers */ 149*f7e26ffaSEric DeVolder MemoryRegion iomem_mr; 150*f7e26ffaSEric DeVolder 151*f7e26ffaSEric DeVolder /* Exchange buffer */ 152*f7e26ffaSEric DeVolder MemoryRegion exchange_mr; 153*f7e26ffaSEric DeVolder 154*f7e26ffaSEric DeVolder /* Interface state */ 155*f7e26ffaSEric DeVolder uint8_t operation; 156*f7e26ffaSEric DeVolder uint8_t busy_status; 157*f7e26ffaSEric DeVolder uint8_t command_status; 158*f7e26ffaSEric DeVolder uint32_t record_offset; 159*f7e26ffaSEric DeVolder uint64_t reg_action; 160*f7e26ffaSEric DeVolder uint64_t reg_value; 161*f7e26ffaSEric DeVolder uint64_t record_identifier; 162*f7e26ffaSEric DeVolder ERSTStorageHeader *header; 163*f7e26ffaSEric DeVolder unsigned first_record_index; 164*f7e26ffaSEric DeVolder unsigned last_record_index; 165*f7e26ffaSEric DeVolder unsigned next_record_index; 166*f7e26ffaSEric DeVolder 167*f7e26ffaSEric DeVolder } ERSTDeviceState; 168*f7e26ffaSEric DeVolder 169*f7e26ffaSEric DeVolder /*******************************************************************/ 170*f7e26ffaSEric DeVolder /*******************************************************************/ 171*f7e26ffaSEric DeVolder static uint8_t *get_nvram_ptr_by_index(ERSTDeviceState *s, unsigned index) 172*f7e26ffaSEric DeVolder { 173*f7e26ffaSEric DeVolder uint8_t *rc = NULL; 174*f7e26ffaSEric DeVolder off_t offset = (index * le32_to_cpu(s->header->record_size)); 175*f7e26ffaSEric DeVolder 176*f7e26ffaSEric DeVolder g_assert(offset < s->storage_size); 177*f7e26ffaSEric DeVolder 178*f7e26ffaSEric DeVolder rc = memory_region_get_ram_ptr(s->hostmem_mr); 179*f7e26ffaSEric DeVolder rc += offset; 180*f7e26ffaSEric DeVolder 181*f7e26ffaSEric DeVolder return rc; 182*f7e26ffaSEric DeVolder } 183*f7e26ffaSEric DeVolder 184*f7e26ffaSEric DeVolder static void make_erst_storage_header(ERSTDeviceState *s) 185*f7e26ffaSEric DeVolder { 186*f7e26ffaSEric DeVolder ERSTStorageHeader *header = s->header; 187*f7e26ffaSEric DeVolder unsigned mapsz, headersz; 188*f7e26ffaSEric DeVolder 189*f7e26ffaSEric DeVolder header->magic = cpu_to_le64(ERST_STORE_MAGIC); 190*f7e26ffaSEric DeVolder header->record_size = cpu_to_le32(s->default_record_size); 191*f7e26ffaSEric DeVolder header->version = cpu_to_le16(0x0100); 192*f7e26ffaSEric DeVolder header->reserved = cpu_to_le16(0x0000); 193*f7e26ffaSEric DeVolder 194*f7e26ffaSEric DeVolder /* Compute mapsize */ 195*f7e26ffaSEric DeVolder mapsz = s->storage_size / s->default_record_size; 196*f7e26ffaSEric DeVolder mapsz *= sizeof(uint64_t); 197*f7e26ffaSEric DeVolder /* Compute header+map size */ 198*f7e26ffaSEric DeVolder headersz = sizeof(ERSTStorageHeader) + mapsz; 199*f7e26ffaSEric DeVolder /* Round up to nearest integer multiple of ERST_RECORD_SIZE */ 200*f7e26ffaSEric DeVolder headersz = QEMU_ALIGN_UP(headersz, s->default_record_size); 201*f7e26ffaSEric DeVolder header->storage_offset = cpu_to_le32(headersz); 202*f7e26ffaSEric DeVolder 203*f7e26ffaSEric DeVolder /* 204*f7e26ffaSEric DeVolder * The HostMemoryBackend initializes contents to zero, 205*f7e26ffaSEric DeVolder * so all record_ids stashed in the map are zero'd. 206*f7e26ffaSEric DeVolder * As well the record_count is zero. Properly initialized. 207*f7e26ffaSEric DeVolder */ 208*f7e26ffaSEric DeVolder } 209*f7e26ffaSEric DeVolder 210*f7e26ffaSEric DeVolder static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) 211*f7e26ffaSEric DeVolder { 212*f7e26ffaSEric DeVolder ERSTStorageHeader *header; 213*f7e26ffaSEric DeVolder uint32_t record_size; 214*f7e26ffaSEric DeVolder 215*f7e26ffaSEric DeVolder header = memory_region_get_ram_ptr(s->hostmem_mr); 216*f7e26ffaSEric DeVolder s->header = header; 217*f7e26ffaSEric DeVolder 218*f7e26ffaSEric DeVolder /* Ensure pointer to header is 64-bit aligned */ 219*f7e26ffaSEric DeVolder g_assert(QEMU_PTR_IS_ALIGNED(header, sizeof(uint64_t))); 220*f7e26ffaSEric DeVolder 221*f7e26ffaSEric DeVolder /* 222*f7e26ffaSEric DeVolder * Check if header is uninitialized; HostMemoryBackend inits to 0 223*f7e26ffaSEric DeVolder */ 224*f7e26ffaSEric DeVolder if (le64_to_cpu(header->magic) == 0UL) { 225*f7e26ffaSEric DeVolder make_erst_storage_header(s); 226*f7e26ffaSEric DeVolder } 227*f7e26ffaSEric DeVolder 228*f7e26ffaSEric DeVolder /* Validity check record_size */ 229*f7e26ffaSEric DeVolder record_size = le32_to_cpu(header->record_size); 230*f7e26ffaSEric DeVolder if (!( 231*f7e26ffaSEric DeVolder (record_size) && /* non zero */ 232*f7e26ffaSEric DeVolder (record_size >= UEFI_CPER_RECORD_MIN_SIZE) && 233*f7e26ffaSEric DeVolder (((record_size - 1) & record_size) == 0) && /* is power of 2 */ 234*f7e26ffaSEric DeVolder (record_size >= 4096) /* PAGE_SIZE */ 235*f7e26ffaSEric DeVolder )) { 236*f7e26ffaSEric DeVolder error_setg(errp, "ERST record_size %u is invalid", record_size); 237*f7e26ffaSEric DeVolder } 238*f7e26ffaSEric DeVolder 239*f7e26ffaSEric DeVolder /* Validity check header */ 240*f7e26ffaSEric DeVolder if (!( 241*f7e26ffaSEric DeVolder (le64_to_cpu(header->magic) == ERST_STORE_MAGIC) && 242*f7e26ffaSEric DeVolder ((le32_to_cpu(header->storage_offset) % record_size) == 0) && 243*f7e26ffaSEric DeVolder (le16_to_cpu(header->version) == 0x0100) && 244*f7e26ffaSEric DeVolder (le16_to_cpu(header->reserved) == 0) 245*f7e26ffaSEric DeVolder )) { 246*f7e26ffaSEric DeVolder error_setg(errp, "ERST backend storage header is invalid"); 247*f7e26ffaSEric DeVolder } 248*f7e26ffaSEric DeVolder 249*f7e26ffaSEric DeVolder /* Check storage_size against record_size */ 250*f7e26ffaSEric DeVolder if (((s->storage_size % record_size) != 0) || 251*f7e26ffaSEric DeVolder (record_size > s->storage_size)) { 252*f7e26ffaSEric DeVolder error_setg(errp, "ACPI ERST requires storage size be multiple of " 253*f7e26ffaSEric DeVolder "record size (%uKiB)", record_size); 254*f7e26ffaSEric DeVolder } 255*f7e26ffaSEric DeVolder 256*f7e26ffaSEric DeVolder /* Compute offset of first and last record storage slot */ 257*f7e26ffaSEric DeVolder s->first_record_index = le32_to_cpu(header->storage_offset) 258*f7e26ffaSEric DeVolder / record_size; 259*f7e26ffaSEric DeVolder s->last_record_index = (s->storage_size / record_size); 260*f7e26ffaSEric DeVolder } 261*f7e26ffaSEric DeVolder 262*f7e26ffaSEric DeVolder static void update_map_entry(ERSTDeviceState *s, unsigned index, 263*f7e26ffaSEric DeVolder uint64_t record_id) 264*f7e26ffaSEric DeVolder { 265*f7e26ffaSEric DeVolder if (index < s->last_record_index) { 266*f7e26ffaSEric DeVolder s->header->map[index] = cpu_to_le64(record_id); 267*f7e26ffaSEric DeVolder } 268*f7e26ffaSEric DeVolder } 269*f7e26ffaSEric DeVolder 270*f7e26ffaSEric DeVolder static unsigned find_next_empty_record_index(ERSTDeviceState *s) 271*f7e26ffaSEric DeVolder { 272*f7e26ffaSEric DeVolder unsigned rc = 0; /* 0 not a valid index */ 273*f7e26ffaSEric DeVolder unsigned index = s->first_record_index; 274*f7e26ffaSEric DeVolder 275*f7e26ffaSEric DeVolder for (; index < s->last_record_index; ++index) { 276*f7e26ffaSEric DeVolder if (le64_to_cpu(s->header->map[index]) == ERST_UNSPECIFIED_RECORD_ID) { 277*f7e26ffaSEric DeVolder rc = index; 278*f7e26ffaSEric DeVolder break; 279*f7e26ffaSEric DeVolder } 280*f7e26ffaSEric DeVolder } 281*f7e26ffaSEric DeVolder 282*f7e26ffaSEric DeVolder return rc; 283*f7e26ffaSEric DeVolder } 284*f7e26ffaSEric DeVolder 285*f7e26ffaSEric DeVolder static unsigned lookup_erst_record(ERSTDeviceState *s, 286*f7e26ffaSEric DeVolder uint64_t record_identifier) 287*f7e26ffaSEric DeVolder { 288*f7e26ffaSEric DeVolder unsigned rc = 0; /* 0 not a valid index */ 289*f7e26ffaSEric DeVolder 290*f7e26ffaSEric DeVolder /* Find the record_identifier in the map */ 291*f7e26ffaSEric DeVolder if (record_identifier != ERST_UNSPECIFIED_RECORD_ID) { 292*f7e26ffaSEric DeVolder /* 293*f7e26ffaSEric DeVolder * Count number of valid records encountered, and 294*f7e26ffaSEric DeVolder * short-circuit the loop if identifier not found 295*f7e26ffaSEric DeVolder */ 296*f7e26ffaSEric DeVolder uint32_t record_count = le32_to_cpu(s->header->record_count); 297*f7e26ffaSEric DeVolder unsigned count = 0; 298*f7e26ffaSEric DeVolder unsigned index; 299*f7e26ffaSEric DeVolder for (index = s->first_record_index; index < s->last_record_index && 300*f7e26ffaSEric DeVolder count < record_count; ++index) { 301*f7e26ffaSEric DeVolder if (le64_to_cpu(s->header->map[index]) == record_identifier) { 302*f7e26ffaSEric DeVolder rc = index; 303*f7e26ffaSEric DeVolder break; 304*f7e26ffaSEric DeVolder } 305*f7e26ffaSEric DeVolder if (le64_to_cpu(s->header->map[index]) != 306*f7e26ffaSEric DeVolder ERST_UNSPECIFIED_RECORD_ID) { 307*f7e26ffaSEric DeVolder ++count; 308*f7e26ffaSEric DeVolder } 309*f7e26ffaSEric DeVolder } 310*f7e26ffaSEric DeVolder } 311*f7e26ffaSEric DeVolder 312*f7e26ffaSEric DeVolder return rc; 313*f7e26ffaSEric DeVolder } 314*f7e26ffaSEric DeVolder 315*f7e26ffaSEric DeVolder /* 316*f7e26ffaSEric DeVolder * ACPI 4.0: 17.4.1.1 Serialization Actions, also see 317*f7e26ffaSEric DeVolder * ACPI 4.0: 17.4.2.2 Operations - Reading 6.c and 2.c 318*f7e26ffaSEric DeVolder */ 319*f7e26ffaSEric DeVolder static unsigned get_next_record_identifier(ERSTDeviceState *s, 320*f7e26ffaSEric DeVolder uint64_t *record_identifier, bool first) 321*f7e26ffaSEric DeVolder { 322*f7e26ffaSEric DeVolder unsigned found = 0; 323*f7e26ffaSEric DeVolder unsigned index; 324*f7e26ffaSEric DeVolder 325*f7e26ffaSEric DeVolder /* For operations needing to return 'first' record identifier */ 326*f7e26ffaSEric DeVolder if (first) { 327*f7e26ffaSEric DeVolder /* Reset initial index to beginning */ 328*f7e26ffaSEric DeVolder s->next_record_index = s->first_record_index; 329*f7e26ffaSEric DeVolder } 330*f7e26ffaSEric DeVolder index = s->next_record_index; 331*f7e26ffaSEric DeVolder 332*f7e26ffaSEric DeVolder *record_identifier = ERST_EMPTY_END_RECORD_ID; 333*f7e26ffaSEric DeVolder 334*f7e26ffaSEric DeVolder if (le32_to_cpu(s->header->record_count)) { 335*f7e26ffaSEric DeVolder for (; index < s->last_record_index; ++index) { 336*f7e26ffaSEric DeVolder if (le64_to_cpu(s->header->map[index]) != 337*f7e26ffaSEric DeVolder ERST_UNSPECIFIED_RECORD_ID) { 338*f7e26ffaSEric DeVolder /* where to start next time */ 339*f7e26ffaSEric DeVolder s->next_record_index = index + 1; 340*f7e26ffaSEric DeVolder *record_identifier = le64_to_cpu(s->header->map[index]); 341*f7e26ffaSEric DeVolder found = 1; 342*f7e26ffaSEric DeVolder break; 343*f7e26ffaSEric DeVolder } 344*f7e26ffaSEric DeVolder } 345*f7e26ffaSEric DeVolder } 346*f7e26ffaSEric DeVolder if (!found) { 347*f7e26ffaSEric DeVolder /* at end (ie scan complete), reset */ 348*f7e26ffaSEric DeVolder s->next_record_index = s->first_record_index; 349*f7e26ffaSEric DeVolder } 350*f7e26ffaSEric DeVolder 351*f7e26ffaSEric DeVolder return STATUS_SUCCESS; 352*f7e26ffaSEric DeVolder } 353*f7e26ffaSEric DeVolder 354*f7e26ffaSEric DeVolder /* ACPI 4.0: 17.4.2.3 Operations - Clearing */ 355*f7e26ffaSEric DeVolder static unsigned clear_erst_record(ERSTDeviceState *s) 356*f7e26ffaSEric DeVolder { 357*f7e26ffaSEric DeVolder unsigned rc = STATUS_RECORD_NOT_FOUND; 358*f7e26ffaSEric DeVolder unsigned index; 359*f7e26ffaSEric DeVolder 360*f7e26ffaSEric DeVolder /* Check for valid record identifier */ 361*f7e26ffaSEric DeVolder if (!ERST_IS_VALID_RECORD_ID(s->record_identifier)) { 362*f7e26ffaSEric DeVolder return STATUS_FAILED; 363*f7e26ffaSEric DeVolder } 364*f7e26ffaSEric DeVolder 365*f7e26ffaSEric DeVolder index = lookup_erst_record(s, s->record_identifier); 366*f7e26ffaSEric DeVolder if (index) { 367*f7e26ffaSEric DeVolder /* No need to wipe record, just invalidate its map entry */ 368*f7e26ffaSEric DeVolder uint32_t record_count; 369*f7e26ffaSEric DeVolder update_map_entry(s, index, ERST_UNSPECIFIED_RECORD_ID); 370*f7e26ffaSEric DeVolder record_count = le32_to_cpu(s->header->record_count); 371*f7e26ffaSEric DeVolder record_count -= 1; 372*f7e26ffaSEric DeVolder s->header->record_count = cpu_to_le32(record_count); 373*f7e26ffaSEric DeVolder rc = STATUS_SUCCESS; 374*f7e26ffaSEric DeVolder } 375*f7e26ffaSEric DeVolder 376*f7e26ffaSEric DeVolder return rc; 377*f7e26ffaSEric DeVolder } 378*f7e26ffaSEric DeVolder 379*f7e26ffaSEric DeVolder /* ACPI 4.0: 17.4.2.2 Operations - Reading */ 380*f7e26ffaSEric DeVolder static unsigned read_erst_record(ERSTDeviceState *s) 381*f7e26ffaSEric DeVolder { 382*f7e26ffaSEric DeVolder unsigned rc = STATUS_RECORD_NOT_FOUND; 383*f7e26ffaSEric DeVolder unsigned exchange_length; 384*f7e26ffaSEric DeVolder unsigned index; 385*f7e26ffaSEric DeVolder 386*f7e26ffaSEric DeVolder /* Check if backend storage is empty */ 387*f7e26ffaSEric DeVolder if (le32_to_cpu(s->header->record_count) == 0) { 388*f7e26ffaSEric DeVolder return STATUS_RECORD_STORE_EMPTY; 389*f7e26ffaSEric DeVolder } 390*f7e26ffaSEric DeVolder 391*f7e26ffaSEric DeVolder exchange_length = memory_region_size(&s->exchange_mr); 392*f7e26ffaSEric DeVolder 393*f7e26ffaSEric DeVolder /* Check for record identifier of all 0s */ 394*f7e26ffaSEric DeVolder if (s->record_identifier == ERST_UNSPECIFIED_RECORD_ID) { 395*f7e26ffaSEric DeVolder /* Set to 'first' record in storage */ 396*f7e26ffaSEric DeVolder get_next_record_identifier(s, &s->record_identifier, true); 397*f7e26ffaSEric DeVolder /* record_identifier is now a valid id, or all 1s */ 398*f7e26ffaSEric DeVolder } 399*f7e26ffaSEric DeVolder 400*f7e26ffaSEric DeVolder /* Check for record identifier of all 1s */ 401*f7e26ffaSEric DeVolder if (s->record_identifier == ERST_EMPTY_END_RECORD_ID) { 402*f7e26ffaSEric DeVolder return STATUS_FAILED; 403*f7e26ffaSEric DeVolder } 404*f7e26ffaSEric DeVolder 405*f7e26ffaSEric DeVolder /* Validate record_offset */ 406*f7e26ffaSEric DeVolder if (s->record_offset > (exchange_length - UEFI_CPER_RECORD_MIN_SIZE)) { 407*f7e26ffaSEric DeVolder return STATUS_FAILED; 408*f7e26ffaSEric DeVolder } 409*f7e26ffaSEric DeVolder 410*f7e26ffaSEric DeVolder index = lookup_erst_record(s, s->record_identifier); 411*f7e26ffaSEric DeVolder if (index) { 412*f7e26ffaSEric DeVolder uint8_t *nvram; 413*f7e26ffaSEric DeVolder uint8_t *exchange; 414*f7e26ffaSEric DeVolder uint32_t record_length; 415*f7e26ffaSEric DeVolder 416*f7e26ffaSEric DeVolder /* Obtain pointer to the exchange buffer */ 417*f7e26ffaSEric DeVolder exchange = memory_region_get_ram_ptr(&s->exchange_mr); 418*f7e26ffaSEric DeVolder exchange += s->record_offset; 419*f7e26ffaSEric DeVolder /* Obtain pointer to slot in storage */ 420*f7e26ffaSEric DeVolder nvram = get_nvram_ptr_by_index(s, index); 421*f7e26ffaSEric DeVolder /* Validate CPER record_length */ 422*f7e26ffaSEric DeVolder memcpy((uint8_t *)&record_length, 423*f7e26ffaSEric DeVolder &nvram[UEFI_CPER_RECORD_LENGTH_OFFSET], 424*f7e26ffaSEric DeVolder sizeof(uint32_t)); 425*f7e26ffaSEric DeVolder record_length = le32_to_cpu(record_length); 426*f7e26ffaSEric DeVolder if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { 427*f7e26ffaSEric DeVolder rc = STATUS_FAILED; 428*f7e26ffaSEric DeVolder } 429*f7e26ffaSEric DeVolder if ((s->record_offset + record_length) > exchange_length) { 430*f7e26ffaSEric DeVolder rc = STATUS_FAILED; 431*f7e26ffaSEric DeVolder } 432*f7e26ffaSEric DeVolder /* If all is ok, copy the record to the exchange buffer */ 433*f7e26ffaSEric DeVolder if (rc != STATUS_FAILED) { 434*f7e26ffaSEric DeVolder memcpy(exchange, nvram, record_length); 435*f7e26ffaSEric DeVolder rc = STATUS_SUCCESS; 436*f7e26ffaSEric DeVolder } 437*f7e26ffaSEric DeVolder } else { 438*f7e26ffaSEric DeVolder /* 439*f7e26ffaSEric DeVolder * See "Reading : 'The steps performed by the platform ...' 2.c" 440*f7e26ffaSEric DeVolder * Set to 'first' record in storage 441*f7e26ffaSEric DeVolder */ 442*f7e26ffaSEric DeVolder get_next_record_identifier(s, &s->record_identifier, true); 443*f7e26ffaSEric DeVolder } 444*f7e26ffaSEric DeVolder 445*f7e26ffaSEric DeVolder return rc; 446*f7e26ffaSEric DeVolder } 447*f7e26ffaSEric DeVolder 448*f7e26ffaSEric DeVolder /* ACPI 4.0: 17.4.2.1 Operations - Writing */ 449*f7e26ffaSEric DeVolder static unsigned write_erst_record(ERSTDeviceState *s) 450*f7e26ffaSEric DeVolder { 451*f7e26ffaSEric DeVolder unsigned rc = STATUS_FAILED; 452*f7e26ffaSEric DeVolder unsigned exchange_length; 453*f7e26ffaSEric DeVolder unsigned index; 454*f7e26ffaSEric DeVolder uint64_t record_identifier; 455*f7e26ffaSEric DeVolder uint32_t record_length; 456*f7e26ffaSEric DeVolder uint8_t *exchange; 457*f7e26ffaSEric DeVolder uint8_t *nvram = NULL; 458*f7e26ffaSEric DeVolder bool record_found = false; 459*f7e26ffaSEric DeVolder 460*f7e26ffaSEric DeVolder exchange_length = memory_region_size(&s->exchange_mr); 461*f7e26ffaSEric DeVolder 462*f7e26ffaSEric DeVolder /* Validate record_offset */ 463*f7e26ffaSEric DeVolder if (s->record_offset > (exchange_length - UEFI_CPER_RECORD_MIN_SIZE)) { 464*f7e26ffaSEric DeVolder return STATUS_FAILED; 465*f7e26ffaSEric DeVolder } 466*f7e26ffaSEric DeVolder 467*f7e26ffaSEric DeVolder /* Obtain pointer to record in the exchange buffer */ 468*f7e26ffaSEric DeVolder exchange = memory_region_get_ram_ptr(&s->exchange_mr); 469*f7e26ffaSEric DeVolder exchange += s->record_offset; 470*f7e26ffaSEric DeVolder 471*f7e26ffaSEric DeVolder /* Validate CPER record_length */ 472*f7e26ffaSEric DeVolder memcpy((uint8_t *)&record_length, &exchange[UEFI_CPER_RECORD_LENGTH_OFFSET], 473*f7e26ffaSEric DeVolder sizeof(uint32_t)); 474*f7e26ffaSEric DeVolder record_length = le32_to_cpu(record_length); 475*f7e26ffaSEric DeVolder if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { 476*f7e26ffaSEric DeVolder return STATUS_FAILED; 477*f7e26ffaSEric DeVolder } 478*f7e26ffaSEric DeVolder if ((s->record_offset + record_length) > exchange_length) { 479*f7e26ffaSEric DeVolder return STATUS_FAILED; 480*f7e26ffaSEric DeVolder } 481*f7e26ffaSEric DeVolder 482*f7e26ffaSEric DeVolder /* Extract record identifier */ 483*f7e26ffaSEric DeVolder memcpy((uint8_t *)&record_identifier, &exchange[UEFI_CPER_RECORD_ID_OFFSET], 484*f7e26ffaSEric DeVolder sizeof(uint64_t)); 485*f7e26ffaSEric DeVolder record_identifier = le64_to_cpu(record_identifier); 486*f7e26ffaSEric DeVolder 487*f7e26ffaSEric DeVolder /* Check for valid record identifier */ 488*f7e26ffaSEric DeVolder if (!ERST_IS_VALID_RECORD_ID(record_identifier)) { 489*f7e26ffaSEric DeVolder return STATUS_FAILED; 490*f7e26ffaSEric DeVolder } 491*f7e26ffaSEric DeVolder 492*f7e26ffaSEric DeVolder index = lookup_erst_record(s, record_identifier); 493*f7e26ffaSEric DeVolder if (index) { 494*f7e26ffaSEric DeVolder /* Record found, overwrite existing record */ 495*f7e26ffaSEric DeVolder nvram = get_nvram_ptr_by_index(s, index); 496*f7e26ffaSEric DeVolder record_found = true; 497*f7e26ffaSEric DeVolder } else { 498*f7e26ffaSEric DeVolder /* Record not found, not an overwrite, allocate for write */ 499*f7e26ffaSEric DeVolder index = find_next_empty_record_index(s); 500*f7e26ffaSEric DeVolder if (index) { 501*f7e26ffaSEric DeVolder nvram = get_nvram_ptr_by_index(s, index); 502*f7e26ffaSEric DeVolder } else { 503*f7e26ffaSEric DeVolder /* All slots are occupied */ 504*f7e26ffaSEric DeVolder rc = STATUS_NOT_ENOUGH_SPACE; 505*f7e26ffaSEric DeVolder } 506*f7e26ffaSEric DeVolder } 507*f7e26ffaSEric DeVolder if (nvram) { 508*f7e26ffaSEric DeVolder /* Write the record into the slot */ 509*f7e26ffaSEric DeVolder memcpy(nvram, exchange, record_length); 510*f7e26ffaSEric DeVolder memset(nvram + record_length, exchange_length - record_length, 0xFF); 511*f7e26ffaSEric DeVolder /* If a new record, increment the record_count */ 512*f7e26ffaSEric DeVolder if (!record_found) { 513*f7e26ffaSEric DeVolder uint32_t record_count; 514*f7e26ffaSEric DeVolder record_count = le32_to_cpu(s->header->record_count); 515*f7e26ffaSEric DeVolder record_count += 1; /* writing new record */ 516*f7e26ffaSEric DeVolder s->header->record_count = cpu_to_le32(record_count); 517*f7e26ffaSEric DeVolder } 518*f7e26ffaSEric DeVolder update_map_entry(s, index, record_identifier); 519*f7e26ffaSEric DeVolder rc = STATUS_SUCCESS; 520*f7e26ffaSEric DeVolder } 521*f7e26ffaSEric DeVolder 522*f7e26ffaSEric DeVolder return rc; 523*f7e26ffaSEric DeVolder } 524*f7e26ffaSEric DeVolder 525*f7e26ffaSEric DeVolder /*******************************************************************/ 526*f7e26ffaSEric DeVolder 527*f7e26ffaSEric DeVolder static uint64_t erst_rd_reg64(hwaddr addr, 528*f7e26ffaSEric DeVolder uint64_t reg, unsigned size) 529*f7e26ffaSEric DeVolder { 530*f7e26ffaSEric DeVolder uint64_t rdval; 531*f7e26ffaSEric DeVolder uint64_t mask; 532*f7e26ffaSEric DeVolder unsigned shift; 533*f7e26ffaSEric DeVolder 534*f7e26ffaSEric DeVolder if (size == sizeof(uint64_t)) { 535*f7e26ffaSEric DeVolder /* 64b access */ 536*f7e26ffaSEric DeVolder mask = 0xFFFFFFFFFFFFFFFFUL; 537*f7e26ffaSEric DeVolder shift = 0; 538*f7e26ffaSEric DeVolder } else { 539*f7e26ffaSEric DeVolder /* 32b access */ 540*f7e26ffaSEric DeVolder mask = 0x00000000FFFFFFFFUL; 541*f7e26ffaSEric DeVolder shift = ((addr & 0x4) == 0x4) ? 32 : 0; 542*f7e26ffaSEric DeVolder } 543*f7e26ffaSEric DeVolder 544*f7e26ffaSEric DeVolder rdval = reg; 545*f7e26ffaSEric DeVolder rdval >>= shift; 546*f7e26ffaSEric DeVolder rdval &= mask; 547*f7e26ffaSEric DeVolder 548*f7e26ffaSEric DeVolder return rdval; 549*f7e26ffaSEric DeVolder } 550*f7e26ffaSEric DeVolder 551*f7e26ffaSEric DeVolder static uint64_t erst_wr_reg64(hwaddr addr, 552*f7e26ffaSEric DeVolder uint64_t reg, uint64_t val, unsigned size) 553*f7e26ffaSEric DeVolder { 554*f7e26ffaSEric DeVolder uint64_t wrval; 555*f7e26ffaSEric DeVolder uint64_t mask; 556*f7e26ffaSEric DeVolder unsigned shift; 557*f7e26ffaSEric DeVolder 558*f7e26ffaSEric DeVolder if (size == sizeof(uint64_t)) { 559*f7e26ffaSEric DeVolder /* 64b access */ 560*f7e26ffaSEric DeVolder mask = 0xFFFFFFFFFFFFFFFFUL; 561*f7e26ffaSEric DeVolder shift = 0; 562*f7e26ffaSEric DeVolder } else { 563*f7e26ffaSEric DeVolder /* 32b access */ 564*f7e26ffaSEric DeVolder mask = 0x00000000FFFFFFFFUL; 565*f7e26ffaSEric DeVolder shift = ((addr & 0x4) == 0x4) ? 32 : 0; 566*f7e26ffaSEric DeVolder } 567*f7e26ffaSEric DeVolder 568*f7e26ffaSEric DeVolder val &= mask; 569*f7e26ffaSEric DeVolder val <<= shift; 570*f7e26ffaSEric DeVolder mask <<= shift; 571*f7e26ffaSEric DeVolder wrval = reg; 572*f7e26ffaSEric DeVolder wrval &= ~mask; 573*f7e26ffaSEric DeVolder wrval |= val; 574*f7e26ffaSEric DeVolder 575*f7e26ffaSEric DeVolder return wrval; 576*f7e26ffaSEric DeVolder } 577*f7e26ffaSEric DeVolder 578*f7e26ffaSEric DeVolder static void erst_reg_write(void *opaque, hwaddr addr, 579*f7e26ffaSEric DeVolder uint64_t val, unsigned size) 580*f7e26ffaSEric DeVolder { 581*f7e26ffaSEric DeVolder ERSTDeviceState *s = (ERSTDeviceState *)opaque; 582*f7e26ffaSEric DeVolder 583*f7e26ffaSEric DeVolder /* 584*f7e26ffaSEric DeVolder * NOTE: All actions/operations/side effects happen on the WRITE, 585*f7e26ffaSEric DeVolder * by this implementation's design. The READs simply return the 586*f7e26ffaSEric DeVolder * reg_value contents. 587*f7e26ffaSEric DeVolder */ 588*f7e26ffaSEric DeVolder trace_acpi_erst_reg_write(addr, val, size); 589*f7e26ffaSEric DeVolder 590*f7e26ffaSEric DeVolder switch (addr) { 591*f7e26ffaSEric DeVolder case ERST_VALUE_OFFSET + 0: 592*f7e26ffaSEric DeVolder case ERST_VALUE_OFFSET + 4: 593*f7e26ffaSEric DeVolder s->reg_value = erst_wr_reg64(addr, s->reg_value, val, size); 594*f7e26ffaSEric DeVolder break; 595*f7e26ffaSEric DeVolder case ERST_ACTION_OFFSET + 0: 596*f7e26ffaSEric DeVolder /* 597*f7e26ffaSEric DeVolder * NOTE: all valid values written to this register are of the 598*f7e26ffaSEric DeVolder * ACTION_* variety. Thus there is no need to make this a 64-bit 599*f7e26ffaSEric DeVolder * register, 32-bits is appropriate. As such ERST_ACTION_OFFSET+4 600*f7e26ffaSEric DeVolder * is not needed. 601*f7e26ffaSEric DeVolder */ 602*f7e26ffaSEric DeVolder switch (val) { 603*f7e26ffaSEric DeVolder case ACTION_BEGIN_WRITE_OPERATION: 604*f7e26ffaSEric DeVolder case ACTION_BEGIN_READ_OPERATION: 605*f7e26ffaSEric DeVolder case ACTION_BEGIN_CLEAR_OPERATION: 606*f7e26ffaSEric DeVolder case ACTION_BEGIN_DUMMY_WRITE_OPERATION: 607*f7e26ffaSEric DeVolder case ACTION_END_OPERATION: 608*f7e26ffaSEric DeVolder s->operation = val; 609*f7e26ffaSEric DeVolder break; 610*f7e26ffaSEric DeVolder case ACTION_SET_RECORD_OFFSET: 611*f7e26ffaSEric DeVolder s->record_offset = s->reg_value; 612*f7e26ffaSEric DeVolder break; 613*f7e26ffaSEric DeVolder case ACTION_EXECUTE_OPERATION: 614*f7e26ffaSEric DeVolder if ((uint8_t)s->reg_value == ERST_EXECUTE_OPERATION_MAGIC) { 615*f7e26ffaSEric DeVolder s->busy_status = 1; 616*f7e26ffaSEric DeVolder switch (s->operation) { 617*f7e26ffaSEric DeVolder case ACTION_BEGIN_WRITE_OPERATION: 618*f7e26ffaSEric DeVolder s->command_status = write_erst_record(s); 619*f7e26ffaSEric DeVolder break; 620*f7e26ffaSEric DeVolder case ACTION_BEGIN_READ_OPERATION: 621*f7e26ffaSEric DeVolder s->command_status = read_erst_record(s); 622*f7e26ffaSEric DeVolder break; 623*f7e26ffaSEric DeVolder case ACTION_BEGIN_CLEAR_OPERATION: 624*f7e26ffaSEric DeVolder s->command_status = clear_erst_record(s); 625*f7e26ffaSEric DeVolder break; 626*f7e26ffaSEric DeVolder case ACTION_BEGIN_DUMMY_WRITE_OPERATION: 627*f7e26ffaSEric DeVolder s->command_status = STATUS_SUCCESS; 628*f7e26ffaSEric DeVolder break; 629*f7e26ffaSEric DeVolder case ACTION_END_OPERATION: 630*f7e26ffaSEric DeVolder s->command_status = STATUS_SUCCESS; 631*f7e26ffaSEric DeVolder break; 632*f7e26ffaSEric DeVolder default: 633*f7e26ffaSEric DeVolder s->command_status = STATUS_FAILED; 634*f7e26ffaSEric DeVolder break; 635*f7e26ffaSEric DeVolder } 636*f7e26ffaSEric DeVolder s->busy_status = 0; 637*f7e26ffaSEric DeVolder } 638*f7e26ffaSEric DeVolder break; 639*f7e26ffaSEric DeVolder case ACTION_CHECK_BUSY_STATUS: 640*f7e26ffaSEric DeVolder s->reg_value = s->busy_status; 641*f7e26ffaSEric DeVolder break; 642*f7e26ffaSEric DeVolder case ACTION_GET_COMMAND_STATUS: 643*f7e26ffaSEric DeVolder s->reg_value = s->command_status; 644*f7e26ffaSEric DeVolder break; 645*f7e26ffaSEric DeVolder case ACTION_GET_RECORD_IDENTIFIER: 646*f7e26ffaSEric DeVolder s->command_status = get_next_record_identifier(s, 647*f7e26ffaSEric DeVolder &s->reg_value, false); 648*f7e26ffaSEric DeVolder break; 649*f7e26ffaSEric DeVolder case ACTION_SET_RECORD_IDENTIFIER: 650*f7e26ffaSEric DeVolder s->record_identifier = s->reg_value; 651*f7e26ffaSEric DeVolder break; 652*f7e26ffaSEric DeVolder case ACTION_GET_RECORD_COUNT: 653*f7e26ffaSEric DeVolder s->reg_value = le32_to_cpu(s->header->record_count); 654*f7e26ffaSEric DeVolder break; 655*f7e26ffaSEric DeVolder case ACTION_GET_ERROR_LOG_ADDRESS_RANGE: 656*f7e26ffaSEric DeVolder s->reg_value = (hwaddr)pci_get_bar_addr(PCI_DEVICE(s), 1); 657*f7e26ffaSEric DeVolder break; 658*f7e26ffaSEric DeVolder case ACTION_GET_ERROR_LOG_ADDRESS_LENGTH: 659*f7e26ffaSEric DeVolder s->reg_value = le32_to_cpu(s->header->record_size); 660*f7e26ffaSEric DeVolder break; 661*f7e26ffaSEric DeVolder case ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES: 662*f7e26ffaSEric DeVolder s->reg_value = 0x0; /* intentional, not NVRAM mode */ 663*f7e26ffaSEric DeVolder break; 664*f7e26ffaSEric DeVolder case ACTION_GET_EXECUTE_OPERATION_TIMINGS: 665*f7e26ffaSEric DeVolder s->reg_value = 666*f7e26ffaSEric DeVolder (100ULL << 32) | /* 100us max time */ 667*f7e26ffaSEric DeVolder (10ULL << 0) ; /* 10us min time */ 668*f7e26ffaSEric DeVolder break; 669*f7e26ffaSEric DeVolder default: 670*f7e26ffaSEric DeVolder /* Unknown action/command, NOP */ 671*f7e26ffaSEric DeVolder break; 672*f7e26ffaSEric DeVolder } 673*f7e26ffaSEric DeVolder break; 674*f7e26ffaSEric DeVolder default: 675*f7e26ffaSEric DeVolder /* This should not happen, but if it does, NOP */ 676*f7e26ffaSEric DeVolder break; 677*f7e26ffaSEric DeVolder } 678*f7e26ffaSEric DeVolder } 679*f7e26ffaSEric DeVolder 680*f7e26ffaSEric DeVolder static uint64_t erst_reg_read(void *opaque, hwaddr addr, 681*f7e26ffaSEric DeVolder unsigned size) 682*f7e26ffaSEric DeVolder { 683*f7e26ffaSEric DeVolder ERSTDeviceState *s = (ERSTDeviceState *)opaque; 684*f7e26ffaSEric DeVolder uint64_t val = 0; 685*f7e26ffaSEric DeVolder 686*f7e26ffaSEric DeVolder switch (addr) { 687*f7e26ffaSEric DeVolder case ERST_ACTION_OFFSET + 0: 688*f7e26ffaSEric DeVolder case ERST_ACTION_OFFSET + 4: 689*f7e26ffaSEric DeVolder val = erst_rd_reg64(addr, s->reg_action, size); 690*f7e26ffaSEric DeVolder break; 691*f7e26ffaSEric DeVolder case ERST_VALUE_OFFSET + 0: 692*f7e26ffaSEric DeVolder case ERST_VALUE_OFFSET + 4: 693*f7e26ffaSEric DeVolder val = erst_rd_reg64(addr, s->reg_value, size); 694*f7e26ffaSEric DeVolder break; 695*f7e26ffaSEric DeVolder default: 696*f7e26ffaSEric DeVolder break; 697*f7e26ffaSEric DeVolder } 698*f7e26ffaSEric DeVolder trace_acpi_erst_reg_read(addr, val, size); 699*f7e26ffaSEric DeVolder return val; 700*f7e26ffaSEric DeVolder } 701*f7e26ffaSEric DeVolder 702*f7e26ffaSEric DeVolder static const MemoryRegionOps erst_reg_ops = { 703*f7e26ffaSEric DeVolder .read = erst_reg_read, 704*f7e26ffaSEric DeVolder .write = erst_reg_write, 705*f7e26ffaSEric DeVolder .endianness = DEVICE_NATIVE_ENDIAN, 706*f7e26ffaSEric DeVolder }; 707*f7e26ffaSEric DeVolder 708*f7e26ffaSEric DeVolder /*******************************************************************/ 709*f7e26ffaSEric DeVolder /*******************************************************************/ 710*f7e26ffaSEric DeVolder static int erst_post_load(void *opaque, int version_id) 711*f7e26ffaSEric DeVolder { 712*f7e26ffaSEric DeVolder ERSTDeviceState *s = opaque; 713*f7e26ffaSEric DeVolder 714*f7e26ffaSEric DeVolder /* Recompute pointer to header */ 715*f7e26ffaSEric DeVolder s->header = (ERSTStorageHeader *)get_nvram_ptr_by_index(s, 0); 716*f7e26ffaSEric DeVolder trace_acpi_erst_post_load(s->header, le32_to_cpu(s->header->record_size)); 717*f7e26ffaSEric DeVolder 718*f7e26ffaSEric DeVolder return 0; 719*f7e26ffaSEric DeVolder } 720*f7e26ffaSEric DeVolder 721*f7e26ffaSEric DeVolder static const VMStateDescription erst_vmstate = { 722*f7e26ffaSEric DeVolder .name = "acpi-erst", 723*f7e26ffaSEric DeVolder .version_id = 1, 724*f7e26ffaSEric DeVolder .minimum_version_id = 1, 725*f7e26ffaSEric DeVolder .post_load = erst_post_load, 726*f7e26ffaSEric DeVolder .fields = (VMStateField[]) { 727*f7e26ffaSEric DeVolder VMSTATE_UINT8(operation, ERSTDeviceState), 728*f7e26ffaSEric DeVolder VMSTATE_UINT8(busy_status, ERSTDeviceState), 729*f7e26ffaSEric DeVolder VMSTATE_UINT8(command_status, ERSTDeviceState), 730*f7e26ffaSEric DeVolder VMSTATE_UINT32(record_offset, ERSTDeviceState), 731*f7e26ffaSEric DeVolder VMSTATE_UINT64(reg_action, ERSTDeviceState), 732*f7e26ffaSEric DeVolder VMSTATE_UINT64(reg_value, ERSTDeviceState), 733*f7e26ffaSEric DeVolder VMSTATE_UINT64(record_identifier, ERSTDeviceState), 734*f7e26ffaSEric DeVolder VMSTATE_UINT32(next_record_index, ERSTDeviceState), 735*f7e26ffaSEric DeVolder VMSTATE_END_OF_LIST() 736*f7e26ffaSEric DeVolder } 737*f7e26ffaSEric DeVolder }; 738*f7e26ffaSEric DeVolder 739*f7e26ffaSEric DeVolder static void erst_realizefn(PCIDevice *pci_dev, Error **errp) 740*f7e26ffaSEric DeVolder { 741*f7e26ffaSEric DeVolder ERSTDeviceState *s = ACPIERST(pci_dev); 742*f7e26ffaSEric DeVolder 743*f7e26ffaSEric DeVolder trace_acpi_erst_realizefn_in(); 744*f7e26ffaSEric DeVolder 745*f7e26ffaSEric DeVolder if (!s->hostmem) { 746*f7e26ffaSEric DeVolder error_setg(errp, "'" ACPI_ERST_MEMDEV_PROP "' property is not set"); 747*f7e26ffaSEric DeVolder return; 748*f7e26ffaSEric DeVolder } else if (host_memory_backend_is_mapped(s->hostmem)) { 749*f7e26ffaSEric DeVolder error_setg(errp, "can't use already busy memdev: %s", 750*f7e26ffaSEric DeVolder object_get_canonical_path_component(OBJECT(s->hostmem))); 751*f7e26ffaSEric DeVolder return; 752*f7e26ffaSEric DeVolder } 753*f7e26ffaSEric DeVolder 754*f7e26ffaSEric DeVolder s->hostmem_mr = host_memory_backend_get_memory(s->hostmem); 755*f7e26ffaSEric DeVolder 756*f7e26ffaSEric DeVolder /* HostMemoryBackend size will be multiple of PAGE_SIZE */ 757*f7e26ffaSEric DeVolder s->storage_size = object_property_get_int(OBJECT(s->hostmem), "size", errp); 758*f7e26ffaSEric DeVolder 759*f7e26ffaSEric DeVolder /* Initialize backend storage and record_count */ 760*f7e26ffaSEric DeVolder check_erst_backend_storage(s, errp); 761*f7e26ffaSEric DeVolder 762*f7e26ffaSEric DeVolder /* BAR 0: Programming registers */ 763*f7e26ffaSEric DeVolder memory_region_init_io(&s->iomem_mr, OBJECT(pci_dev), &erst_reg_ops, s, 764*f7e26ffaSEric DeVolder TYPE_ACPI_ERST, ERST_REG_SIZE); 765*f7e26ffaSEric DeVolder pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem_mr); 766*f7e26ffaSEric DeVolder 767*f7e26ffaSEric DeVolder /* BAR 1: Exchange buffer memory */ 768*f7e26ffaSEric DeVolder memory_region_init_ram(&s->exchange_mr, OBJECT(pci_dev), 769*f7e26ffaSEric DeVolder "erst.exchange", 770*f7e26ffaSEric DeVolder le32_to_cpu(s->header->record_size), errp); 771*f7e26ffaSEric DeVolder pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, 772*f7e26ffaSEric DeVolder &s->exchange_mr); 773*f7e26ffaSEric DeVolder 774*f7e26ffaSEric DeVolder /* Include the backend storage in the migration stream */ 775*f7e26ffaSEric DeVolder vmstate_register_ram_global(s->hostmem_mr); 776*f7e26ffaSEric DeVolder 777*f7e26ffaSEric DeVolder trace_acpi_erst_realizefn_out(s->storage_size); 778*f7e26ffaSEric DeVolder } 779*f7e26ffaSEric DeVolder 780*f7e26ffaSEric DeVolder static void erst_reset(DeviceState *dev) 781*f7e26ffaSEric DeVolder { 782*f7e26ffaSEric DeVolder ERSTDeviceState *s = ACPIERST(dev); 783*f7e26ffaSEric DeVolder 784*f7e26ffaSEric DeVolder trace_acpi_erst_reset_in(le32_to_cpu(s->header->record_count)); 785*f7e26ffaSEric DeVolder s->operation = 0; 786*f7e26ffaSEric DeVolder s->busy_status = 0; 787*f7e26ffaSEric DeVolder s->command_status = STATUS_SUCCESS; 788*f7e26ffaSEric DeVolder s->record_identifier = ERST_UNSPECIFIED_RECORD_ID; 789*f7e26ffaSEric DeVolder s->record_offset = 0; 790*f7e26ffaSEric DeVolder s->next_record_index = s->first_record_index; 791*f7e26ffaSEric DeVolder /* NOTE: first/last_record_index are computed only once */ 792*f7e26ffaSEric DeVolder trace_acpi_erst_reset_out(le32_to_cpu(s->header->record_count)); 793*f7e26ffaSEric DeVolder } 794*f7e26ffaSEric DeVolder 795*f7e26ffaSEric DeVolder static Property erst_properties[] = { 796*f7e26ffaSEric DeVolder DEFINE_PROP_LINK(ACPI_ERST_MEMDEV_PROP, ERSTDeviceState, hostmem, 797*f7e26ffaSEric DeVolder TYPE_MEMORY_BACKEND, HostMemoryBackend *), 798*f7e26ffaSEric DeVolder DEFINE_PROP_UINT32(ACPI_ERST_RECORD_SIZE_PROP, ERSTDeviceState, 799*f7e26ffaSEric DeVolder default_record_size, ERST_RECORD_SIZE), 800*f7e26ffaSEric DeVolder DEFINE_PROP_END_OF_LIST(), 801*f7e26ffaSEric DeVolder }; 802*f7e26ffaSEric DeVolder 803*f7e26ffaSEric DeVolder static void erst_class_init(ObjectClass *klass, void *data) 804*f7e26ffaSEric DeVolder { 805*f7e26ffaSEric DeVolder DeviceClass *dc = DEVICE_CLASS(klass); 806*f7e26ffaSEric DeVolder PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 807*f7e26ffaSEric DeVolder 808*f7e26ffaSEric DeVolder trace_acpi_erst_class_init_in(); 809*f7e26ffaSEric DeVolder k->realize = erst_realizefn; 810*f7e26ffaSEric DeVolder k->vendor_id = PCI_VENDOR_ID_REDHAT; 811*f7e26ffaSEric DeVolder k->device_id = PCI_DEVICE_ID_REDHAT_ACPI_ERST; 812*f7e26ffaSEric DeVolder k->revision = 0x00; 813*f7e26ffaSEric DeVolder k->class_id = PCI_CLASS_OTHERS; 814*f7e26ffaSEric DeVolder dc->reset = erst_reset; 815*f7e26ffaSEric DeVolder dc->vmsd = &erst_vmstate; 816*f7e26ffaSEric DeVolder dc->user_creatable = true; 817*f7e26ffaSEric DeVolder dc->hotpluggable = false; 818*f7e26ffaSEric DeVolder device_class_set_props(dc, erst_properties); 819*f7e26ffaSEric DeVolder dc->desc = "ACPI Error Record Serialization Table (ERST) device"; 820*f7e26ffaSEric DeVolder set_bit(DEVICE_CATEGORY_MISC, dc->categories); 821*f7e26ffaSEric DeVolder trace_acpi_erst_class_init_out(); 822*f7e26ffaSEric DeVolder } 823*f7e26ffaSEric DeVolder 824*f7e26ffaSEric DeVolder static const TypeInfo erst_type_info = { 825*f7e26ffaSEric DeVolder .name = TYPE_ACPI_ERST, 826*f7e26ffaSEric DeVolder .parent = TYPE_PCI_DEVICE, 827*f7e26ffaSEric DeVolder .class_init = erst_class_init, 828*f7e26ffaSEric DeVolder .instance_size = sizeof(ERSTDeviceState), 829*f7e26ffaSEric DeVolder .interfaces = (InterfaceInfo[]) { 830*f7e26ffaSEric DeVolder { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 831*f7e26ffaSEric DeVolder { } 832*f7e26ffaSEric DeVolder } 833*f7e26ffaSEric DeVolder }; 834*f7e26ffaSEric DeVolder 835*f7e26ffaSEric DeVolder static void erst_register_types(void) 836*f7e26ffaSEric DeVolder { 837*f7e26ffaSEric DeVolder type_register_static(&erst_type_info); 838*f7e26ffaSEric DeVolder } 839*f7e26ffaSEric DeVolder 840*f7e26ffaSEric DeVolder type_init(erst_register_types) 841