ia64/xen-unstable

view tools/firmware/hvmloader/hvmloader.c @ 10976:49dcd838b7df

[HVMLOADER] HVM loader initialises hypercall shim and uses
it to interrogate Xen version information. Also add support
for HVM hypercall execution on 64-bit host.

Signed-off-by: Steven Smith <ssmith@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Aug 04 20:30:12 2006 +0100 (2006-08-04)
parents 2e3b121662dc
children 323eb29083e6
line source
1 /*
2 * hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader.
3 *
4 * A quicky so that we can boot rom images as if they were a Linux kernel.
5 * This code will copy the rom images (ROMBIOS/VGABIOS/VM86) into their
6 * respective spaces and transfer control to VM86 to execute the BIOSes.
7 *
8 * Leendert van Doorn, leendert@watson.ibm.com
9 * Copyright (c) 2005, International Business Machines Corporation.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2, as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 * Place - Suite 330, Boston, MA 02111-1307 USA.
23 */
24 #include "roms.h"
25 #include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
26 #include "hypercall.h"
27 #include "util.h"
28 #include <xen/version.h>
29 #include <xen/hvm/hvm_info_table.h>
31 /* memory map */
32 #define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
33 #define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
34 #define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
35 #define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
37 /* invoke SVM's paged realmode support */
38 #define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
40 /*
41 * C runtime start off
42 */
43 asm(
44 " .text \n"
45 " .globl _start \n"
46 "_start: \n"
47 " cld \n"
48 " cli \n"
49 " lgdt gdt_desr \n"
50 " movl $stack_top, %esp \n"
51 " movl %esp, %ebp \n"
52 " call main \n"
53 " jmp halt \n"
54 " \n"
55 "gdt_desr: \n"
56 " .word gdt_end - gdt - 1 \n"
57 " .long gdt \n"
58 " \n"
59 " .align 8 \n"
60 "gdt: \n"
61 " .quad 0x0000000000000000 \n"
62 " .quad 0x00CF92000000FFFF \n"
63 " .quad 0x00CF9A000000FFFF \n"
64 "gdt_end: \n"
65 " \n"
66 "halt: \n"
67 " sti \n"
68 " jmp . \n"
69 " \n"
70 " .bss \n"
71 " .align 8 \n"
72 "stack: \n"
73 " .skip 0x4000 \n"
74 "stack_top: \n"
75 );
77 extern int get_acpi_enabled(void);
78 extern int acpi_madt_update(unsigned char* acpi_start);
79 extern void create_mp_tables(void);
80 struct hvm_info_table *get_hvm_info_table(void);
82 static int
83 cirrus_check(void)
84 {
85 outw(0x3C4, 0x9206);
86 return inb(0x3C5) == 0x12;
87 }
89 static int
90 vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
91 {
92 int eax;
94 __asm__ __volatile__(
95 ".byte 0x0F,0x01,0xD9"
96 : "=a" (eax)
97 : "a"(function),
98 "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi)
99 );
100 return eax;
101 }
103 static int
104 check_amd(void)
105 {
106 char id[12];
108 __asm__ __volatile__(
109 "cpuid"
110 : "=b" (*(int *)(&id[0])),
111 "=c" (*(int *)(&id[8])),
112 "=d" (*(int *)(&id[4]))
113 : "a" (0)
114 );
115 return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
116 }
118 static void
119 cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
120 {
121 __asm__ __volatile__(
122 "cpuid"
123 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
124 : "0" (idx) );
125 }
127 static void
128 wrmsr(uint32_t idx, uint64_t v)
129 {
130 __asm__ __volatile__(
131 "wrmsr"
132 : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
133 }
135 static void
136 init_hypercalls(void)
137 {
138 uint32_t eax, ebx, ecx, edx;
139 unsigned long i;
140 char signature[13], number[13];
141 xen_extraversion_t extraversion;
143 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
145 *(uint32_t *)(signature + 0) = ebx;
146 *(uint32_t *)(signature + 4) = ecx;
147 *(uint32_t *)(signature + 8) = edx;
148 signature[12] = '\0';
150 if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
151 puts("FATAL: Xen hypervisor not detected\n");
152 __asm__ __volatile__( "ud2" );
153 }
155 cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
157 puts("Detected Xen v");
158 puts(itoa(number, eax >> 16));
159 puts(".");
160 puts(itoa(number, eax & 0xffff));
162 cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
164 for (i = 0; i < eax; i++)
165 wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
167 hypercall_xen_version(XENVER_extraversion, extraversion);
168 puts(extraversion);
169 puts("\n");
170 }
172 int
173 main(void)
174 {
175 struct hvm_info_table *t = get_hvm_info_table();
177 puts("HVM Loader\n");
179 init_hypercalls();
181 puts("Loading ROMBIOS ...\n");
182 memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
183 if (t->apic_enabled)
184 create_mp_tables();
186 if (cirrus_check()) {
187 puts("Loading Cirrus VGABIOS ...\n");
188 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
189 vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
190 } else {
191 puts("Loading Standard VGABIOS ...\n");
192 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
193 vgabios_stdvga, sizeof(vgabios_stdvga));
194 }
196 if (get_acpi_enabled() != 0) {
197 puts("Loading ACPI ...\n");
198 acpi_madt_update((unsigned char *) acpi);
199 if (ACPI_PHYSICAL_ADDRESS+sizeof(acpi) <= 0xF0000) {
200 /*
201 * Make sure acpi table does not overlap rombios
202 * currently acpi less than 8K will be OK.
203 */
204 memcpy((void *)ACPI_PHYSICAL_ADDRESS, acpi,
205 sizeof(acpi));
206 }
207 }
209 if (check_amd()) {
210 /* AMD implies this is SVM */
211 puts("SVM go ...\n");
212 vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
213 } else {
214 puts("Loading VMXAssist ...\n");
215 memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
216 vmxassist, sizeof(vmxassist));
218 puts("VMX go ...\n");
219 __asm__ __volatile__(
220 "jmp *%%eax"
221 : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
222 );
223 }
225 puts("Failed to invoke ROMBIOS\n");
226 return 0;
227 }