xref: /qemu/hw/acpi/erst.c (revision c9cd06ca00acd142c3249594b041d7c84409e536)
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