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