Start putting together ACPI for guests.
authorRonald G. Minnich <rminnich@gmail.com>
Sat, 29 Aug 2015 01:13:38 +0000 (18:13 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 Nov 2015 23:53:49 +0000 (18:53 -0500)
This sucks, but has to happen if we want to let guests use
x2apic without lots of mods to the kernel.

But I still hate acpi.

This needs to get all library-ized once I learn how to make it work.

Worst case is we end up writing ACPI code and compiling it with iasl.

I'd really rather avoid that.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/acpi.c
kern/include/acpi.h
tests/vmm/vmrunkernel.c
user/vmm/decode.c

index 9ff3eb8..d5aa3a3 100644 (file)
@@ -498,6 +498,7 @@ static char *dumpfadt(char *start, char *end, struct Fadt *fp)
                return NULL;
        }
 
+       start = seprintf(start, end, "acpi: FADT@%p\n", fp);
        start = seprintf(start, end, "acpi: fadt: facs: $%p\n", fp->facs);
        start = seprintf(start, end, "acpi: fadt: dsdt: $%p\n", fp->dsdt);
        start = seprintf(start, end, "acpi: fadt: pmprofile: $%p\n", fp->pmprofile);
@@ -684,7 +685,7 @@ static struct Atable *acpimsct(uint8_t * p, int len)
 
 static char *dumpsrat(char *start, char *end, struct Srat *st)
 {
-       start = seprintf(start, end, "acpi: srat:\n");
+       start = seprintf(start, end, "acpi: START@%p:\n", st);
        for (; st != NULL; st = st->next)
                switch (st->type) {
                        case SRlapic:
@@ -885,8 +886,8 @@ static char *dumpmadt(char *start, char *end, struct Madt *apics)
        struct Apicst *st;
 
        start =
-               seprintf(start, end, "acpi: madt lapic paddr %p pcat %d:\n",
-                                apics->lapicpa, apics->pcat);
+               seprintf(start, end, "acpi: MADT@%p: lapic paddr %p pcat %d:\n",
+                               apics, apics->lapicpa, apics->pcat);
        for (st = apics->st; st != NULL; st = st->next)
 
                switch (st->type) {
index 284ed4c..56031df 100644 (file)
@@ -384,6 +384,7 @@ struct Xsdt {
        uint8_t *p;
 };
 
+
 extern uintptr_t acpimblocksize(uintptr_t, int *);
 
 int acpiinit(void);
index a43295f..07cc712 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/mman.h>
 #include <vmm/coreboot_tables.h>
 #include <vmm/vmm.h>
+#include <acpi/acpi.h>
 #include <ros/arch/mmu.h>
 #include <ros/vmx.h>
 #include <parlib/uthread.h>
  */
 /* assume they're all 256 bytes long just to make it easy. Just have pointers that point to aligned things. */
 
-struct Rsdp rsdp = {
-       .signature = "RSDP PTR ",
-       .rchecksum = 0,
-       .oemid = "AKAROS",
-       .raddr = [0x00, 0x01, 0xe0, 0x00], // 0x00e00100
+struct acpi_table_rsdp rsdp = {
+       .signature = "RSD PTR ",
+       .oem_id = "AKAROS",
        .revision = 2,
        .length = 36,
 };
 
+struct acpi_table_xsdt xsdt = {
+       .header = {
+               .signature= "XSDT",
+               // This is so stupid. Incredibly stupid.
+               .revision = 0,
+               .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= "FADT",
+               // This is so stupid. Incredibly stupid.
+               .revision = 0,
+               .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.
- * this starts at 0xe00100
  */
-struct Sdthdr fmadt = {
-       .sig = "MADT",
-       .length = 0,
-       .rev = 0,
-       .csum = 0,
-       .oemid = "AKAROS",
-       .oemtblid = "GOOGGOOD",
-       .oemrev = "WORK",
-       .creatorid = "NAN ",
-       .creatorrev = "WAN "
+struct acpi_table_madt madt = {
+       .header = {
+               .signature = "APIC",
+               .revision = 0,
+               .oem_id = "AKAROS",
+               .oem_table_id = "ALPHABET",
+               .oem_revision = 0,
+               .asl_compiler_id = "RON ",
+               .asl_compiler_revision = 0,
+       },
+       
+       .address = 0xfee00000ULL,
 };
 
-struct Madt madt = {
-       .lapicpa = 0xfee00000ULL,
-       .pcat = 0,
-       // Intel screwed this up. They put a pointer here, but it seems to imply an array? Who knows? 
-       .st = 0x00e00200;
-};
+struct acpi_madt_local_apic Apic0 = {.header = {.type = ACPI_MADT_TYPE_LOCAL_APIC, .length = sizeof(struct acpi_madt_local_apic)},
+                                    .processor_id = 0, .id = 0};
+struct acpi_madt_io_apic Apic1 = {.header = {.type = ACPI_MADT_TYPE_IO_APIC, .length = sizeof(struct acpi_madt_io_apic)},
+                                 .id = 1, .address = 0xfec00000, .global_irq_base = 0};
 
-struct Apicst Apic0 = {.type = 0, .next = 0x00e00300, .pid = 0, .id = 0};
-struct Apicst Apic1 = {.type = 1, .next = 0x00000000, .id = 1, .ibase = 0xfec00000, .ibase 0};
-       
-/* the array of things. These get copied to consecutive 256-byte boundary areas starting at 0xe0000 */
-void *apicarray[] = { &rsdp, &fmadt, &madt, &Apic0, &Apic1};
 /* this test will run the "kernel" in the negative address space. We hope. */
 void *low1m;
 uint8_t low4k[4096];
@@ -213,21 +231,53 @@ 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;
+       printf("tbchecksum %p for %d", buffer, length);
+       while (buffer < end) {
+               if (end - buffer < 2)
+                       printf("%02x\n", sum);
+               sum = (uint8_t)(sum + *(buffer++));
+       }
+       printf(" 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.
+       printf("gencsum %p target %p source %d bytes\n", target, data, len);
+       *target = 0;
+       csum  = acpi_tb_checksum((uint8_t *)data, len);
+       *target = ~csum + 1;
+       printf("Cmoputed is %02x\n", *target);
+}
+
 int main(int argc, char **argv)
 {
+       void *a = (void *)0xe0000;
+       struct acpi_table_rsdp *r;
+       struct acpi_table_fadt *f;
+       struct acpi_table_madt *m;
+       struct acpi_table_xsdt *x;
        uint64_t virtiobase = 0x100000000ULL;
        // lowmem is a bump allocated pointer to 2M at the "physbase" of memory 
        void *lowmem = (void *) 0x1000000;
-       void *rsdp = (void *) 0x1000000;
        struct vmctl vmctl;
        int amt;
        int vmmflags = 0; // Disabled probably forever. VMM_VMCALL_PRINTF;
        uint64_t entry = 0x1200000, kerneladdress = 0x1200000;
        int nr_gpcs = 1;
        int fd = open("#c/vmctl", O_RDWR), ret;
-       void * x;
+       void * xp;
        int kfd = -1;
        static char cmd[512];
+       int i;
+       uint8_t csum;
        void *coreboot_tables = (void *) 0x1165000;
 printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
 
@@ -238,6 +288,10 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
        }
        memset(_kernel, 0, sizeof(_kernel));
        memset(lowmem, 0xff, 2*1048576);
+       memset(low4k, 0xff, 4096);
+       // avoid at all costs, requires too much instruction emulation.
+       //low4k[0x40e] = 0;
+       //low4k[0x40f] = 0xe0;
 
        if (fd < 0) {
                perror("#cons/sysctl");
@@ -282,9 +336,9 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                exit(1);
        }
        // read in the kernel.
-       x = (void *)kerneladdress;
+       xp = (void *)kerneladdress;
        for(;;) {
-               amt = read(kfd, x, 1048576);
+               amt = read(kfd, xp, 1048576);
                if (amt < 0) {
                        perror("read");
                        exit(1);
@@ -292,13 +346,12 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                if (amt == 0) {
                        break;
                }
-               x += amt;
+               xp += amt;
        }
-       fprintf(stderr, "Read in %d bytes\n", x-kerneladdress);
+       fprintf(stderr, "Read in %d bytes\n", xp-kerneladdress);
        close(kfd);
-       /* blob that is faulted in from the EPT first.  we need this to be in low
-        * memory (not above the normal mmap_break), so the EPT can look it up.
-        * Note that we won't get 4096.  The min is 1MB now, and ld is there. */
+
+       // The low 1m so we can fill in bullshit like ACPI. */
        low1m = mmap((int*)4096, MiB-4096, PROT_READ | PROT_WRITE,
                         MAP_ANONYMOUS, -1, 0);
        if (low1m != (void *)4096) {
@@ -306,28 +359,72 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                exit(1);
        }
        memset(low1m, 0xff, MiB-4096);
+       r = a;
+       fprintf(stderr, "install rsdp to %p\n", r);
+       *r = rsdp;
+       a += sizeof(*r);
+       memmove(&r->xsdt_physical_address, &a, sizeof(a));
+       gencsum(&r->checksum, r, ACPI_RSDP_CHECKSUM_LENGTH);
+       if ((csum = acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_CHECKSUM_LENGTH)) != 0) {
+               printf("RSDP has bad checksum; summed to %x\n", csum);
+               exit(1);
+       }
 
-       /* read in acpi. */
-       kfd = open("#P/realmodemem", 0);
-       if (kfd < 0) {
-               perror("#P/realmodemem");
+       /* 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)) {
+               printf("RSDP has bad checksum v2\n");
+               exit(1);
        }
-       amt = read(kfd, low4k, sizeof(low4k));
-       if (amt < sizeof(low4k)) {
-               fprintf(stderr, "read 4k: %d\n", amt);
-               perror("read");
+
+       /* 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[2] = (uint64_t) f;
+       a += sizeof(*f);
+       f->header.length = a - (void *)f;
+       gencsum(&f->header.checksum, f, f->header.length);
+       if (acpi_tb_checksum((uint8_t *)f, f->header.length) != 0) {
+               printf("ffadt has bad checksum v2\n");
                exit(1);
        }
-       memset(low4k, 0xff, 4096);
-       amt = read(kfd, low1m, MiB-4096);
-       if (amt < MiB-4096) {
-               fprintf(stderr, "read mib-4k: %d\n", amt);
-               perror("read");
+
+       m = a;
+       *m = madt;
+       x->table_offset_entry[3] = (uint64_t) m;
+       a += sizeof(*m);
+       fprintf(stderr, "install madt to %p\n", m);
+       memmove(a, &Apic0, sizeof(Apic0));
+       a += sizeof(Apic0);
+       memmove(a, &Apic1, sizeof(Apic1));
+       a += sizeof(Apic1);
+       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) {
+               printf("madt has bad checksum v2\n");
                exit(1);
        }
-       close(kfd);
-       printf("Read in %d bytes for RSDP\n", MiB-4096);
-       hexdump(stdout, low4k, 4096);
+       fprintf(stderr, "allchecksums ok\n");
+
+       gencsum(&x->header.checksum, x, x->header.length);
+       if ((csum = acpi_tb_checksum((uint8_t *) x, x->header.length)) != 0) {
+               printf("XSDT has bad checksum; summed to %x\n", csum);
+               exit(1);
+       }
+
+       hexdump(stdout, r, a-(void *)r);
 
        if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
                perror("Guest pcore setup failed");
@@ -346,7 +443,7 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_threads - 1);          /* ghetto incremental interface */
                for (int i = 0; i < nr_threads; i++) {
-                       x = __procinfo.vcoremap;
+                       xp = __procinfo.vcoremap;
                        printf("%p\n", __procinfo.vcoremap);
                        printf("Vcore %d mapped to pcore %d\n", i,
                                __procinfo.vcoremap[i].pcoreid);
@@ -373,7 +470,7 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
        p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
        p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
 #define _2MiB (0x200000)
-       int i;
+
        for (i = 0; i < 512; i++) {
                p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
        }
@@ -444,6 +541,8 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                                hexdump(stdout, regp, size);
                        } else {
                                printf("EPT violation: can't handle %p\n", gpa);
+                               printf("RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
+                               showstatus(stdout, &vmctl);
                                quit = 1;
                                break;
                        }
index d717878..4aa0420 100644 (file)
@@ -100,6 +100,10 @@ static int target(void *insn, int *store)
        case 0x8b:
        case 0x81:
                *store = !(*byte & 2);
+               break;
+       default:
+               fprintf(stderr, "%s: Can't happen\n", __func__);
+               break;
        }
        return s;
 }