* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include <glib/gprintf.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <stdbool.h>
-#include <string.h>
#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;
}
}
+/*
+ * Build NAME(XXXX, 0x00000000) where 0x00000000 is encoded as a dword,
+ * and return the offset to 0x00000000 for runtime patching.
+ *
+ * Warning: runtime patching is best avoided. Only use this as
+ * a replacement for DataTableRegion (for guests that don't
+ * support it).
+ */
+int
+build_append_named_dword(GArray *array, const char *name_format, ...)
+{
+ int offset;
+ va_list ap;
+
+ build_append_byte(array, 0x08); /* NameOp */
+ va_start(ap, name_format);
+ build_append_namestringv(array, name_format, ap);
+ va_end(ap);
+
+ build_append_byte(array, 0x0C); /* DWordPrefix */
+
+ offset = array->len;
+ build_append_int_noprefix(array, 0x00000000, 4);
+ assert(array->len == offset + 4);
+
+ return offset;
+}
+
static GPtrArray *alloc_list;
static Aml *aml_alloc(void)
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 aml_opcode(op);
+}
+
+/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToInteger */
+Aml *aml_to_integer(Aml *arg)
+{
+ Aml *var = aml_opcode(0x99 /* ToIntegerOp */);
+ aml_append(var, arg);
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ return var;
+}
+
+/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToHexString */
+Aml *aml_to_hexstring(Aml *src, Aml *dst)
+{
+ Aml *var = aml_opcode(0x98 /* ToHexStringOp */);
+ aml_append(var, src);
+ if (dst) {
+ aml_append(var, dst);
+ } else {
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ }
+ return var;
+}
+
+/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToBuffer */
+Aml *aml_to_buffer(Aml *src, Aml *dst)
+{
+ Aml *var = aml_opcode(0x96 /* ToBufferOp */);
+ aml_append(var, src);
+ if (dst) {
+ aml_append(var, dst);
+ } else {
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ }
return var;
}
return var;
}
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */
-Aml *aml_and(Aml *arg1, Aml *arg2)
+/**
+ * build_opcode_2arg_dst:
+ * @op: 1-byte opcode
+ * @arg1: 1st operand
+ * @arg2: 2nd operand
+ * @dst: optional target to store to, set to NULL if it's not required
+ *
+ * An internal helper to compose AML terms that have
+ * "Op Operand Operand Target"
+ * pattern.
+ *
+ * Returns: The newly allocated and composed according to patter Aml object.
+ */
+static Aml *
+build_opcode_2arg_dst(uint8_t op, Aml *arg1, Aml *arg2, Aml *dst)
{
- Aml *var = aml_opcode(0x7B /* AndOp */);
+ Aml *var = aml_opcode(op);
aml_append(var, arg1);
aml_append(var, arg2);
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ if (dst) {
+ aml_append(var, dst);
+ } else {
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ }
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */
+Aml *aml_and(Aml *arg1, Aml *arg2, Aml *dst)
+{
+ return build_opcode_2arg_dst(0x7B /* AndOp */, arg1, arg2, dst);
+}
+
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefOr */
-Aml *aml_or(Aml *arg1, Aml *arg2)
+Aml *aml_or(Aml *arg1, Aml *arg2, Aml *dst)
{
- Aml *var = aml_opcode(0x7D /* OrOp */);
+ return build_opcode_2arg_dst(0x7D /* OrOp */, arg1, arg2, dst);
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLOr */
+Aml *aml_lor(Aml *arg1, Aml *arg2)
+{
+ Aml *var = aml_opcode(0x91 /* LOrOp */);
aml_append(var, arg1);
aml_append(var, arg2);
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
return var;
}
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftLeft */
Aml *aml_shiftleft(Aml *arg1, Aml *count)
{
- Aml *var = aml_opcode(0x79 /* ShiftLeftOp */);
- aml_append(var, arg1);
- aml_append(var, count);
- build_append_byte(var->buf, 0x00); /* NullNameOp */
- return var;
+ return build_opcode_2arg_dst(0x79 /* ShiftLeftOp */, arg1, count, NULL);
}
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftRight */
-Aml *aml_shiftright(Aml *arg1, Aml *count)
+Aml *aml_shiftright(Aml *arg1, Aml *count, Aml *dst)
{
- Aml *var = aml_opcode(0x7A /* ShiftRightOp */);
- aml_append(var, arg1);
- aml_append(var, count);
- build_append_byte(var->buf, 0x00); /* NullNameOp */
- return var;
+ return build_opcode_2arg_dst(0x7A /* ShiftRightOp */, arg1, count, dst);
}
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLLess */
}
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAdd */
-Aml *aml_add(Aml *arg1, Aml *arg2)
+Aml *aml_add(Aml *arg1, Aml *arg2, Aml *dst)
{
- Aml *var = aml_opcode(0x72 /* AddOp */);
- aml_append(var, arg1);
- aml_append(var, arg2);
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
- return var;
+ return build_opcode_2arg_dst(0x72 /* AddOp */, arg1, arg2, dst);
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSubtract */
+Aml *aml_subtract(Aml *arg1, Aml *arg2, Aml *dst)
+{
+ return build_opcode_2arg_dst(0x74 /* SubtractOp */, arg1, arg2, dst);
}
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIncrement */
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDecrement */
+Aml *aml_decrement(Aml *arg)
+{
+ Aml *var = aml_opcode(0x76 /* DecrementOp */);
+ aml_append(var, arg);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIndex */
Aml *aml_index(Aml *arg1, Aml *idx)
{
- Aml *var = aml_opcode(0x88 /* IndexOp */);
- aml_append(var, arg1);
- aml_append(var, idx);
- build_append_byte(var->buf, 0x00 /* NullNameOp */);
- return var;
+ return build_opcode_2arg_dst(0x88 /* IndexOp */, arg1, idx, NULL);
}
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
return var;
}
+/* helper to call method with 1 argument */
+Aml *aml_call0(const char *method)
+{
+ Aml *var = aml_alloc();
+ build_append_namestring(var->buf, "%s", method);
+ return var;
+}
+
/* helper to call method with 1 argument */
Aml *aml_call1(const char *method, Aml *arg1)
{
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
return var;
}
+/*
+ * ACPI 5.0: 19.5.53
+ * GpioInt(GPIO Interrupt Connection Resource Descriptor Macro)
+ */
+Aml *aml_gpio_int(AmlConsumerAndProducer con_and_pro,
+ AmlLevelAndEdge edge_level,
+ AmlActiveHighAndLow active_level, AmlShared shared,
+ AmlPinConfig pin_config, uint16_t debounce_timeout,
+ const uint32_t pin_list[], uint32_t pin_count,
+ const char *resource_source_name,
+ const uint8_t *vendor_data, uint16_t vendor_data_len)
+{
+ uint8_t flags = edge_level | (active_level << 1) | (shared << 3);
+
+ return aml_gpio_connection(AML_INTERRUPT_CONNECTION, con_and_pro, flags,
+ pin_config, 0, debounce_timeout, pin_list,
+ pin_count, resource_source_name, vendor_data,
+ vendor_data_len);
+}
+
/*
* ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
* (Type 1, Large Item Name 0x6)
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreater */
+Aml *aml_lgreater(Aml *arg1, Aml *arg2)
+{
+ Aml *var = aml_opcode(0x94 /* LGreaterOp */);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreaterEqual */
+Aml *aml_lgreater_equal(Aml *arg1, Aml *arg2)
+{
+ /* LGreaterEqualOp := LNotOp LLessOp */
+ Aml *var = aml_opcode(0x92 /* LNotOp */);
+ build_append_byte(var->buf, 0x95 /* LLessOp */);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */
Aml *aml_if(Aml *predicate)
{
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */
Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
- uint32_t offset, uint32_t len)
+ Aml *offset, uint32_t len)
{
Aml *var = aml_alloc();
build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
build_append_byte(var->buf, 0x80); /* OpRegionOp */
build_append_namestring(var->buf, "%s", name);
build_append_byte(var->buf, rs);
- build_append_int(var->buf, offset);
+ aml_append(var, offset);
build_append_int(var->buf, len);
return var;
}
}
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */
-Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule)
+Aml *aml_field(const char *name, AmlAccessType type, AmlLockRule lock,
+ AmlUpdateRule rule)
{
Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE);
uint8_t flags = rule << 5 | type;
+ flags |= lock << 4; /* LockRule at 4 bit offset */
+
build_append_namestring(var->buf, "%s", name);
build_append_byte(var->buf, flags);
return var;
}
-/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */
-Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
+static
+Aml *create_field_common(int opcode, Aml *srcbuf, Aml *index, const char *name)
{
- Aml *var = aml_alloc();
- build_append_byte(var->buf, 0x8A); /* CreateDWordFieldOp */
+ Aml *var = aml_opcode(opcode);
aml_append(var, srcbuf);
aml_append(var, index);
build_append_namestring(var->buf, "%s", name);
return var;
}
+/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateField */
+Aml *aml_create_field(Aml *srcbuf, Aml *bit_index, Aml *num_bits,
+ const char *name)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x13); /* CreateFieldOp */
+ aml_append(var, srcbuf);
+ aml_append(var, bit_index);
+ aml_append(var, num_bits);
+ build_append_namestring(var->buf, "%s", name);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */
+Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
+{
+ return create_field_common(0x8A /* CreateDWordFieldOp */,
+ srcbuf, index, name);
+}
+
+/* ACPI 2.0a: 17.2.4.2 Named Objects Encoding: DefCreateQWordField */
+Aml *aml_create_qword_field(Aml *srcbuf, Aml *index, const char *name)
+{
+ return create_field_common(0x8F /* CreateQWordFieldOp */,
+ srcbuf, index, name);
+}
+
/* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
Aml *aml_string(const char *name_format, ...)
{
/* 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 */
addr_trans, len, flags);
}
+/* ACPI 1.0b: 6.4.2.2 DMA Format/6.4.2.2.1 ASL Macro for DMA Descriptor */
+Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz,
+ uint8_t channel)
+{
+ Aml *var = aml_alloc();
+ uint8_t flags = sz | bm << 2 | typ << 5;
+
+ assert(channel < 8);
+ build_append_byte(var->buf, 0x2A); /* Byte 0: DMA Descriptor */
+ build_append_byte(var->buf, 1U << channel); /* Byte 1: _DMA - DmaChannel */
+ build_append_byte(var->buf, flags); /* Byte 2 */
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefSleep */
+Aml *aml_sleep(uint64_t msec)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x22); /* SleepOp */
+ aml_append(var, aml_int(msec));
+ return var;
+}
+
static uint8_t Hex2Byte(const char *src)
{
int hi, lo;
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)
+{
+ Aml *var = aml_opcode(0x83 /* DerefOfOp */);
+ aml_append(var, arg);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSizeOf */
+Aml *aml_sizeof(Aml *arg)
+{
+ Aml *var = aml_opcode(0x87 /* SizeOfOp */);
+ aml_append(var, arg);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMutex */
+Aml *aml_mutex(const char *name, uint8_t sync_level)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x01); /* MutexOp */
+ build_append_namestring(var->buf, "%s", name);
+ assert(!(sync_level & 0xF0));
+ build_append_byte(var->buf, sync_level);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAcquire */
+Aml *aml_acquire(Aml *mutex, uint16_t timeout)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x23); /* AcquireOp */
+ aml_append(var, mutex);
+ build_append_int_noprefix(var->buf, timeout, sizeof(timeout));
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefRelease */
+Aml *aml_release(Aml *mutex)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x27); /* ReleaseOp */
+ aml_append(var, mutex);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.1 Name Space Modifier Objects Encoding: DefAlias */
+Aml *aml_alias(const char *source_object, const char *alias_object)
+{
+ Aml *var = aml_opcode(0x06 /* AliasOp */);
+ aml_append(var, aml_name("%s", source_object));
+ aml_append(var, aml_name("%s", alias_object));
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefConcat */
+Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target)
+{
+ return build_opcode_2arg_dst(0x73 /* ConcatOp */, source1, source2,
+ 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,
- AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
+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;
- memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
- memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
- memcpy(h->oem_table_id + 4, sig, 4);
+
+ if (oem_id) {
+ strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id);
+ } else {
+ memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
+ }
+
+ if (oem_table_id) {
+ strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id));
+ } else {
+ memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
+ memcpy(h->oem_table_id + 4, sig, 4);
+ }
+
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->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 *)rsdt, "RSDT", rsdt_len, 1);
+ (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->type = ACPI_SRAT_MEMORY;
+ numamem->length = sizeof(*numamem);
+ numamem->proximity = cpu_to_le32(node);
+ numamem->flags = cpu_to_le32(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);
}