[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC XEN PATCH 10/16] tools/libacpi: add a simple AML builder



On 01/27/17 16:19 -0500, Konrad Rzeszutek Wilk wrote:
On Mon, Oct 10, 2016 at 08:32:29AM +0800, Haozhong Zhang wrote:
It is used by libacpi to generate SSDTs from ACPI namespace devices
built by the device model.

Would it make sense to include a link to document outlining the
the AML code? Or perhaps even just include an simple example
of ASL and what the resulting AML code should look like?

And maybe what subset of the AML code this implements?
(with some simple ASL examples?)


I'll add the reference to chapters of ACPI spec and more comments and
examples.

Also adding Ross who wrote an AML builder as well.


Sure


Signed-off-by: Haozhong Zhang <haozhong.zhang@xxxxxxxxx>
---
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
---
 tools/firmware/hvmloader/Makefile |   3 +-
 tools/libacpi/aml_build.c         | 254 ++++++++++++++++++++++++++++++++++++++
 tools/libacpi/aml_build.h         |  83 +++++++++++++
 tools/libxl/Makefile              |   3 +-
 4 files changed, 341 insertions(+), 2 deletions(-)
 create mode 100644 tools/libacpi/aml_build.c
 create mode 100644 tools/libacpi/aml_build.h

diff --git a/tools/firmware/hvmloader/Makefile 
b/tools/firmware/hvmloader/Makefile
index 77d7551..cf0dac3 100644
--- a/tools/firmware/hvmloader/Makefile
+++ b/tools/firmware/hvmloader/Makefile
@@ -79,11 +79,12 @@ smbios.o: CFLAGS += 
-D__SMBIOS_DATE__="\"$(SMBIOS_REL_DATE)\""

 ACPI_PATH = ../../libacpi
 ACPI_FILES = dsdt_anycpu.c dsdt_15cpu.c dsdt_anycpu_qemu_xen.c
-ACPI_OBJS = $(patsubst %.c,%.o,$(ACPI_FILES)) build.o static_tables.o
+ACPI_OBJS = $(patsubst %.c,%.o,$(ACPI_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)
diff --git a/tools/libacpi/aml_build.c b/tools/libacpi/aml_build.c
new file mode 100644
index 0000000..b6f23f4
--- /dev/null
+++ b/tools/libacpi/aml_build.c
@@ -0,0 +1,254 @@
+/*
+ * tools/libacpi/aml_build.c
+ *
+ * Copyright (c) 2016, Intel Corporation.

.. now 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by

The libacpi is LGPL.

Could this be licensed as LGPL please?


I didn't notice libacpi is LGPL licensed. I'll fix the license here
and below to LGPL.

+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Haozhong Zhang <haozhong.zhang@xxxxxxxxx>
+ */
+
+#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;
+
+enum { ALLOC_OVERFLOW, ALLOC_NOT_NEEDED, ALLOC_NEEDED };

Why not make this a named enum?

Ok, will do.

+
+static int alloc_needed(uint32_t size)
+{
+    uint32_t len = alloc.used + size;
+
+    if ( len < alloc.used )
+        return ALLOC_OVERFLOW;
+    else if ( len <= alloc.capacity )
+        return ALLOC_NOT_NEEDED;
+    else
+        return ALLOC_NEEDED;
+}
+
+static uint8_t *aml_buf_alloc(uint32_t size)
+{
+    int needed = alloc_needed(size);

And then this can be an enum? Or alternatively make this unsigned int.


will change to enum

+    uint8_t *buf = NULL;
+    struct acpi_ctxt *ctxt = alloc.ctxt;
+    uint32_t alloc_size, alloc_align = ctxt->min_alloc_align;
+
+    switch ( needed )
+    {
+    case ALLOC_OVERFLOW:
+        break;
+
+    case ALLOC_NEEDED:
+        alloc_size = (size + alloc_align) & ~(alloc_align - 1);

Perhaps multiply times two so we have more wiggle room?

Yes, it can allocate a little more then required.
Thanks,
Haozhong


+        buf = ctxt->mem_ops.alloc(ctxt, alloc_size, alloc_align);
+        if ( !buf )
+            break;
+        if ( alloc.buf + alloc.capacity != buf )
+        {
+            buf = NULL;
+            break;
+        }
+        alloc.capacity += alloc_size;
+        alloc.used += size;
+        break;
+
+    case ALLOC_NOT_NEEDED:
+        buf = alloc.buf + alloc.used;
+        alloc.used += size;
+        break;
+
+    default:
+        break;
+    }
+
+    return buf;
+}
+
+static uint32_t get_package_length(uint8_t *pkg)
+{
+    uint32_t len;
+
+    len = pkg - alloc.buf;
+    len = alloc.used - len;
+
+    return len;
+}
+
+static void build_prepend_byte(uint8_t *buf, uint8_t byte)
+{
+    uint32_t len;
+
+    len = buf - alloc.buf;
+    len = alloc.used - len;
+
+    aml_buf_alloc(sizeof(uint8_t));
+    if ( len )
+        memmove(buf + 1, buf, len);
+    buf[0] = byte;
+}
+
+/*
+ * XXX: names of multiple segments (e.g. X.Y.Z) are not supported
+ */
+static void 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 == '^' )
+    {
+        build_prepend_byte(p, (uint8_t) *s);
+        ++p;
+        ++s;
+    }
+
+    if ( !*s )
+    {
+        build_prepend_byte(p, 0x00);
+        return;
+    }
+
+    len = p - alloc.buf;
+    len = alloc.used - len;
+    name_len = strlen(s);
+    ASSERT(strlen(s) <= ACPI_NAMESEG_LEN);
+
+    aml_buf_alloc(ACPI_NAMESEG_LEN);
+    if ( len )
+        memmove(p + ACPI_NAMESEG_LEN, p, len);
+    memcpy(p, s, name_len);
+    memcpy(p + name_len, "____", ACPI_NAMESEG_LEN - name_len);
+}
+
+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,
+};
+
+static void build_prepend_package_length(uint8_t *pkg, uint32_t length)
+{
+    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;
+        build_prepend_byte(pkg, byte);
+        return;
+    case 4:
+        byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT;
+        build_prepend_byte(pkg, byte);
+        length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1;
+        /* fall through */
+    case 3:
+        byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT;
+        build_prepend_byte(pkg, byte);
+        length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1;
+        /* fall through */
+    case 2:
+        byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT;
+        build_prepend_byte(pkg, byte);
+        length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1;
+        /* fall through */
+    }
+    /*
+     * 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;
+    build_prepend_byte(pkg, byte);
+}
+
+static void build_prepend_package(uint8_t *buf, uint8_t op)
+{
+    uint32_t length = get_package_length(buf);
+    build_prepend_package_length(buf, length);
+    build_prepend_byte(buf, op);
+}
+
+static void build_prepend_ext_packge(uint8_t *buf, uint8_t op)
+{
+    build_prepend_package(buf, op);
+    build_prepend_byte(buf, AML_OP_EXT);
+}
+
+void *aml_build_begin(struct acpi_ctxt *ctxt)
+{
+    alloc.ctxt = ctxt;
+    alloc.buf = ctxt->mem_ops.alloc(ctxt,
+                                    ctxt->min_alloc_unit, 
ctxt->min_alloc_align);
+    alloc.capacity = ctxt->min_alloc_unit;
+    alloc.used = 0;
+    return alloc.buf;
+}
+
+uint32_t aml_build_end(void)
+{
+    return alloc.used;
+}
+
+void aml_prepend_blob(uint8_t *buf, const void *blob, uint32_t blob_length)
+{
+    uint32_t len;
+
+    len = buf - alloc.buf;
+    len = alloc.used - len;
+
+    aml_buf_alloc(blob_length);
+    if ( len )
+        memmove(buf + blob_length, buf, len);
+
+    memcpy(buf, blob, blob_length);
+}
+
+void aml_prepend_device(uint8_t *buf, const char *name)
+{
+    build_prepend_name(buf, name);
+    build_prepend_ext_packge(buf, AML_OP_DEVICE);
+}
+
+void aml_prepend_scope(uint8_t *buf, const char *name)
+{
+    build_prepend_name(buf, name);
+    build_prepend_package(buf, AML_OP_SCOPE);
+}
diff --git a/tools/libacpi/aml_build.h b/tools/libacpi/aml_build.h
new file mode 100644
index 0000000..ed68f66
--- /dev/null
+++ b/tools/libacpi/aml_build.h
@@ -0,0 +1,83 @@
+/*
+ * tools/libacpi/aml_build.h
+ *
+ * Copyright (c) 2016, Intel Corporation.

Now 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.

Again this needs to be LGPL license.

+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Haozhong Zhang <haozhong.zhang@xxxxxxxxx>
+ */
+
+#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().
+ */
+
+/**
+ * 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.
+ *
+ * Parameters:
+ *   @buf:    pointer to the builder buffer
+ *   @blob:   pointer to the blob
+ *   @length: the number of bytes in the blob
+ */
+void 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.
+ *
+ * Parameters:
+ *   @buf:  pointer to the builder buffer
+ *   @name: the name of the device
+ */
+void 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.
+ *
+ * Parameters:
+ *   @buf:  pointer to the builder buffer
+ *   @name: the name of the scope
+ */
+void aml_prepend_scope(uint8_t *buf, const char *name);
+
+#endif /* _AML_BUILD_H_ */
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index c4e4117..a904927 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -77,11 +77,12 @@ endif

 ACPI_PATH  = $(XEN_ROOT)/tools/libacpi
 ACPI_FILES = dsdt_pvh.c
-ACPI_OBJS  = $(patsubst %.c,%.o,$(ACPI_FILES)) build.o static_tables.o
+ACPI_OBJS  = $(patsubst %.c,%.o,$(ACPI_FILES)) build.o static_tables.o 
aml_build.o
 $(ACPI_FILES): 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
--
2.10.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.