From patchwork Mon Sep 11 04:38:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haozhong Zhang X-Patchwork-Id: 9946609 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 12E3E6035D for ; Mon, 11 Sep 2017 04:42:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0827927D0C for ; Mon, 11 Sep 2017 04:42:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F0F9028429; Mon, 11 Sep 2017 04:42:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0457A27D0C for ; Mon, 11 Sep 2017 04:42:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1drGVs-0002ln-Gf; Mon, 11 Sep 2017 04:40:00 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1drGVr-0002g5-En for xen-devel@lists.xen.org; Mon, 11 Sep 2017 04:39:59 +0000 Received: from [193.109.254.147] by server-2.bemta-6.messagelabs.com id 2B/62-15060-F9316B95; Mon, 11 Sep 2017 04:39:59 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrHLMWRWlGSWpSXmKPExsXS1tYhojtPeFu kwcVLUhZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa8bJt0EFnfkVbWudGxgbw7oYuTiEBKYzSmy9 tYi5i5GTQ0KAV+LIshmsXYwcQHaAxImdRSBhIYFeRom519hBbDYBfYkVjw+ygtgiAtIS1z5fZ gSZwyxwikmi4fRssCJhAU+Jxn3rwGwWAVWJ93O+g9m8AnYSvf+uMELskpfY1XYRbBAnUPzgy3 fMEMtsJRacXsA6gZF3ASPDKkaN4tSistQiXSNzvaSizPSMktzEzBxdQwMzvdzU4uLE9NScxKR iveT83E2MwFBgAIIdjIvXBh5ilORgUhLlfXd8S6QQX1J+SmVGYnFGfFFpTmrxIUYZDg4lCV4V oW2RQoJFqempFWmZOcCghElLcPAoifBGgaR5iwsSc4sz0yFSpxiNOQ5MuPKHiaPj5t0/TEIse fl5qVLivHIgpQIgpRmleXCDYNFyiVFWSpiXEeg0IZ6C1KLczBJU+VeM4hyMSsK8ESBTeDLzSu D2vQI6hQnoFJ5LW0BOKUlESEk1MNYeK2ee9tzk/s8Us7JlQhHL43+8n2z53WPC7nPZi/42ewc LHj8u+d5S93wsz6FyjoWH77b8ULjy+uJd3qcybkfinl0uYuVtfOwhG3FT8lnU/6MLbTlvd990 DHu21V7Yq8jv0LL7ZbOOf3Kr+/OmbUeezkVbP7XGjV7mbJ8a3tdozxaft/MQZ6sSS3FGoqEWc 1FxIgB/ZivTkQIAAA== X-Env-Sender: haozhong.zhang@intel.com X-Msg-Ref: server-2.tower-27.messagelabs.com!1505104735!56506342!28 X-Originating-IP: [134.134.136.20] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTM0LjEzNC4xMzYuMjAgPT4gMzU1MzU4\n X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 51469 invoked from network); 11 Sep 2017 04:39:57 -0000 Received: from mga02.intel.com (HELO mga02.intel.com) (134.134.136.20) by server-2.tower-27.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 11 Sep 2017 04:39:57 -0000 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 10 Sep 2017 21:39:57 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.42,376,1500966000"; d="scan'208"; a="1217078581" Received: from hz-desktop.sh.intel.com (HELO localhost) ([10.239.159.142]) by fmsmga002.fm.intel.com with ESMTP; 10 Sep 2017 21:39:55 -0700 From: Haozhong Zhang To: xen-devel@lists.xen.org Date: Mon, 11 Sep 2017 12:38:14 +0800 Message-Id: <20170911043820.14617-34-haozhong.zhang@intel.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170911043820.14617-1-haozhong.zhang@intel.com> References: <20170911043820.14617-1-haozhong.zhang@intel.com> Cc: Haozhong Zhang , Wei Liu , Andrew Cooper , Ian Jackson , Jan Beulich , Chao Peng , Dan Williams Subject: [Xen-devel] [RFC XEN PATCH v3 33/39] tools/libacpi: add a simple AML builder X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP It is used by libacpi to generate SSDTs from ACPI namespace devices built by the device model. Signed-off-by: Haozhong Zhang --- Cc: Andrew Cooper Cc: Jan Beulich Cc: Ian Jackson Cc: Wei Liu --- 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 diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index 7c4c0ce535..3e917507c8 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -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) diff --git a/tools/libacpi/aml_build.c b/tools/libacpi/aml_build.c new file mode 100644 index 0000000000..9b4e28ad95 --- /dev/null +++ b/tools/libacpi/aml_build.c @@ -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 . + */ + +#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; +} diff --git a/tools/libacpi/aml_build.h b/tools/libacpi/aml_build.h new file mode 100644 index 0000000000..30acc0f7a1 --- /dev/null +++ b/tools/libacpi/aml_build.h @@ -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 . + */ + +#ifndef _AML_BUILD_H_ +#define _AML_BUILD_H_ + +#include +#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_ */ diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index aee0a4c374..791c9ad05e 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -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