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