Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Ported palacios to Kbuild
[palacios.git] / bios / vmxassist / setup.c
diff --git a/bios/vmxassist/setup.c b/bios/vmxassist/setup.c
new file mode 100644 (file)
index 0000000..0576900
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * setup.c: Setup the world for vmxassist.
+ *
+ * Leendert van Doorn, leendert@watson.ibm.com
+ * Copyright (c) 2005, International Business Machines Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "vm86.h"
+#include "util.h"
+#include "machine.h"
+
+#if (VMXASSIST_BASE != TEXTADDR)
+#error VMXAssist base mismatch
+#endif
+
+#define        NR_PGD          (PGSIZE / sizeof(unsigned))
+
+#define        min(a, b)       ((a) > (b) ? (b) : (a))
+
+/* Which CPU are we booting, and what is the initial CS segment? */
+int booting_cpu, booting_vector;
+
+unsigned long long gdt[] __attribute__ ((aligned(32))) = {
+       0x0000000000000000ULL,          /* 0x00: reserved */
+       0x0000890000000000ULL,          /* 0x08: 32-bit TSS */
+       0x00CF9A000000FFFFULL,          /* 0x10: CS 32-bit */
+       0x00CF92000000FFFFULL,          /* 0x18: DS 32-bit */
+};
+
+struct dtr gdtr = { sizeof(gdt)-1, (unsigned long) &gdt };
+
+struct tss tss __attribute__ ((aligned(4)));
+
+unsigned long long idt[NR_TRAPS] __attribute__ ((aligned(32)));
+
+struct dtr idtr = { sizeof(idt)-1, (unsigned long) &idt };
+
+#ifdef TEST
+unsigned pgd[NR_PGD] __attribute__ ((aligned(PGSIZE))) = { 0 };
+
+struct e820entry e820map[] = {
+       { 0x0000000000000000ULL, 0x000000000009F800ULL, E820_RAM },
+       { 0x000000000009F800ULL, 0x0000000000000800ULL, E820_RESERVED },
+       { 0x00000000000A0000ULL, 0x0000000000020000ULL, E820_IO },
+       { 0x00000000000C0000ULL, 0x0000000000040000ULL, E820_RESERVED },
+       { 0x0000000000100000ULL, 0x0000000000000000ULL, E820_RAM },
+       { 0x0000000000000000ULL, 0x0000000000001000ULL, E820_SHARED_PAGE },
+       { 0x0000000000000000ULL, 0x0000000000003000ULL, E820_NVS },
+       { 0x0000000000003000ULL, 0x000000000000A000ULL, E820_ACPI },
+       { 0x00000000FEC00000ULL, 0x0000000001400000ULL, E820_IO },
+};
+#endif /* TEST */
+
+struct vmx_assist_context oldctx;
+struct vmx_assist_context newctx;
+
+unsigned long memory_size;
+int initialize_real_mode;
+
+extern char stack[], stack_top[];
+extern unsigned trap_handlers[];
+
+void
+banner(void)
+{
+       printf("VMXAssist (%s)\n", __DATE__);
+
+       /* Bochs its way to convey memory size */
+       memory_size = ((get_cmos(0x35) << 8) | get_cmos(0x34)) << 6;
+       if (memory_size > 0x3bc000)
+               memory_size = 0x3bc000;
+       memory_size = (memory_size << 10) + 0xF00000;
+       if (memory_size <= 0xF00000)
+               memory_size =
+                   (((get_cmos(0x31) << 8) | get_cmos(0x30)) + 0x400) << 10;
+       memory_size += 0x400 << 10; /* + 1MB */
+
+#ifdef TEST
+       /* Create an SMAP for our debug environment */
+       e820map[4].size = memory_size - e820map[4].addr - PGSIZE;
+       e820map[5].addr = memory_size - PGSIZE;
+       e820map[6].addr = memory_size;
+       e820map[7].addr += memory_size;
+
+       *E820_MAP_NR = sizeof(e820map)/sizeof(e820map[0]);
+       memcpy(E820_MAP, e820map, sizeof(e820map));
+#endif
+
+       printf("Memory size %ld MB\n", memory_size >> 20);
+       printf("E820 map:\n");
+       print_e820_map(E820_MAP, *E820_MAP_NR);
+       printf("\n");
+}
+
+#ifdef TEST
+void
+setup_paging(void)
+{
+       unsigned long i;
+
+       if (((unsigned)pgd & ~PGMASK) != 0)
+               panic("PGD not page aligned");
+       set_cr4(get_cr4() | CR4_PSE);
+       for (i = 0; i < NR_PGD; i++)
+               pgd[i] = (i * LPGSIZE)| PTE_PS | PTE_US | PTE_RW | PTE_P;
+       set_cr3((unsigned) pgd);
+       set_cr0(get_cr0() | (CR0_PE|CR0_PG));
+}
+#endif /* TEST */
+
+void
+setup_gdt(void)
+{
+       unsigned long long addr = (unsigned long long) &tss;
+
+       /* setup task state segment */
+       memset(&tss, 0, sizeof(tss));
+       tss.ss0 = DATA_SELECTOR;
+       tss.esp0 = (unsigned) stack_top - 4*4;
+       tss.iomap_base = offsetof(struct tss, iomap);
+
+       /* initialize gdt's tss selector */
+       gdt[TSS_SELECTOR / sizeof(gdt[0])] |=
+               ((addr & 0xFF000000) << (56-24)) |
+               ((addr & 0x00FF0000) << (32-16)) |
+               ((addr & 0x0000FFFF) << (16)) |
+               (sizeof(tss) - 1);
+
+       /* switch to our own gdt and set current tss */
+       __asm__ __volatile__ ("lgdt %0" : : "m" (gdtr));
+       __asm__ __volatile__ ("movl %%eax,%%ds;"
+                             "movl %%eax,%%es;"
+                             "movl %%eax,%%fs;"
+                             "movl %%eax,%%gs;"
+                             "movl %%eax,%%ss" : : "a" (DATA_SELECTOR));
+
+       __asm__ __volatile__ ("ljmp %0,$1f; 1:" : : "i" (CODE_SELECTOR));
+
+       __asm__ __volatile__ ("ltr %%ax" : : "a" (TSS_SELECTOR));
+}
+
+void
+set_intr_gate(int i, unsigned handler)
+{
+       unsigned long long addr = handler;
+
+       idt[i] = ((addr & 0xFFFF0000ULL) << 32) | (0x8E00ULL << 32) |
+               (addr & 0xFFFFULL) | (CODE_SELECTOR << 16);
+}
+
+void
+setup_idt(void)
+{
+       int i;
+
+       for (i = 0; i < NR_TRAPS; i++)
+               set_intr_gate(i, trap_handlers[i]);
+       __asm__ __volatile__ ("lidt %0" : : "m" (idtr));
+}
+
+void
+setup_pic(void)
+{
+       /* mask all interrupts */
+       outb(PIC_MASTER + PIC_IMR, 0xFF);
+       outb(PIC_SLAVE + PIC_IMR, 0xFF);
+
+       /* setup master PIC */
+       outb(PIC_MASTER + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */
+       outb(PIC_MASTER + PIC_IMR, NR_EXCEPTION_HANDLER);
+       outb(PIC_MASTER + PIC_IMR, 1 << 2); /* slave on channel 2 */
+       outb(PIC_MASTER + PIC_IMR, 0x01);
+
+       /* setup slave PIC */
+       outb(PIC_SLAVE + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */
+       outb(PIC_SLAVE + PIC_IMR, NR_EXCEPTION_HANDLER + 8);
+       outb(PIC_SLAVE + PIC_IMR, 0x02); /* slave identity is 2 */
+       outb(PIC_SLAVE + PIC_IMR, 0x01);
+
+       /* enable all interrupts */
+       outb(PIC_MASTER + PIC_IMR, 0);
+       outb(PIC_SLAVE + PIC_IMR, 0);
+}
+
+void
+setiomap(int port)
+{
+       tss.iomap[port >> 3] |= 1 << (port & 7);
+}
+
+void
+enter_real_mode(struct regs *regs)
+{
+       /* mask off TSS busy bit */
+        gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL;
+
+       /* start 8086 emulation of BIOS */
+       if (initialize_real_mode) {
+               initialize_real_mode = 0;
+               regs->eflags |= EFLAGS_VM | 0x02;
+               regs->ves = regs->vds = regs->vfs = regs->vgs = 0xF000;
+               if (booting_cpu == 0) {
+                       regs->cs = 0xF000; /* ROM BIOS POST entry point */
+#ifdef TEST
+                       regs->eip = 0xFFE0;
+#else
+                       regs->eip = 0xFFF0;
+#endif
+               } else {
+                       regs->cs = booting_vector << 8; /* AP entry point */
+                       regs->eip = 0;
+               }
+               regs->uesp = 0;
+               regs->uss = 0;
+
+               /* intercept accesses to the PIC */
+               setiomap(PIC_MASTER+PIC_CMD);
+               setiomap(PIC_MASTER+PIC_IMR);
+               setiomap(PIC_SLAVE+PIC_CMD);
+               setiomap(PIC_SLAVE+PIC_IMR);
+
+               printf("Starting emulated 16-bit real-mode: ip=%04x:%04x\n",
+                       regs->cs, regs->eip);
+
+               mode = VM86_REAL; /* becomes previous mode */
+               set_mode(regs, VM86_REAL);
+
+               /* this should get us into 16-bit mode */
+               return;
+       } else {
+               /* go from protected to real mode */
+               regs->eflags |= EFLAGS_VM;
+
+               set_mode(regs, VM86_PROTECTED_TO_REAL);
+
+               emulate(regs);
+       }
+}
+
+/*
+ * Setup the environment for VMX assist.
+ * This environment consists of flat segments (code and data),
+ * its own gdt, idt, and tr.
+ */
+void
+setup_ctx(void)
+{
+       struct vmx_assist_context *c = &newctx;
+
+       memset(c, 0, sizeof(*c));
+       c->eip = (unsigned long) switch_to_real_mode;
+       c->esp = (unsigned) stack_top - 4*4;
+       c->eflags = 0x2; /* no interrupts, please */
+
+       /*
+        * Obviously, vmx assist is not running with CR0_PE disabled.
+        * The reason why the vmx assist cr0 has CR0.PE disabled is
+        * that a transtion to CR0.PE causes a world switch. It seems
+        * more natural to enable CR0.PE to cause a world switch to
+        * protected mode rather than disabling it.
+        */
+#ifdef TEST
+       c->cr0 = (get_cr0() | CR0_NE | CR0_PG) & ~CR0_PE;
+       c->cr3 = (unsigned long) pgd;
+#else
+       c->cr0 = (get_cr0() | CR0_NE) & ~CR0_PE;
+       c->cr3 = 0;
+#endif
+       c->cr4 = get_cr4();
+
+       c->idtr_limit = sizeof(idt)-1;
+       c->idtr_base = (unsigned long) &idt;
+
+       c->gdtr_limit = sizeof(gdt)-1;
+       c->gdtr_base = (unsigned long) &gdt;
+
+       c->cs_sel = CODE_SELECTOR;
+       c->cs_limit = 0xFFFFFFFF;
+       c->cs_base = 0;
+       c->cs_arbytes.fields.seg_type = 0xb;
+       c->cs_arbytes.fields.s = 1;
+       c->cs_arbytes.fields.dpl = 0;
+       c->cs_arbytes.fields.p = 1;
+       c->cs_arbytes.fields.avl = 0;
+       c->cs_arbytes.fields.default_ops_size = 1;
+       c->cs_arbytes.fields.g = 1;
+
+       c->ds_sel = DATA_SELECTOR;
+       c->ds_limit = 0xFFFFFFFF;
+       c->ds_base = 0;
+       c->ds_arbytes = c->cs_arbytes;
+       c->ds_arbytes.fields.seg_type = 0x3;
+
+       c->es_sel = DATA_SELECTOR;
+       c->es_limit = 0xFFFFFFFF;
+       c->es_base = 0;
+       c->es_arbytes = c->ds_arbytes;
+
+       c->ss_sel = DATA_SELECTOR;
+       c->ss_limit = 0xFFFFFFFF;
+       c->ss_base = 0;
+       c->ss_arbytes = c->ds_arbytes;
+
+       c->fs_sel = DATA_SELECTOR;
+       c->fs_limit = 0xFFFFFFFF;
+       c->fs_base = 0;
+       c->fs_arbytes = c->ds_arbytes;
+
+       c->gs_sel = DATA_SELECTOR;
+       c->gs_limit = 0xFFFFFFFF;
+       c->gs_base = 0;
+       c->gs_arbytes = c->ds_arbytes;
+
+       c->tr_sel = TSS_SELECTOR;
+       c->tr_limit = sizeof(tss) - 1;
+       c->tr_base = (unsigned long) &tss;
+       c->tr_arbytes.fields.seg_type = 0xb; /* 0x9 | 0x2 (busy) */
+       c->tr_arbytes.fields.s = 0;
+       c->tr_arbytes.fields.dpl = 0;
+       c->tr_arbytes.fields.p = 1;
+       c->tr_arbytes.fields.avl = 0;
+       c->tr_arbytes.fields.default_ops_size = 0;
+       c->tr_arbytes.fields.g = 0;
+
+       c->ldtr_sel = 0;
+       c->ldtr_limit = 0;
+       c->ldtr_base = 0;
+       c->ldtr_arbytes = c->ds_arbytes;
+       c->ldtr_arbytes.fields.seg_type = 0x2;
+       c->ldtr_arbytes.fields.s = 0;
+       c->ldtr_arbytes.fields.dpl = 0;
+       c->ldtr_arbytes.fields.p = 1;
+       c->ldtr_arbytes.fields.avl = 0;
+       c->ldtr_arbytes.fields.default_ops_size = 0;
+       c->ldtr_arbytes.fields.g = 0;
+}
+
+/*
+ * Start BIOS by causing a world switch to vmxassist, which causes
+ * VM8086 to be enabled and control is transfered to F000:FFF0.
+ */
+void
+start_bios(void)
+{
+       if (booting_cpu == 0)
+               printf("Start BIOS ...\n");
+       else
+               printf("Start AP %d from %08x ...\n",
+                      booting_cpu, booting_vector << 12);
+
+       initialize_real_mode = 1;
+       set_cr0(get_cr0() & ~CR0_PE);
+       panic("vmxassist returned"); /* "cannot happen" */
+}
+
+int
+main(void)
+{
+
+  printf("Hello from VMXAssist\n");
+
+       if (booting_cpu == 0)
+               banner();
+
+#ifdef TEST
+       setup_paging();
+#endif
+
+       setup_gdt();
+       setup_idt();
+
+#ifndef        TEST
+       set_cr4(get_cr4() | CR4_VME);
+#endif
+
+       setup_ctx();
+
+       if (booting_cpu == 0)
+               setup_pic();
+
+       start_bios();
+
+       return 0;
+}