From nobody Tue Feb 10 04:29:36 2026 Delivered-To: importer@patchew.org Received-SPF: none (zohomail.com: 78.46.105.101 is neither permitted nor denied by domain of seabios.org) client-ip=78.46.105.101; envelope-from=seabios-bounces@seabios.org; helo=coreboot.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=none (zohomail.com: 78.46.105.101 is neither permitted nor denied by domain of seabios.org) smtp.mailfrom=seabios-bounces@seabios.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1588168501; cv=none; d=zohomail.com; s=zohoarc; b=UC95Rwljca4jK7A8N3JNuDsepDZUi4icMlrFiUlDcDsod96EVVhI35TxHM9CvtD5mNaE7xr0EZlJJ6XUdRQAoTRsSsvu60YGXyMLlZL+3OfNETMK2FfZJLQl39Hucx9UL01zJcJ3Gg8xbVQ/wBOKrM4qGP1C2p0mS4gC8i2KGbI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588168501; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Subject:To; bh=CwiYpB/hKy8gAR3UMyKoV23KIbnpiUaHZ5+aafO0W3A=; b=d5JUJnqH0I+PlgCehA5mZJ81nqdheYmm826KkCKwJu0uUnGRLakZdXeEbeG2EEEWnpGse5ogQH0Wcz0+HN4sJwn7Gq/NxQmzoPPv2avjAQeBQHnMkx4nGA4e3wB4sH6gF5cIOU7gR7jyjQ/6mrmZRVo9/iy/VsV42gsfMmuxDSI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=none (zohomail.com: 78.46.105.101 is neither permitted nor denied by domain of seabios.org) smtp.mailfrom=seabios-bounces@seabios.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from coreboot.org (coreboot.org [78.46.105.101]) by mx.zohomail.com with SMTPS id 1588168501970657.9049517605105; Wed, 29 Apr 2020 06:55:01 -0700 (PDT) Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP]) by coreboot.org (Postfix) with ESMTPA id D04E910C1958; Wed, 29 Apr 2020 13:54:57 +0000 (UTC) Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP]) by coreboot.org (Postfix) with ESMTP id C4E2B10C195E for ; Wed, 29 Apr 2020 13:53:23 +0000 (UTC) Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP]) [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-236-wmJMKs-4PqWWGkwPxPHjeg-1; Wed, 29 Apr 2020 09:47:01 -0400 Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id F337945F for ; Wed, 29 Apr 2020 13:47:00 +0000 (UTC) Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0C8F11001281; Wed, 29 Apr 2020 13:46:57 +0000 (UTC) Received: from authenticated-user (PRIMARY_HOSTNAME [PUBLIC_IP]) id 2746B9DA0; Wed, 29 Apr 2020 15:46:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1588168402; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=D8a86RW1IOuzwiwYk1Fdm138bfrBUsE3XQKruQ93O0Q=; b=OQ1rSW+r2oebqljudWVyUfMBUDcyWprzxoEnlEpUTO6IiijuNTRWYoVT5N83ovMi89+C+o /M+PaRlXR6gJ7zXg0e0FlZ9hhfj3uJXQev/OrT+TLi+DgEz1FoP9omil7GPrf/fTxVdc9G 3Fy3I55sfWHfIfu4KKC3Hvsz2J7vcGA= X-MC-Unique: wmJMKs-4PqWWGkwPxPHjeg-1 From: Gerd Hoffmann To: seabios@seabios.org Date: Wed, 29 Apr 2020 15:46:41 +0200 Message-Id: <20200429134643.2001-8-kraxel@redhat.com> In-Reply-To: <20200429134643.2001-1-kraxel@redhat.com> References: <20200429134643.2001-1-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Level: ***** Message-ID-Hash: Q4Q5IAN3XO7IVYJO5WLNDT4NRAUBMULT X-Message-ID-Hash: Q4Q5IAN3XO7IVYJO5WLNDT4NRAUBMULT X-MailFrom: kraxel@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-seabios.seabios.org-0; header-match-seabios.seabios.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: Gerd Hoffmann X-Mailman-Version: 3.3.1 Precedence: list Subject: [SeaBIOS] [PATCH v3 7/9] acpi: add dsdt parser List-Id: SeaBIOS mailing list Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Authentication-Results: coreboot.org; auth=pass smtp.auth=mailman@coreboot.org smtp.mailfrom=seabios-bounces@seabios.org X-Spamd-Bar: / X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Create a list of devices found in the DSDT table. Add helper functions to find devices, walk the list and figure device informations like mmio ranges and irqs. Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- src/util.h | 11 + src/fw/biostables.c | 9 + src/fw/dsdt_parser.c | 668 +++++++++++++++++++++++++++++++++++++++++++ src/fw/paravirt.c | 5 +- src/Kconfig | 7 + 6 files changed, 699 insertions(+), 3 deletions(-) create mode 100644 src/fw/dsdt_parser.c diff --git a/Makefile b/Makefile index 985ef591a13b..f02eda314784 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ SRC32FLAT=3D$(SRCBOTH) post.c e820map.c malloc.c romfile.= c x86.c optionroms.c \ hw/pcidevice.c hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdc= ard.c \ fw/coreboot.c fw/lzmadecode.c fw/multiboot.c fw/csm.c fw/biostables.c \ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/= xen.c \ - fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \ + fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c f= w/dsdt_parser.c \ hw/virtio-ring.c hw/virtio-pci.c hw/virtio-mmio.c hw/virtio-blk.c hw/v= irtio-scsi.c \ hw/tpm_drivers.c hw/nvme.c SRC32SEG=3Dstring.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio= .c diff --git a/src/util.h b/src/util.h index 4f27fc307439..0de35229dc0c 100644 --- a/src/util.h +++ b/src/util.h @@ -94,6 +94,17 @@ void display_uuid(void); void copy_table(void *pos); void smbios_setup(void); =20 +// fw/dsdt_parser.c +struct acpi_device; +void acpi_dsdt_parse(void); +struct acpi_device *acpi_dsdt_find_string(struct acpi_device *prev, const = char *hid); +struct acpi_device *acpi_dsdt_find_eisaid(struct acpi_device *prev, u16 ei= said); +char *acpi_dsdt_name(struct acpi_device *dev); +int acpi_dsdt_present_eisaid(u16 eisaid); +int acpi_dsdt_find_io(struct acpi_device *dev, u64 *min, u64 *max); +int acpi_dsdt_find_mem(struct acpi_device *dev, u64 *min, u64 *max); +int acpi_dsdt_find_irq(struct acpi_device *dev, u64 *irq); + // fw/coreboot.c extern const char *CBvendor, *CBpart; struct cbfs_file; diff --git a/src/fw/biostables.c b/src/fw/biostables.c index 0d4fdb9c22e8..0597459e9875 100644 --- a/src/fw/biostables.c +++ b/src/fw/biostables.c @@ -4,6 +4,14 @@ // // This file may be distributed under the terms of the GNU LGPLv3 license. =20 +#include "byteorder.h" // le32_to_cpu +#include "config.h" // CONFIG_* +// Support for manipulating bios tables (pir, mptable, acpi, smbios). +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + #include "byteorder.h" // le32_to_cpu #include "config.h" // CONFIG_* #include "hw/pci.h" // pci_config_writeb @@ -256,6 +264,7 @@ find_acpi_features(void) void *p =3D fadt; acpi_set_reset_reg(p + 116, *(u8 *)(p + 128)); } + acpi_dsdt_parse(); } =20 =20 diff --git a/src/fw/dsdt_parser.c b/src/fw/dsdt_parser.c new file mode 100644 index 000000000000..87c1a3ac3a00 --- /dev/null +++ b/src/fw/dsdt_parser.c @@ -0,0 +1,668 @@ +// Support for parsing dsdt acpi tables +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_* +#include "list.h" // hlist_* +#include "malloc.h" // malloc_* +#include "output.h" // dprintf +#include "string.h" // memcpy +#include "util.h" +#include "std/acpi.h" // struct rsdp_descriptor + +/**************************************************************** + * DSDT parser + ****************************************************************/ + +struct acpi_device { + struct hlist_node node; + char name[16]; + u8 *hid_aml; + u8 *sta_aml; + u8 *crs_data; + int crs_size; +}; +static struct hlist_head acpi_devices VARVERIFY32INIT; +static const int parse_dumpdevs =3D 0; + +struct parse_state { + char name[32]; + struct acpi_device *dev; + int error; + int depth; +}; + +static void parse_termlist(struct parse_state *s, + u8 *ptr, int offset, int pkglength); + +static void hex(const u8 *ptr, int count, int lvl, const char *item) +{ + int l =3D 0, i; + + do { + dprintf(lvl, "%s: %04x: ", item, l); + for (i =3D l; i < l+16; i +=3D 4) + dprintf(lvl, "%02x %02x %02x %02x ", + ptr[i+0], ptr[i+1], ptr[i+2], ptr[i+3]); + for (i =3D l; i < l+16; i++) + dprintf(lvl, "%c", (ptr[i] > 0x20 && ptr[i] < 0x80) + ? ptr[i] : '.'); + dprintf(lvl, "\n"); + l +=3D 16; + } while (l < count); +} + +static u64 parse_resource_int(u8 *ptr, int count) +{ + u64 value =3D 0; + int index =3D 0; + + for (index =3D 0; index < count; index++) + value |=3D (u64)ptr[index] << (index * 8); + return value; +} + +static int parse_resource_bit(u8 *ptr, int count) +{ + int bit; + + for (bit =3D 0; bit < count*8; bit++) + if (ptr[bit/8] & (1 << (bit%8))) + return bit; + return 0; +} + +static int parse_resource(u8 *ptr, int length, int *type, u64 *min, u64 *m= ax) +{ + int rname, rsize; + u64 len; + + *type =3D -1; + *min =3D 0; + *max =3D 0; + len =3D 0; + if (!(ptr[0] & 0x80)) { + /* small resource */ + rname =3D (ptr[0] >> 3) & 0x0f; + rsize =3D ptr[0] & 0x07; + rsize++; + switch (rname) { + case 0x04: /* irq */ + *min =3D parse_resource_bit(ptr + 1, rsize); + *max =3D *min; + *type =3D 3; + break; + case 0x0f: /* end marker */ + return 0; + case 0x08: /* io */ + *min =3D parse_resource_int(ptr + 2, 2); + *max =3D parse_resource_int(ptr + 4, 2); + if (*min =3D=3D *max) { + *max =3D *min + ptr[7] - 1; + *type =3D 1; + } + break; + case 0x09: /* fixed io */ + *min =3D parse_resource_int(ptr + 2, 2); + *max =3D *min + ptr[4] - 1; + *type =3D 1; + break; + default: + dprintf(3, "%s: small: 0x%x (len %d)\n", + __func__, rname, rsize); + break; + } + } else { + /* large resource */ + rname =3D ptr[0] & 0x7f; + rsize =3D ptr[2] << 8 | ptr[1]; + rsize +=3D 3; + switch (rname) { + case 0x06: /* 32-bit Fixed Location Memory Range Descriptor */ + *min =3D parse_resource_int(ptr + 4, 4); + len =3D parse_resource_int(ptr + 8, 4); + *max =3D *min + len - 1; + *type =3D 0; + break; + case 0x07: /* DWORD Address Space Descriptor */ + *min =3D parse_resource_int(ptr + 10, 4); + *max =3D parse_resource_int(ptr + 14, 4); + *type =3D ptr[3]; + break; + case 0x08: /* WORD Address Space Descriptor */ + *min =3D parse_resource_int(ptr + 8, 2); + *max =3D parse_resource_int(ptr + 10, 2); + *type =3D ptr[3]; + break; + case 0x09: /* irq */ + *min =3D parse_resource_int(ptr + 5, 4); + *max =3D *min; + *type =3D 3; + break; + case 0x0a: /* QWORD Address Space Descriptor */ + *min =3D parse_resource_int(ptr + 14, 8); + *max =3D parse_resource_int(ptr + 22, 8); + *type =3D ptr[3]; + break; + default: + dprintf(3, "%s: large: 0x%x (len %d)\n", __func__, rname, rsiz= e); + break; + } + } + return rsize; +} + +static int find_resource(u8 *ptr, int len, int kind, u64 *min, u64 *max) +{ + int type, size, offset =3D 0; + + do { + size =3D parse_resource(ptr + offset, len - offset, + &type, min, max); + if (kind =3D=3D type) + return 0; + offset +=3D size; + } while (size > 0 && offset < len); + return -1; +} + +static int print_resources(const char *prefix, u8 *ptr, int len) +{ + static const char *typename[] =3D { "mem", "i/o", "bus" }; + int type, size, offset =3D 0; + u64 min, max; + + do { + size =3D parse_resource(ptr + offset, len - offset, + &type, &min, &max); + switch (type) { + case 0: + case 1: + case 2: + dprintf(1, "%s%s 0x%llx -> 0x%llx\n", + prefix, typename[type], min, max); + break; + case 3: + dprintf(1, "%sirq %lld\n", prefix, min); + break; + } + offset +=3D size; + } while (size > 0 && offset < len); + return -1; +} + +static int parse_nameseg(u8 *ptr, char **dst) +{ + if (dst && *dst) { + *(dst[0]++) =3D ptr[0]; + if (ptr[1] !=3D '_') + *(dst[0]++) =3D ptr[1]; + if (ptr[2] !=3D '_') + *(dst[0]++) =3D ptr[2]; + if (ptr[3] !=3D '_') + *(dst[0]++) =3D ptr[3]; + *(dst[0]) =3D 0; + } + return 4; +} + +static int parse_namestring(struct parse_state *s, + u8 *ptr, const char *item) +{ + char *dst =3D s->name; + int offset =3D 0; + int i, count; + + for (;;) { + switch (ptr[offset]) { + case 0: /* null name */ + offset++; + *(dst++) =3D 0; + break; + case 0x2e: + offset++; + offset +=3D parse_nameseg(ptr + offset, &dst); + *(dst++) =3D '.'; + offset +=3D parse_nameseg(ptr + offset, &dst); + break; + case 0x2f: + offset++; + count =3D ptr[offset]; + offset++; + for (i =3D 0; i < count; i++) { + if (i) + *(dst++) =3D '.'; + offset +=3D parse_nameseg(ptr + offset, &dst); + } + break; + case '\\': + *(dst++) =3D '\\'; + offset++; + continue; + case '^': + *(dst++) =3D '^'; + offset++; + continue; + case 'A' ... 'Z': + case '_': + offset +=3D parse_nameseg(ptr, &dst); + break; + default: + hex(ptr, 16, 3, __func__); + s->error =3D 1; + break; + } + break; + } + dprintf(5, "%s: %d %s '%s'\n", __func__, s->depth, + item, s->name); + return offset; +} + +static int parse_termarg_int(u8 *ptr, int *error, u64 *dst) +{ + u64 value; + int offset =3D 1; + + switch (ptr[0]) { + case 0x00: /* zero */ + value =3D 0; + break; + case 0x01: /* one */ + value =3D 1; + break; + case 0x0a: /* byte prefix */ + value =3D ptr[1]; + offset++; + break; + case 0x0b: /* word prefix */ + value =3D ptr[1] | + ((unsigned long)ptr[2] << 8); + offset +=3D 2; + break; + case 0x0c: /* dword prefix */ + value =3D ptr[1] | + ((unsigned long)ptr[2] << 8) | + ((unsigned long)ptr[3] << 16) | + ((unsigned long)ptr[4] << 24); + offset +=3D 4; + break; + default: + value =3D 0; + hex(ptr, 16, 3, __func__); + if (error) + *error =3D 1; + break; + } + + if (dst) + *dst =3D value; + dprintf(5, "%s: 0x%llx\n", __func__, value); + return offset; +} + +static int parse_pkglength(u8 *ptr, int *pkglength) +{ + int offset =3D 2; + + *pkglength =3D 0; + switch (ptr[0] >> 6) { + case 3: + *pkglength |=3D ptr[3] << 20; + offset++; + case 2: + *pkglength |=3D ptr[2] << 12; + offset++; + case 1: + *pkglength |=3D ptr[1] << 4; + *pkglength |=3D ptr[0] & 0x0f; + return offset; + case 0: + default: + *pkglength |=3D ptr[0] & 0x3f; + return 1; + } +} + +static int parse_pkg_common(struct parse_state *s, + u8 *ptr, const char *item, int *pkglength) +{ + int offset; + + offset =3D parse_pkglength(ptr, pkglength); + offset +=3D parse_namestring(s, ptr + offset, item); + return offset; +} + +static int parse_pkg_scope(struct parse_state *s, + u8 *ptr) +{ + int offset, pkglength; + + offset =3D parse_pkg_common(s, ptr, "scope", &pkglength); + parse_termlist(s, ptr, offset, pkglength); + return pkglength; +} + +static int parse_pkg_device(struct parse_state *s, + u8 *ptr) +{ + int offset, pkglength; + + offset =3D parse_pkg_common(s, ptr, "device", &pkglength); + + s->dev =3D malloc_tmp(sizeof(struct acpi_device)); + if (!s->dev) { + warn_noalloc(); + s->error =3D 1; + return pkglength; + } + + memset(s->dev, 0, sizeof(struct acpi_device)); + hlist_add_head(&s->dev->node, &acpi_devices); + strtcpy(s->dev->name, s->name, sizeof(s->name)); + parse_termlist(s, ptr, offset, pkglength); + s->dev =3D NULL; + + return pkglength; +} + +static int parse_pkg_buffer(struct parse_state *s, + u8 *ptr) +{ + u64 blen; + int pkglength, offset; + + offset =3D parse_pkglength(ptr, &pkglength); + offset +=3D parse_termarg_int(ptr + offset, &s->error, &blen); + if (s->dev && strcmp(s->name, "_CRS") =3D=3D 0) { + s->dev->crs_data =3D ptr + offset; + s->dev->crs_size =3D blen; + } + return pkglength; +} + +static int parse_pkg_skip(struct parse_state *s, + u8 *ptr, int op, int name) +{ + int pkglength, offset; + char item[8]; + + snprintf(item, sizeof(item), "op %x", op); + offset =3D parse_pkglength(ptr, &pkglength); + if (name) { + parse_namestring(s, ptr + offset, item); + } else { + dprintf(5, "%s: %s (%d)\n", __func__, item, pkglength); + } + return pkglength; +} + +static int parse_termobj(struct parse_state *s, + u8 *ptr) +{ + int offset =3D 1; + + if (s->depth =3D=3D 16) { + dprintf(1, "%s: deep recursion\n", __func__); + s->error =3D 1; + return offset; + } + + s->depth++; + switch (ptr[0]) { + case 0x00: /* zero */ + break; + case 0x01: /* one */ + break; + case 0x08: /* name op */ + offset +=3D parse_namestring(s, ptr + offset, "name"); + offset +=3D parse_termobj(s, ptr + offset); + if (s->dev && strcmp(s->name, "_HID") =3D=3D 0) + s->dev->hid_aml =3D ptr; + if (s->dev && strcmp(s->name, "_STA") =3D=3D 0) + s->dev->sta_aml =3D ptr; + break; + case 0x0a: /* byte prefix */ + offset++; + break; + case 0x0b: /* word prefix */ + offset +=3D 2; + break; + case 0x0c: /* dword prefix */ + offset +=3D 4; + break; + case 0x0d: /* string prefix */ + while (ptr[offset]) + offset++; + offset++; + break; + case 0x10: /* scope op */ + offset +=3D parse_pkg_scope(s, ptr + offset); + break; + case 0x11: /* buffer op */ + offset +=3D parse_pkg_buffer(s, ptr + offset); + break; + case 0x12: /* package op */ + case 0x13: /* var package op */ + offset +=3D parse_pkg_skip(s, ptr + offset, ptr[0], 0); + break; + case 0x14: /* method op */ + offset +=3D parse_pkg_skip(s, ptr + offset, ptr[0], 1); + if (s->dev && strcmp(s->name, "_STA") =3D=3D 0) + s->dev->sta_aml =3D ptr; + break; + case 0x5b: /* ext op prefix */ + offset++; + switch (ptr[1]) { + case 0x01: /* mutex op */ + offset +=3D parse_namestring(s, ptr + offset, "mutex"); + offset++; /* sync flags */ + break; + case 0x80: /* op region op */ + offset +=3D parse_namestring(s, ptr + offset, "op region"); + offset++; /* region space */ + offset +=3D parse_termarg_int(ptr + offset, &s->error, NULL); + offset +=3D parse_termarg_int(ptr + offset, &s->error, NULL); + break; + case 0x81: /* field op */ + case 0x83: /* processor op */ + case 0x84: /* power resource op */ + case 0x85: /* thermal zone op */ + offset +=3D parse_pkg_skip(s, ptr + offset, 0x5b00 | ptr[1], 1= ); + break; + case 0x82: /* device op */ + offset +=3D parse_pkg_device(s, ptr + offset); + break; + default: + hex(ptr, 16, 3, __func__); + s->error =3D 1; + break; + } + break; + default: + hex(ptr, 16, 3, __func__); + s->error =3D 1; + break; + } + s->depth--; + + return offset; +} + +static void parse_termlist(struct parse_state *s, + u8 *ptr, int offset, int pkglength) +{ + for (;;) { + offset +=3D parse_termobj(s, ptr + offset); + if (offset =3D=3D pkglength) + return; + if (offset > pkglength) { + dprintf(1, "%s: overrun: %d/%d\n", __func__, + offset, pkglength); + s->error =3D 1; + return; + } + if (s->error) { + dprintf(1, "%s: parse error, skip from %d/%d\n", __func__, + offset, pkglength); + s->error =3D 0; + return; + } + } +} + +static struct acpi_device *acpi_dsdt_find(struct acpi_device *prev, + const u8 *aml, int size) +{ + struct acpi_device *dev; + struct hlist_node *node; + + if (!prev) + node =3D acpi_devices.first; + else + node =3D prev->node.next; + + for (; node !=3D NULL; node =3D dev->node.next) { + dev =3D container_of(node, struct acpi_device, node); + if (!aml) + return dev; + if (!dev->hid_aml) + continue; + if (memcmp(dev->hid_aml + 5, aml, size) =3D=3D 0) + return dev; + } + return NULL; +} + +static int acpi_dsdt_present(struct acpi_device *dev) +{ + if (!dev) + return 0; /* no */ + if (!dev->sta_aml) + return 1; /* yes */ + if (dev->sta_aml[0] =3D=3D 0x14) + return -1; /* unknown (can't evaluate method) */ + if (dev->sta_aml[0] =3D=3D 0x08) { + u64 value =3D 0; + parse_termarg_int(dev->sta_aml + 5, NULL, &value); + if (value =3D=3D 0) + return 0; /* no */ + else + return 1; /* yes */ + } + return -1; /* unknown (should not happen) */ +} + +/**************************************************************** + * DSDT parser, public interface + ****************************************************************/ + +struct acpi_device *acpi_dsdt_find_string(struct acpi_device *prev, + const char *hid) +{ + if (!CONFIG_ACPI_PARSE) + return NULL; + + u8 aml[10]; + int len =3D snprintf((char*)aml, sizeof(aml), "\x0d%s", hid); + return acpi_dsdt_find(prev, aml, len); +} + +struct acpi_device *acpi_dsdt_find_eisaid(struct acpi_device *prev, u16 ei= said) +{ + if (!CONFIG_ACPI_PARSE) + return NULL; + u8 aml[] =3D { + 0x0c, 0x41, 0xd0, + eisaid >> 8, + eisaid & 0xff + }; + return acpi_dsdt_find(prev, aml, 5); +} + +char *acpi_dsdt_name(struct acpi_device *dev) +{ + if (!CONFIG_ACPI_PARSE || !dev) + return NULL; + return dev->name; +} + +int acpi_dsdt_find_io(struct acpi_device *dev, u64 *min, u64 *max) +{ + if (!CONFIG_ACPI_PARSE || !dev || !dev->crs_data) + return -1; + return find_resource(dev->crs_data, dev->crs_size, + 1 /* I/O */, min, max); +} + +int acpi_dsdt_find_mem(struct acpi_device *dev, u64 *min, u64 *max) +{ + if (!CONFIG_ACPI_PARSE || !dev || !dev->crs_data) + return -1; + return find_resource(dev->crs_data, dev->crs_size, + 0 /* mem */, min, max); +} + +int acpi_dsdt_find_irq(struct acpi_device *dev, u64 *irq) +{ + u64 max; + if (!CONFIG_ACPI_PARSE || !dev || !dev->crs_data) + return -1; + return find_resource(dev->crs_data, dev->crs_size, + 3 /* irq */, irq, &max); +} + +int acpi_dsdt_present_eisaid(u16 eisaid) +{ + if (!CONFIG_ACPI_PARSE) + return -1; /* unknown */ + if (hlist_empty(&acpi_devices)) + return -1; /* unknown (no dsdt table) */ + + struct acpi_device *dev =3D acpi_dsdt_find_eisaid(NULL, eisaid); + return acpi_dsdt_present(dev); +} + +void acpi_dsdt_parse(void) +{ + if (!CONFIG_ACPI_PARSE) + return; + + struct fadt_descriptor_rev1 *fadt =3D find_acpi_table(FACP_SIGNATURE); + if (!fadt) + return; + u8 *dsdt =3D (void*)(fadt->dsdt); + if (!dsdt) + return; + + u32 length =3D *(u32*)(dsdt + 4); + u32 offset =3D 0x24; + dprintf(1, "ACPI: parse DSDT at %p (len %d)\n", dsdt, length); + + struct parse_state s; + memset(&s, 0, sizeof(s)); + parse_termlist(&s, dsdt, offset, length); + + if (!parse_dumpdevs) + return; + + struct acpi_device *dev; + dprintf(1, "ACPI: dumping dsdt devices\n"); + for (dev =3D acpi_dsdt_find(NULL, NULL, 0); + dev !=3D NULL; + dev =3D acpi_dsdt_find(dev, NULL, 0)) { + dprintf(1, " %s", acpi_dsdt_name(dev)); + if (dev->hid_aml) + dprintf(1, ", hid"); + if (dev->sta_aml) + dprintf(1, ", sta (0x%x)", dev->sta_aml[0]); + if (dev->crs_data) + dprintf(1, ", crs"); + dprintf(1, "\n"); + if (dev->crs_data) + print_resources(" ", dev->crs_data, dev->crs_size); + } +} diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index 119280c574fd..9247288a28c3 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -233,9 +233,10 @@ qemu_platform_setup(void) =20 RsdpAddr =3D find_acpi_rsdp(); =20 - if (RsdpAddr) + if (RsdpAddr) { + acpi_dsdt_parse(); return; - + } /* If present, loader should have installed an RSDP. * Not installed? We might still be able to continue * using the builtin RSDP. diff --git a/src/Kconfig b/src/Kconfig index 6606ce4d46c9..3a8ffa15fded 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -524,6 +524,13 @@ menu "BIOS Tables" This option can be disabled for QEMU 1.6 and older to save some space in the ROM file. If unsure, say Y. + config ACPI_PARSE + bool "Include ACPI DSDT parser." + default y + help + Support parsing ACPI DSDT for device probing. + Needed to find virtio-mmio devices. + If unsure, say Y. endmenu =20 source vgasrc/Kconfig --=20 2.18.2 _______________________________________________ SeaBIOS mailing list -- seabios@seabios.org To unsubscribe send an email to seabios-leave@seabios.org