ia64/xen-unstable

annotate tools/firmware/hvmloader/hvmloader.c @ 18621:8d993552673a

x86, hvm: Hyper-V guest interface support with small set of enlightenments

A minimal implementation of the Viridian (Hyper-V) guest
interface. The only enlightenments advertised and supported are vAPIC
MSRs and long-spin-wait notifications. The set of enlightenments can
easily be extended in future, as they are found to provide a
performance win, and configured via an extended HVM_PARAM_VIRIDIAN hvm
parameter.

Signed-off-by: Peter Johnston <peter.johnston@citrix.com>
Signed-off-by: Tim Deegan <tim.deegan@citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Oct 14 10:45:29 2008 +0100 (2008-10-14)
parents 22c9434c5d3e
children 612218519cb5
rev   line source
kaf24@8708 1 /*
keir@16992 2 * hvmloader.c: HVM bootloader.
kaf24@8708 3 *
kaf24@8708 4 * Leendert van Doorn, leendert@watson.ibm.com
kaf24@8708 5 * Copyright (c) 2005, International Business Machines Corporation.
kaf24@8708 6 *
kfraser@12554 7 * Copyright (c) 2006, Keir Fraser, XenSource Inc.
kfraser@12554 8 *
kaf24@8708 9 * This program is free software; you can redistribute it and/or modify it
kaf24@8708 10 * under the terms and conditions of the GNU General Public License,
kaf24@8708 11 * version 2, as published by the Free Software Foundation.
kaf24@8708 12 *
kaf24@8708 13 * This program is distributed in the hope it will be useful, but WITHOUT
kaf24@8708 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kaf24@8708 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
kaf24@8708 16 * more details.
kaf24@8708 17 *
kaf24@8708 18 * You should have received a copy of the GNU General Public License along with
kaf24@8708 19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
kaf24@8708 20 * Place - Suite 330, Boston, MA 02111-1307 USA.
kaf24@8708 21 */
kfraser@14959 22
kaf24@8708 23 #include "roms.h"
kfraser@14959 24 #include "acpi/acpi2_0.h"
kfraser@10976 25 #include "hypercall.h"
kfraser@10976 26 #include "util.h"
kfraser@12548 27 #include "config.h"
kaf24@12571 28 #include "apic_regs.h"
kfraser@12554 29 #include "pci_regs.h"
keir@15303 30 #include "e820.h"
keir@17374 31 #include "option_rom.h"
kfraser@10976 32 #include <xen/version.h>
kfraser@11081 33 #include <xen/hvm/params.h>
kaf24@8708 34
keir@17463 35 asm (
kfraser@12548 36 " .text \n"
kfraser@12548 37 " .globl _start \n"
kfraser@12548 38 "_start: \n"
kfraser@14373 39 /* C runtime kickoff. */
kfraser@12548 40 " cld \n"
kfraser@12548 41 " cli \n"
kfraser@14373 42 " movl $stack_top,%esp \n"
kfraser@14373 43 " movl %esp,%ebp \n"
kfraser@14373 44 " call main \n"
kfraser@14373 45 /* Relocate real-mode trampoline to 0x0. */
kfraser@14373 46 " mov $trampoline_start,%esi \n"
kfraser@14373 47 " xor %edi,%edi \n"
kfraser@14373 48 " mov $trampoline_end,%ecx \n"
kfraser@14373 49 " sub %esi,%ecx \n"
kfraser@14373 50 " rep movsb \n"
kfraser@14373 51 /* Load real-mode compatible segment state (base 0x0000, limit 0xffff). */
kfraser@12548 52 " lgdt gdt_desr \n"
kfraser@14373 53 " mov $0x0010,%ax \n"
kfraser@14373 54 " mov %ax,%ds \n"
kfraser@14373 55 " mov %ax,%es \n"
kfraser@14373 56 " mov %ax,%fs \n"
kfraser@14373 57 " mov %ax,%gs \n"
kfraser@14373 58 " mov %ax,%ss \n"
kfraser@14391 59 /* Initialise all 32-bit GPRs to zero. */
kfraser@14391 60 " xor %eax,%eax \n"
kfraser@14391 61 " xor %ebx,%ebx \n"
kfraser@14391 62 " xor %ecx,%ecx \n"
kfraser@14391 63 " xor %edx,%edx \n"
kfraser@14391 64 " xor %esp,%esp \n"
kfraser@14391 65 " xor %ebp,%ebp \n"
kfraser@14391 66 " xor %esi,%esi \n"
kfraser@14391 67 " xor %edi,%edi \n"
kfraser@14373 68 /* Enter real mode, reload all segment registers and IDT. */
kfraser@14391 69 " ljmp $0x8,$0x0 \n"
kfraser@14373 70 "trampoline_start: .code16 \n"
kfraser@14373 71 " mov %eax,%cr0 \n"
kfraser@14373 72 " ljmp $0,$1f-trampoline_start\n"
kfraser@14391 73 "1: mov %ax,%ds \n"
kfraser@14373 74 " mov %ax,%es \n"
kfraser@14373 75 " mov %ax,%fs \n"
kfraser@14373 76 " mov %ax,%gs \n"
kfraser@14373 77 " mov %ax,%ss \n"
kfraser@14373 78 " lidt 1f-trampoline_start \n"
kfraser@14373 79 " ljmp $0xf000,$0xfff0 \n"
kfraser@14373 80 "1: .word 0x3ff,0,0 \n"
kfraser@14373 81 "trampoline_end: .code32 \n"
kfraser@12548 82 " \n"
kfraser@12548 83 "gdt_desr: \n"
kfraser@12548 84 " .word gdt_end - gdt - 1 \n"
kfraser@12548 85 " .long gdt \n"
kfraser@12548 86 " \n"
kfraser@12548 87 " .align 8 \n"
kfraser@12548 88 "gdt: \n"
kfraser@12548 89 " .quad 0x0000000000000000 \n"
kfraser@14373 90 " .quad 0x00009a000000ffff \n" /* Ring 0 code, base 0 limit 0xffff */
kfraser@14373 91 " .quad 0x000092000000ffff \n" /* Ring 0 data, base 0 limit 0xffff */
kfraser@12548 92 "gdt_end: \n"
kfraser@12548 93 " \n"
kfraser@12548 94 " .bss \n"
kfraser@12548 95 " .align 8 \n"
kfraser@12548 96 "stack: \n"
kfraser@12548 97 " .skip 0x4000 \n"
kfraser@12548 98 "stack_top: \n"
keir@17467 99 " .text \n"
kfraser@12548 100 );
kaf24@8708 101
keir@17694 102 static enum { VGA_none, VGA_std, VGA_cirrus } virtual_vga = VGA_none;
kaf24@8708 103
keir@18621 104 static void init_hypercalls(void)
kfraser@10976 105 {
kfraser@12548 106 uint32_t eax, ebx, ecx, edx;
kfraser@12548 107 unsigned long i;
kfraser@12554 108 char signature[13];
kfraser@12548 109 xen_extraversion_t extraversion;
keir@18621 110 uint32_t base;
kfraser@10976 111
keir@18621 112 for ( base = 0x40000000; base < 0x40001000; base += 0x100 )
keir@18621 113 {
keir@18621 114 cpuid(base, &eax, &ebx, &ecx, &edx);
kfraser@10976 115
keir@18621 116 *(uint32_t *)(signature + 0) = ebx;
keir@18621 117 *(uint32_t *)(signature + 4) = ecx;
keir@18621 118 *(uint32_t *)(signature + 8) = edx;
keir@18621 119 signature[12] = '\0';
keir@18621 120
keir@18621 121 if ( !strcmp("XenVMMXenVMM", signature) )
keir@18621 122 break;
keir@18621 123 }
keir@18621 124
keir@18621 125 BUG_ON(strcmp("XenVMMXenVMM", signature) || ((eax - base) < 2));
kfraser@10976 126
kfraser@12554 127 /* Fill in hypercall transfer pages. */
keir@18621 128 cpuid(base + 2, &eax, &ebx, &ecx, &edx);
kfraser@12548 129 for ( i = 0; i < eax; i++ )
kfraser@12548 130 wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
kfraser@12548 131
kfraser@12554 132 /* Print version information. */
keir@18621 133 cpuid(base + 1, &eax, &ebx, &ecx, &edx);
kfraser@12548 134 hypercall_xen_version(XENVER_extraversion, extraversion);
kfraser@12554 135 printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
kfraser@10976 136 }
kfraser@10976 137
kfraser@12548 138 static void apic_setup(void)
kaf24@8708 139 {
kaf24@12571 140 /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
kaf24@12571 141 ioapic_write(0x00, IOAPIC_ID);
kaf24@8708 142
kaf24@12571 143 /* Set up Virtual Wire mode. */
kaf24@12571 144 lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
kaf24@12571 145 lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
kaf24@12571 146 lapic_write(APIC_LVT1, APIC_MODE_NMI << 8);
kaf24@8708 147 }
kaf24@8708 148
kfraser@12554 149 static void pci_setup(void)
kfraser@12554 150 {
keir@16835 151 uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd;
kfraser@12554 152 uint16_t class, vendor_id, device_id;
kfraser@12554 153 unsigned int bar, pin, link, isa_irq;
kfraser@12554 154
keir@16835 155 /* Resources assignable to PCI devices via BARs. */
keir@16835 156 struct resource {
keir@16835 157 uint32_t base, max;
keir@16835 158 } *resource;
keir@17476 159 struct resource mem_resource = { PCI_MEMBASE, PCI_MEMBASE + PCI_MEMSIZE };
keir@16835 160 struct resource io_resource = { 0xc000, 0x10000 };
keir@16835 161
keir@16834 162 /* Create a list of device BARs in descending order of size. */
keir@16834 163 struct bars {
keir@16834 164 uint32_t devfn, bar_reg, bar_sz;
keir@17694 165 } *bars = (struct bars *)SCRATCH_PHYSICAL_ADDRESS;
keir@16834 166 unsigned int i, nr_bars = 0;
keir@16834 167
kfraser@12554 168 /* Program PCI-ISA bridge with appropriate link routes. */
kfraser@15581 169 isa_irq = 0;
kfraser@15581 170 for ( link = 0; link < 4; link++ )
kfraser@12554 171 {
kfraser@15581 172 do { isa_irq = (isa_irq + 1) & 15;
kfraser@15581 173 } while ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) );
kfraser@12554 174 pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
kfraser@12554 175 printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq);
kfraser@12554 176 }
kfraser@12554 177
kfraser@12554 178 /* Program ELCR to match PCI-wired IRQs. */
kfraser@12554 179 outb(0x4d0, (uint8_t)(PCI_ISA_IRQ_MASK >> 0));
kfraser@12554 180 outb(0x4d1, (uint8_t)(PCI_ISA_IRQ_MASK >> 8));
kfraser@12554 181
kfraser@12554 182 /* Scan the PCI bus and map resources. */
kfraser@12554 183 for ( devfn = 0; devfn < 128; devfn++ )
kfraser@12554 184 {
kfraser@12554 185 class = pci_readw(devfn, PCI_CLASS_DEVICE);
kfraser@12554 186 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
kfraser@12554 187 device_id = pci_readw(devfn, PCI_DEVICE_ID);
kfraser@12554 188 if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
kfraser@12554 189 continue;
kfraser@12554 190
kfraser@12554 191 ASSERT((devfn != PCI_ISA_DEVFN) ||
kfraser@12554 192 ((vendor_id == 0x8086) && (device_id == 0x7000)));
kfraser@12554 193
kfraser@12554 194 switch ( class )
kfraser@12554 195 {
keir@17694 196 case 0x0300:
keir@17694 197 if ( (vendor_id == 0x1234) && (device_id == 0x1111) )
keir@17694 198 virtual_vga = VGA_std;
keir@17694 199 if ( (vendor_id == 0x1013) && (device_id == 0xb8) )
keir@17694 200 virtual_vga = VGA_cirrus;
keir@17694 201 break;
kfraser@12554 202 case 0x0680:
keir@17698 203 /* PIIX4 ACPI PM. Special device with special PCI config space. */
kfraser@12554 204 ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
kfraser@12554 205 pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
kfraser@12554 206 pci_writew(devfn, 0x22, 0x0000);
kfraser@12554 207 pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
kfraser@12554 208 pci_writew(devfn, 0x3d, 0x0001);
kfraser@12554 209 break;
kfraser@12554 210 case 0x0101:
keir@17911 211 if ( vendor_id == 0x8086 )
keir@17911 212 {
keir@17911 213 /* Intel ICHs since PIIX3: enable IDE legacy mode. */
keir@17911 214 pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
keir@17911 215 pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
keir@17911 216 }
keir@17698 217 break;
keir@17698 218 }
kfraser@12554 219
keir@17698 220 /* Map the I/O memory and port resources. */
keir@17698 221 for ( bar = 0; bar < 7; bar++ )
keir@17698 222 {
keir@17698 223 bar_reg = PCI_BASE_ADDRESS_0 + 4*bar;
keir@17698 224 if ( bar == 6 )
keir@17698 225 bar_reg = PCI_ROM_ADDRESS;
kfraser@12554 226
keir@17698 227 bar_data = pci_readl(devfn, bar_reg);
keir@17698 228 pci_writel(devfn, bar_reg, ~0);
keir@17698 229 bar_sz = pci_readl(devfn, bar_reg);
keir@17698 230 pci_writel(devfn, bar_reg, bar_data);
keir@17698 231 if ( bar_sz == 0 )
keir@17698 232 continue;
keir@16834 233
keir@17698 234 bar_sz &= (((bar_data & PCI_BASE_ADDRESS_SPACE) ==
keir@17698 235 PCI_BASE_ADDRESS_SPACE_MEMORY) ?
keir@17698 236 PCI_BASE_ADDRESS_MEM_MASK :
keir@17698 237 (PCI_BASE_ADDRESS_IO_MASK & 0xffff));
keir@17698 238 bar_sz &= ~(bar_sz - 1);
keir@16834 239
keir@17698 240 for ( i = 0; i < nr_bars; i++ )
keir@17698 241 if ( bars[i].bar_sz < bar_sz )
keir@17698 242 break;
keir@17698 243
keir@17698 244 if ( i != nr_bars )
keir@17698 245 memmove(&bars[i+1], &bars[i], (nr_bars-i) * sizeof(*bars));
keir@17698 246
keir@17698 247 bars[i].devfn = devfn;
keir@17698 248 bars[i].bar_reg = bar_reg;
keir@17698 249 bars[i].bar_sz = bar_sz;
keir@17698 250
keir@17698 251 nr_bars++;
keir@18405 252
keir@18405 253 /* Skip the upper-half of the address for a 64-bit BAR. */
keir@18405 254 if ( (bar_data & (PCI_BASE_ADDRESS_SPACE |
keir@18405 255 PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
keir@18405 256 (PCI_BASE_ADDRESS_SPACE_MEMORY |
keir@18405 257 PCI_BASE_ADDRESS_MEM_TYPE_64) )
keir@18405 258 bar++;
kfraser@12554 259 }
kfraser@12554 260
kfraser@12554 261 /* Map the interrupt. */
kfraser@12554 262 pin = pci_readb(devfn, PCI_INTERRUPT_PIN);
kfraser@12554 263 if ( pin != 0 )
kfraser@12554 264 {
kfraser@12554 265 /* This is the barber's pole mapping used by Xen. */
kfraser@12554 266 link = ((pin - 1) + (devfn >> 3)) & 3;
kfraser@12554 267 isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link);
kfraser@12554 268 pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq);
kfraser@12554 269 printf("pci dev %02x:%x INT%c->IRQ%u\n",
kfraser@12554 270 devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
kfraser@12554 271 }
kfraser@12554 272 }
keir@16834 273
keir@16834 274 /* Assign iomem and ioport resources in descending order of size. */
keir@16834 275 for ( i = 0; i < nr_bars; i++ )
keir@16834 276 {
keir@16834 277 devfn = bars[i].devfn;
keir@16834 278 bar_reg = bars[i].bar_reg;
keir@16834 279 bar_sz = bars[i].bar_sz;
keir@16834 280
keir@16834 281 bar_data = pci_readl(devfn, bar_reg);
keir@16834 282
keir@16834 283 if ( (bar_data & PCI_BASE_ADDRESS_SPACE) ==
keir@16834 284 PCI_BASE_ADDRESS_SPACE_MEMORY )
keir@16834 285 {
keir@16835 286 resource = &mem_resource;
keir@16834 287 bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
keir@16834 288 }
keir@16834 289 else
keir@16834 290 {
keir@16835 291 resource = &io_resource;
keir@16834 292 bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
keir@16834 293 }
keir@16834 294
keir@16835 295 base = (resource->base + bar_sz - 1) & ~(bar_sz - 1);
keir@16835 296 bar_data |= base;
keir@16835 297 base += bar_sz;
keir@16835 298
keir@16835 299 if ( (base < resource->base) || (base > resource->max) )
keir@16835 300 {
keir@16835 301 printf("pci dev %02x:%x bar %02x size %08x: no space for "
keir@16835 302 "resource!\n", devfn>>3, devfn&7, bar_reg, bar_sz);
keir@16835 303 continue;
keir@16835 304 }
keir@16835 305
keir@16835 306 resource->base = base;
keir@16834 307
keir@16834 308 pci_writel(devfn, bar_reg, bar_data);
keir@16835 309 printf("pci dev %02x:%x bar %02x size %08x: %08x\n",
keir@16835 310 devfn>>3, devfn&7, bar_reg, bar_sz, bar_data);
keir@16834 311
keir@16834 312 /* Now enable the memory or I/O mapping. */
keir@16834 313 cmd = pci_readw(devfn, PCI_COMMAND);
keir@16834 314 if ( (bar_reg == PCI_ROM_ADDRESS) ||
keir@16834 315 ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
keir@16834 316 PCI_BASE_ADDRESS_SPACE_MEMORY) )
keir@16834 317 cmd |= PCI_COMMAND_MEMORY;
keir@16834 318 else
keir@16834 319 cmd |= PCI_COMMAND_IO;
keir@16834 320 pci_writew(devfn, PCI_COMMAND, cmd);
keir@16834 321 }
kfraser@12554 322 }
kfraser@12554 323
keir@16960 324 /*
keir@16960 325 * Scan the PCI bus for the first NIC supported by etherboot, and copy
keir@16960 326 * the corresponding rom data to *copy_rom_dest. Returns the length of the
keir@16960 327 * selected rom, or 0 if no NIC found.
keir@16960 328 */
keir@16960 329 static int scan_etherboot_nic(void *copy_rom_dest)
keir@16960 330 {
keir@17374 331 struct option_rom_header *rom;
keir@17374 332 struct option_rom_pnp_header *pnph;
keir@17374 333 struct option_rom_pci_header *pcih;
keir@16960 334 uint32_t devfn;
keir@16960 335 uint16_t class, vendor_id, device_id;
keir@17374 336 uint8_t csum;
keir@17374 337 int i;
keir@16960 338
keir@16960 339 for ( devfn = 0; devfn < 128; devfn++ )
keir@16960 340 {
keir@16960 341 class = pci_readw(devfn, PCI_CLASS_DEVICE);
keir@16960 342 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
keir@16960 343 device_id = pci_readw(devfn, PCI_DEVICE_ID);
keir@16960 344
keir@16960 345 if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
keir@16960 346 continue;
keir@16960 347
keir@17374 348 /* We're only interested in NICs. */
keir@17374 349 if ( class != 0x0200 )
keir@16960 350 continue;
keir@16960 351
keir@17374 352 rom = (struct option_rom_header *)etherboot;
keir@17374 353 for ( ; ; )
keir@17374 354 {
keir@17374 355 /* Invalid signature means we're out of option ROMs. */
keir@17430 356 if ( strncmp((char *)rom->signature, "\x55\xaa", 2) ||
keir@17374 357 (rom->rom_size == 0) )
keir@17374 358 break;
keir@17374 359
keir@17374 360 /* Invalid checksum means we're out of option ROMs. */
keir@17374 361 csum = 0;
keir@17374 362 for ( i = 0; i < (rom->rom_size * 512); i++ )
keir@17374 363 csum += ((uint8_t *)rom)[i];
keir@17374 364 if ( csum != 0 )
keir@17374 365 break;
keir@17374 366
keir@17374 367 /* Check the PCI PnP header (if any) for a match. */
keir@17374 368 pcih = (struct option_rom_pci_header *)
keir@17374 369 ((char *)rom + rom->pci_header_offset);
keir@17412 370 if ( (rom->pci_header_offset != 0) &&
keir@17430 371 !strncmp((char *)pcih->signature, "PCIR", 4) &&
keir@17412 372 (pcih->vendor_id == vendor_id) &&
keir@17412 373 (pcih->device_id == device_id) )
keir@17412 374 goto found;
keir@17374 375
keir@17412 376 rom = (struct option_rom_header *)
keir@17412 377 ((char *)rom + rom->rom_size * 512);
keir@17374 378 }
keir@16960 379 }
keir@16960 380
keir@16960 381 return 0;
keir@16960 382
keir@16960 383 found:
keir@17412 384 /* Find the PnP expansion header (if any). */
keir@17412 385 pnph = ((rom->expansion_header_offset != 0)
keir@17412 386 ? ((struct option_rom_pnp_header *)
keir@17412 387 ((char *)rom + rom->expansion_header_offset))
keir@17412 388 : ((struct option_rom_pnp_header *)NULL));
keir@17430 389 while ( (pnph != NULL) && strncmp((char *)pnph->signature, "$PnP", 4) )
keir@17412 390 pnph = ((pnph->next_header_offset != 0)
keir@17412 391 ? ((struct option_rom_pnp_header *)
keir@17412 392 ((char *)rom + pnph->next_header_offset))
keir@17412 393 : ((struct option_rom_pnp_header *)NULL));
keir@17412 394
keir@17374 395 printf("Loading PXE ROM ...\n");
keir@17374 396 if ( (pnph != NULL) && (pnph->manufacturer_name_offset != 0) )
keir@17374 397 printf(" - Manufacturer: %s\n",
keir@17374 398 (char *)rom + pnph->manufacturer_name_offset);
keir@17374 399 if ( (pnph != NULL) && (pnph->product_name_offset != 0) )
keir@17374 400 printf(" - Product name: %s\n",
keir@17374 401 (char *)rom + pnph->product_name_offset);
keir@17374 402 memcpy(copy_rom_dest, rom, rom->rom_size * 512);
keir@17374 403 return rom->rom_size * 512;
keir@16960 404 }
keir@16960 405
keir@14449 406 /* Replace possibly erroneous memory-size CMOS fields with correct values. */
keir@14449 407 static void cmos_write_memory_size(void)
keir@14449 408 {
keir@15303 409 struct e820entry *map = HVM_E820;
keir@15303 410 int i, nr = *HVM_E820_NR;
keir@14449 411 uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0;
keir@14449 412
keir@14449 413 for ( i = 0; i < nr; i++ )
keir@14449 414 if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) )
keir@14449 415 break;
keir@14449 416
keir@14449 417 if ( i != nr )
keir@14449 418 {
keir@14449 419 alt_mem = ext_mem = map[i].addr + map[i].size;
keir@14449 420 ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
keir@14449 421 if ( ext_mem > 0xffff )
keir@14449 422 ext_mem = 0xffff;
keir@14449 423 alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
keir@14449 424 }
keir@14449 425
keir@14877 426 /* All BIOSes: conventional memory (CMOS *always* reports 640kB). */
keir@14449 427 cmos_outb(0x15, (uint8_t)(base_mem >> 0));
keir@14449 428 cmos_outb(0x16, (uint8_t)(base_mem >> 8));
keir@14449 429
keir@14449 430 /* All BIOSes: extended memory (1kB chunks above 1MB). */
keir@14449 431 cmos_outb(0x17, (uint8_t)( ext_mem >> 0));
keir@14449 432 cmos_outb(0x18, (uint8_t)( ext_mem >> 8));
keir@14449 433 cmos_outb(0x30, (uint8_t)( ext_mem >> 0));
keir@14449 434 cmos_outb(0x31, (uint8_t)( ext_mem >> 8));
keir@14449 435
keir@14449 436 /* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */
keir@14449 437 cmos_outb(0x34, (uint8_t)( alt_mem >> 0));
keir@14449 438 cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
Tim@13140 439 }
Tim@13140 440
keir@18394 441 static uint16_t init_xen_platform_io_base(void)
keir@18030 442 {
keir@18030 443 struct bios_info *bios_info = (struct bios_info *)ACPI_PHYSICAL_ADDRESS;
keir@18030 444 uint32_t devfn, bar_data;
keir@18030 445 uint16_t vendor_id, device_id;
keir@18030 446
keir@18394 447 bios_info->xen_pfiob = 0;
keir@18394 448
keir@18030 449 for ( devfn = 0; devfn < 128; devfn++ )
keir@18030 450 {
keir@18030 451 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
keir@18030 452 device_id = pci_readw(devfn, PCI_DEVICE_ID);
keir@18030 453 if ( (vendor_id != 0x5853) || (device_id != 0x0001) )
keir@18030 454 continue;
keir@18030 455 bar_data = pci_readl(devfn, PCI_BASE_ADDRESS_0);
keir@18030 456 bios_info->xen_pfiob = bar_data & PCI_BASE_ADDRESS_IO_MASK;
keir@18030 457 }
keir@18394 458
keir@18394 459 return bios_info->xen_pfiob;
keir@18030 460 }
keir@18030 461
kfraser@12548 462 int main(void)
kfraser@12548 463 {
keir@18191 464 int vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
keir@18394 465 uint32_t vga_ram = 0;
keir@18394 466 uint16_t xen_pfiob;
kaf24@12574 467
kfraser@12554 468 printf("HVM Loader\n");
kfraser@12548 469
kfraser@12548 470 init_hypercalls();
kfraser@12548 471
keir@17363 472 printf("CPU speed is %u MHz\n", get_cpu_mhz());
keir@17363 473
keir@17463 474 smp_initialise();
keir@17463 475
keir@18358 476 perform_tests();
keir@18358 477
kfraser@12554 478 printf("Writing SMBIOS tables ...\n");
kfraser@14959 479 smbios_sz = hvm_write_smbios_tables();
kfraser@12548 480
kfraser@12554 481 printf("Loading ROMBIOS ...\n");
kfraser@14959 482 rombios_sz = sizeof(rombios);
kfraser@14959 483 if ( rombios_sz > 0x10000 )
kfraser@14959 484 rombios_sz = 0x10000;
kfraser@14959 485 memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, rombios_sz);
kaf24@13656 486 highbios_setup();
kfraser@12548 487
kfraser@12548 488 apic_setup();
kfraser@12554 489 pci_setup();
kaf24@12574 490
kfraser@12600 491 if ( (get_vcpu_nr() > 1) || get_apic_mode() )
kaf24@12574 492 create_mp_tables();
kfraser@12548 493
keir@17694 494 switch ( virtual_vga )
kfraser@12548 495 {
keir@17694 496 case VGA_cirrus:
kfraser@12554 497 printf("Loading Cirrus VGABIOS ...\n");
kfraser@12548 498 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
kfraser@12548 499 vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
kfraser@14959 500 vgabios_sz = sizeof(vgabios_cirrusvga);
keir@17694 501 break;
keir@17694 502 case VGA_std:
kfraser@12554 503 printf("Loading Standard VGABIOS ...\n");
kfraser@12548 504 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
kfraser@12548 505 vgabios_stdvga, sizeof(vgabios_stdvga));
kfraser@14959 506 vgabios_sz = sizeof(vgabios_stdvga);
keir@17694 507 break;
keir@17694 508 default:
keir@17694 509 printf("No emulated VGA adaptor ...\n");
keir@17694 510 break;
kfraser@12548 511 }
kfraser@12548 512
keir@18394 513 if ( virtual_vga != VGA_none )
keir@18394 514 {
keir@18394 515 vga_ram = e820_malloc(8 << 20, 4096);
keir@18394 516 printf("VGA RAM at %08x\n", vga_ram);
keir@18394 517 }
keir@18394 518
keir@16960 519 etherboot_sz = scan_etherboot_nic((void*)ETHERBOOT_PHYSICAL_ADDRESS);
Tim@13140 520
kfraser@14959 521 if ( get_acpi_enabled() )
kfraser@12548 522 {
kfraser@12554 523 printf("Loading ACPI ...\n");
keir@18191 524 acpi_build_tables();
kfraser@12548 525 }
kfraser@12548 526
keir@14449 527 cmos_write_memory_size();
keir@14449 528
kfraser@14959 529 printf("BIOS map:\n");
kfraser@14959 530 if ( vgabios_sz )
kfraser@14959 531 printf(" %05x-%05x: VGA BIOS\n",
kfraser@14959 532 VGABIOS_PHYSICAL_ADDRESS,
kfraser@14959 533 VGABIOS_PHYSICAL_ADDRESS + vgabios_sz - 1);
kfraser@14959 534 if ( etherboot_sz )
kfraser@14959 535 printf(" %05x-%05x: Etherboot ROM\n",
kfraser@14959 536 ETHERBOOT_PHYSICAL_ADDRESS,
kfraser@14959 537 ETHERBOOT_PHYSICAL_ADDRESS + etherboot_sz - 1);
kfraser@14959 538 if ( smbios_sz )
kfraser@14959 539 printf(" %05x-%05x: SMBIOS tables\n",
kfraser@14959 540 SMBIOS_PHYSICAL_ADDRESS,
kfraser@14959 541 SMBIOS_PHYSICAL_ADDRESS + smbios_sz - 1);
kfraser@14959 542 if ( rombios_sz )
kfraser@14959 543 printf(" %05x-%05x: Main BIOS\n",
kfraser@14959 544 ROMBIOS_PHYSICAL_ADDRESS,
kfraser@14959 545 ROMBIOS_PHYSICAL_ADDRESS + rombios_sz - 1);
kfraser@14959 546
keir@18394 547 xen_pfiob = init_xen_platform_io_base();
keir@18394 548 if ( xen_pfiob && vga_ram )
keir@18394 549 outl(xen_pfiob + 4, vga_ram);
keir@18030 550
kfraser@14373 551 printf("Invoking ROMBIOS ...\n");
kfraser@12548 552 return 0;
kfraser@12548 553 }
kfraser@12548 554
kfraser@12548 555 /*
kfraser@12548 556 * Local variables:
kfraser@12548 557 * mode: C
kfraser@12548 558 * c-set-style: "BSD"
kfraser@12548 559 * c-basic-offset: 4
kfraser@12548 560 * tab-width: 4
kfraser@12548 561 * indent-tabs-mode: nil
kfraser@12548 562 * End:
kfraser@12548 563 */