ia64/xen-unstable

view tools/firmware/hvmloader/hvmloader.c @ 12651:9164f836943d

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