#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
#include "qemu/bitops.h"
-#include "hw/acpi/bios-linker-loader.h"
+#include "sysemu/numa.h"
static GArray *build_alloc_array(void)
{
build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
}
-static void build_append_int_noprefix(GArray *table, uint64_t value, int size)
+void build_append_int_noprefix(GArray *table, uint64_t value, int size)
{
int i;
Aml *init_aml_allocator(void)
{
- Aml *var;
-
assert(!alloc_list);
alloc_list = g_ptr_array_new();
- var = aml_alloc();
- return var;
+ return aml_alloc();
}
void free_aml_allocator(void)
return var;
}
+/* ACPI 1.0b: 16.2.6.3 Debug Objects Encoding: DebugObj */
+Aml *aml_debug(void)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x31); /* DebugOp */
+ return var;
+}
+
/*
* ACPI 1.0b: 16.2.3 Data Objects Encoding:
* encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp
/* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */
Aml *aml_arg(int pos)
{
- Aml *var;
uint8_t op = 0x68 /* ARG0 op */ + pos;
assert(pos <= 6);
- var = aml_opcode(op);
- return var;
+ return aml_opcode(op);
}
/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToInteger */
return var;
}
+/* helper to call method with 5 arguments */
+Aml *aml_call5(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
+ Aml *arg5)
+{
+ Aml *var = aml_alloc();
+ build_append_namestring(var->buf, "%s", method);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ aml_append(var, arg3);
+ aml_append(var, arg4);
+ aml_append(var, arg5);
+ return var;
+}
+
/*
* ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
* Type 1, Large Item Name 0xC
/* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */
Aml *aml_local(int num)
{
- Aml *var;
uint8_t op = 0x60 /* Local0Op */ + num;
assert(num <= 7);
- var = aml_opcode(op);
- return var;
+ return aml_opcode(op);
}
/* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefRefOf */
+Aml *aml_refof(Aml *arg)
+{
+ Aml *var = aml_opcode(0x71 /* RefOfOp */);
+ aml_append(var, arg);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */
Aml *aml_derefof(Aml *arg)
{
target);
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefObjectType */
+Aml *aml_object_type(Aml *object)
+{
+ Aml *var = aml_opcode(0x8E /* ObjectTypeOp */);
+ aml_append(var, object);
+ return var;
+}
+
void
-build_header(GArray *linker, GArray *table_data,
+build_header(BIOSLinker *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
const char *oem_id, const char *oem_table_id)
{
+ unsigned tbl_offset = (char *)h - table_data->data;
+ unsigned checksum_offset = (char *)&h->checksum - table_data->data;
memcpy(&h->signature, sig, 4);
h->length = cpu_to_le32(len);
h->revision = rev;
h->oem_revision = cpu_to_le32(1);
memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
h->asl_compiler_revision = cpu_to_le32(1);
- h->checksum = 0;
/* Checksum to be filled in by Guest linker */
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
- table_data, h, len, &h->checksum);
+ tbl_offset, len, checksum_offset);
}
void *acpi_data_push(GArray *table_data, unsigned size)
void acpi_add_table(GArray *table_offsets, GArray *table_data)
{
- uint32_t offset = cpu_to_le32(table_data->len);
+ uint32_t offset = table_data->len;
g_array_append_val(table_offsets, offset);
}
tables->rsdp = g_array_new(false, true /* clear */, 1);
tables->table_data = g_array_new(false, true /* clear */, 1);
tables->tcpalog = g_array_new(false, true /* clear */, 1);
+ tables->vmgenid = g_array_new(false, true /* clear */, 1);
tables->linker = bios_linker_loader_init();
}
void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
{
- void *linker_data = bios_linker_loader_cleanup(tables->linker);
- g_free(linker_data);
+ bios_linker_loader_cleanup(tables->linker);
g_array_free(tables->rsdp, true);
g_array_free(tables->table_data, true);
g_array_free(tables->tcpalog, mfre);
+ g_array_free(tables->vmgenid, mfre);
}
/* Build rsdt table */
void
-build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets,
+build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
const char *oem_id, const char *oem_table_id)
{
- AcpiRsdtDescriptorRev1 *rsdt;
- size_t rsdt_len;
int i;
- const int table_data_len = (sizeof(uint32_t) * table_offsets->len);
+ unsigned rsdt_entries_offset;
+ AcpiRsdtDescriptorRev1 *rsdt;
+ const unsigned table_data_len = (sizeof(uint32_t) * table_offsets->len);
+ const unsigned rsdt_entry_size = sizeof(rsdt->table_offset_entry[0]);
+ const size_t rsdt_len = sizeof(*rsdt) + table_data_len;
- rsdt_len = sizeof(*rsdt) + table_data_len;
rsdt = acpi_data_push(table_data, rsdt_len);
- memcpy(rsdt->table_offset_entry, table_offsets->data, table_data_len);
+ rsdt_entries_offset = (char *)rsdt->table_offset_entry - table_data->data;
for (i = 0; i < table_offsets->len; ++i) {
+ uint32_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i);
+ uint32_t rsdt_entry_offset = rsdt_entries_offset + rsdt_entry_size * i;
+
/* rsdt->table_offset_entry to be filled by Guest linker */
bios_linker_loader_add_pointer(linker,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_FILE,
- table_data, &rsdt->table_offset_entry[i],
- sizeof(uint32_t));
+ ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, rsdt_entry_size,
+ ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
}
build_header(linker, table_data,
(void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
}
+/* Build xsdt table */
+void
+build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
+ const char *oem_id, const char *oem_table_id)
+{
+ int i;
+ unsigned xsdt_entries_offset;
+ AcpiXsdtDescriptorRev2 *xsdt;
+ const unsigned table_data_len = (sizeof(uint64_t) * table_offsets->len);
+ const unsigned xsdt_entry_size = sizeof(xsdt->table_offset_entry[0]);
+ const size_t xsdt_len = sizeof(*xsdt) + table_data_len;
+
+ xsdt = acpi_data_push(table_data, xsdt_len);
+ xsdt_entries_offset = (char *)xsdt->table_offset_entry - table_data->data;
+ for (i = 0; i < table_offsets->len; ++i) {
+ uint64_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i);
+ uint64_t xsdt_entry_offset = xsdt_entries_offset + xsdt_entry_size * i;
+
+ /* xsdt->table_offset_entry to be filled by Guest linker */
+ bios_linker_loader_add_pointer(linker,
+ ACPI_BUILD_TABLE_FILE, xsdt_entry_offset, xsdt_entry_size,
+ ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
+ }
+ build_header(linker, table_data,
+ (void *)xsdt, "XSDT", xsdt_len, 1, oem_id, oem_table_id);
+}
+
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
uint64_t len, int node, MemoryAffinityFlags flags)
{
numamem->base_addr = cpu_to_le64(base);
numamem->range_length = cpu_to_le64(len);
}
+
+/*
+ * ACPI spec 5.2.17 System Locality Distance Information Table
+ * (Revision 2.0 or later)
+ */
+void build_slit(GArray *table_data, BIOSLinker *linker)
+{
+ int slit_start, i, j;
+ slit_start = table_data->len;
+
+ acpi_data_push(table_data, sizeof(AcpiTableHeader));
+
+ build_append_int_noprefix(table_data, nb_numa_nodes, 8);
+ for (i = 0; i < nb_numa_nodes; i++) {
+ for (j = 0; j < nb_numa_nodes; j++) {
+ assert(numa_info[i].distance[j]);
+ build_append_int_noprefix(table_data, numa_info[i].distance[j], 1);
+ }
+ }
+
+ build_header(linker, table_data,
+ (void *)(table_data->data + slit_start),
+ "SLIT",
+ table_data->len - slit_start, 1, NULL, NULL);
+}