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 <kra...@redhat.com>
---
 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=$(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/sdcard.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 
fw/dsdt_parser.c \
     hw/virtio-ring.c hw/virtio-pci.c hw/virtio-mmio.c hw/virtio-blk.c 
hw/virtio-scsi.c \
     hw/tpm_drivers.c hw/nvme.c
 SRC32SEG=string.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);
 
+// 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 
eisaid);
+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.
 
+#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 <ke...@koconnor.net>
+//
+// 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 = fadt;
         acpi_set_reset_reg(p + 116, *(u8 *)(p + 128));
     }
+    acpi_dsdt_parse();
 }
 
 
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 <ke...@koconnor.net>
+//
+// 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 = 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 = 0, i;
+
+    do {
+        dprintf(lvl, "%s: %04x:  ", item, l);
+        for (i = l; i < l+16; i += 4)
+            dprintf(lvl, "%02x %02x %02x %02x  ",
+                    ptr[i+0], ptr[i+1], ptr[i+2], ptr[i+3]);
+        for (i = l; i < l+16; i++)
+            dprintf(lvl, "%c", (ptr[i] > 0x20 && ptr[i] < 0x80)
+                    ? ptr[i] : '.');
+        dprintf(lvl, "\n");
+        l += 16;
+    } while (l < count);
+}
+
+static u64 parse_resource_int(u8 *ptr, int count)
+{
+    u64 value = 0;
+    int index = 0;
+
+    for (index = 0; index < count; index++)
+        value |= (u64)ptr[index] << (index * 8);
+    return value;
+}
+
+static int parse_resource_bit(u8 *ptr, int count)
+{
+    int bit;
+
+    for (bit = 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 *max)
+{
+    int rname, rsize;
+    u64 len;
+
+    *type = -1;
+    *min = 0;
+    *max = 0;
+    len = 0;
+    if (!(ptr[0] & 0x80)) {
+        /* small resource */
+        rname = (ptr[0] >> 3) & 0x0f;
+        rsize = ptr[0] & 0x07;
+        rsize++;
+        switch (rname) {
+        case 0x04: /* irq */
+            *min = parse_resource_bit(ptr + 1, rsize);
+            *max = *min;
+            *type = 3;
+            break;
+        case 0x0f: /* end marker */
+            return 0;
+        case 0x08: /* io */
+            *min = parse_resource_int(ptr + 2, 2);
+            *max = parse_resource_int(ptr + 4, 2);
+            if (*min == *max) {
+                *max = *min + ptr[7] - 1;
+                *type = 1;
+            }
+            break;
+        case 0x09: /* fixed io */
+            *min = parse_resource_int(ptr + 2, 2);
+            *max = *min + ptr[4] - 1;
+            *type = 1;
+            break;
+        default:
+            dprintf(3, "%s: small: 0x%x (len %d)\n",
+                    __func__, rname, rsize);
+            break;
+        }
+    } else {
+        /* large resource */
+        rname = ptr[0] & 0x7f;
+        rsize = ptr[2] << 8 | ptr[1];
+        rsize += 3;
+        switch (rname) {
+        case 0x06: /* 32-bit Fixed Location Memory Range Descriptor */
+            *min = parse_resource_int(ptr + 4, 4);
+            len = parse_resource_int(ptr + 8, 4);
+            *max = *min + len - 1;
+            *type = 0;
+            break;
+        case 0x07: /* DWORD Address Space Descriptor */
+            *min = parse_resource_int(ptr + 10, 4);
+            *max = parse_resource_int(ptr + 14, 4);
+            *type = ptr[3];
+            break;
+        case 0x08: /* WORD Address Space Descriptor */
+            *min = parse_resource_int(ptr +  8, 2);
+            *max = parse_resource_int(ptr + 10, 2);
+            *type = ptr[3];
+            break;
+        case 0x09: /* irq */
+            *min = parse_resource_int(ptr +  5, 4);
+            *max = *min;
+            *type = 3;
+            break;
+        case 0x0a: /* QWORD Address Space Descriptor */
+            *min = parse_resource_int(ptr + 14, 8);
+            *max = parse_resource_int(ptr + 22, 8);
+            *type = ptr[3];
+            break;
+        default:
+            dprintf(3, "%s: large: 0x%x (len %d)\n", __func__, rname, rsize);
+            break;
+        }
+    }
+    return rsize;
+}
+
+static int find_resource(u8 *ptr, int len, int kind, u64 *min, u64 *max)
+{
+    int type, size, offset = 0;
+
+    do {
+        size = parse_resource(ptr + offset, len - offset,
+                              &type, min, max);
+        if (kind == type)
+            return 0;
+        offset += size;
+    } while (size > 0 && offset < len);
+    return -1;
+}
+
+static int print_resources(const char *prefix, u8 *ptr, int len)
+{
+    static const char *typename[] = { "mem", "i/o", "bus" };
+    int type, size, offset = 0;
+    u64 min, max;
+
+    do {
+        size = 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 += size;
+    } while (size > 0 && offset < len);
+    return -1;
+}
+
+static int parse_nameseg(u8 *ptr, char **dst)
+{
+    if (dst && *dst) {
+        *(dst[0]++) = ptr[0];
+        if (ptr[1] != '_')
+            *(dst[0]++) = ptr[1];
+        if (ptr[2] != '_')
+            *(dst[0]++) = ptr[2];
+        if (ptr[3] != '_')
+            *(dst[0]++) = ptr[3];
+        *(dst[0]) = 0;
+    }
+    return 4;
+}
+
+static int parse_namestring(struct parse_state *s,
+                            u8 *ptr, const char *item)
+{
+    char *dst = s->name;
+    int offset = 0;
+    int i, count;
+
+    for (;;) {
+        switch (ptr[offset]) {
+        case 0: /* null name */
+            offset++;
+            *(dst++) = 0;
+            break;
+        case 0x2e:
+            offset++;
+            offset += parse_nameseg(ptr + offset, &dst);
+            *(dst++) = '.';
+            offset += parse_nameseg(ptr + offset, &dst);
+            break;
+        case 0x2f:
+            offset++;
+            count = ptr[offset];
+            offset++;
+            for (i = 0; i < count; i++) {
+                if (i)
+                    *(dst++) = '.';
+                offset += parse_nameseg(ptr + offset, &dst);
+            }
+            break;
+        case '\\':
+            *(dst++) = '\\';
+            offset++;
+            continue;
+        case '^':
+            *(dst++) = '^';
+            offset++;
+            continue;
+        case 'A' ... 'Z':
+        case '_':
+            offset += parse_nameseg(ptr, &dst);
+            break;
+        default:
+            hex(ptr, 16, 3, __func__);
+            s->error = 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 = 1;
+
+    switch (ptr[0]) {
+    case 0x00: /* zero */
+        value = 0;
+        break;
+    case 0x01: /* one */
+        value = 1;
+        break;
+    case 0x0a: /* byte prefix */
+        value = ptr[1];
+        offset++;
+        break;
+    case 0x0b: /* word prefix */
+        value = ptr[1] |
+            ((unsigned long)ptr[2] << 8);
+        offset += 2;
+        break;
+    case 0x0c: /* dword prefix */
+        value = ptr[1] |
+            ((unsigned long)ptr[2] << 8) |
+            ((unsigned long)ptr[3] << 16) |
+            ((unsigned long)ptr[4] << 24);
+        offset += 4;
+        break;
+    default:
+        value = 0;
+        hex(ptr, 16, 3, __func__);
+        if (error)
+            *error = 1;
+        break;
+    }
+
+    if (dst)
+        *dst = value;
+    dprintf(5, "%s: 0x%llx\n", __func__, value);
+    return offset;
+}
+
+static int parse_pkglength(u8 *ptr, int *pkglength)
+{
+    int offset = 2;
+
+    *pkglength = 0;
+    switch (ptr[0] >> 6) {
+    case 3:
+        *pkglength |= ptr[3] << 20;
+        offset++;
+    case 2:
+        *pkglength |= ptr[2] << 12;
+        offset++;
+    case 1:
+        *pkglength |= ptr[1] << 4;
+        *pkglength |= ptr[0] & 0x0f;
+        return offset;
+    case 0:
+    default:
+        *pkglength |= ptr[0] & 0x3f;
+        return 1;
+    }
+}
+
+static int parse_pkg_common(struct parse_state *s,
+                            u8 *ptr, const char *item, int *pkglength)
+{
+    int offset;
+
+    offset = parse_pkglength(ptr, pkglength);
+    offset += parse_namestring(s, ptr + offset, item);
+    return offset;
+}
+
+static int parse_pkg_scope(struct parse_state *s,
+                           u8 *ptr)
+{
+    int offset, pkglength;
+
+    offset = 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 = parse_pkg_common(s, ptr, "device", &pkglength);
+
+    s->dev = malloc_tmp(sizeof(struct acpi_device));
+    if (!s->dev) {
+        warn_noalloc();
+        s->error = 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 = NULL;
+
+    return pkglength;
+}
+
+static int parse_pkg_buffer(struct parse_state *s,
+                            u8 *ptr)
+{
+    u64 blen;
+    int pkglength, offset;
+
+    offset = parse_pkglength(ptr, &pkglength);
+    offset += parse_termarg_int(ptr + offset, &s->error, &blen);
+    if (s->dev && strcmp(s->name, "_CRS") == 0) {
+        s->dev->crs_data = ptr + offset;
+        s->dev->crs_size = 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 = 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 = 1;
+
+    if (s->depth == 16) {
+        dprintf(1, "%s: deep recursion\n", __func__);
+        s->error = 1;
+        return offset;
+    }
+
+    s->depth++;
+    switch (ptr[0]) {
+    case 0x00: /* zero */
+        break;
+    case 0x01: /* one */
+        break;
+    case 0x08: /* name op */
+        offset += parse_namestring(s, ptr + offset, "name");
+        offset += parse_termobj(s, ptr + offset);
+        if (s->dev && strcmp(s->name, "_HID") == 0)
+            s->dev->hid_aml = ptr;
+        if (s->dev && strcmp(s->name, "_STA") == 0)
+            s->dev->sta_aml = ptr;
+        break;
+    case 0x0a: /* byte prefix */
+        offset++;
+        break;
+    case 0x0b: /* word prefix */
+        offset += 2;
+        break;
+    case 0x0c: /* dword prefix */
+        offset += 4;
+        break;
+    case 0x0d: /* string prefix */
+        while (ptr[offset])
+            offset++;
+        offset++;
+        break;
+    case 0x10: /* scope op */
+        offset += parse_pkg_scope(s, ptr + offset);
+        break;
+    case 0x11: /* buffer op */
+        offset += parse_pkg_buffer(s, ptr + offset);
+        break;
+    case 0x12: /* package op */
+    case 0x13: /* var package op */
+        offset += parse_pkg_skip(s, ptr + offset, ptr[0], 0);
+        break;
+    case 0x14: /* method op */
+        offset += parse_pkg_skip(s, ptr + offset, ptr[0], 1);
+        if (s->dev && strcmp(s->name, "_STA") == 0)
+            s->dev->sta_aml = ptr;
+        break;
+    case 0x5b: /* ext op prefix */
+        offset++;
+        switch (ptr[1]) {
+        case 0x01: /* mutex op */
+            offset += parse_namestring(s, ptr + offset, "mutex");
+            offset++; /* sync flags */
+            break;
+        case 0x80: /* op region op */
+            offset += parse_namestring(s, ptr + offset, "op region");
+            offset++; /* region space */
+            offset += parse_termarg_int(ptr + offset, &s->error, NULL);
+            offset += 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 += parse_pkg_skip(s, ptr + offset, 0x5b00 | ptr[1], 1);
+            break;
+        case 0x82: /* device op */
+            offset += parse_pkg_device(s, ptr + offset);
+            break;
+        default:
+            hex(ptr, 16, 3, __func__);
+            s->error = 1;
+            break;
+        }
+        break;
+    default:
+        hex(ptr, 16, 3, __func__);
+        s->error = 1;
+        break;
+    }
+    s->depth--;
+
+    return offset;
+}
+
+static void parse_termlist(struct parse_state *s,
+                           u8 *ptr, int offset, int pkglength)
+{
+    for (;;) {
+        offset += parse_termobj(s, ptr + offset);
+        if (offset == pkglength)
+            return;
+        if (offset > pkglength) {
+            dprintf(1, "%s: overrun: %d/%d\n", __func__,
+                    offset, pkglength);
+            s->error = 1;
+            return;
+        }
+        if (s->error) {
+            dprintf(1, "%s: parse error, skip from %d/%d\n", __func__,
+                    offset, pkglength);
+            s->error = 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 = acpi_devices.first;
+    else
+        node = prev->node.next;
+
+    for (; node != NULL; node = dev->node.next) {
+        dev = container_of(node, struct acpi_device, node);
+        if (!aml)
+            return dev;
+        if (!dev->hid_aml)
+            continue;
+        if (memcmp(dev->hid_aml + 5, aml, size) == 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] == 0x14)
+        return -1; /* unknown (can't evaluate method) */
+    if (dev->sta_aml[0] == 0x08) {
+        u64 value = 0;
+        parse_termarg_int(dev->sta_aml + 5, NULL, &value);
+        if (value == 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 = 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 eisaid)
+{
+    if (!CONFIG_ACPI_PARSE)
+        return NULL;
+    u8 aml[] = {
+        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 = 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 = find_acpi_table(FACP_SIGNATURE);
+    if (!fadt)
+        return;
+    u8 *dsdt = (void*)(fadt->dsdt);
+    if (!dsdt)
+        return;
+
+    u32 length = *(u32*)(dsdt + 4);
+    u32 offset = 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 = acpi_dsdt_find(NULL, NULL, 0);
+         dev != NULL;
+         dev = 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)
 
         RsdpAddr = find_acpi_rsdp();
 
-        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
 
 source vgasrc/Kconfig
-- 
2.18.2
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-le...@seabios.org

Reply via email to