source: trunk/packages/xen-3.1/xen-3.1/tools/firmware/hvmloader/hvmloader.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 14.6 KB
Line 
1/*
2 * hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader.
3 *
4 * Leendert van Doorn, leendert@watson.ibm.com
5 * Copyright (c) 2005, International Business Machines Corporation.
6 *
7 * Copyright (c) 2006, Keir Fraser, XenSource Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 * Place - Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23#include "roms.h"
24#include "acpi/acpi2_0.h"
25#include "hypercall.h"
26#include "util.h"
27#include "config.h"
28#include "apic_regs.h"
29#include "pci_regs.h"
30#include <xen/version.h>
31#include <xen/hvm/params.h>
32
33asm(
34    "    .text                       \n"
35    "    .globl _start               \n"
36    "_start:                         \n"
37    /* C runtime kickoff. */
38    "    cld                         \n"
39    "    cli                         \n"
40    "    movl $stack_top,%esp        \n"
41    "    movl %esp,%ebp              \n"
42    "    call main                   \n"
43    /* Relocate real-mode trampoline to 0x0. */
44    "    mov  $trampoline_start,%esi \n"
45    "    xor  %edi,%edi              \n"
46    "    mov  $trampoline_end,%ecx   \n"
47    "    sub  %esi,%ecx              \n"
48    "    rep  movsb                  \n"
49    /* Load real-mode compatible segment state (base 0x0000, limit 0xffff). */
50    "    lgdt gdt_desr               \n"
51    "    mov  $0x0010,%ax            \n"
52    "    mov  %ax,%ds                \n"
53    "    mov  %ax,%es                \n"
54    "    mov  %ax,%fs                \n"
55    "    mov  %ax,%gs                \n"
56    "    mov  %ax,%ss                \n"
57    /* Initialise all 32-bit GPRs to zero. */
58    "    xor  %eax,%eax              \n"
59    "    xor  %ebx,%ebx              \n"
60    "    xor  %ecx,%ecx              \n"
61    "    xor  %edx,%edx              \n"
62    "    xor  %esp,%esp              \n"
63    "    xor  %ebp,%ebp              \n"
64    "    xor  %esi,%esi              \n"
65    "    xor  %edi,%edi              \n"
66    /* Enter real mode, reload all segment registers and IDT. */
67    "    ljmp $0x8,$0x0              \n"
68    "trampoline_start: .code16       \n"
69    "    mov  %eax,%cr0              \n"
70    "    ljmp $0,$1f-trampoline_start\n"
71    "1:  mov  %ax,%ds                \n"
72    "    mov  %ax,%es                \n"
73    "    mov  %ax,%fs                \n"
74    "    mov  %ax,%gs                \n"
75    "    mov  %ax,%ss                \n"
76    "    lidt 1f-trampoline_start    \n"
77    "    ljmp $0xf000,$0xfff0        \n"
78    "1:  .word 0x3ff,0,0             \n"
79    "trampoline_end:   .code32       \n"
80    "                                \n"
81    "gdt_desr:                       \n"
82    "    .word gdt_end - gdt - 1     \n"
83    "    .long gdt                   \n"
84    "                                \n"
85    "    .align 8                    \n"
86    "gdt:                            \n"
87    "    .quad 0x0000000000000000    \n"
88    "    .quad 0x00009a000000ffff    \n" /* Ring 0 code, base 0 limit 0xffff */
89    "    .quad 0x000092000000ffff    \n" /* Ring 0 data, base 0 limit 0xffff */
90    "gdt_end:                        \n"
91    "                                \n"
92    "    .bss                        \n"
93    "    .align    8                 \n"
94    "stack:                          \n"
95    "    .skip    0x4000             \n"
96    "stack_top:                      \n"
97    );
98
99void create_mp_tables(void);
100int hvm_write_smbios_tables(void);
101
102static int
103cirrus_check(void)
104{
105    outw(0x3C4, 0x9206);
106    return inb(0x3C5) == 0x12;
107}
108
109static int
110check_amd(void)
111{
112    char id[12];
113
114    __asm__ __volatile__ (
115        "cpuid" 
116        : "=b" (*(int *)(&id[0])),
117        "=c" (*(int *)(&id[8])),
118        "=d" (*(int *)(&id[4]))
119        : "a" (0) );
120    return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
121}
122
123static void
124wrmsr(uint32_t idx, uint64_t v)
125{
126    __asm__ __volatile__ (
127        "wrmsr"
128        : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
129}
130
131static void
132init_hypercalls(void)
133{
134    uint32_t eax, ebx, ecx, edx;
135    unsigned long i;
136    char signature[13];
137    xen_extraversion_t extraversion;
138
139    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
140
141    *(uint32_t *)(signature + 0) = ebx;
142    *(uint32_t *)(signature + 4) = ecx;
143    *(uint32_t *)(signature + 8) = edx;
144    signature[12] = '\0';
145
146    if ( strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002) )
147    {
148        printf("FATAL: Xen hypervisor not detected\n");
149        __asm__ __volatile__( "ud2" );
150    }
151
152    /* Fill in hypercall transfer pages. */
153    cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
154    for ( i = 0; i < eax; i++ )
155        wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
156
157    /* Print version information. */
158    cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
159    hypercall_xen_version(XENVER_extraversion, extraversion);
160    printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
161}
162
163static void apic_setup(void)
164{
165    /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
166    ioapic_write(0x00, IOAPIC_ID);
167
168    /* Set up Virtual Wire mode. */
169    lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
170    lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
171    lapic_write(APIC_LVT1, APIC_MODE_NMI    << 8);
172}
173
174static void pci_setup(void)
175{
176    uint32_t devfn, bar_reg, bar_data, bar_sz, cmd;
177    uint32_t *base, io_base = 0xc000, mem_base = HVM_BELOW_4G_MMIO_START;
178    uint16_t class, vendor_id, device_id;
179    unsigned int bar, pin, link, isa_irq;
180
181    /* Program PCI-ISA bridge with appropriate link routes. */
182    link = 0;
183    for ( isa_irq = 0; isa_irq < 15; isa_irq++ )
184    {
185        if ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) )
186            continue;
187        pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
188        printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq);
189        if ( link++ == 4 )
190            break;
191    }
192
193    /* Program ELCR to match PCI-wired IRQs. */
194    outb(0x4d0, (uint8_t)(PCI_ISA_IRQ_MASK >> 0));
195    outb(0x4d1, (uint8_t)(PCI_ISA_IRQ_MASK >> 8));
196
197    /* Scan the PCI bus and map resources. */
198    for ( devfn = 0; devfn < 128; devfn++ )
199    {
200        class     = pci_readw(devfn, PCI_CLASS_DEVICE);
201        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
202        device_id = pci_readw(devfn, PCI_DEVICE_ID);
203        if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
204            continue;
205
206        ASSERT((devfn != PCI_ISA_DEVFN) ||
207               ((vendor_id == 0x8086) && (device_id == 0x7000)));
208
209        switch ( class )
210        {
211        case 0x0680:
212            ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
213            /*
214             * PIIX4 ACPI PM. Special device with special PCI config space.
215             * No ordinary BARs.
216             */
217            pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
218            pci_writew(devfn, 0x22, 0x0000);
219            pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
220            pci_writew(devfn, 0x3d, 0x0001);
221            break;
222        case 0x0101:
223            /* PIIX3 IDE */
224            ASSERT((vendor_id == 0x8086) && (device_id == 0x7010));
225            pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
226            pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
227            /* fall through */
228        default:
229            /* Default memory mappings. */
230            for ( bar = 0; bar < 7; bar++ )
231            {
232                bar_reg = PCI_BASE_ADDRESS_0 + 4*bar;
233                if ( bar == 6 )
234                    bar_reg = PCI_ROM_ADDRESS;
235
236                bar_data = pci_readl(devfn, bar_reg);
237
238                pci_writel(devfn, bar_reg, ~0);
239                bar_sz = pci_readl(devfn, bar_reg);
240                if ( bar_sz == 0 )
241                    continue;
242
243                if ( (bar_data & PCI_BASE_ADDRESS_SPACE) ==
244                     PCI_BASE_ADDRESS_SPACE_MEMORY )
245                {
246                    base = &mem_base;
247                    bar_sz &= PCI_BASE_ADDRESS_MEM_MASK;
248                    bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
249                }
250                else
251                {
252                    base = &io_base;
253                    bar_sz &= PCI_BASE_ADDRESS_IO_MASK & 0xffff;
254                    bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
255                }
256                bar_sz &= ~(bar_sz - 1);
257
258                *base = (*base + bar_sz - 1) & ~(bar_sz - 1);
259                bar_data |= *base;
260                *base += bar_sz;
261
262                pci_writel(devfn, bar_reg, bar_data);
263                printf("pci dev %02x:%x bar %02x size %08x: %08x\n",
264                       devfn>>3, devfn&7, bar_reg, bar_sz, bar_data);
265
266                /* Now enable the memory or I/O mapping. */
267                cmd = pci_readw(devfn, PCI_COMMAND);
268                if ( (bar_reg == PCI_ROM_ADDRESS) ||
269                     ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
270                      PCI_BASE_ADDRESS_SPACE_MEMORY) )
271                    cmd |= PCI_COMMAND_MEMORY;
272                else
273                    cmd |= PCI_COMMAND_IO;
274                pci_writew(devfn, PCI_COMMAND, cmd);
275            }
276            break;
277        }
278
279        /* Map the interrupt. */
280        pin = pci_readb(devfn, PCI_INTERRUPT_PIN);
281        if ( pin != 0 )
282        {
283            /* This is the barber's pole mapping used by Xen. */
284            link = ((pin - 1) + (devfn >> 3)) & 3;
285            isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link);
286            pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq);
287            printf("pci dev %02x:%x INT%c->IRQ%u\n",
288                   devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
289        }
290    }
291}
292
293/*
294 * If the network card is in the boot order, load the Etherboot option ROM.
295 * Read the boot order bytes from CMOS and check if any of them are 0x4.
296 */
297static int must_load_nic(void) 
298{
299    uint8_t boot_order;
300
301    /* Read CMOS register 0x3d (boot choices 0 and 1). */
302    boot_order = cmos_inb(0x3d);
303    if ( ((boot_order & 0xf) == 0x4) || ((boot_order & 0xf0) == 0x40) ) 
304        return 1;
305
306    /* Read CMOS register 0x38 (boot choice 2 and FDD test flag). */
307    boot_order = cmos_inb(0x38);
308    return ((boot_order & 0xf0) == 0x40);
309}
310
311/* Replace possibly erroneous memory-size CMOS fields with correct values. */
312static void cmos_write_memory_size(void)
313{
314    struct e820entry *map = E820_MAP;
315    int i, nr = *E820_MAP_NR;
316    uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0;
317
318    for ( i = 0; i < nr; i++ )
319        if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) )
320            break;
321
322    if ( i != nr )
323    {
324        alt_mem = ext_mem = map[i].addr + map[i].size;
325        ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
326        if ( ext_mem > 0xffff )
327            ext_mem = 0xffff;
328        alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
329    }
330
331    /* All BIOSes: conventional memory (CMOS *always* reports 640kB). */
332    cmos_outb(0x15, (uint8_t)(base_mem >> 0));
333    cmos_outb(0x16, (uint8_t)(base_mem >> 8));
334
335    /* All BIOSes: extended memory (1kB chunks above 1MB). */
336    cmos_outb(0x17, (uint8_t)( ext_mem >> 0));
337    cmos_outb(0x18, (uint8_t)( ext_mem >> 8));
338    cmos_outb(0x30, (uint8_t)( ext_mem >> 0));
339    cmos_outb(0x31, (uint8_t)( ext_mem >> 8));
340
341    /* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */
342    cmos_outb(0x34, (uint8_t)( alt_mem >> 0));
343    cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
344}
345
346int main(void)
347{
348    int acpi_sz = 0, vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
349
350    printf("HVM Loader\n");
351
352    init_hypercalls();
353
354    printf("Writing SMBIOS tables ...\n");
355    smbios_sz = hvm_write_smbios_tables();
356
357    printf("Loading ROMBIOS ...\n");
358    rombios_sz = sizeof(rombios);
359    if ( rombios_sz > 0x10000 )
360        rombios_sz = 0x10000;
361    memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, rombios_sz);
362    highbios_setup();
363
364    apic_setup();
365    pci_setup();
366
367    if ( (get_vcpu_nr() > 1) || get_apic_mode() )
368        create_mp_tables();
369
370    if ( cirrus_check() )
371    {
372        printf("Loading Cirrus VGABIOS ...\n");
373        memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
374               vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
375        vgabios_sz = sizeof(vgabios_cirrusvga);
376    }
377    else
378    {
379        printf("Loading Standard VGABIOS ...\n");
380        memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
381               vgabios_stdvga, sizeof(vgabios_stdvga));
382        vgabios_sz = sizeof(vgabios_stdvga);
383    }
384
385    if ( must_load_nic() )
386    {
387        printf("Loading ETHERBOOT ...\n");
388        memcpy((void *)ETHERBOOT_PHYSICAL_ADDRESS,
389               etherboot, sizeof(etherboot));
390        etherboot_sz = sizeof(etherboot);
391    }
392
393    if ( get_acpi_enabled() )
394    {
395        printf("Loading ACPI ...\n");
396        acpi_sz = acpi_build_tables((uint8_t *)ACPI_PHYSICAL_ADDRESS);
397        ASSERT((ACPI_PHYSICAL_ADDRESS + acpi_sz) <= 0xF0000);
398    }
399
400    cmos_write_memory_size();
401
402    printf("BIOS map:\n");
403    if ( vgabios_sz )
404        printf(" %05x-%05x: VGA BIOS\n",
405               VGABIOS_PHYSICAL_ADDRESS,
406               VGABIOS_PHYSICAL_ADDRESS + vgabios_sz - 1);
407    if ( etherboot_sz )
408        printf(" %05x-%05x: Etherboot ROM\n",
409               ETHERBOOT_PHYSICAL_ADDRESS,
410               ETHERBOOT_PHYSICAL_ADDRESS + etherboot_sz - 1);
411    if ( !check_amd() )
412        printf(" %05x-%05x: VMXAssist\n",
413               VMXASSIST_PHYSICAL_ADDRESS,
414               VMXASSIST_PHYSICAL_ADDRESS + sizeof(vmxassist) - 1);
415    if ( smbios_sz )
416        printf(" %05x-%05x: SMBIOS tables\n",
417               SMBIOS_PHYSICAL_ADDRESS,
418               SMBIOS_PHYSICAL_ADDRESS + smbios_sz - 1);
419    if ( acpi_sz )
420        printf(" %05x-%05x: ACPI tables\n",
421               ACPI_PHYSICAL_ADDRESS,
422               ACPI_PHYSICAL_ADDRESS + acpi_sz - 1);
423    if ( rombios_sz )
424        printf(" %05x-%05x: Main BIOS\n",
425               ROMBIOS_PHYSICAL_ADDRESS,
426               ROMBIOS_PHYSICAL_ADDRESS + rombios_sz - 1);
427
428    if ( !check_amd() )
429    {
430        printf("Loading VMXAssist ...\n");
431        memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
432               vmxassist, sizeof(vmxassist));
433
434        printf("VMX go ...\n");
435        __asm__ __volatile__(
436            "jmp *%%eax"
437            : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
438            );
439    }
440
441    printf("Invoking ROMBIOS ...\n");
442    return 0;
443}
444
445/*
446 * Local variables:
447 * mode: C
448 * c-set-style: "BSD"
449 * c-basic-offset: 4
450 * tab-width: 4
451 * indent-tabs-mode: nil
452 * End:
453 */
Note: See TracBrowser for help on using the repository browser.