@@ -76,11 +76,12 @@ smbios.o: CFLAGS += -D__SMBIOS_DATE__="\"$(SMBIOS_REL_DATE)\""
ACPI_PATH = ../../libacpi
DSDT_FILES = dsdt_anycpu.c dsdt_15cpu.c dsdt_anycpu_qemu_xen.c
-ACPI_OBJS = $(patsubst %.c,%.o,$(DSDT_FILES)) build.o static_tables.o
+ACPI_OBJS = $(patsubst %.c,%.o,$(DSDT_FILES)) build.o static_tables.o aml_build.o
$(ACPI_OBJS): CFLAGS += -I. -DLIBACPI_STDUTILS=\"$(CURDIR)/util.h\"
CFLAGS += -I$(ACPI_PATH)
vpath build.c $(ACPI_PATH)
vpath static_tables.c $(ACPI_PATH)
+vpath aml_build.c $(ACPI_PATH)
OBJS += $(ACPI_OBJS)
hvmloader: $(OBJS)
new file mode 100644
@@ -0,0 +1,326 @@
+/*
+ * tools/libacpi/aml_build.c
+ *
+ * Copyright (C) 2017, Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License, version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include LIBACPI_STDUTILS
+#include "libacpi.h"
+#include "aml_build.h"
+
+#define AML_OP_SCOPE 0x10
+#define AML_OP_EXT 0x5B
+#define AML_OP_DEVICE 0x82
+
+#define ACPI_NAMESEG_LEN 4
+
+struct aml_build_alloctor {
+ struct acpi_ctxt *ctxt;
+ uint8_t *buf;
+ uint32_t capacity;
+ uint32_t used;
+};
+static struct aml_build_alloctor alloc;
+
+static uint8_t *aml_buf_alloc(uint32_t size)
+{
+ uint8_t *buf = NULL;
+ struct acpi_ctxt *ctxt = alloc.ctxt;
+ uint32_t alloc_size, alloc_align = ctxt->min_alloc_byte_align;
+ uint32_t length = alloc.used + size;
+
+ /* Overflow ... */
+ if ( length < alloc.used )
+ return NULL;
+
+ if ( length <= alloc.capacity )
+ {
+ buf = alloc.buf + alloc.used;
+ alloc.used += size;
+ }
+ else
+ {
+ alloc_size = length - alloc.capacity;
+ alloc_size = (alloc_size + alloc_align) & ~(alloc_align - 1);
+ buf = ctxt->mem_ops.alloc(ctxt, alloc_size, alloc_align);
+
+ if ( buf &&
+ buf == alloc.buf + alloc.capacity /* cont to existing buf */ )
+ {
+ alloc.capacity += alloc_size;
+ buf = alloc.buf + alloc.used;
+ alloc.used += size;
+ }
+ else
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+static uint32_t get_package_length(uint8_t *pkg)
+{
+ uint32_t len;
+
+ len = pkg - alloc.buf;
+ len = alloc.used - len;
+
+ return len;
+}
+
+/*
+ * On success, an object in the following form is stored at @buf.
+ * @byte
+ * the original content in @buf
+ */
+static int build_prepend_byte(uint8_t *buf, uint8_t byte)
+{
+ uint32_t len;
+
+ len = buf - alloc.buf;
+ len = alloc.used - len;
+
+ if ( !aml_buf_alloc(sizeof(uint8_t)) )
+ return -1;
+
+ if ( len )
+ memmove(buf + 1, buf, len);
+ buf[0] = byte;
+
+ return 0;
+}
+
+/*
+ * On success, an object in the following form is stored at @buf.
+ * AML encoding of four-character @name
+ * the original content in @buf
+ *
+ * Refer to ACPI spec 6.1, Sec 20.2.2 "Name Objects Encoding".
+ *
+ * XXX: names of multiple segments (e.g. X.Y.Z) are not supported
+ */
+static int build_prepend_name(uint8_t *buf, const char *name)
+{
+ uint8_t *p = buf;
+ const char *s = name;
+ uint32_t len, name_len;
+
+ while ( *s == '\\' || *s == '^' )
+ {
+ if ( build_prepend_byte(p, (uint8_t) *s) )
+ return -1;
+ ++p;
+ ++s;
+ }
+
+ if ( !*s )
+ return build_prepend_byte(p, 0x00);
+
+ len = p - alloc.buf;
+ len = alloc.used - len;
+ name_len = strlen(s);
+ ASSERT(name_len <= ACPI_NAMESEG_LEN);
+
+ if ( !aml_buf_alloc(ACPI_NAMESEG_LEN) )
+ return -1;
+ if ( len )
+ memmove(p + ACPI_NAMESEG_LEN, p, len);
+ memcpy(p, s, name_len);
+ memcpy(p + name_len, "____", ACPI_NAMESEG_LEN - name_len);
+
+ return 0;
+}
+
+enum {
+ PACKAGE_LENGTH_1BYTE_SHIFT = 6, /* Up to 63 - use extra 2 bits. */
+ PACKAGE_LENGTH_2BYTE_SHIFT = 4,
+ PACKAGE_LENGTH_3BYTE_SHIFT = 12,
+ PACKAGE_LENGTH_4BYTE_SHIFT = 20,
+};
+
+/*
+ * On success, an object in the following form is stored at @pkg.
+ * AML encoding of package length @length
+ * the original content in @pkg
+ *
+ * Refer to ACPI spec 6.1, Sec 20.2.4 "Package Length Encoding".
+ */
+static int build_prepend_package_length(uint8_t *pkg, uint32_t length)
+{
+ int rc = 0;
+ uint8_t byte;
+ unsigned length_bytes;
+
+ if ( length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT) )
+ length_bytes = 1;
+ else if ( length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT) )
+ length_bytes = 2;
+ else if ( length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT) )
+ length_bytes = 3;
+ else
+ length_bytes = 4;
+
+ length += length_bytes;
+
+ switch ( length_bytes )
+ {
+ case 1:
+ byte = length;
+ return build_prepend_byte(pkg, byte);
+
+ case 4:
+ byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT;
+ if ( build_prepend_byte(pkg, byte) )
+ break;
+ length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1;
+ /* fall through */
+ case 3:
+ byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT;
+ if ( build_prepend_byte(pkg, byte) )
+ break;
+ length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1;
+ /* fall through */
+ case 2:
+ byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT;
+ if ( build_prepend_byte(pkg, byte) )
+ break;
+ length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1;
+ /* fall through */
+ }
+
+ if ( !rc )
+ {
+ /*
+ * Most significant two bits of byte zero indicate how many
+ * following bytes are in PkgLength encoding.
+ */
+ byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length;
+ rc = build_prepend_byte(pkg, byte);
+ }
+
+ return rc;
+}
+
+/*
+ * On success, an object in the following form is stored at @buf.
+ * @op
+ * AML encoding of package length of @buf
+ * original content in @buf
+ *
+ * Refer to comments of callers for ACPI spec sections.
+ */
+static int build_prepend_package(uint8_t *buf, uint8_t op)
+{
+ uint32_t length = get_package_length(buf);
+
+ if ( !build_prepend_package_length(buf, length) )
+ return build_prepend_byte(buf, op);
+ else
+ return -1;
+}
+
+/*
+ * On success, an object in the following form is stored at @buf.
+ * AML_OP_EXT
+ * @op
+ * AML encoding of package length of @buf
+ * original content in @buf
+ *
+ * Refer to comments of callers for ACPI spec sections.
+ */
+static int build_prepend_ext_package(uint8_t *buf, uint8_t op)
+{
+ if ( !build_prepend_package(buf, op) )
+ return build_prepend_byte(buf, AML_OP_EXT);
+ else
+ return -1;
+}
+
+void *aml_build_begin(struct acpi_ctxt *ctxt)
+{
+ uint32_t align = ctxt->min_alloc_byte_align;
+
+ alloc.ctxt = ctxt;
+ alloc.buf = ctxt->mem_ops.alloc(ctxt, align, align);
+ alloc.capacity = align;
+ alloc.used = 0;
+
+ return alloc.buf;
+}
+
+uint32_t aml_build_end(void)
+{
+ return alloc.used;
+}
+
+/*
+ * On success, an object in the following form is stored at @buf.
+ * the first @length bytes in @blob
+ * the original content in @buf
+ */
+int aml_prepend_blob(uint8_t *buf, const void *blob, uint32_t blob_length)
+{
+ uint32_t len;
+
+ ASSERT(buf >= alloc.buf);
+ len = buf - alloc.buf;
+ ASSERT(alloc.used >= len);
+ len = alloc.used - len;
+
+ if ( !aml_buf_alloc(blob_length) )
+ return -1;
+ if ( len )
+ memmove(buf + blob_length, buf, len);
+
+ memcpy(buf, blob, blob_length);
+
+ return 0;
+}
+
+/*
+ * On success, an object decoded as below is stored at @buf.
+ * Device (@name)
+ * {
+ * the original content in @buf
+ * }
+ *
+ * Refer to ACPI spec 6.1, Sec 20.2.5.2 "Named Objects Encoding" -
+ * "DefDevice".
+ */
+int aml_prepend_device(uint8_t *buf, const char *name)
+{
+ if ( !build_prepend_name(buf, name) )
+ return build_prepend_ext_package(buf, AML_OP_DEVICE);
+ else
+ return -1;
+}
+
+/*
+ * On success, an object decoded as below is stored at @buf.
+ * Scope (@name)
+ * {
+ * the original content in @buf
+ * }
+ *
+ * Refer to ACPI spec 6.1, Sec 20.2.5.1 "Namespace Modifier Objects
+ * Encoding" - "DefScope".
+ */
+int aml_prepend_scope(uint8_t *buf, const char *name)
+{
+ if ( !build_prepend_name(buf, name) )
+ return build_prepend_package(buf, AML_OP_SCOPE);
+ else
+ return -1;
+}
new file mode 100644
@@ -0,0 +1,116 @@
+/*
+ * tools/libacpi/aml_build.h
+ *
+ * Copyright (C) 2017, Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License, version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _AML_BUILD_H_
+#define _AML_BUILD_H_
+
+#include <stdint.h>
+#include "libacpi.h"
+
+/*
+ * NB: All aml_prepend_* calls, which build AML code in one ACPI
+ * table, should be placed between a pair of calls to
+ * aml_build_begin() and aml_build_end(). Nested aml_build_begin()
+ * and aml_build_end() are not supported.
+ *
+ * NB: If a call to aml_prepend_*() fails, the AML builder buffer
+ * will be in an inconsistent state, and any following calls to
+ * aml_prepend_*() will result in undefined behavior.
+ */
+
+/**
+ * Reset the AML builder and begin a new round of building.
+ *
+ * Parameters:
+ * ctxt: ACPI context used by the AML builder
+ *
+ * Returns:
+ * a pointer to the builder buffer where the AML code will be stored
+ */
+void *aml_build_begin(struct acpi_ctxt *ctxt);
+
+/**
+ * Mark the end of a round of AML building.
+ *
+ * Returns:
+ * the number of bytes in the builder buffer built in this round
+ */
+uint32_t aml_build_end(void);
+
+/**
+ * Prepend a blob, which can contain arbitrary content, to the builder buffer.
+ *
+ * On success, an object in the following form is stored at @buf.
+ * the first @length bytes in @blob
+ * the original content in @buf
+ *
+ * Parameters:
+ * buf: pointer to the builder buffer
+ * blob: pointer to the blob
+ * length: the number of bytes in the blob
+ *
+ * Return:
+ * 0 on success, -1 on failure.
+ */
+int aml_prepend_blob(uint8_t *buf, const void *blob, uint32_t length);
+
+/**
+ * Prepend an AML device structure to the builder buffer. The existing
+ * data in the builder buffer is included in the AML device.
+ *
+ * On success, an object decoded as below is stored at @buf.
+ * Device (@name)
+ * {
+ * the original content in @buf
+ * }
+ *
+ * Refer to ACPI spec 6.1, Sec 20.2.5.2 "Named Objects Encoding" -
+ * "DefDevice".
+ *
+ * Parameters:
+ * buf: pointer to the builder buffer
+ * name: the name of the device
+ *
+ * Return:
+ * 0 on success, -1 on failure.
+ */
+int aml_prepend_device(uint8_t *buf, const char *name);
+
+/**
+ * Prepend an AML scope structure to the builder buffer. The existing
+ * data in the builder buffer is included in the AML scope.
+ *
+ * On success, an object decoded as below is stored at @buf.
+ * Scope (@name)
+ * {
+ * the original content in @buf
+ * }
+ *
+ * Refer to ACPI spec 6.1, Sec 20.2.5.1 "Namespace Modifier Objects
+ * Encoding" - "DefScope".
+ *
+ * Parameters:
+ * buf: pointer to the builder buffer
+ * name: the name of the scope
+ *
+ * Return:
+ * 0 on success, -1 on failure.
+ */
+int aml_prepend_scope(uint8_t *buf, const char *name);
+
+#endif /* _AML_BUILD_H_ */
@@ -77,11 +77,12 @@ endif
ACPI_PATH = $(XEN_ROOT)/tools/libacpi
DSDT_FILES-$(CONFIG_X86) = dsdt_pvh.c
-ACPI_OBJS = $(patsubst %.c,%.o,$(DSDT_FILES-y)) build.o static_tables.o
+ACPI_OBJS = $(patsubst %.c,%.o,$(DSDT_FILES-y)) build.o static_tables.o aml_build.o
$(DSDT_FILES-y): acpi
$(ACPI_OBJS): CFLAGS += -I. -DLIBACPI_STDUTILS=\"$(CURDIR)/libxl_x86_acpi.h\"
vpath build.c $(ACPI_PATH)/
vpath static_tables.c $(ACPI_PATH)/
+vpath aml_build.c $(ACPI_PATH)/
LIBXL_OBJS-$(CONFIG_X86) += $(ACPI_OBJS)
.PHONY: acpi
It is used by libacpi to generate SSDTs from ACPI namespace devices built by the device model. Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com> --- Cc: Jan Beulich <jbeulich@suse.com> Cc: Andrew Cooper <andrew.cooper3@citrix.com> Cc: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Wei Liu <wei.liu2@citrix.com> Cc: ross.philipson@ainfosec.com Changes in v2: * Add code comment for what is built by each function. * Change the license to LGPL. --- tools/firmware/hvmloader/Makefile | 3 +- tools/libacpi/aml_build.c | 326 ++++++++++++++++++++++++++++++++++++++ tools/libacpi/aml_build.h | 116 ++++++++++++++ tools/libxl/Makefile | 3 +- 4 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 tools/libacpi/aml_build.c create mode 100644 tools/libacpi/aml_build.h