ia64/xen-unstable

annotate tools/firmware/hvmloader/hvmloader.c @ 18394:dade7f0bdc8d

hvm: Use main memory for video memory.

When creating an HVM domain, if e.g. another domain is created before
qemu allocates video memory, the extra 8MB memory ballooning is not
available any more, because it got consumed by the other domain.

This fixes it by taking video memory from the main memory:

- make hvmloader use e820_malloc to reserve some of the main memory
and notify ioemu of its address through the Xen platform PCI card.
- add XENMAPSPACE_mfn to the xen_add_to_physmap memory op, to allow
ioemu to move the MFNs between the original position and the PCI
mapping, when LFB acceleration is disabled/enabled
- add a remove_from_physmap memory op, to allow ioemu to unmap it
completely for the case of old guests with acceleration disabled.
- add xc_domain_memory_translate_gpfn_list to libxc to allow ioemu to
get the MFNs of the video memory.
- have xend save the PCI memory space instead of ioemu: if a memory
page is there, the guest can access it like usual memory, so xend
can safely be responsible to save it. The extra benefit is that
live migration will apply the logdirty optimization there too.
- handle old saved images, populating the video memory from ioemu if
really needed.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 14:53:39 2008 +0100 (2008-08-27)
parents 2ec019301ad8
children 1ac3e2a44dc9
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
kfraser@10976 104 static void
kfraser@10976 105 init_hypercalls(void)
kfraser@10976 106 {
kfraser@12548 107 uint32_t eax, ebx, ecx, edx;
kfraser@12548 108 unsigned long i;
kfraser@12554 109 char signature[13];
kfraser@12548 110 xen_extraversion_t extraversion;
kfraser@10976 111
kfraser@12548 112 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
kfraser@10976 113
kfraser@12548 114 *(uint32_t *)(signature + 0) = ebx;
kfraser@12548 115 *(uint32_t *)(signature + 4) = ecx;
kfraser@12548 116 *(uint32_t *)(signature + 8) = edx;
kfraser@12548 117 signature[12] = '\0';
kfraser@10976 118
keir@17448 119 BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
kfraser@10976 120
kfraser@12554 121 /* Fill in hypercall transfer pages. */
kfraser@12548 122 cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
kfraser@12548 123 for ( i = 0; i < eax; i++ )
kfraser@12548 124 wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
kfraser@12548 125
kfraser@12554 126 /* Print version information. */
kfraser@12554 127 cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
kfraser@12548 128 hypercall_xen_version(XENVER_extraversion, extraversion);
kfraser@12554 129 printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
kfraser@10976 130 }
kfraser@10976 131
kfraser@12548 132 static void apic_setup(void)
kaf24@8708 133 {
kaf24@12571 134 /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
kaf24@12571 135 ioapic_write(0x00, IOAPIC_ID);
kaf24@8708 136
kaf24@12571 137 /* Set up Virtual Wire mode. */
kaf24@12571 138 lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
kaf24@12571 139 lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
kaf24@12571 140 lapic_write(APIC_LVT1, APIC_MODE_NMI << 8);
kaf24@8708 141 }
kaf24@8708 142
kfraser@12554 143 static void pci_setup(void)
kfraser@12554 144 {
keir@16835 145 uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd;
kfraser@12554 146 uint16_t class, vendor_id, device_id;
kfraser@12554 147 unsigned int bar, pin, link, isa_irq;
kfraser@12554 148
keir@16835 149 /* Resources assignable to PCI devices via BARs. */
keir@16835 150 struct resource {
keir@16835 151 uint32_t base, max;
keir@16835 152 } *resource;
keir@17476 153 struct resource mem_resource = { PCI_MEMBASE, PCI_MEMBASE + PCI_MEMSIZE };
keir@16835 154 struct resource io_resource = { 0xc000, 0x10000 };
keir@16835 155
keir@16834 156 /* Create a list of device BARs in descending order of size. */
keir@16834 157 struct bars {
keir@16834 158 uint32_t devfn, bar_reg, bar_sz;
keir@17694 159 } *bars = (struct bars *)SCRATCH_PHYSICAL_ADDRESS;
keir@16834 160 unsigned int i, nr_bars = 0;
keir@16834 161
kfraser@12554 162 /* Program PCI-ISA bridge with appropriate link routes. */
kfraser@15581 163 isa_irq = 0;
kfraser@15581 164 for ( link = 0; link < 4; link++ )
kfraser@12554 165 {
kfraser@15581 166 do { isa_irq = (isa_irq + 1) & 15;
kfraser@15581 167 } while ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) );
kfraser@12554 168 pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
kfraser@12554 169 printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq);
kfraser@12554 170 }
kfraser@12554 171
kfraser@12554 172 /* Program ELCR to match PCI-wired IRQs. */
kfraser@12554 173 outb(0x4d0, (uint8_t)(PCI_ISA_IRQ_MASK >> 0));
kfraser@12554 174 outb(0x4d1, (uint8_t)(PCI_ISA_IRQ_MASK >> 8));
kfraser@12554 175
kfraser@12554 176 /* Scan the PCI bus and map resources. */
kfraser@12554 177 for ( devfn = 0; devfn < 128; devfn++ )
kfraser@12554 178 {
kfraser@12554 179 class = pci_readw(devfn, PCI_CLASS_DEVICE);
kfraser@12554 180 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
kfraser@12554 181 device_id = pci_readw(devfn, PCI_DEVICE_ID);
kfraser@12554 182 if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
kfraser@12554 183 continue;
kfraser@12554 184
kfraser@12554 185 ASSERT((devfn != PCI_ISA_DEVFN) ||
kfraser@12554 186 ((vendor_id == 0x8086) && (device_id == 0x7000)));
kfraser@12554 187
kfraser@12554 188 switch ( class )
kfraser@12554 189 {
keir@17694 190 case 0x0300:
keir@17694 191 if ( (vendor_id == 0x1234) && (device_id == 0x1111) )
keir@17694 192 virtual_vga = VGA_std;
keir@17694 193 if ( (vendor_id == 0x1013) && (device_id == 0xb8) )
keir@17694 194 virtual_vga = VGA_cirrus;
keir@17694 195 break;
kfraser@12554 196 case 0x0680:
keir@17698 197 /* PIIX4 ACPI PM. Special device with special PCI config space. */
kfraser@12554 198 ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
kfraser@12554 199 pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
kfraser@12554 200 pci_writew(devfn, 0x22, 0x0000);
kfraser@12554 201 pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
kfraser@12554 202 pci_writew(devfn, 0x3d, 0x0001);
kfraser@12554 203 break;
kfraser@12554 204 case 0x0101:
keir@17911 205 if ( vendor_id == 0x8086 )
keir@17911 206 {
keir@17911 207 /* Intel ICHs since PIIX3: enable IDE legacy mode. */
keir@17911 208 pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
keir@17911 209 pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
keir@17911 210 }
keir@17698 211 break;
keir@17698 212 }
kfraser@12554 213
keir@17698 214 /* Map the I/O memory and port resources. */
keir@17698 215 for ( bar = 0; bar < 7; bar++ )
keir@17698 216 {
keir@17698 217 bar_reg = PCI_BASE_ADDRESS_0 + 4*bar;
keir@17698 218 if ( bar == 6 )
keir@17698 219 bar_reg = PCI_ROM_ADDRESS;
kfraser@12554 220
keir@17698 221 bar_data = pci_readl(devfn, bar_reg);
keir@17698 222 pci_writel(devfn, bar_reg, ~0);
keir@17698 223 bar_sz = pci_readl(devfn, bar_reg);
keir@17698 224 pci_writel(devfn, bar_reg, bar_data);
keir@17698 225 if ( bar_sz == 0 )
keir@17698 226 continue;
keir@16834 227
keir@17698 228 bar_sz &= (((bar_data & PCI_BASE_ADDRESS_SPACE) ==
keir@17698 229 PCI_BASE_ADDRESS_SPACE_MEMORY) ?
keir@17698 230 PCI_BASE_ADDRESS_MEM_MASK :
keir@17698 231 (PCI_BASE_ADDRESS_IO_MASK & 0xffff));
keir@17698 232 bar_sz &= ~(bar_sz - 1);
keir@16834 233
keir@17698 234 for ( i = 0; i < nr_bars; i++ )
keir@17698 235 if ( bars[i].bar_sz < bar_sz )
keir@17698 236 break;
keir@17698 237
keir@17698 238 if ( i != nr_bars )
keir@17698 239 memmove(&bars[i+1], &bars[i], (nr_bars-i) * sizeof(*bars));
keir@17698 240
keir@17698 241 bars[i].devfn = devfn;
keir@17698 242 bars[i].bar_reg = bar_reg;
keir@17698 243 bars[i].bar_sz = bar_sz;
keir@17698 244
keir@17698 245 nr_bars++;
kfraser@12554 246 }
kfraser@12554 247
kfraser@12554 248 /* Map the interrupt. */
kfraser@12554 249 pin = pci_readb(devfn, PCI_INTERRUPT_PIN);
kfraser@12554 250 if ( pin != 0 )
kfraser@12554 251 {
kfraser@12554 252 /* This is the barber's pole mapping used by Xen. */
kfraser@12554 253 link = ((pin - 1) + (devfn >> 3)) & 3;
kfraser@12554 254 isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link);
kfraser@12554 255 pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq);
kfraser@12554 256 printf("pci dev %02x:%x INT%c->IRQ%u\n",
kfraser@12554 257 devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
kfraser@12554 258 }
kfraser@12554 259 }
keir@16834 260
keir@16834 261 /* Assign iomem and ioport resources in descending order of size. */
keir@16834 262 for ( i = 0; i < nr_bars; i++ )
keir@16834 263 {
keir@16834 264 devfn = bars[i].devfn;
keir@16834 265 bar_reg = bars[i].bar_reg;
keir@16834 266 bar_sz = bars[i].bar_sz;
keir@16834 267
keir@16834 268 bar_data = pci_readl(devfn, bar_reg);
keir@16834 269
keir@16834 270 if ( (bar_data & PCI_BASE_ADDRESS_SPACE) ==
keir@16834 271 PCI_BASE_ADDRESS_SPACE_MEMORY )
keir@16834 272 {
keir@16835 273 resource = &mem_resource;
keir@16834 274 bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
keir@16834 275 }
keir@16834 276 else
keir@16834 277 {
keir@16835 278 resource = &io_resource;
keir@16834 279 bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
keir@16834 280 }
keir@16834 281
keir@16835 282 base = (resource->base + bar_sz - 1) & ~(bar_sz - 1);
keir@16835 283 bar_data |= base;
keir@16835 284 base += bar_sz;
keir@16835 285
keir@16835 286 if ( (base < resource->base) || (base > resource->max) )
keir@16835 287 {
keir@16835 288 printf("pci dev %02x:%x bar %02x size %08x: no space for "
keir@16835 289 "resource!\n", devfn>>3, devfn&7, bar_reg, bar_sz);
keir@16835 290 continue;
keir@16835 291 }
keir@16835 292
keir@16835 293 resource->base = base;
keir@16834 294
keir@16834 295 pci_writel(devfn, bar_reg, bar_data);
keir@16835 296 printf("pci dev %02x:%x bar %02x size %08x: %08x\n",
keir@16835 297 devfn>>3, devfn&7, bar_reg, bar_sz, bar_data);
keir@16834 298
keir@16834 299 /* Now enable the memory or I/O mapping. */
keir@16834 300 cmd = pci_readw(devfn, PCI_COMMAND);
keir@16834 301 if ( (bar_reg == PCI_ROM_ADDRESS) ||
keir@16834 302 ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
keir@16834 303 PCI_BASE_ADDRESS_SPACE_MEMORY) )
keir@16834 304 cmd |= PCI_COMMAND_MEMORY;
keir@16834 305 else
keir@16834 306 cmd |= PCI_COMMAND_IO;
keir@16834 307 pci_writew(devfn, PCI_COMMAND, cmd);
keir@16834 308 }
kfraser@12554 309 }
kfraser@12554 310
keir@16747 311 static int must_load_extboot(void)
keir@16747 312 {
keir@16747 313 return (inb(0x404) == 1);
keir@16747 314 }
keir@16747 315
keir@16960 316 /*
keir@16960 317 * Scan the PCI bus for the first NIC supported by etherboot, and copy
keir@16960 318 * the corresponding rom data to *copy_rom_dest. Returns the length of the
keir@16960 319 * selected rom, or 0 if no NIC found.
keir@16960 320 */
keir@16960 321 static int scan_etherboot_nic(void *copy_rom_dest)
keir@16960 322 {
keir@17374 323 struct option_rom_header *rom;
keir@17374 324 struct option_rom_pnp_header *pnph;
keir@17374 325 struct option_rom_pci_header *pcih;
keir@16960 326 uint32_t devfn;
keir@16960 327 uint16_t class, vendor_id, device_id;
keir@17374 328 uint8_t csum;
keir@17374 329 int i;
keir@16960 330
keir@16960 331 for ( devfn = 0; devfn < 128; devfn++ )
keir@16960 332 {
keir@16960 333 class = pci_readw(devfn, PCI_CLASS_DEVICE);
keir@16960 334 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
keir@16960 335 device_id = pci_readw(devfn, PCI_DEVICE_ID);
keir@16960 336
keir@16960 337 if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
keir@16960 338 continue;
keir@16960 339
keir@17374 340 /* We're only interested in NICs. */
keir@17374 341 if ( class != 0x0200 )
keir@16960 342 continue;
keir@16960 343
keir@17374 344 rom = (struct option_rom_header *)etherboot;
keir@17374 345 for ( ; ; )
keir@17374 346 {
keir@17374 347 /* Invalid signature means we're out of option ROMs. */
keir@17430 348 if ( strncmp((char *)rom->signature, "\x55\xaa", 2) ||
keir@17374 349 (rom->rom_size == 0) )
keir@17374 350 break;
keir@17374 351
keir@17374 352 /* Invalid checksum means we're out of option ROMs. */
keir@17374 353 csum = 0;
keir@17374 354 for ( i = 0; i < (rom->rom_size * 512); i++ )
keir@17374 355 csum += ((uint8_t *)rom)[i];
keir@17374 356 if ( csum != 0 )
keir@17374 357 break;
keir@17374 358
keir@17374 359 /* Check the PCI PnP header (if any) for a match. */
keir@17374 360 pcih = (struct option_rom_pci_header *)
keir@17374 361 ((char *)rom + rom->pci_header_offset);
keir@17412 362 if ( (rom->pci_header_offset != 0) &&
keir@17430 363 !strncmp((char *)pcih->signature, "PCIR", 4) &&
keir@17412 364 (pcih->vendor_id == vendor_id) &&
keir@17412 365 (pcih->device_id == device_id) )
keir@17412 366 goto found;
keir@17374 367
keir@17412 368 rom = (struct option_rom_header *)
keir@17412 369 ((char *)rom + rom->rom_size * 512);
keir@17374 370 }
keir@16960 371 }
keir@16960 372
keir@16960 373 return 0;
keir@16960 374
keir@16960 375 found:
keir@17412 376 /* Find the PnP expansion header (if any). */
keir@17412 377 pnph = ((rom->expansion_header_offset != 0)
keir@17412 378 ? ((struct option_rom_pnp_header *)
keir@17412 379 ((char *)rom + rom->expansion_header_offset))
keir@17412 380 : ((struct option_rom_pnp_header *)NULL));
keir@17430 381 while ( (pnph != NULL) && strncmp((char *)pnph->signature, "$PnP", 4) )
keir@17412 382 pnph = ((pnph->next_header_offset != 0)
keir@17412 383 ? ((struct option_rom_pnp_header *)
keir@17412 384 ((char *)rom + pnph->next_header_offset))
keir@17412 385 : ((struct option_rom_pnp_header *)NULL));
keir@17412 386
keir@17374 387 printf("Loading PXE ROM ...\n");
keir@17374 388 if ( (pnph != NULL) && (pnph->manufacturer_name_offset != 0) )
keir@17374 389 printf(" - Manufacturer: %s\n",
keir@17374 390 (char *)rom + pnph->manufacturer_name_offset);
keir@17374 391 if ( (pnph != NULL) && (pnph->product_name_offset != 0) )
keir@17374 392 printf(" - Product name: %s\n",
keir@17374 393 (char *)rom + pnph->product_name_offset);
keir@17374 394 memcpy(copy_rom_dest, rom, rom->rom_size * 512);
keir@17374 395 return rom->rom_size * 512;
keir@16960 396 }
keir@16960 397
keir@14449 398 /* Replace possibly erroneous memory-size CMOS fields with correct values. */
keir@14449 399 static void cmos_write_memory_size(void)
keir@14449 400 {
keir@15303 401 struct e820entry *map = HVM_E820;
keir@15303 402 int i, nr = *HVM_E820_NR;
keir@14449 403 uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0;
keir@14449 404
keir@14449 405 for ( i = 0; i < nr; i++ )
keir@14449 406 if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) )
keir@14449 407 break;
keir@14449 408
keir@14449 409 if ( i != nr )
keir@14449 410 {
keir@14449 411 alt_mem = ext_mem = map[i].addr + map[i].size;
keir@14449 412 ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
keir@14449 413 if ( ext_mem > 0xffff )
keir@14449 414 ext_mem = 0xffff;
keir@14449 415 alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
keir@14449 416 }
keir@14449 417
keir@14877 418 /* All BIOSes: conventional memory (CMOS *always* reports 640kB). */
keir@14449 419 cmos_outb(0x15, (uint8_t)(base_mem >> 0));
keir@14449 420 cmos_outb(0x16, (uint8_t)(base_mem >> 8));
keir@14449 421
keir@14449 422 /* All BIOSes: extended memory (1kB chunks above 1MB). */
keir@14449 423 cmos_outb(0x17, (uint8_t)( ext_mem >> 0));
keir@14449 424 cmos_outb(0x18, (uint8_t)( ext_mem >> 8));
keir@14449 425 cmos_outb(0x30, (uint8_t)( ext_mem >> 0));
keir@14449 426 cmos_outb(0x31, (uint8_t)( ext_mem >> 8));
keir@14449 427
keir@14449 428 /* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */
keir@14449 429 cmos_outb(0x34, (uint8_t)( alt_mem >> 0));
keir@14449 430 cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
Tim@13140 431 }
Tim@13140 432
keir@18394 433 static uint16_t init_xen_platform_io_base(void)
keir@18030 434 {
keir@18030 435 struct bios_info *bios_info = (struct bios_info *)ACPI_PHYSICAL_ADDRESS;
keir@18030 436 uint32_t devfn, bar_data;
keir@18030 437 uint16_t vendor_id, device_id;
keir@18030 438
keir@18394 439 bios_info->xen_pfiob = 0;
keir@18394 440
keir@18030 441 for ( devfn = 0; devfn < 128; devfn++ )
keir@18030 442 {
keir@18030 443 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
keir@18030 444 device_id = pci_readw(devfn, PCI_DEVICE_ID);
keir@18030 445 if ( (vendor_id != 0x5853) || (device_id != 0x0001) )
keir@18030 446 continue;
keir@18030 447 bar_data = pci_readl(devfn, PCI_BASE_ADDRESS_0);
keir@18030 448 bios_info->xen_pfiob = bar_data & PCI_BASE_ADDRESS_IO_MASK;
keir@18030 449 }
keir@18394 450
keir@18394 451 return bios_info->xen_pfiob;
keir@18030 452 }
keir@18030 453
kfraser@12548 454 int main(void)
kfraser@12548 455 {
keir@18191 456 int vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
keir@16747 457 int extboot_sz = 0;
keir@18394 458 uint32_t vga_ram = 0;
keir@18394 459 uint16_t xen_pfiob;
kaf24@12574 460
kfraser@12554 461 printf("HVM Loader\n");
kfraser@12548 462
kfraser@12548 463 init_hypercalls();
kfraser@12548 464
keir@17363 465 printf("CPU speed is %u MHz\n", get_cpu_mhz());
keir@17363 466
keir@17463 467 smp_initialise();
keir@17463 468
keir@18358 469 perform_tests();
keir@18358 470
kfraser@12554 471 printf("Writing SMBIOS tables ...\n");
kfraser@14959 472 smbios_sz = hvm_write_smbios_tables();
kfraser@12548 473
kfraser@12554 474 printf("Loading ROMBIOS ...\n");
kfraser@14959 475 rombios_sz = sizeof(rombios);
kfraser@14959 476 if ( rombios_sz > 0x10000 )
kfraser@14959 477 rombios_sz = 0x10000;
kfraser@14959 478 memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, rombios_sz);
kaf24@13656 479 highbios_setup();
kfraser@12548 480
kfraser@12548 481 apic_setup();
kfraser@12554 482 pci_setup();
kaf24@12574 483
kfraser@12600 484 if ( (get_vcpu_nr() > 1) || get_apic_mode() )
kaf24@12574 485 create_mp_tables();
kfraser@12548 486
keir@17694 487 switch ( virtual_vga )
kfraser@12548 488 {
keir@17694 489 case VGA_cirrus:
kfraser@12554 490 printf("Loading Cirrus VGABIOS ...\n");
kfraser@12548 491 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
kfraser@12548 492 vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
kfraser@14959 493 vgabios_sz = sizeof(vgabios_cirrusvga);
keir@17694 494 break;
keir@17694 495 case VGA_std:
kfraser@12554 496 printf("Loading Standard VGABIOS ...\n");
kfraser@12548 497 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
kfraser@12548 498 vgabios_stdvga, sizeof(vgabios_stdvga));
kfraser@14959 499 vgabios_sz = sizeof(vgabios_stdvga);
keir@17694 500 break;
keir@17694 501 default:
keir@17694 502 printf("No emulated VGA adaptor ...\n");
keir@17694 503 break;
kfraser@12548 504 }
kfraser@12548 505
keir@18394 506 if ( virtual_vga != VGA_none )
keir@18394 507 {
keir@18394 508 vga_ram = e820_malloc(8 << 20, 4096);
keir@18394 509 printf("VGA RAM at %08x\n", vga_ram);
keir@18394 510 }
keir@18394 511
keir@16960 512 etherboot_sz = scan_etherboot_nic((void*)ETHERBOOT_PHYSICAL_ADDRESS);
Tim@13140 513
keir@16747 514 if ( must_load_extboot() )
keir@16747 515 {
keir@16747 516 printf("Loading EXTBOOT ...\n");
keir@16747 517 memcpy((void *)EXTBOOT_PHYSICAL_ADDRESS,
keir@16747 518 extboot, sizeof(extboot));
keir@16747 519 extboot_sz = sizeof(extboot);
keir@16747 520 }
keir@16747 521
kfraser@14959 522 if ( get_acpi_enabled() )
kfraser@12548 523 {
kfraser@12554 524 printf("Loading ACPI ...\n");
keir@18191 525 acpi_build_tables();
kfraser@12548 526 }
kfraser@12548 527
keir@14449 528 cmos_write_memory_size();
keir@14449 529
kfraser@14959 530 printf("BIOS map:\n");
kfraser@14959 531 if ( vgabios_sz )
kfraser@14959 532 printf(" %05x-%05x: VGA BIOS\n",
kfraser@14959 533 VGABIOS_PHYSICAL_ADDRESS,
kfraser@14959 534 VGABIOS_PHYSICAL_ADDRESS + vgabios_sz - 1);
kfraser@14959 535 if ( etherboot_sz )
kfraser@14959 536 printf(" %05x-%05x: Etherboot ROM\n",
kfraser@14959 537 ETHERBOOT_PHYSICAL_ADDRESS,
kfraser@14959 538 ETHERBOOT_PHYSICAL_ADDRESS + etherboot_sz - 1);
keir@16747 539 if ( extboot_sz )
keir@16747 540 printf(" %05x-%05x: Extboot ROM\n",
keir@16747 541 EXTBOOT_PHYSICAL_ADDRESS,
keir@16747 542 EXTBOOT_PHYSICAL_ADDRESS + extboot_sz - 1);
kfraser@14959 543 if ( smbios_sz )
kfraser@14959 544 printf(" %05x-%05x: SMBIOS tables\n",
kfraser@14959 545 SMBIOS_PHYSICAL_ADDRESS,
kfraser@14959 546 SMBIOS_PHYSICAL_ADDRESS + smbios_sz - 1);
kfraser@14959 547 if ( rombios_sz )
kfraser@14959 548 printf(" %05x-%05x: Main BIOS\n",
kfraser@14959 549 ROMBIOS_PHYSICAL_ADDRESS,
kfraser@14959 550 ROMBIOS_PHYSICAL_ADDRESS + rombios_sz - 1);
kfraser@14959 551
keir@18394 552 xen_pfiob = init_xen_platform_io_base();
keir@18394 553 if ( xen_pfiob && vga_ram )
keir@18394 554 outl(xen_pfiob + 4, vga_ram);
keir@18030 555
kfraser@14373 556 printf("Invoking ROMBIOS ...\n");
kfraser@12548 557 return 0;
kfraser@12548 558 }
kfraser@12548 559
kfraser@12548 560 /*
kfraser@12548 561 * Local variables:
kfraser@12548 562 * mode: C
kfraser@12548 563 * c-set-style: "BSD"
kfraser@12548 564 * c-basic-offset: 4
kfraser@12548 565 * tab-width: 4
kfraser@12548 566 * indent-tabs-mode: nil
kfraser@12548 567 * End:
kfraser@12548 568 */