ia64/xen-unstable

annotate tools/firmware/hvmloader/hvmloader.c @ 12634:514ed4f0e5da

[HVMLOADER][ACPI] Move SSDT initialisation to acpi/ dir.
This kills off a few hundred lines of unnecessary code.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue Nov 28 15:47:52 2006 +0000 (2006-11-28)
parents 9d6bc06919e0
children b258c7587d8d
rev   line source
kaf24@8708 1 /*
kaf24@8708 2 * hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader.
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 */
kaf24@8708 22 #include "roms.h"
kfraser@12057 23 #include "acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
kfraser@10976 24 #include "hypercall.h"
kfraser@10976 25 #include "util.h"
kfraser@11115 26 #include "smbios.h"
kfraser@12548 27 #include "config.h"
kaf24@12571 28 #include "apic_regs.h"
kfraser@12554 29 #include "pci_regs.h"
kfraser@10976 30 #include <xen/version.h>
kfraser@11081 31 #include <xen/hvm/params.h>
kfraser@12554 32 #include <xen/hvm/e820.h>
kaf24@8708 33
kaf24@8708 34 /* memory map */
kfraser@12548 35 #define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
kfraser@12548 36 #define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
kfraser@12548 37 #define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
kfraser@12548 38 #define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
kaf24@8708 39
kaf24@8708 40 /* invoke SVM's paged realmode support */
kfraser@12548 41 #define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
kaf24@8708 42
kaf24@8708 43 /*
kaf24@8708 44 * C runtime start off
kaf24@8708 45 */
kaf24@8708 46 asm(
kfraser@12548 47 " .text \n"
kfraser@12548 48 " .globl _start \n"
kfraser@12548 49 "_start: \n"
kfraser@12548 50 " cld \n"
kfraser@12548 51 " cli \n"
kfraser@12548 52 " lgdt gdt_desr \n"
kfraser@12548 53 " movl $stack_top, %esp \n"
kfraser@12548 54 " movl %esp, %ebp \n"
kfraser@12548 55 " call main \n"
kfraser@12548 56 " ud2 \n"
kfraser@12548 57 " \n"
kfraser@12548 58 "gdt_desr: \n"
kfraser@12548 59 " .word gdt_end - gdt - 1 \n"
kfraser@12548 60 " .long gdt \n"
kfraser@12548 61 " \n"
kfraser@12548 62 " .align 8 \n"
kfraser@12548 63 "gdt: \n"
kfraser@12548 64 " .quad 0x0000000000000000 \n"
kfraser@12548 65 " .quad 0x00CF92000000FFFF \n"
kfraser@12548 66 " .quad 0x00CF9A000000FFFF \n"
kfraser@12548 67 "gdt_end: \n"
kfraser@12548 68 " \n"
kfraser@12548 69 " .bss \n"
kfraser@12548 70 " .align 8 \n"
kfraser@12548 71 "stack: \n"
kfraser@12548 72 " .skip 0x4000 \n"
kfraser@12548 73 "stack_top: \n"
kfraser@12548 74 );
kaf24@8708 75
kaf24@10575 76 extern void create_mp_tables(void);
kaf24@8708 77
kfraser@10976 78 static int
kaf24@8708 79 cirrus_check(void)
kaf24@8708 80 {
kfraser@12548 81 outw(0x3C4, 0x9206);
kfraser@12548 82 return inb(0x3C5) == 0x12;
kaf24@8708 83 }
kaf24@8708 84
kfraser@10976 85 static int
kfraser@10893 86 vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
kaf24@8708 87 {
kfraser@12548 88 int eax;
kaf24@8708 89
kfraser@12548 90 __asm__ __volatile__ (
kfraser@12548 91 ".byte 0x0F,0x01,0xD9"
kfraser@12548 92 : "=a" (eax)
kfraser@12548 93 : "a"(function),
kfraser@12548 94 "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) );
kfraser@12548 95 return eax;
kaf24@8708 96 }
kaf24@8708 97
kfraser@10976 98 static int
kaf24@8708 99 check_amd(void)
kaf24@8708 100 {
kfraser@12548 101 char id[12];
kaf24@8708 102
kfraser@12548 103 __asm__ __volatile__ (
kfraser@12548 104 "cpuid"
kfraser@12548 105 : "=b" (*(int *)(&id[0])),
kfraser@12548 106 "=c" (*(int *)(&id[8])),
kfraser@12548 107 "=d" (*(int *)(&id[4]))
kfraser@12548 108 : "a" (0) );
kfraser@12548 109 return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
kaf24@8708 110 }
kaf24@8708 111
kfraser@10976 112 static void
kfraser@10976 113 wrmsr(uint32_t idx, uint64_t v)
kfraser@10976 114 {
kfraser@12548 115 __asm__ __volatile__ (
kfraser@12548 116 "wrmsr"
kfraser@12548 117 : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
kfraser@10976 118 }
kfraser@10976 119
kfraser@10976 120 static void
kfraser@10976 121 init_hypercalls(void)
kfraser@10976 122 {
kfraser@12548 123 uint32_t eax, ebx, ecx, edx;
kfraser@12548 124 unsigned long i;
kfraser@12554 125 char signature[13];
kfraser@12548 126 xen_extraversion_t extraversion;
kfraser@10976 127
kfraser@12548 128 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
kfraser@10976 129
kfraser@12548 130 *(uint32_t *)(signature + 0) = ebx;
kfraser@12548 131 *(uint32_t *)(signature + 4) = ecx;
kfraser@12548 132 *(uint32_t *)(signature + 8) = edx;
kfraser@12548 133 signature[12] = '\0';
kfraser@10976 134
kfraser@12548 135 if ( strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002) )
kfraser@12548 136 {
kfraser@12554 137 printf("FATAL: Xen hypervisor not detected\n");
kfraser@12548 138 __asm__ __volatile__( "ud2" );
kfraser@12548 139 }
kfraser@10976 140
kfraser@12554 141 /* Fill in hypercall transfer pages. */
kfraser@12548 142 cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
kfraser@12548 143 for ( i = 0; i < eax; i++ )
kfraser@12548 144 wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
kfraser@12548 145
kfraser@12554 146 /* Print version information. */
kfraser@12554 147 cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
kfraser@12548 148 hypercall_xen_version(XENVER_extraversion, extraversion);
kfraser@12554 149 printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
kfraser@10976 150 }
kfraser@10976 151
kfraser@12548 152 static void apic_setup(void)
kaf24@8708 153 {
kaf24@12571 154 /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
kaf24@12571 155 ioapic_write(0x00, IOAPIC_ID);
kaf24@8708 156
kaf24@12571 157 /* Set up Virtual Wire mode. */
kaf24@12571 158 lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
kaf24@12571 159 lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
kaf24@12571 160 lapic_write(APIC_LVT1, APIC_MODE_NMI << 8);
kaf24@8708 161 }
kaf24@8708 162
kfraser@12554 163 static void pci_setup(void)
kfraser@12554 164 {
kfraser@12554 165 uint32_t devfn, bar_reg, bar_data, bar_sz, cmd;
kfraser@12554 166 uint32_t *base, io_base = 0xc000, mem_base = HVM_BELOW_4G_MMIO_START;
kfraser@12554 167 uint16_t class, vendor_id, device_id;
kfraser@12554 168 unsigned int bar, pin, link, isa_irq;
kfraser@12554 169
kfraser@12554 170 /* Program PCI-ISA bridge with appropriate link routes. */
kfraser@12554 171 link = 0;
kfraser@12554 172 for ( isa_irq = 0; isa_irq < 15; isa_irq++ )
kfraser@12554 173 {
kfraser@12554 174 if ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) )
kfraser@12554 175 continue;
kfraser@12554 176 pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
kfraser@12554 177 printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq);
kfraser@12554 178 if ( link++ == 4 )
kfraser@12554 179 break;
kfraser@12554 180 }
kfraser@12554 181
kfraser@12554 182 /* Program ELCR to match PCI-wired IRQs. */
kfraser@12554 183 outb(0x4d0, (uint8_t)(PCI_ISA_IRQ_MASK >> 0));
kfraser@12554 184 outb(0x4d1, (uint8_t)(PCI_ISA_IRQ_MASK >> 8));
kfraser@12554 185
kfraser@12554 186 /* Scan the PCI bus and map resources. */
kfraser@12554 187 for ( devfn = 0; devfn < 128; devfn++ )
kfraser@12554 188 {
kfraser@12554 189 class = pci_readw(devfn, PCI_CLASS_DEVICE);
kfraser@12554 190 vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
kfraser@12554 191 device_id = pci_readw(devfn, PCI_DEVICE_ID);
kfraser@12554 192 if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
kfraser@12554 193 continue;
kfraser@12554 194
kfraser@12554 195 ASSERT((devfn != PCI_ISA_DEVFN) ||
kfraser@12554 196 ((vendor_id == 0x8086) && (device_id == 0x7000)));
kfraser@12554 197
kfraser@12554 198 switch ( class )
kfraser@12554 199 {
kfraser@12554 200 case 0x0680:
kfraser@12554 201 ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
kfraser@12554 202 /*
kfraser@12554 203 * PIIX4 ACPI PM. Special device with special PCI config space.
kfraser@12554 204 * No ordinary BARs.
kfraser@12554 205 */
kfraser@12554 206 pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
kfraser@12554 207 pci_writew(devfn, 0x22, 0x0000);
kfraser@12554 208 pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
kfraser@12554 209 pci_writew(devfn, 0x3d, 0x0001);
kfraser@12554 210 break;
kfraser@12554 211 case 0x0101:
kfraser@12554 212 /* PIIX3 IDE */
kfraser@12554 213 ASSERT((vendor_id == 0x8086) && (device_id == 0x7010));
kfraser@12554 214 pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
kfraser@12554 215 pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
kfraser@12554 216 /* fall through */
kfraser@12554 217 default:
kfraser@12554 218 /* Default memory mappings. */
kfraser@12554 219 for ( bar = 0; bar < 7; bar++ )
kfraser@12554 220 {
kfraser@12554 221 bar_reg = PCI_BASE_ADDRESS_0 + 4*bar;
kfraser@12554 222 if ( bar == 6 )
kfraser@12554 223 bar_reg = PCI_ROM_ADDRESS;
kfraser@12554 224
kfraser@12554 225 bar_data = pci_readl(devfn, bar_reg);
kfraser@12554 226
kfraser@12554 227 pci_writel(devfn, bar_reg, ~0);
kfraser@12554 228 bar_sz = pci_readl(devfn, bar_reg);
kfraser@12554 229 if ( bar_sz == 0 )
kfraser@12554 230 continue;
kfraser@12554 231
kfraser@12554 232 if ( (bar_data & PCI_BASE_ADDRESS_SPACE) ==
kfraser@12554 233 PCI_BASE_ADDRESS_SPACE_MEMORY )
kfraser@12554 234 {
kfraser@12554 235 base = &mem_base;
kfraser@12554 236 bar_sz &= PCI_BASE_ADDRESS_MEM_MASK;
kfraser@12554 237 bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
kfraser@12554 238 }
kfraser@12554 239 else
kfraser@12554 240 {
kfraser@12554 241 base = &io_base;
kfraser@12554 242 bar_sz &= PCI_BASE_ADDRESS_IO_MASK & 0xffff;
kfraser@12554 243 bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
kfraser@12554 244 }
kfraser@12554 245 bar_sz &= ~(bar_sz - 1);
kfraser@12554 246
kfraser@12554 247 *base = (*base + bar_sz - 1) & ~(bar_sz - 1);
kfraser@12554 248 bar_data |= *base;
kfraser@12554 249 *base += bar_sz;
kfraser@12554 250
kfraser@12554 251 pci_writel(devfn, bar_reg, bar_data);
kfraser@12554 252 printf("pci dev %02x:%x bar %02x size %08x: %08x\n",
kfraser@12554 253 devfn>>3, devfn&7, bar_reg, bar_sz, bar_data);
kfraser@12554 254
kfraser@12554 255 /* Now enable the memory or I/O mapping. */
kfraser@12554 256 cmd = pci_readw(devfn, PCI_COMMAND);
kfraser@12554 257 if ( (bar_reg == PCI_ROM_ADDRESS) ||
kfraser@12554 258 ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
kfraser@12554 259 PCI_BASE_ADDRESS_SPACE_MEMORY) )
kfraser@12554 260 cmd |= PCI_COMMAND_MEMORY;
kfraser@12554 261 else
kfraser@12554 262 cmd |= PCI_COMMAND_IO;
kfraser@12554 263 pci_writew(devfn, PCI_COMMAND, cmd);
kfraser@12554 264 }
kfraser@12554 265 break;
kfraser@12554 266 }
kfraser@12554 267
kfraser@12554 268 /* Map the interrupt. */
kfraser@12554 269 pin = pci_readb(devfn, PCI_INTERRUPT_PIN);
kfraser@12554 270 if ( pin != 0 )
kfraser@12554 271 {
kfraser@12554 272 /* This is the barber's pole mapping used by Xen. */
kfraser@12554 273 link = ((pin - 1) + (devfn >> 3)) & 3;
kfraser@12554 274 isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link);
kfraser@12554 275 pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq);
kfraser@12554 276 printf("pci dev %02x:%x INT%c->IRQ%u\n",
kfraser@12554 277 devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
kfraser@12554 278 }
kfraser@12554 279 }
kfraser@12554 280 }
kfraser@12554 281
kfraser@12548 282 int main(void)
kfraser@12548 283 {
kaf24@12574 284 int acpi_sz;
kaf24@12574 285
kfraser@12554 286 printf("HVM Loader\n");
kfraser@12548 287
kfraser@12548 288 init_hypercalls();
kfraser@12548 289
kfraser@12554 290 printf("Writing SMBIOS tables ...\n");
kfraser@12548 291 hvm_write_smbios_tables();
kfraser@12548 292
kfraser@12554 293 printf("Loading ROMBIOS ...\n");
kfraser@12548 294 memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
kfraser@12548 295
kfraser@12548 296 apic_setup();
kfraser@12554 297 pci_setup();
kaf24@12574 298
kfraser@12600 299 if ( (get_vcpu_nr() > 1) || get_apic_mode() )
kaf24@12574 300 create_mp_tables();
kfraser@12548 301
kfraser@12548 302 if ( cirrus_check() )
kfraser@12548 303 {
kfraser@12554 304 printf("Loading Cirrus VGABIOS ...\n");
kfraser@12548 305 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
kfraser@12548 306 vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
kfraser@12548 307 }
kfraser@12548 308 else
kfraser@12548 309 {
kfraser@12554 310 printf("Loading Standard VGABIOS ...\n");
kfraser@12548 311 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
kfraser@12548 312 vgabios_stdvga, sizeof(vgabios_stdvga));
kfraser@12548 313 }
kfraser@12548 314
kfraser@12548 315 if ( get_acpi_enabled() != 0 )
kfraser@12548 316 {
kfraser@12554 317 printf("Loading ACPI ...\n");
kaf24@12574 318 acpi_sz = acpi_build_tables((uint8_t *)ACPI_PHYSICAL_ADDRESS);
kfraser@12634 319 ASSERT((ACPI_PHYSICAL_ADDRESS + acpi_sz) <= 0xF0000);
kfraser@12548 320 }
kfraser@12548 321
kfraser@12548 322 if ( check_amd() )
kfraser@12548 323 {
kfraser@12548 324 /* AMD implies this is SVM */
kfraser@12554 325 printf("SVM go ...\n");
kfraser@12548 326 vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
kfraser@12548 327 }
kfraser@12548 328 else
kfraser@12548 329 {
kfraser@12554 330 printf("Loading VMXAssist ...\n");
kfraser@12548 331 memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
kfraser@12548 332 vmxassist, sizeof(vmxassist));
kfraser@12548 333
kfraser@12554 334 printf("VMX go ...\n");
kfraser@12548 335 __asm__ __volatile__(
kfraser@12548 336 "jmp *%%eax"
kfraser@12548 337 : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
kfraser@12548 338 );
kfraser@12548 339 }
kfraser@12548 340
kfraser@12554 341 printf("Failed to invoke ROMBIOS\n");
kfraser@12548 342 return 0;
kfraser@12548 343 }
kfraser@12548 344
kfraser@12548 345 /*
kfraser@12548 346 * Local variables:
kfraser@12548 347 * mode: C
kfraser@12548 348 * c-set-style: "BSD"
kfraser@12548 349 * c-basic-offset: 4
kfraser@12548 350 * tab-width: 4
kfraser@12548 351 * indent-tabs-mode: nil
kfraser@12548 352 * End:
kfraser@12548 353 */