From patchwork Mon Mar 20 00:09:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haozhong Zhang X-Patchwork-Id: 9632913 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 BFA866020B for ; Mon, 20 Mar 2017 00:16:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B2AE327F60 for ; Mon, 20 Mar 2017 00:16:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A75F927F9F; Mon, 20 Mar 2017 00:16:14 +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.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID 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 AA6F427F60 for ; Mon, 20 Mar 2017 00:16:13 +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 1cpkwy-0006tQ-Nt; Mon, 20 Mar 2017 00:13:28 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cpkwx-0006np-1N for xen-devel@lists.xen.org; Mon, 20 Mar 2017 00:13:27 +0000 Received: from [85.158.137.68] by server-13.bemta-3.messagelabs.com id 3E/DC-05091-6AE1FC85; Mon, 20 Mar 2017 00:13:26 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupkkeJIrShJLcpLzFFi42I5YG5SrLtU7ny Ewcv93BZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa8bLVQuZCyYUVLy9t5GxgfF9WBcjFweLwC0m iZ17lrCAOEIC0xkl3s39wdjFyMkhIcArcWTZDFYI20/i05ePbBBFvYwSpx//BUuwCehLrHh8E MwWEZCWuPb5MiNIEbPATiaJ5/ffsIEkhAU8Je4/+sMMYrMIqEpM/9rKDmLzCthJLJr3lB1ig7 zEhaunWEBsTqD4mku3weJCArYS+29NY5vAyLeAkWEVo0ZxalFZapGuoYleUlFmekZJbmJmjq6 hgbFebmpxcWJ6ak5iUrFecn7uJkZgsDAAwQ7GFds9DzFKcjApifKW/zgRIcSXlJ9SmZFYnBFf VJqTWnyIUYaDQ0mC94jSyQghwaLU9NSKtMwcYNjCpCU4eJREeHNB0rzFBYm5xZnpEKlTjLoci /7tfsMkxJKXn5cqJc57AaRIAKQoozQPbgQshi4xykoJ8zICHSXEU5BalJtZgir/ilGcg1FJmH czyBSezLwSuE2vgI5gAjri7YcTIEeUJCKkpBoYdV9K7HvLMunwvN+768KuPts+1+3n6uf88vz SPKY5tWbXYrdy3yk882/OCcej7+9c51N8Y7Kgen/F61X/TEMDJH2PbqmTflznUOAndO1L5v9f ug/CLuqdL857z/vW37ljhVrQZt8VE2Jmr5k/VfHKAh5vn948k8kM5vknakrdPLaWnZrK5zvpt hJLcUaioRZzUXEiAN3fI/6cAgAA X-Env-Sender: haozhong.zhang@intel.com X-Msg-Ref: server-8.tower-31.messagelabs.com!1489968802!91050058!1 X-Originating-IP: [192.55.52.115] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 57119 invoked from network); 20 Mar 2017 00:13:24 -0000 Received: from mga14.intel.com (HELO mga14.intel.com) (192.55.52.115) by server-8.tower-31.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 20 Mar 2017 00:13:24 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=intel; t=1489968804; x=1521504804; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=0V4Na86ZOJ8g/tNTer05oHvWjwiuZDX3Nb/NS2tswVQ=; b=pRYXN+OhdnXPJEumKSnpsmqMdaoGP+IjsZexXvZUJCXjtVDchZSlhV/n nSICHLwhCzNNgTbIl84rYeMHtthlkQ==; Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Mar 2017 17:13:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,191,1486454400"; d="scan'208";a="78799218" Received: from hz-desktop.sh.intel.com (HELO localhost) ([10.239.159.153]) by fmsmga006.fm.intel.com with ESMTP; 19 Mar 2017 17:13:22 -0700 From: Haozhong Zhang To: xen-devel@lists.xen.org Date: Mon, 20 Mar 2017 08:09:44 +0800 Message-Id: <20170320000949.24675-11-haozhong.zhang@intel.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20170320000949.24675-1-haozhong.zhang@intel.com> References: <20170320000949.24675-1-haozhong.zhang@intel.com> Cc: Haozhong Zhang , Wei Liu , Andrew Cooper , Ian Jackson , ross.philipson@ainfosec.com, Jan Beulich , Konrad Rzeszutek Wilk , Dan Williams Subject: [Xen-devel] [RFC XEN PATCH v2 10/15] 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: Jan Beulich Cc: Andrew Cooper Cc: Ian Jackson Cc: Wei Liu 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 diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index 80d7b448a5..abbdaaeb40 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 f00d9ef355..a3e5e9909f 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