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