Skip to content

Commit

Permalink
ACPI ERST: build the ACPI ERST table
Browse files Browse the repository at this point in the history
This builds the ACPI ERST table to inform OSPM how to communicate
with the acpi-erst device.

Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
Reviewed-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <1643402289-22216-7-git-send-email-eric.devolder@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
Eric DeVolder authored and mstsirkin committed Feb 6, 2022
1 parent f7e26ff commit c9cd06c
Showing 1 changed file with 211 additions and 0 deletions.
211 changes: 211 additions & 0 deletions hw/acpi/erst.c
Expand Up @@ -55,6 +55,27 @@
#define STATUS_RECORD_STORE_EMPTY 0x04
#define STATUS_RECORD_NOT_FOUND 0x05

/* ACPI 4.0: Table 17-19 Serialization Instructions */
#define INST_READ_REGISTER 0x00
#define INST_READ_REGISTER_VALUE 0x01
#define INST_WRITE_REGISTER 0x02
#define INST_WRITE_REGISTER_VALUE 0x03
#define INST_NOOP 0x04
#define INST_LOAD_VAR1 0x05
#define INST_LOAD_VAR2 0x06
#define INST_STORE_VAR1 0x07
#define INST_ADD 0x08
#define INST_SUBTRACT 0x09
#define INST_ADD_VALUE 0x0A
#define INST_SUBTRACT_VALUE 0x0B
#define INST_STALL 0x0C
#define INST_STALL_WHILE_TRUE 0x0D
#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
#define INST_GOTO 0x0F
#define INST_SET_SRC_ADDRESS_BASE 0x10
#define INST_SET_DST_ADDRESS_BASE 0x11
#define INST_MOVE_DATA 0x12

/* UEFI 2.1: Appendix N Common Platform Error Record */
#define UEFI_CPER_RECORD_MIN_SIZE 128U
#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U
Expand Down Expand Up @@ -166,6 +187,196 @@ typedef struct {

} ERSTDeviceState;

/*******************************************************************/
/*******************************************************************/
typedef struct {
GArray *table_data;
pcibus_t bar;
uint8_t instruction;
uint8_t flags;
uint8_t register_bit_width;
pcibus_t register_offset;
} BuildSerializationInstructionEntry;

/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
static void build_serialization_instruction(
BuildSerializationInstructionEntry *e,
uint8_t serialization_action,
uint64_t value)
{
/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
struct AcpiGenericAddress gas;
uint64_t mask;

/* Serialization Action */
build_append_int_noprefix(e->table_data, serialization_action, 1);
/* Instruction */
build_append_int_noprefix(e->table_data, e->instruction, 1);
/* Flags */
build_append_int_noprefix(e->table_data, e->flags, 1);
/* Reserved */
build_append_int_noprefix(e->table_data, 0, 1);
/* Register Region */
gas.space_id = AML_SYSTEM_MEMORY;
gas.bit_width = e->register_bit_width;
gas.bit_offset = 0;
gas.access_width = (uint8_t)ctz32(e->register_bit_width) - 2;
gas.address = (uint64_t)(e->bar + e->register_offset);
build_append_gas_from_struct(e->table_data, &gas);
/* Value */
build_append_int_noprefix(e->table_data, value, 8);
/* Mask */
mask = (1ULL << (e->register_bit_width - 1) << 1) - 1;
build_append_int_noprefix(e->table_data, mask, 8);
}

/* ACPI 4.0: 17.4.1 Serialization Action Table */
void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
const char *oem_id, const char *oem_table_id)
{
/*
* Serialization Action Table
* The serialization action table must be generated first
* so that its size can be known in order to populate the
* Instruction Entry Count field.
*/
unsigned action;
GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
.oem_table_id = oem_table_id };
/* Contexts for the different ways ACTION and VALUE are accessed */
BuildSerializationInstructionEntry rd_value_32_val = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_READ_REGISTER_VALUE,
.register_bit_width = 32,
.register_offset = ERST_VALUE_OFFSET,
};
BuildSerializationInstructionEntry rd_value_32 = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_READ_REGISTER,
.register_bit_width = 32,
.register_offset = ERST_VALUE_OFFSET,
};
BuildSerializationInstructionEntry rd_value_64 = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_READ_REGISTER,
.register_bit_width = 64,
.register_offset = ERST_VALUE_OFFSET,
};
BuildSerializationInstructionEntry wr_value_32_val = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_WRITE_REGISTER_VALUE,
.register_bit_width = 32,
.register_offset = ERST_VALUE_OFFSET,
};
BuildSerializationInstructionEntry wr_value_32 = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_WRITE_REGISTER,
.register_bit_width = 32,
.register_offset = ERST_VALUE_OFFSET,
};
BuildSerializationInstructionEntry wr_value_64 = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_WRITE_REGISTER,
.register_bit_width = 64,
.register_offset = ERST_VALUE_OFFSET,
};
BuildSerializationInstructionEntry wr_action = {
.table_data = table_instruction_data, .bar = bar0, .flags = 0,
.instruction = INST_WRITE_REGISTER_VALUE,
.register_bit_width = 32,
.register_offset = ERST_ACTION_OFFSET,
};

trace_acpi_erst_pci_bar_0(bar0);

/* Serialization Instruction Entries */
action = ACTION_BEGIN_WRITE_OPERATION;
build_serialization_instruction(&wr_action, action, action);

action = ACTION_BEGIN_READ_OPERATION;
build_serialization_instruction(&wr_action, action, action);

action = ACTION_BEGIN_CLEAR_OPERATION;
build_serialization_instruction(&wr_action, action, action);

action = ACTION_END_OPERATION;
build_serialization_instruction(&wr_action, action, action);

action = ACTION_SET_RECORD_OFFSET;
build_serialization_instruction(&wr_value_32, action, 0);
build_serialization_instruction(&wr_action, action, action);

action = ACTION_EXECUTE_OPERATION;
build_serialization_instruction(&wr_value_32_val, action,
ERST_EXECUTE_OPERATION_MAGIC);
build_serialization_instruction(&wr_action, action, action);

action = ACTION_CHECK_BUSY_STATUS;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_32_val, action, 0x01);

action = ACTION_GET_COMMAND_STATUS;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_32, action, 0);

action = ACTION_GET_RECORD_IDENTIFIER;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_64, action, 0);

action = ACTION_SET_RECORD_IDENTIFIER;
build_serialization_instruction(&wr_value_64, action, 0);
build_serialization_instruction(&wr_action, action, action);

action = ACTION_GET_RECORD_COUNT;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_32, action, 0);

action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
build_serialization_instruction(&wr_action, action, action);

action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_64, action, 0);

action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_64, action, 0);

action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_32, action, 0);

action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
build_serialization_instruction(&wr_action, action, action);
build_serialization_instruction(&rd_value_64, action, 0);

/* Serialization Header */
acpi_table_begin(&table, table_data);

/* Serialization Header Size */
build_append_int_noprefix(table_data, 48, 4);

/* Reserved */
build_append_int_noprefix(table_data, 0, 4);

/*
* Instruction Entry Count
* Each instruction entry is 32 bytes
*/
g_assert((table_instruction_data->len) % 32 == 0);
build_append_int_noprefix(table_data,
(table_instruction_data->len / 32), 4);

/* Serialization Instruction Entries */
g_array_append_vals(table_data, table_instruction_data->data,
table_instruction_data->len);
g_array_free(table_instruction_data, TRUE);

acpi_table_end(linker, &table);
}

/*******************************************************************/
/*******************************************************************/
static uint8_t *get_nvram_ptr_by_index(ERSTDeviceState *s, unsigned index)
Expand Down

0 comments on commit c9cd06c

Please sign in to comment.