vmm: move biostables to the library
authorRonald G. Minnich <rminnich@gmail.com>
Fri, 21 Apr 2017 18:18:13 +0000 (14:18 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 1 May 2017 13:42:36 +0000 (09:42 -0400)
Put the bios tables in the user/vmm library.
vmrunkernel is becoming simpler and the library
is becoming more capable.

This is tested with a full prodkernel boot.

Change-Id: If29d6b5d8da4a3475e5fd26a3e1edeeb4d7614bc
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
[checkpatch/formatting]
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tests/vmm/vmrunkernel.c
user/vmm/biostables.c [new file with mode: 0644]
user/vmm/include/vmm/vmm.h

index e139e10..25f26dc 100644 (file)
@@ -16,7 +16,6 @@
 #include <sys/mman.h>
 #include <vmm/vmm.h>
 #include <vmm/acpi/acpi.h>
-#include <vmm/acpi/vmm_simple_dsdt.h>
 #include <ros/arch/mmu.h>
 #include <ros/arch/membar.h>
 #include <ros/vmm.h>
 #include <sys/uio.h>
 #include <parlib/opts.h>
 
-#define APIC_GPA                       0xfee00000ULL
-
 struct virtual_machine local_vm, *vm = &local_vm;
 struct vmm_gpcore_init *gpcis;
 
-/* By 1999, you could just scan the hardware
- * and work it out. But 2005, that was no longer possible. How sad.
- * so we have to fake acpi to make it all work.
- * This will be copied to memory at 0xe0000, so the kernel can find it.
- */
-
-/* assume they're all 256 bytes long just to make it easy.
- * Just have pointers that point to aligned things.
- */
-
-struct acpi_table_rsdp rsdp = {
-       .signature = ACPI_SIG_RSDP,
-       .oem_id = "AKAROS",
-       .revision = 2,
-       .length = 36,
-};
-
-struct acpi_table_xsdt xsdt = {
-       .header = {
-               .signature = ACPI_SIG_DSDT,
-               .revision = 2,
-               .oem_id = "AKAROS",
-               .oem_table_id = "ALPHABET",
-               .oem_revision = 0,
-               .asl_compiler_id = "RON ",
-               .asl_compiler_revision = 0,
-       },
-};
-struct acpi_table_fadt fadt = {
-       .header = {
-               .signature = ACPI_SIG_FADT,
-               .revision = 2,
-               .oem_id = "AKAROS",
-               .oem_table_id = "ALPHABET",
-               .oem_revision = 0,
-               .asl_compiler_id = "RON ",
-               .asl_compiler_revision = 0,
-       },
-};
-
-
-/* This has to be dropped into memory, then the other crap just follows it.
- */
-struct acpi_table_madt madt = {
-       .header = {
-               .signature = ACPI_SIG_MADT,
-               .revision = 2,
-               .oem_id = "AKAROS",
-               .oem_table_id = "ALPHABET",
-               .oem_revision = 0,
-               .asl_compiler_id = "RON ",
-               .asl_compiler_revision = 0,
-       },
-
-       .address = APIC_GPA,
-       .flags = 0,
-};
-
-struct acpi_madt_io_apic Apic1 = {.header = {.type = ACPI_MADT_TYPE_IO_APIC, .length = sizeof(struct acpi_madt_io_apic)},
-                                  .id = 0, .address = 0xfec00000, .global_irq_base = 0};
-
-struct acpi_madt_interrupt_override isor[] = {
-       /* From the ACPI Specification Version 6.1:
-        * For example, if your machine has the ISA Programmable Interrupt Timer
-        * (PIT) connected to ISA IRQ 0, but in APIC mode, it is connected to I/O
-        * APIC interrupt input 2, then you would need an Interrupt Source Override
-        * where the source entry is ‘0’ and the Global System Interrupt is ‘2.’
-        */
-};
-
 void vapic_status_dump(FILE *f, void *vapic);
 
 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
@@ -252,71 +179,6 @@ static struct virtio_vq_dev blk_vqdev = {
        }
 };
 
-void lowmem() {
-       __asm__ __volatile__ (".section .lowmem, \"aw\"\n\tlow: \n\t.=0x1000\n\t.align 0x100000\n\t.previous\n");
-}
-
-static uint8_t acpi_tb_checksum(uint8_t *buffer, uint32_t length)
-{
-       uint8_t sum = 0;
-       uint8_t *end = buffer + length;
-       fprintf(stderr, "tbchecksum %p for %d", buffer, length);
-       while (buffer < end) {
-               if (end - buffer < 2)
-                       fprintf(stderr, "%02x\n", sum);
-               sum = (uint8_t)(sum + *(buffer++));
-       }
-       fprintf(stderr, " is %02x\n", sum);
-       return (sum);
-}
-
-static void gencsum(uint8_t *target, void *data, int len)
-{
-       uint8_t csum;
-       // blast target to zero so it does not get counted
-       // (it might be in the struct we checksum) And, yes, it is, goodness.
-       fprintf(stderr, "gencsum %p target %p source %d bytes\n", target, data, len);
-       *target = 0;
-       csum  = acpi_tb_checksum((uint8_t *)data, len);
-       *target = ~csum + 1;
-       fprintf(stderr, "Cmoputed is %02x\n", *target);
-}
-
-/* TODO: put this in a library somewhere */
-int cat(char *file, void *where)
-{
-       int fd;
-       int amt, tot = 0;
-
-       fd = open(file, O_RDONLY);
-       if (fd < 0)
-               return -1;
-
-       while (amt = read(fd, where, 4096)) {
-               if (amt < 0) {
-                       close(fd);
-                       return -1;
-               }
-               tot += amt;
-               where += amt;
-       }
-       close(fd);
-       return tot;
-}
-
-int smbios(char *smbiostable, void *esegment)
-{
-       int amt;
-
-       amt = cat(smbiostable, esegment);
-       if (amt < 0) {
-               fprintf(stderr, "%s: %r\n", smbiostable);
-               exit(1);
-       }
-
-       return amt;
-}
-
 /* Parse func: given a line of text, it sets any vnet options */
 static void __parse_vnet_opts(char *_line)
 {
@@ -393,38 +255,6 @@ static void set_vnet_port_fwds(char *net_opts)
                perror("parse opts file");
 }
 
-/* Initialize the MADT structs for each local apic. */
-void *init_madt_local_apic(void *start)
-{
-       struct acpi_madt_local_apic *apic = start;
-
-       for (int i = 0; i < vm->nr_gpcs; i++) {
-               apic->header.type = ACPI_MADT_TYPE_LOCAL_APIC;
-               apic->header.length = sizeof(struct acpi_madt_local_apic);
-               apic->processor_id = i;
-               apic->id = i;
-               apic->lapic_flags = 1;
-               apic = (void *)apic + sizeof(struct acpi_madt_local_apic);
-       }
-       return apic;
-}
-
-/* Initialize the MADT structs for each local x2apic. */
-void *init_madt_local_x2apic(void *start)
-{
-       struct acpi_madt_local_x2apic *apic = start;
-
-       for (int i = 0; i < vm->nr_gpcs; i++) {
-               apic->header.type = ACPI_MADT_TYPE_LOCAL_X2APIC;
-               apic->header.length = sizeof(struct acpi_madt_local_x2apic);
-               apic->local_apic_id = i;
-               apic->uid = i;
-               apic->lapic_flags = 1;
-               apic = (void *)apic + sizeof(struct acpi_madt_local_x2apic);
-       }
-       return apic;
-}
-
 /* We map the APIC-access page, the per core Virtual APIC page and the
  * per core Posted Interrupt Descriptors.
  * Note: check if the PID/PIR needs to be a 4k page. */
@@ -476,7 +306,6 @@ int main(int argc, char **argv)
 {
        void *cr3;
        int debug = 0;
-       void *low1m;
        unsigned long long memsize = GiB;
        uintptr_t memstart = MinMemory;
        uintptr_t stack;
@@ -485,14 +314,9 @@ int main(int argc, char **argv)
        char *cmdline_extra = "\0";
        char *cmdline;
        void *a = (void *)0xe0000;
-       struct acpi_table_rsdp *r;
-       struct acpi_table_fadt *f;
-       struct acpi_table_madt *m;
-       struct acpi_table_xsdt *x;
        int vmmflags = 0; // Disabled probably forever. VMM_VMCALL_PRINTF;
        uint64_t entry = 0;
        int ret;
-       uint8_t csum;
        struct vm_trapframe *vm_tf;
        uint64_t tsc_freq_khz;
        char *cmdlinep;
@@ -657,114 +481,7 @@ int main(int argc, char **argv)
                exit(1);
        }
 
-
-       // The low 1m is so we can fill in bullshit like ACPI.
-       // And, sorry, due to the STUPID format of the RSDP for now we need the low 1M.
-       low1m = mmap((int*)4096, MiB-4096, PROT_READ | PROT_WRITE,
-                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
-       if (low1m != (void *)4096) {
-               perror("Unable to mmap low 1m");
-               exit(1);
-       }
-
-       /* As I understood it, the spec was that SMBIOS
-        * tables live at f0000. We've been finding that
-        * they can have pointers to exxxx. So, for now,
-        * we assume you will take a 128K snapshot of flash
-        * and we'll just splat the whole mess in at
-        * 0xe0000. We can get more sophisticated about
-        * this later if needed. TODO: parse the table,
-        * and make sure that ACPI doesn't trash it.
-        * Although you'll know instantly if that happens
-        * as you'll get dmidecode errors. But it still needs
-        * to be better. */
-       if (smbiostable) {
-               fprintf(stderr, "Using SMBIOS table %s\n", smbiostable);
-               smbios(smbiostable, (void *)0xe0000);
-       }
-
-       r = a;
-       fprintf(stderr, "install rsdp to %p\n", r);
-       *r = rsdp;
-       a += sizeof(*r);
-       r->xsdt_physical_address = (uint64_t)a;
-       gencsum(&r->checksum, r, ACPI_RSDP_CHECKSUM_LENGTH);
-       if ((csum = acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_CHECKSUM_LENGTH)) != 0) {
-               fprintf(stderr, "RSDP has bad checksum; summed to %x\n", csum);
-               exit(1);
-       }
-
-       /* Check extended checksum if table version >= 2 */
-       gencsum(&r->extended_checksum, r, ACPI_RSDP_XCHECKSUM_LENGTH);
-       if ((rsdp.revision >= 2) &&
-           (acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
-               fprintf(stderr, "RSDP has bad checksum v2\n");
-               exit(1);
-       }
-
-       /* just leave a bunch of space for the xsdt. */
-       /* we need to zero the area since it has pointers. */
-       x = a;
-       a += sizeof(*x) + 8*sizeof(void *);
-       memset(x, 0, a - (void *)x);
-       fprintf(stderr, "install xsdt to %p\n", x);
-       *x = xsdt;
-       x->table_offset_entry[0] = 0;
-       x->table_offset_entry[1] = 0;
-       x->header.length = a - (void *)x;
-
-       f = a;
-       fprintf(stderr, "install fadt to %p\n", f);
-       *f = fadt;
-       x->table_offset_entry[0] = (uint64_t)f; // fadt MUST be first in xsdt!
-       a += sizeof(*f);
-       f->header.length = a - (void *)f;
-
-       f->Xdsdt = (uint64_t) a;
-       fprintf(stderr, "install dsdt to %p\n", a);
-       memcpy(a, &DSDT_DSDTTBL_Header, 36);
-       a += 36;
-
-       gencsum(&f->header.checksum, f, f->header.length);
-       if (acpi_tb_checksum((uint8_t *)f, f->header.length) != 0) {
-               fprintf(stderr, "fadt has bad checksum v2\n");
-               exit(1);
-       }
-
-       m = a;
-       *m = madt;
-       x->table_offset_entry[3] = (uint64_t) m;
-       a += sizeof(*m);
-       fprintf(stderr, "install madt to %p\n", m);
-
-       a = init_madt_local_apic(a);
-
-       memmove(a, &Apic1, sizeof(Apic1));
-       a += sizeof(Apic1);
-
-       a = init_madt_local_x2apic(a);
-
-       memmove(a, &isor, sizeof(isor));
-       a += sizeof(isor);
-       m->header.length = a - (void *)m;
-
-       gencsum(&m->header.checksum, m, m->header.length);
-       if (acpi_tb_checksum((uint8_t *) m, m->header.length) != 0) {
-               fprintf(stderr, "madt has bad checksum v2\n");
-               exit(1);
-       }
-
-       gencsum(&x->header.checksum, x, x->header.length);
-       if ((csum = acpi_tb_checksum((uint8_t *) x, x->header.length)) != 0) {
-               fprintf(stderr, "XSDT has bad checksum; summed to %x\n", csum);
-               exit(1);
-       }
-
-       fprintf(stderr, "allchecksums ok\n");
-
-       hexdump(stdout, r, a-(void *)r);
-
-       a = (void *)(((unsigned long)a + 0xfff) & ~0xfff);
+       a = setup_biostables(vm, a, smbiostable);
 
        bp = a;
        a = init_e820map(bp, memstart, memsize);
diff --git a/user/vmm/biostables.c b/user/vmm/biostables.c
new file mode 100644 (file)
index 0000000..6855b65
--- /dev/null
@@ -0,0 +1,311 @@
+/* Copyright (c) 2017 Google Inc.
+ * See LICENSE for details.
+ *
+ * ACPI setup. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <ros/arch/mmu.h>
+#include <vmm/vmm.h>
+
+#include <vmm/acpi/acpi.h>
+#include <vmm/acpi/vmm_simple_dsdt.h>
+
+/* By 1999, you could just scan the hardware
+ * and work it out. But 2005, that was no longer possible. How sad.
+ * so we have to fake acpi to make it all work.
+ * This will be copied to memory at 0xe0000, so the kernel can find it.
+ */
+
+/* assume they're all 256 bytes long just to make it easy.
+ * Just have pointers that point to aligned things.
+ */
+
+struct acpi_table_rsdp rsdp = {
+       .signature = ACPI_SIG_RSDP,
+       .oem_id = "AKAROS",
+       .revision = 2,
+       .length = 36,
+};
+
+struct acpi_table_xsdt xsdt = {
+       .header = {
+               .signature = ACPI_SIG_DSDT,
+               .revision = 2,
+               .oem_id = "AKAROS",
+               .oem_table_id = "ALPHABET",
+               .oem_revision = 0,
+               .asl_compiler_id = "RON ",
+               .asl_compiler_revision = 0,
+       },
+};
+struct acpi_table_fadt fadt = {
+       .header = {
+               .signature = ACPI_SIG_FADT,
+               .revision = 2,
+               .oem_id = "AKAROS",
+               .oem_table_id = "ALPHABET",
+               .oem_revision = 0,
+               .asl_compiler_id = "RON ",
+               .asl_compiler_revision = 0,
+       },
+};
+
+
+/* This has to be dropped into memory, then the other crap just follows it.
+ */
+struct acpi_table_madt madt = {
+       .header = {
+               .signature = ACPI_SIG_MADT,
+               .revision = 2,
+               .oem_id = "AKAROS",
+               .oem_table_id = "ALPHABET",
+               .oem_revision = 0,
+               .asl_compiler_id = "RON ",
+               .asl_compiler_revision = 0,
+       },
+
+       .address = APIC_GPA,
+       .flags = 0,
+};
+
+struct acpi_madt_io_apic
+       Apic1 = {.header = {.type = ACPI_MADT_TYPE_IO_APIC,
+                .length = sizeof(struct acpi_madt_io_apic)},
+                .id = 0, .address = 0xfec00000, .global_irq_base = 0};
+
+struct acpi_madt_interrupt_override isor[] = {
+       /* From the ACPI Specification Version 6.1: For example, if your machine has
+        * the ISA Programmable Interrupt Timer (PIT) connected to ISA IRQ 0, but in
+        * APIC mode, it is connected to I/O APIC interrupt input 2, then you would
+        * need an Interrupt Source Override where the source entry is ‘0’
+        * and the Global System Interrupt is ‘2.’ */
+};
+
+void lowmem(void)
+{
+       asm volatile (".section .lowmem, \"aw\";"
+                     "low: ;"
+                     ".=0x1000;"
+                     ".align 0x100000;"
+                     ".previous;");
+}
+
+static uint8_t acpi_tb_checksum(uint8_t *buffer, uint32_t length)
+{
+       uint8_t sum = 0;
+       uint8_t *end = buffer + length;
+
+       fprintf(stderr, "tbchecksum %p for %d", buffer, length);
+       while (buffer < end) {
+               if (end - buffer < 2)
+                       fprintf(stderr, "%02x\n", sum);
+               sum = (uint8_t)(sum + *(buffer++));
+       }
+       fprintf(stderr, " is %02x\n", sum);
+       return sum;
+}
+
+static void gencsum(uint8_t *target, void *data, int len)
+{
+       uint8_t csum;
+       // blast target to zero so it does not get counted
+       // (it might be in the struct we checksum) And, yes, it is, goodness.
+       fprintf(stderr, "gencsum %p target %p source %d bytes\n", target, data,
+               len);
+       *target = 0;
+       csum = acpi_tb_checksum((uint8_t *)data, len);
+       *target = ~csum + 1;
+       fprintf(stderr, "Cmoputed is %02x\n", *target);
+}
+
+/* Initialize the MADT structs for each local apic. */
+static void *init_madt_local_apic(struct virtual_machine *vm, void *start)
+{
+       struct acpi_madt_local_apic *apic = start;
+
+       for (int i = 0; i < vm->nr_gpcs; i++) {
+               apic->header.type = ACPI_MADT_TYPE_LOCAL_APIC;
+               apic->header.length = sizeof(struct acpi_madt_local_apic);
+               apic->processor_id = i;
+               apic->id = i;
+               apic->lapic_flags = 1;
+               apic = (void *)apic + sizeof(struct acpi_madt_local_apic);
+       }
+       return apic;
+}
+
+/* Initialize the MADT structs for each local x2apic. */
+static void *init_madt_local_x2apic(struct virtual_machine *vm, void *start)
+{
+       struct acpi_madt_local_x2apic *apic = start;
+
+       for (int i = 0; i < vm->nr_gpcs; i++) {
+               apic->header.type = ACPI_MADT_TYPE_LOCAL_X2APIC;
+               apic->header.length = sizeof(struct acpi_madt_local_x2apic);
+               apic->local_apic_id = i;
+               apic->uid = i;
+               apic->lapic_flags = 1;
+               apic = (void *)apic + sizeof(struct acpi_madt_local_x2apic);
+       }
+       return apic;
+}
+
+static int cat(char *file, void *where)
+{
+       int fd;
+       int amt, tot = 0;
+
+       fd = open(file, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       while (amt = read(fd, where, 4096)) {
+               if (amt < 0) {
+                       close(fd);
+                       return -1;
+               }
+               tot += amt;
+               where += amt;
+       }
+       close(fd);
+       return tot;
+}
+
+static int smbios(char *smbiostable, void *esegment)
+{
+       int amt;
+
+       amt = cat(smbiostable, esegment);
+       if (amt < 0) {
+               fprintf(stderr, "%s: %r\n", smbiostable);
+               exit(1);
+       }
+
+       return amt;
+}
+
+void *setup_biostables(struct virtual_machine *vm,
+                       void *a, void *smbiostable)
+{
+       struct acpi_table_rsdp *r;
+       struct acpi_table_fadt *f;
+       struct acpi_table_madt *m;
+       struct acpi_table_xsdt *x;
+       void *low1m;
+       uint8_t csum;
+
+
+       // The low 1m is so we can fill in bullshit like ACPI.
+       // And, sorry, due to the STUPID format of the RSDP for now we need the low
+       // 1M.
+       low1m = mmap((int*)4096, MiB-4096, PROT_READ | PROT_WRITE,
+                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+       if (low1m != (void *)4096) {
+               perror("Unable to mmap low 1m");
+               exit(1);
+       }
+
+       /* As I understood it, the spec was that SMBIOS
+        * tables live at f0000. We've been finding that
+        * they can have pointers to exxxx. So, for now,
+        * we assume you will take a 128K snapshot of flash
+        * and we'll just splat the whole mess in at
+        * 0xe0000. We can get more sophisticated about
+        * this later if needed. TODO: parse the table,
+        * and make sure that ACPI doesn't trash it.
+        * Although you'll know instantly if that happens
+        * as you'll get dmidecode errors. But it still needs
+        * to be better. */
+       if (smbiostable) {
+               fprintf(stderr, "Using SMBIOS table %s\n", smbiostable);
+               smbios(smbiostable, (void *)0xe0000);
+       }
+
+       r = a;
+       fprintf(stderr, "install rsdp to %p\n", r);
+       *r = rsdp;
+       a += sizeof(*r);
+       r->xsdt_physical_address = (uint64_t)a;
+       gencsum(&r->checksum, r, ACPI_RSDP_CHECKSUM_LENGTH);
+       csum = acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_CHECKSUM_LENGTH);
+       if (csum != 0) {
+               fprintf(stderr, "RSDP has bad checksum; summed to %x\n", csum);
+               exit(1);
+       }
+
+       /* Check extended checksum if table version >= 2 */
+       gencsum(&r->extended_checksum, r, ACPI_RSDP_XCHECKSUM_LENGTH);
+       if ((rsdp.revision >= 2) &&
+           (acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+               fprintf(stderr, "RSDP has bad checksum v2\n");
+               exit(1);
+       }
+
+       /* just leave a bunch of space for the xsdt. */
+       /* we need to zero the area since it has pointers. */
+       x = a;
+       a += sizeof(*x) + 8*sizeof(void *);
+       memset(x, 0, a - (void *)x);
+       fprintf(stderr, "install xsdt to %p\n", x);
+       *x = xsdt;
+       x->table_offset_entry[0] = 0;
+       x->table_offset_entry[1] = 0;
+       x->header.length = a - (void *)x;
+
+       f = a;
+       fprintf(stderr, "install fadt to %p\n", f);
+       *f = fadt;
+       x->table_offset_entry[0] = (uint64_t)f; // fadt MUST be first in xsdt!
+       a += sizeof(*f);
+       f->header.length = a - (void *)f;
+
+       f->Xdsdt = (uint64_t) a;
+       fprintf(stderr, "install dsdt to %p\n", a);
+       memcpy(a, &DSDT_DSDTTBL_Header, 36);
+       a += 36;
+
+       gencsum(&f->header.checksum, f, f->header.length);
+       if (acpi_tb_checksum((uint8_t *)f, f->header.length) != 0) {
+               fprintf(stderr, "fadt has bad checksum v2\n");
+               exit(1);
+       }
+
+       m = a;
+       *m = madt;
+       x->table_offset_entry[3] = (uint64_t) m;
+       a += sizeof(*m);
+       fprintf(stderr, "install madt to %p\n", m);
+
+       a = init_madt_local_apic(vm, a);
+
+       memmove(a, &Apic1, sizeof(Apic1));
+       a += sizeof(Apic1);
+
+       a = init_madt_local_x2apic(vm, a);
+
+       memmove(a, &isor, sizeof(isor));
+       a += sizeof(isor);
+       m->header.length = a - (void *)m;
+
+       gencsum(&m->header.checksum, m, m->header.length);
+       if (acpi_tb_checksum((uint8_t *) m, m->header.length) != 0) {
+               fprintf(stderr, "madt has bad checksum v2\n");
+               exit(1);
+       }
+
+       gencsum(&x->header.checksum, x, x->header.length);
+       csum = acpi_tb_checksum((uint8_t *) x, x->header.length);
+       if (csum != 0) {
+               fprintf(stderr, "XSDT has bad checksum; summed to %x\n", csum);
+               exit(1);
+       }
+
+       fprintf(stderr, "allchecksums ok\n");
+
+       a = (void *)(((unsigned long)a + 0xfff) & ~0xfff);
+
+       return a;
+}
index 47b8c70..566b4e4 100644 (file)
@@ -28,6 +28,9 @@
 
 #define VM_PAGE_FAULT                  14
 
+// APIC Guest Physical Address, a well known constant.
+#define APIC_GPA                       0xfee00000ULL
+
 /* The listing of VIRTIO MMIO devices. We currently only expect to have 2,
  * console and network. Only the console is fully implemented right now.*/
 enum {
@@ -118,3 +121,5 @@ void checkmemaligned(unsigned long long memstart, unsigned long long memsize);
 void mmap_memory(unsigned long long memstart, unsigned long long memsize);
 void *setup_paging(unsigned long long memstart, unsigned long long memsize,
                    bool debug);
+void *setup_biostables(struct virtual_machine *vm,
+                       void *a, void *smbiostable);