ia64/xen-unstable

annotate tools/firmware/vmxassist/setup.c @ 12773:275a8f9a0710

Remove useless segments push/pop in VMXAssist.
According to Intel Spec, segments registors are cleared when exiting
virtual-8086 mode through trap or interrupts gate, so it's no need to
save their values in stack.
Signed-off-by: Xin Li <xin.b.li@intel.com>
author kfraser@localhost.localdomain
date Mon Dec 04 09:20:12 2006 +0000 (2006-12-04)
parents 45e34f00a78f
children 44319e9dc0c5
rev   line source
kaf24@5370 1 /*
kaf24@5370 2 * setup.c: Setup the world for vmxassist.
kaf24@5370 3 *
kaf24@5370 4 * Leendert van Doorn, leendert@watson.ibm.com
kaf24@5370 5 * Copyright (c) 2005, International Business Machines Corporation.
kaf24@5370 6 *
kaf24@5370 7 * This program is free software; you can redistribute it and/or modify it
kaf24@5370 8 * under the terms and conditions of the GNU General Public License,
kaf24@5370 9 * version 2, as published by the Free Software Foundation.
kaf24@5370 10 *
kaf24@5370 11 * This program is distributed in the hope it will be useful, but WITHOUT
kaf24@5370 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kaf24@5370 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
kaf24@5370 14 * more details.
kaf24@5370 15 *
kaf24@5370 16 * You should have received a copy of the GNU General Public License along with
kaf24@5370 17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
kaf24@5370 18 * Place - Suite 330, Boston, MA 02111-1307 USA.
kaf24@5370 19 */
kaf24@5370 20 #include "vm86.h"
kaf24@5370 21 #include "util.h"
kaf24@5370 22 #include "machine.h"
kaf24@5370 23
kaf24@5370 24 #if (VMXASSIST_BASE != TEXTADDR)
kaf24@5370 25 #error VMXAssist base mismatch
kaf24@5370 26 #endif
kaf24@5370 27
kaf24@5370 28 #define NR_PGD (PGSIZE / sizeof(unsigned))
kaf24@5370 29
kaf24@5370 30 #define min(a, b) ((a) > (b) ? (b) : (a))
kaf24@5370 31
kaf24@7095 32 /* Which CPU are we booting, and what is the initial CS segment? */
kaf24@7095 33 int booting_cpu, booting_vector;
kaf24@7095 34
kaf24@5370 35 unsigned long long gdt[] __attribute__ ((aligned(32))) = {
kaf24@5370 36 0x0000000000000000ULL, /* 0x00: reserved */
kaf24@5370 37 0x0000890000000000ULL, /* 0x08: 32-bit TSS */
kaf24@5370 38 0x00CF9A000000FFFFULL, /* 0x10: CS 32-bit */
kaf24@5370 39 0x00CF92000000FFFFULL, /* 0x18: DS 32-bit */
kaf24@5370 40 };
kaf24@5370 41
kaf24@5370 42 struct dtr gdtr = { sizeof(gdt)-1, (unsigned long) &gdt };
kaf24@5370 43
kaf24@5370 44 struct tss tss __attribute__ ((aligned(4)));
kaf24@5370 45
kaf24@5370 46 unsigned long long idt[NR_TRAPS] __attribute__ ((aligned(32)));
kaf24@5370 47
kaf24@5370 48 struct dtr idtr = { sizeof(idt)-1, (unsigned long) &idt };
kaf24@5370 49
kaf24@5370 50 #ifdef TEST
kaf24@5370 51 unsigned pgd[NR_PGD] __attribute__ ((aligned(PGSIZE))) = { 0 };
leendert@5591 52
leendert@5591 53 struct e820entry e820map[] = {
leendert@5591 54 { 0x0000000000000000ULL, 0x000000000009F800ULL, E820_RAM },
leendert@5591 55 { 0x000000000009F800ULL, 0x0000000000000800ULL, E820_RESERVED },
leendert@5591 56 { 0x00000000000C0000ULL, 0x0000000000040000ULL, E820_RESERVED },
leendert@5591 57 { 0x0000000000100000ULL, 0x0000000000000000ULL, E820_RAM },
leendert@5591 58 { 0x0000000000000000ULL, 0x0000000000003000ULL, E820_NVS },
leendert@5591 59 { 0x0000000000003000ULL, 0x000000000000A000ULL, E820_ACPI },
leendert@5591 60 };
leendert@5591 61 #endif /* TEST */
kaf24@5370 62
kaf24@5370 63 struct vmx_assist_context oldctx;
kaf24@5370 64 struct vmx_assist_context newctx;
kaf24@5370 65
kaf24@5370 66 unsigned long memory_size;
kaf24@5370 67 int initialize_real_mode;
kaf24@5370 68
kfraser@12773 69 extern char stack_top[];
kaf24@5370 70 extern unsigned trap_handlers[];
kaf24@5370 71
kaf24@5370 72 void
kaf24@5370 73 banner(void)
kaf24@5370 74 {
kaf24@5370 75 printf("VMXAssist (%s)\n", __DATE__);
kaf24@5370 76
kaf24@5370 77 /* Bochs its way to convey memory size */
kaf24@5370 78 memory_size = ((get_cmos(0x35) << 8) | get_cmos(0x34)) << 6;
kaf24@5370 79 if (memory_size > 0x3bc000)
kaf24@5370 80 memory_size = 0x3bc000;
kaf24@5370 81 memory_size = (memory_size << 10) + 0xF00000;
kaf24@5370 82 if (memory_size <= 0xF00000)
kaf24@5370 83 memory_size =
kaf24@5370 84 (((get_cmos(0x31) << 8) | get_cmos(0x30)) + 0x400) << 10;
kaf24@5370 85 memory_size += 0x400 << 10; /* + 1MB */
kaf24@5370 86
leendert@5591 87 #ifdef TEST
leendert@5591 88 /* Create an SMAP for our debug environment */
leendert@5591 89 e820map[4].size = memory_size - e820map[4].addr - PGSIZE;
leendert@5591 90 e820map[5].addr = memory_size - PGSIZE;
leendert@5591 91 e820map[6].addr = memory_size;
leendert@5591 92 e820map[7].addr += memory_size;
leendert@5591 93
kaf24@11092 94 *E820_MAP_NR = sizeof(e820map)/sizeof(e820map[0]);
kaf24@11092 95 memcpy(E820_MAP, e820map, sizeof(e820map));
leendert@5591 96 #endif
leendert@5591 97
kaf24@5370 98 printf("Memory size %ld MB\n", memory_size >> 20);
leendert@5591 99 printf("E820 map:\n");
kaf24@11092 100 print_e820_map(E820_MAP, *E820_MAP_NR);
kaf24@5370 101 printf("\n");
kaf24@5370 102 }
kaf24@5370 103
kaf24@5370 104 #ifdef TEST
kaf24@5370 105 void
kaf24@5370 106 setup_paging(void)
kaf24@5370 107 {
kaf24@5370 108 unsigned long i;
kaf24@5370 109
kaf24@5370 110 if (((unsigned)pgd & ~PGMASK) != 0)
kaf24@5370 111 panic("PGD not page aligned");
kaf24@5370 112 set_cr4(get_cr4() | CR4_PSE);
kaf24@5370 113 for (i = 0; i < NR_PGD; i++)
kaf24@5370 114 pgd[i] = (i * LPGSIZE)| PTE_PS | PTE_US | PTE_RW | PTE_P;
kaf24@5370 115 set_cr3((unsigned) pgd);
kaf24@5370 116 set_cr0(get_cr0() | (CR0_PE|CR0_PG));
kaf24@5370 117 }
kaf24@5370 118 #endif /* TEST */
kaf24@5370 119
kaf24@5370 120 void
kaf24@5370 121 setup_gdt(void)
kaf24@5370 122 {
kaf24@9137 123 unsigned long long addr = (unsigned long long) &tss;
kaf24@9137 124
kaf24@5370 125 /* setup task state segment */
kaf24@5773 126 memset(&tss, 0, sizeof(tss));
kaf24@5370 127 tss.ss0 = DATA_SELECTOR;
kaf24@5370 128 tss.esp0 = (unsigned) stack_top - 4*4;
kaf24@5370 129 tss.iomap_base = offsetof(struct tss, iomap);
kaf24@5370 130
kaf24@5370 131 /* initialize gdt's tss selector */
kaf24@9137 132 gdt[TSS_SELECTOR / sizeof(gdt[0])] |=
kaf24@5370 133 ((addr & 0xFF000000) << (56-24)) |
kaf24@5370 134 ((addr & 0x00FF0000) << (32-16)) |
kaf24@5370 135 ((addr & 0x0000FFFF) << (16)) |
kaf24@5370 136 (sizeof(tss) - 1);
kaf24@5370 137
kaf24@5370 138 /* switch to our own gdt and set current tss */
kaf24@5370 139 __asm__ __volatile__ ("lgdt %0" : : "m" (gdtr));
kaf24@5370 140 __asm__ __volatile__ ("movl %%eax,%%ds;"
kaf24@5370 141 "movl %%eax,%%es;"
kaf24@5370 142 "movl %%eax,%%fs;"
kaf24@5370 143 "movl %%eax,%%gs;"
kaf24@5370 144 "movl %%eax,%%ss" : : "a" (DATA_SELECTOR));
leendert@5519 145
leendert@5519 146 __asm__ __volatile__ ("ljmp %0,$1f; 1:" : : "i" (CODE_SELECTOR));
kaf24@5370 147
kaf24@5370 148 __asm__ __volatile__ ("ltr %%ax" : : "a" (TSS_SELECTOR));
kaf24@5370 149 }
kaf24@5370 150
kaf24@5370 151 void
kaf24@5370 152 set_intr_gate(int i, unsigned handler)
kaf24@5370 153 {
kaf24@5370 154 unsigned long long addr = handler;
kaf24@5370 155
kaf24@5370 156 idt[i] = ((addr & 0xFFFF0000ULL) << 32) | (0x8E00ULL << 32) |
kaf24@5370 157 (addr & 0xFFFFULL) | (CODE_SELECTOR << 16);
kaf24@5370 158 }
kaf24@5370 159
kaf24@5370 160 void
kaf24@5370 161 setup_idt(void)
kaf24@5370 162 {
kaf24@5370 163 int i;
kaf24@5370 164
kaf24@5370 165 for (i = 0; i < NR_TRAPS; i++)
kaf24@5370 166 set_intr_gate(i, trap_handlers[i]);
kaf24@5370 167 __asm__ __volatile__ ("lidt %0" : : "m" (idtr));
kaf24@5370 168 }
kaf24@5370 169
kaf24@5370 170 void
kaf24@5370 171 setup_pic(void)
kaf24@5370 172 {
kaf24@5370 173 /* mask all interrupts */
kaf24@5370 174 outb(PIC_MASTER + PIC_IMR, 0xFF);
kaf24@5370 175 outb(PIC_SLAVE + PIC_IMR, 0xFF);
kaf24@5370 176
kaf24@5370 177 /* setup master PIC */
kaf24@5370 178 outb(PIC_MASTER + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */
kaf24@5370 179 outb(PIC_MASTER + PIC_IMR, NR_EXCEPTION_HANDLER);
kaf24@5370 180 outb(PIC_MASTER + PIC_IMR, 1 << 2); /* slave on channel 2 */
kaf24@5370 181 outb(PIC_MASTER + PIC_IMR, 0x01);
kaf24@5370 182
kaf24@5370 183 /* setup slave PIC */
kaf24@5370 184 outb(PIC_SLAVE + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */
kaf24@5370 185 outb(PIC_SLAVE + PIC_IMR, NR_EXCEPTION_HANDLER + 8);
kaf24@5370 186 outb(PIC_SLAVE + PIC_IMR, 0x02); /* slave identity is 2 */
kaf24@5370 187 outb(PIC_SLAVE + PIC_IMR, 0x01);
kaf24@5370 188
kaf24@5370 189 /* enable all interrupts */
kaf24@5370 190 outb(PIC_MASTER + PIC_IMR, 0);
kaf24@5370 191 outb(PIC_SLAVE + PIC_IMR, 0);
kaf24@5370 192 }
kaf24@5370 193
kaf24@5370 194 void
kaf24@8708 195 setiomap(int port)
kaf24@8708 196 {
kaf24@8708 197 tss.iomap[port >> 3] |= 1 << (port & 7);
kaf24@8708 198 }
kaf24@8708 199
kaf24@8708 200 void
kaf24@5370 201 enter_real_mode(struct regs *regs)
kaf24@5370 202 {
kaf24@5370 203 /* mask off TSS busy bit */
kfraser@12773 204 gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL;
kaf24@5370 205
kaf24@5370 206 /* start 8086 emulation of BIOS */
kaf24@5370 207 if (initialize_real_mode) {
kaf24@5370 208 initialize_real_mode = 0;
kaf24@5370 209 regs->eflags |= EFLAGS_VM | 0x02;
kaf24@5370 210 regs->ves = regs->vds = regs->vfs = regs->vgs = 0xF000;
kaf24@7095 211 if (booting_cpu == 0) {
kaf24@7095 212 regs->cs = 0xF000; /* ROM BIOS POST entry point */
kaf24@5370 213 #ifdef TEST
kaf24@7095 214 regs->eip = 0xFFE0;
kaf24@5370 215 #else
kaf24@7095 216 regs->eip = 0xFFF0;
kaf24@5370 217 #endif
kaf24@7095 218 } else {
kaf24@7095 219 regs->cs = booting_vector << 8; /* AP entry point */
kaf24@7095 220 regs->eip = 0;
kaf24@7095 221 }
kfraser@12773 222
kfraser@12773 223 regs->uesp = regs->uss = 0;
kfraser@12773 224 regs->eax = regs->ecx = regs->edx = regs->ebx = 0;
kfraser@12773 225 regs->esp = regs->ebp = regs->esi = regs->edi = 0;
kaf24@8708 226
kaf24@8708 227 /* intercept accesses to the PIC */
kaf24@8708 228 setiomap(PIC_MASTER+PIC_CMD);
kaf24@8708 229 setiomap(PIC_MASTER+PIC_IMR);
kaf24@8708 230 setiomap(PIC_SLAVE+PIC_CMD);
kaf24@8708 231 setiomap(PIC_SLAVE+PIC_IMR);
kaf24@8708 232
kaf24@5370 233 printf("Starting emulated 16-bit real-mode: ip=%04x:%04x\n",
kaf24@5370 234 regs->cs, regs->eip);
kaf24@5370 235
kaf24@5370 236 mode = VM86_REAL; /* becomes previous mode */
kaf24@5370 237 set_mode(regs, VM86_REAL);
kaf24@5370 238
kaf24@7095 239 /* this should get us into 16-bit mode */
kaf24@7095 240 return;
kfraser@12773 241 }
kaf24@5370 242
kfraser@12773 243 /* go from protected to real mode */
kfraser@12773 244 regs->eflags |= EFLAGS_VM;
kfraser@12773 245 set_mode(regs, VM86_PROTECTED_TO_REAL);
kfraser@12773 246 emulate(regs);
kaf24@5370 247 }
kaf24@5370 248
kaf24@5370 249 /*
kaf24@5370 250 * Setup the environment for VMX assist.
kaf24@5370 251 * This environment consists of flat segments (code and data),
kaf24@5370 252 * its own gdt, idt, and tr.
kaf24@5370 253 */
kaf24@5370 254 void
kaf24@5370 255 setup_ctx(void)
kaf24@5370 256 {
kaf24@5370 257 struct vmx_assist_context *c = &newctx;
kaf24@5370 258
kaf24@5370 259 memset(c, 0, sizeof(*c));
kaf24@5370 260 c->eip = (unsigned long) switch_to_real_mode;
kaf24@5370 261 c->esp = (unsigned) stack_top - 4*4;
kaf24@5370 262 c->eflags = 0x2; /* no interrupts, please */
kaf24@5370 263
kaf24@5370 264 /*
kaf24@5370 265 * Obviously, vmx assist is not running with CR0_PE disabled.
kaf24@5370 266 * The reason why the vmx assist cr0 has CR0.PE disabled is
kaf24@5370 267 * that a transtion to CR0.PE causes a world switch. It seems
kaf24@5370 268 * more natural to enable CR0.PE to cause a world switch to
kaf24@5370 269 * protected mode rather than disabling it.
kaf24@5370 270 */
kaf24@5370 271 #ifdef TEST
kaf24@5370 272 c->cr0 = (get_cr0() | CR0_NE | CR0_PG) & ~CR0_PE;
kaf24@5370 273 c->cr3 = (unsigned long) pgd;
kaf24@5370 274 #else
kaf24@5370 275 c->cr0 = (get_cr0() | CR0_NE) & ~CR0_PE;
kaf24@5370 276 c->cr3 = 0;
kaf24@5370 277 #endif
kaf24@5370 278 c->cr4 = get_cr4();
kaf24@5370 279
kaf24@5370 280 c->idtr_limit = sizeof(idt)-1;
kaf24@5370 281 c->idtr_base = (unsigned long) &idt;
kaf24@5370 282
kaf24@5370 283 c->gdtr_limit = sizeof(gdt)-1;
kaf24@5370 284 c->gdtr_base = (unsigned long) &gdt;
kaf24@5370 285
kaf24@5370 286 c->cs_sel = CODE_SELECTOR;
kaf24@5370 287 c->cs_limit = 0xFFFFFFFF;
kaf24@5370 288 c->cs_base = 0;
kaf24@5370 289 c->cs_arbytes.fields.seg_type = 0xb;
kaf24@5370 290 c->cs_arbytes.fields.s = 1;
kaf24@5370 291 c->cs_arbytes.fields.dpl = 0;
kaf24@5370 292 c->cs_arbytes.fields.p = 1;
kaf24@5370 293 c->cs_arbytes.fields.avl = 0;
kaf24@5370 294 c->cs_arbytes.fields.default_ops_size = 1;
kaf24@5370 295 c->cs_arbytes.fields.g = 1;
kaf24@5370 296
kaf24@5370 297 c->ds_sel = DATA_SELECTOR;
kaf24@5370 298 c->ds_limit = 0xFFFFFFFF;
kaf24@5370 299 c->ds_base = 0;
kaf24@5370 300 c->ds_arbytes = c->cs_arbytes;
kaf24@5370 301 c->ds_arbytes.fields.seg_type = 0x3;
kaf24@5370 302
kaf24@5370 303 c->es_sel = DATA_SELECTOR;
kaf24@5370 304 c->es_limit = 0xFFFFFFFF;
kaf24@5370 305 c->es_base = 0;
kaf24@5370 306 c->es_arbytes = c->ds_arbytes;
kaf24@5370 307
kaf24@5370 308 c->ss_sel = DATA_SELECTOR;
kaf24@5370 309 c->ss_limit = 0xFFFFFFFF;
kaf24@5370 310 c->ss_base = 0;
kaf24@5370 311 c->ss_arbytes = c->ds_arbytes;
kaf24@5370 312
kaf24@5370 313 c->fs_sel = DATA_SELECTOR;
kaf24@5370 314 c->fs_limit = 0xFFFFFFFF;
kaf24@5370 315 c->fs_base = 0;
kaf24@5370 316 c->fs_arbytes = c->ds_arbytes;
kaf24@5370 317
kaf24@5370 318 c->gs_sel = DATA_SELECTOR;
kaf24@5370 319 c->gs_limit = 0xFFFFFFFF;
kaf24@5370 320 c->gs_base = 0;
kaf24@5370 321 c->gs_arbytes = c->ds_arbytes;
kaf24@5370 322
kaf24@5370 323 c->tr_sel = TSS_SELECTOR;
kaf24@5370 324 c->tr_limit = sizeof(tss) - 1;
kaf24@5370 325 c->tr_base = (unsigned long) &tss;
kaf24@5370 326 c->tr_arbytes.fields.seg_type = 0xb; /* 0x9 | 0x2 (busy) */
kaf24@5370 327 c->tr_arbytes.fields.s = 0;
kaf24@5370 328 c->tr_arbytes.fields.dpl = 0;
kaf24@5370 329 c->tr_arbytes.fields.p = 1;
kaf24@5370 330 c->tr_arbytes.fields.avl = 0;
kaf24@5370 331 c->tr_arbytes.fields.default_ops_size = 0;
kaf24@5370 332 c->tr_arbytes.fields.g = 0;
kaf24@5370 333
kaf24@5370 334 c->ldtr_sel = 0;
kaf24@5370 335 c->ldtr_limit = 0;
kaf24@5370 336 c->ldtr_base = 0;
kaf24@5370 337 c->ldtr_arbytes = c->ds_arbytes;
kaf24@5370 338 c->ldtr_arbytes.fields.seg_type = 0x2;
kaf24@5370 339 c->ldtr_arbytes.fields.s = 0;
kaf24@5370 340 c->ldtr_arbytes.fields.dpl = 0;
kaf24@5370 341 c->ldtr_arbytes.fields.p = 1;
kaf24@5370 342 c->ldtr_arbytes.fields.avl = 0;
kaf24@5370 343 c->ldtr_arbytes.fields.default_ops_size = 0;
kaf24@5370 344 c->ldtr_arbytes.fields.g = 0;
kaf24@5370 345 }
kaf24@5370 346
kaf24@5370 347 /*
kaf24@5370 348 * Start BIOS by causing a world switch to vmxassist, which causes
kaf24@5370 349 * VM8086 to be enabled and control is transfered to F000:FFF0.
kaf24@5370 350 */
kaf24@5370 351 void
kaf24@5370 352 start_bios(void)
kaf24@5370 353 {
kaf24@7095 354 if (booting_cpu == 0)
kaf24@7095 355 printf("Start BIOS ...\n");
kaf24@7095 356 else
kaf24@7095 357 printf("Start AP %d from %08x ...\n",
kaf24@7095 358 booting_cpu, booting_vector << 12);
kaf24@7095 359
kaf24@5370 360 initialize_real_mode = 1;
kaf24@8838 361 set_cr0(get_cr0() & ~CR0_PE);
kaf24@5370 362 panic("vmxassist returned"); /* "cannot happen" */
kaf24@5370 363 }
kaf24@5370 364
kaf24@5370 365 int
kaf24@7095 366 main(void)
kaf24@5370 367 {
kaf24@7095 368 if (booting_cpu == 0)
kaf24@7095 369 banner();
kaf24@7095 370
kaf24@5370 371 #ifdef TEST
kaf24@5370 372 setup_paging();
kaf24@5370 373 #endif
kaf24@7095 374
kaf24@5370 375 setup_gdt();
kaf24@5370 376 setup_idt();
kaf24@7095 377
kaf24@6611 378 #ifndef TEST
kaf24@7095 379 set_cr4(get_cr4() | CR4_VME);
kaf24@5773 380 #endif
kaf24@7095 381
kaf24@5370 382 setup_ctx();
kaf24@7095 383
kaf24@7095 384 if (booting_cpu == 0)
kaf24@7095 385 setup_pic();
kaf24@7095 386
kaf24@5370 387 start_bios();
kaf24@7095 388
kaf24@5370 389 return 0;
kaf24@5370 390 }