aboutsummaryrefslogtreecommitdiffstats
path: root/tools/firmware/hvmloader/hvmloader.c
diff options
context:
space:
mode:
authorHollis Blanchard <hollisb@us.ibm.com>2006-11-29 14:16:36 -0600
committerHollis Blanchard <hollisb@us.ibm.com>2006-11-29 14:16:36 -0600
commitab26a6a563a0acb589af87a8e063c0e171d75665 (patch)
tree71a432bde5d016e928ab3ad7860fca01312ec787 /tools/firmware/hvmloader/hvmloader.c
parentd3be8a6ca1aa9312cc01e780a2fea56ab8ec12b4 (diff)
parent1c804664cf63f0c2e80d0420e52d5f82c3956685 (diff)
downloadxen-ab26a6a563a0acb589af87a8e063c0e171d75665.tar.gz
xen-ab26a6a563a0acb589af87a8e063c0e171d75665.tar.bz2
xen-ab26a6a563a0acb589af87a8e063c0e171d75665.zip
Merge with xen-unstable.hg.
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Diffstat (limited to 'tools/firmware/hvmloader/hvmloader.c')
-rw-r--r--tools/firmware/hvmloader/hvmloader.c438
1 files changed, 286 insertions, 152 deletions
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
index e1a1c22c20..66c113ec7c 100644
--- a/tools/firmware/hvmloader/hvmloader.c
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -1,13 +1,11 @@
/*
* hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader.
*
- * A quicky so that we can boot rom images as if they were a Linux kernel.
- * This code will copy the rom images (ROMBIOS/VGABIOS/VM86) into their
- * respective spaces and transfer control to VM86 to execute the BIOSes.
- *
* Leendert van Doorn, leendert@watson.ibm.com
* Copyright (c) 2005, International Business Machines Corporation.
*
+ * Copyright (c) 2006, Keir Fraser, XenSource Inc.
+ *
* 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.
@@ -22,205 +20,341 @@
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#include "roms.h"
-#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
+#include "acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
#include "hypercall.h"
#include "util.h"
+#include "acpi_utils.h"
#include "smbios.h"
+#include "config.h"
+#include "apic_regs.h"
+#include "pci_regs.h"
#include <xen/version.h>
#include <xen/hvm/params.h>
+#include <xen/hvm/e820.h>
/* memory map */
-#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
-#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
-#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
-#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
+#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
+#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
+#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
+#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
/* invoke SVM's paged realmode support */
-#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
+#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
/*
* C runtime start off
*/
asm(
-" .text \n"
-" .globl _start \n"
-"_start: \n"
-" cld \n"
-" cli \n"
-" lgdt gdt_desr \n"
-" movl $stack_top, %esp \n"
-" movl %esp, %ebp \n"
-" call main \n"
-" jmp halt \n"
-" \n"
-"gdt_desr: \n"
-" .word gdt_end - gdt - 1 \n"
-" .long gdt \n"
-" \n"
-" .align 8 \n"
-"gdt: \n"
-" .quad 0x0000000000000000 \n"
-" .quad 0x00CF92000000FFFF \n"
-" .quad 0x00CF9A000000FFFF \n"
-"gdt_end: \n"
-" \n"
-"halt: \n"
-" sti \n"
-" jmp . \n"
-" \n"
-" .bss \n"
-" .align 8 \n"
-"stack: \n"
-" .skip 0x4000 \n"
-"stack_top: \n"
-);
-
-extern int get_acpi_enabled(void);
-extern int acpi_madt_update(unsigned char* acpi_start);
+ " .text \n"
+ " .globl _start \n"
+ "_start: \n"
+ " cld \n"
+ " cli \n"
+ " lgdt gdt_desr \n"
+ " movl $stack_top, %esp \n"
+ " movl %esp, %ebp \n"
+ " call main \n"
+ " ud2 \n"
+ " \n"
+ "gdt_desr: \n"
+ " .word gdt_end - gdt - 1 \n"
+ " .long gdt \n"
+ " \n"
+ " .align 8 \n"
+ "gdt: \n"
+ " .quad 0x0000000000000000 \n"
+ " .quad 0x00CF92000000FFFF \n"
+ " .quad 0x00CF9A000000FFFF \n"
+ "gdt_end: \n"
+ " \n"
+ " .bss \n"
+ " .align 8 \n"
+ "stack: \n"
+ " .skip 0x4000 \n"
+ "stack_top: \n"
+ );
+
extern void create_mp_tables(void);
-struct hvm_info_table *get_hvm_info_table(void);
static int
cirrus_check(void)
{
- outw(0x3C4, 0x9206);
- return inb(0x3C5) == 0x12;
+ outw(0x3C4, 0x9206);
+ return inb(0x3C5) == 0x12;
}
static int
vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
{
- int eax;
+ int eax;
- __asm__ __volatile__(
- ".byte 0x0F,0x01,0xD9"
- : "=a" (eax)
- : "a"(function),
- "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi)
- );
- return eax;
+ __asm__ __volatile__ (
+ ".byte 0x0F,0x01,0xD9"
+ : "=a" (eax)
+ : "a"(function),
+ "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) );
+ return eax;
}
static int
check_amd(void)
{
- char id[12];
+ char id[12];
- __asm__ __volatile__(
- "cpuid"
- : "=b" (*(int *)(&id[0])),
- "=c" (*(int *)(&id[8])),
- "=d" (*(int *)(&id[4]))
- : "a" (0)
- );
- return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
+ __asm__ __volatile__ (
+ "cpuid"
+ : "=b" (*(int *)(&id[0])),
+ "=c" (*(int *)(&id[8])),
+ "=d" (*(int *)(&id[4]))
+ : "a" (0) );
+ return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
}
static void
wrmsr(uint32_t idx, uint64_t v)
{
- __asm__ __volatile__(
- "wrmsr"
- : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
+ __asm__ __volatile__ (
+ "wrmsr"
+ : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
}
static void
init_hypercalls(void)
{
- uint32_t eax, ebx, ecx, edx;
- unsigned long i;
- char signature[13], number[13];
- xen_extraversion_t extraversion;
+ uint32_t eax, ebx, ecx, edx;
+ unsigned long i;
+ char signature[13];
+ xen_extraversion_t extraversion;
+
+ cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+
+ *(uint32_t *)(signature + 0) = ebx;
+ *(uint32_t *)(signature + 4) = ecx;
+ *(uint32_t *)(signature + 8) = edx;
+ signature[12] = '\0';
+
+ if ( strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002) )
+ {
+ printf("FATAL: Xen hypervisor not detected\n");
+ __asm__ __volatile__( "ud2" );
+ }
+
+ /* Fill in hypercall transfer pages. */
+ cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+ for ( i = 0; i < eax; i++ )
+ wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
+
+ /* Print version information. */
+ cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+ hypercall_xen_version(XENVER_extraversion, extraversion);
+ printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
+}
+
+static void apic_setup(void)
+{
+ /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
+ ioapic_write(0x00, IOAPIC_ID);
+
+ /* Set up Virtual Wire mode. */
+ lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
+ lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
+ lapic_write(APIC_LVT1, APIC_MODE_NMI << 8);
+}
+
+static void pci_setup(void)
+{
+ uint32_t devfn, bar_reg, bar_data, bar_sz, cmd;
+ uint32_t *base, io_base = 0xc000, mem_base = HVM_BELOW_4G_MMIO_START;
+ uint16_t class, vendor_id, device_id;
+ unsigned int bar, pin, link, isa_irq;
+
+ /* Program PCI-ISA bridge with appropriate link routes. */
+ link = 0;
+ for ( isa_irq = 0; isa_irq < 15; isa_irq++ )
+ {
+ if ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) )
+ continue;
+ pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
+ printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq);
+ if ( link++ == 4 )
+ break;
+ }
- cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+ /* Program ELCR to match PCI-wired IRQs. */
+ outb(0x4d0, (uint8_t)(PCI_ISA_IRQ_MASK >> 0));
+ outb(0x4d1, (uint8_t)(PCI_ISA_IRQ_MASK >> 8));
- *(uint32_t *)(signature + 0) = ebx;
- *(uint32_t *)(signature + 4) = ecx;
- *(uint32_t *)(signature + 8) = edx;
- signature[12] = '\0';
+ /* Scan the PCI bus and map resources. */
+ for ( devfn = 0; devfn < 128; devfn++ )
+ {
+ class = pci_readw(devfn, PCI_CLASS_DEVICE);
+ vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
+ device_id = pci_readw(devfn, PCI_DEVICE_ID);
+ if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
+ continue;
- if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
- puts("FATAL: Xen hypervisor not detected\n");
- __asm__ __volatile__( "ud2" );
- }
+ ASSERT((devfn != PCI_ISA_DEVFN) ||
+ ((vendor_id == 0x8086) && (device_id == 0x7000)));
- cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+ switch ( class )
+ {
+ case 0x0680:
+ ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
+ /*
+ * PIIX4 ACPI PM. Special device with special PCI config space.
+ * No ordinary BARs.
+ */
+ pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
+ pci_writew(devfn, 0x22, 0x0000);
+ pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
+ pci_writew(devfn, 0x3d, 0x0001);
+ break;
+ case 0x0101:
+ /* PIIX3 IDE */
+ ASSERT((vendor_id == 0x8086) && (device_id == 0x7010));
+ pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
+ pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
+ /* fall through */
+ default:
+ /* Default memory mappings. */
+ for ( bar = 0; bar < 7; bar++ )
+ {
+ bar_reg = PCI_BASE_ADDRESS_0 + 4*bar;
+ if ( bar == 6 )
+ bar_reg = PCI_ROM_ADDRESS;
- puts("Detected Xen v");
- puts(itoa(number, eax >> 16));
- puts(".");
- puts(itoa(number, eax & 0xffff));
+ bar_data = pci_readl(devfn, bar_reg);
- cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+ pci_writel(devfn, bar_reg, ~0);
+ bar_sz = pci_readl(devfn, bar_reg);
+ if ( bar_sz == 0 )
+ continue;
- for (i = 0; i < eax; i++)
- wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
+ if ( (bar_data & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY )
+ {
+ base = &mem_base;
+ bar_sz &= PCI_BASE_ADDRESS_MEM_MASK;
+ bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
+ }
+ else
+ {
+ base = &io_base;
+ bar_sz &= PCI_BASE_ADDRESS_IO_MASK & 0xffff;
+ bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
+ }
+ bar_sz &= ~(bar_sz - 1);
- hypercall_xen_version(XENVER_extraversion, extraversion);
- puts(extraversion);
- puts("\n");
+ *base = (*base + bar_sz - 1) & ~(bar_sz - 1);
+ bar_data |= *base;
+ *base += bar_sz;
+
+ pci_writel(devfn, bar_reg, bar_data);
+ printf("pci dev %02x:%x bar %02x size %08x: %08x\n",
+ devfn>>3, devfn&7, bar_reg, bar_sz, bar_data);
+
+ /* Now enable the memory or I/O mapping. */
+ cmd = pci_readw(devfn, PCI_COMMAND);
+ if ( (bar_reg == PCI_ROM_ADDRESS) ||
+ ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY) )
+ cmd |= PCI_COMMAND_MEMORY;
+ else
+ cmd |= PCI_COMMAND_IO;
+ pci_writew(devfn, PCI_COMMAND, cmd);
+ }
+ break;
+ }
+
+ /* Map the interrupt. */
+ pin = pci_readb(devfn, PCI_INTERRUPT_PIN);
+ if ( pin != 0 )
+ {
+ /* This is the barber's pole mapping used by Xen. */
+ link = ((pin - 1) + (devfn >> 3)) & 3;
+ isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link);
+ pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq);
+ printf("pci dev %02x:%x INT%c->IRQ%u\n",
+ devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
+ }
+ }
}
-int
-main(void)
+int main(void)
{
- struct xen_hvm_param hvm_param;
-
- puts("HVM Loader\n");
-
- init_hypercalls();
-
- puts("Loading ROMBIOS ...\n");
- memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
-
- hvm_param.domid = DOMID_SELF;
- hvm_param.index = HVM_PARAM_APIC_ENABLED;
- if (!hypercall_hvm_op(HVMOP_get_param, &hvm_param) && hvm_param.value)
- create_mp_tables();
-
- if (cirrus_check()) {
- puts("Loading Cirrus VGABIOS ...\n");
- memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
- vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
- } else {
- puts("Loading Standard VGABIOS ...\n");
- memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
- vgabios_stdvga, sizeof(vgabios_stdvga));
- }
-
- if (get_acpi_enabled() != 0) {
- puts("Loading ACPI ...\n");
- acpi_madt_update((unsigned char *) acpi);
- if (ACPI_PHYSICAL_ADDRESS+sizeof(acpi) <= 0xF0000) {
- /*
- * Make sure acpi table does not overlap rombios
- * currently acpi less than 8K will be OK.
- */
- memcpy((void *)ACPI_PHYSICAL_ADDRESS, acpi,
- sizeof(acpi));
- }
- }
-
- puts("Writing SMBIOS tables ...\n");
- hvm_write_smbios_tables();
-
- if (check_amd()) {
- /* AMD implies this is SVM */
- puts("SVM go ...\n");
- vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
- } else {
- puts("Loading VMXAssist ...\n");
- memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
- vmxassist, sizeof(vmxassist));
-
- puts("VMX go ...\n");
- __asm__ __volatile__(
- "jmp *%%eax"
- : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
- );
- }
-
- puts("Failed to invoke ROMBIOS\n");
- return 0;
+ int acpi_sz;
+ uint8_t *freemem;
+
+ printf("HVM Loader\n");
+
+ init_hypercalls();
+
+ printf("Writing SMBIOS tables ...\n");
+ hvm_write_smbios_tables();
+
+ printf("Loading ROMBIOS ...\n");
+ memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
+
+ apic_setup();
+ pci_setup();
+
+ if ( (get_vcpu_nr() > 1) || get_apic_mode() )
+ create_mp_tables();
+
+ if ( cirrus_check() )
+ {
+ printf("Loading Cirrus VGABIOS ...\n");
+ memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
+ vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
+ }
+ else
+ {
+ printf("Loading Standard VGABIOS ...\n");
+ memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
+ vgabios_stdvga, sizeof(vgabios_stdvga));
+ }
+
+ if ( get_acpi_enabled() != 0 )
+ {
+ printf("Loading ACPI ...\n");
+ acpi_sz = acpi_build_tables((uint8_t *)ACPI_PHYSICAL_ADDRESS);
+ freemem = (uint8_t *)ACPI_PHYSICAL_ADDRESS + acpi_sz;
+ ASSERT(freemem <= (uint8_t *)0xF0000);
+ acpi_update((unsigned char *)ACPI_PHYSICAL_ADDRESS,
+ freemem - (uint8_t *)ACPI_PHYSICAL_ADDRESS,
+ (unsigned char *)0xF0000,
+ &freemem);
+ }
+
+ if ( check_amd() )
+ {
+ /* AMD implies this is SVM */
+ printf("SVM go ...\n");
+ vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
+ }
+ else
+ {
+ printf("Loading VMXAssist ...\n");
+ memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
+ vmxassist, sizeof(vmxassist));
+
+ printf("VMX go ...\n");
+ __asm__ __volatile__(
+ "jmp *%%eax"
+ : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
+ );
+ }
+
+ printf("Failed to invoke ROMBIOS\n");
+ return 0;
}
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */