debuggers.hg

view tools/firmware/hvmloader/mp_tables.c @ 10986: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 ae245d35457b
children f555a90bcc37
line source
1 /*
2 * mp_tables.c: Dynamically writes MP table info into the ROMBIOS.
3 *
4 * In order to work with various VCPU counts, this code reads the VCPU count
5 * for the HVM partition and creates the correct MP tables for the VCPU count
6 * and places the information into a predetermined location set aside in the
7 * ROMBIOS during build time.
8 *
9 * Please note that many of the values, such as the CPU's
10 * family/model/stepping, are hard-coded based upon the values that were used
11 * in the ROMBIOS and may need to be modified or calculated dynamically to
12 * correspond with what an HVM guest's CPUID returns.
13 *
14 * Travis Betak, travis.betak@amd.com
15 * Copyright (c) 2006, AMD.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms and conditions of the GNU General Public License,
19 * version 2, as published by the Free Software Foundation.
20 *
21 * This program is distributed in the hope it will be useful, but WITHOUT
22 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
24 * more details.
25 *
26 * You should have received a copy of the GNU General Public License along with
27 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
28 * Place - Suite 330, Boston, MA 02111-1307 USA.
29 */
32 /* FIXME find a header that already has types defined!!! */
33 typedef unsigned char uint8_t;
34 typedef signed char int8_t;
35 typedef unsigned short uint16_t;
36 typedef signed short int16_t;
37 typedef unsigned int uint32_t;
38 typedef signed int int32_t;
39 #ifdef __i386__
40 typedef unsigned long long uint64_t;
41 typedef signed long long int64_t;
42 #else
43 typedef unsigned long uint64_t;
44 typedef signed long int64_t;
45 #endif
47 #define ROMBIOS_SEG 0xF000
48 #define ROMBIOS_BEGIN 0x000F0000
49 #define ROMBIOS_SIZE 0x00010000
50 #define ROMBIOS_MAXOFFSET 0x0000FFFF
51 #define ROMBIOS_END (ROMBIOS_BEGIN + ROMBIOS_SIZE)
53 /* number of non-processor MP table entries */
54 #define NR_NONPROC_ENTRIES 18
56 #define ENTRY_TYPE_PROCESSOR 0
57 #define ENTRY_TYPE_BUS 1
58 #define ENTRY_TYPE_IOAPIC 2
59 #define ENTRY_TYPE_IO_INTR 3
60 #define ENTRY_TYPE_LOCAL_INTR 4
62 #define CPU_FLAG_ENABLED 0x01
63 #define CPU_FLAG_BSP 0x02
65 /* TODO change this to correspond with what the guest's see's from CPUID */
66 #define CPU_SIG_FAMILY 0x06
67 #define CPU_SIG_MODEL 0x00
68 #define CPU_SIG_STEPPING 0x00
69 #define CPU_SIGNATURE ((CPU_SIG_FAMILY << 8) \
70 | (CPU_SIG_MODEL << 4) \
71 | (CPU_SIG_STEPPING))
72 #define CPU_FEATURE_FPU (1U << 0)
73 #define CPU_FEATURE_MCE (1U << 7)
74 #define CPU_FEATURE_CX8 (1U << 8)
75 #define CPU_FEATURE_APIC (1U << 9)
76 #define CPU_FEATURES (CPU_FEATURE_FPU | CPU_FEATURE_APIC)
78 #define BUS_TYPE_LENGTH 6
79 #define BUS_TYPE_STR_ISA "ISA "
81 #define LAPIC_BASE_ADDR 0xFEE00000
83 #define IOAPIC_VERSION 0x11
84 #define IOAPIC_BASE_ADDR 0xFEC00000
85 #define IOAPIC_FLAG_ENABLED (1U << 0)
87 #define INTR_TYPE_INT 0
88 #define INTR_TYPE_NMI 1
89 #define INTR_TYPE_SMI 2
90 #define INTR_TYPE_EXTINT 3
92 #define INTR_FLAGS 0
94 #define INTR_MAX_NR 16
96 #include "util.h"
98 extern int get_vcpu_nr(void); /* for the guest's VCPU count */
100 /*
101 * The following structures are defined in the MuliProcessor Specifiation v1.4
102 */
104 /* MP Floating Pointer Structure */
105 struct mp_floating_pointer_struct {
106 uint8_t signature[4];
107 uint32_t mp_table;
108 uint8_t length;
109 uint8_t revision;
110 uint8_t checksum;
111 uint8_t feature[5];
112 };
114 /* MP Configuration Table */
115 struct mp_config_table {
116 uint8_t signature[4];
117 uint16_t length;
118 uint8_t revision;
119 uint8_t checksum;
120 uint8_t oem_id[8];
121 uint8_t vendor_id[12];
122 uint32_t oem_table;
123 uint16_t oem_table_sz;
124 uint16_t nr_entries;
125 uint32_t lapic;
126 uint16_t extended_length;
127 uint8_t extended_checksum;
128 uint8_t reserved;
129 };
131 /* MP Processor Entry */
132 struct mp_proc_entry {
133 uint8_t type;
134 uint8_t lapic_id;
135 uint8_t lapic_version;
136 uint8_t cpu_flags;
137 uint32_t cpu_signature;
138 uint32_t feature_flags;
139 uint8_t reserved[8];
140 };
142 /* MP Bus Entry */
143 struct mp_bus_entry {
144 uint8_t type;
145 uint8_t bus_id;
146 uint8_t bus_type_str[6];
147 };
149 /* MP IOAPIC Entry */
150 struct mp_ioapic_entry {
151 uint8_t type;
152 uint8_t ioapic_id;
153 uint8_t ioapic_version;
154 uint8_t ioapic_flags;
155 uint32_t ioapic_addr;
156 };
158 /* MP IO Interrupt Entry */
159 struct mp_io_intr_entry {
160 uint8_t type;
161 uint8_t intr_type;
162 uint16_t io_intr_flags;
163 uint8_t src_bus_id;
164 uint8_t src_bus_irq;
165 uint8_t dst_ioapic_id;
166 uint8_t dst_ioapic_intin;
167 };
169 /* MP Local Interrupt Entry */
170 struct mp_local_intr_entry {
171 uint8_t type;
172 uint8_t intr_type;
173 uint16_t local_intr_flags;
174 uint8_t src_bus_id;
175 uint8_t src_bus_irq;
176 uint8_t dst_lapic_id;
177 uint8_t dst_lapic_lintin;
178 };
181 /*
182 * fill_mp_config_table - fills in the information for the MP config table
183 *
184 * When calculating the length and nr_entries fields, keep in mind that there
185 * are always 18 non-processor entries and N processor entries
186 *
187 * N vcpu entries
188 * 1 bus entry
189 * 1 IOAPIC entry
190 * + 16 IO intr. entries
191 * ----------------------
192 * 18 + N total entries
193 */
194 void fill_mp_config_table(struct mp_config_table *mpct)
195 {
196 int vcpu_nr;
198 vcpu_nr = get_vcpu_nr();
200 /* fill in the MP configuration table signature, "PCMP" */
201 mpct->signature[0] = 'P';
202 mpct->signature[1] = 'C';
203 mpct->signature[2] = 'M';
204 mpct->signature[3] = 'P';
206 mpct->length = sizeof(struct mp_config_table)
207 + vcpu_nr * sizeof(struct mp_proc_entry)
208 + sizeof(struct mp_ioapic_entry)
209 + sizeof(struct mp_bus_entry)
210 + 16 * sizeof(struct mp_local_intr_entry);
212 mpct->revision = 4;
214 /*
215 * We'll fill in the checksum later after all of the
216 * entries have been created
217 */
218 mpct->checksum = 0;
220 /* fill in the OEM ID string, "_HVMCPU_" */
221 mpct->oem_id[0] = '_'; mpct->oem_id[3] = 'M'; mpct->oem_id[6] = 'U';
222 mpct->oem_id[1] = 'H'; mpct->oem_id[4] = 'C'; mpct->oem_id[7] = '_';
223 mpct->oem_id[2] = 'V'; mpct->oem_id[5] = 'P';
225 /* fill in the Vendor ID string, "XEN " */
226 mpct->vendor_id[0] = 'X'; mpct->vendor_id[6] = ' ';
227 mpct->vendor_id[1] = 'E'; mpct->vendor_id[7] = ' ';
228 mpct->vendor_id[2] = 'N'; mpct->vendor_id[8] = ' ';
229 mpct->vendor_id[3] = ' '; mpct->vendor_id[9] = ' ';
230 mpct->vendor_id[4] = ' '; mpct->vendor_id[10] = ' ';
231 mpct->vendor_id[5] = ' '; mpct->vendor_id[11] = ' ';
233 mpct->oem_table = 0;
234 mpct->oem_table_sz = 0;
236 mpct->nr_entries = vcpu_nr + NR_NONPROC_ENTRIES;
238 mpct->lapic = LAPIC_BASE_ADDR;
239 mpct->extended_length = 0;
240 mpct->extended_checksum = 0;
241 }
244 /* calculates the checksum for the MP configuration table */
245 void fill_mp_config_table_checksum(struct mp_config_table *mpct)
246 {
247 int i;
248 uint8_t checksum;
250 checksum = 0;
251 for (i = 0; i < mpct->length; ++i)
252 checksum += ((uint8_t *)(mpct))[i];
253 mpct->checksum = -checksum;
254 }
257 /* fills in an MP processor entry for VCPU 'vcpu_id' */
258 void fill_mp_proc_entry(struct mp_proc_entry *mppe, int vcpu_id)
259 {
260 mppe->type = ENTRY_TYPE_PROCESSOR;
261 mppe->lapic_id = vcpu_id;
262 mppe->lapic_version = 0x11;
263 mppe->cpu_flags = CPU_FLAG_ENABLED;
264 if (vcpu_id == 0)
265 mppe->cpu_flags |= CPU_FLAG_BSP;
266 mppe->cpu_signature = CPU_SIGNATURE;
267 mppe->feature_flags = CPU_FEATURES;
268 }
271 /* fills in an MP bus entry of type 'type' and bus ID 'bus_id' */
272 void fill_mp_bus_entry(struct mp_bus_entry *mpbe, int bus_id, const char *type)
273 {
274 int i;
276 mpbe->type = ENTRY_TYPE_BUS;
277 mpbe->bus_id = bus_id;
278 for (i = 0; i < BUS_TYPE_LENGTH; ++i)
279 mpbe->bus_type_str[i] = type[i]; /* FIXME length check? */
280 }
283 /* fills in an MP IOAPIC entry for IOAPIC 'ioapic_id' */
284 void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie, int ioapic_id)
285 {
286 mpie->type = ENTRY_TYPE_IOAPIC;
287 mpie->ioapic_id = ioapic_id;
288 mpie->ioapic_version = IOAPIC_VERSION;
289 mpie->ioapic_flags = IOAPIC_FLAG_ENABLED;
290 mpie->ioapic_addr = IOAPIC_BASE_ADDR;
291 }
294 /* fills in an IO interrupt entry for IOAPIC 'ioapic_id' */
295 void fill_mp_io_intr_entry(struct mp_io_intr_entry *mpiie,
296 int src_bus_irq, int ioapic_id, int dst_ioapic_intin)
297 {
298 mpiie->type = ENTRY_TYPE_IO_INTR;
299 mpiie->intr_type = INTR_TYPE_INT;
300 mpiie->io_intr_flags = INTR_FLAGS;
301 mpiie->src_bus_id = 0;
302 mpiie->src_bus_irq = src_bus_irq;
303 mpiie->dst_ioapic_id = ioapic_id;
304 mpiie->dst_ioapic_intin = dst_ioapic_intin;
305 }
308 /* fill in the mp floating processor structure */
309 void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct)
310 {
311 int i;
312 uint8_t checksum;
315 mpfps->signature[0] = '_';
316 mpfps->signature[1] = 'M';
317 mpfps->signature[2] = 'P';
318 mpfps->signature[3] = '_';
320 mpfps->mp_table = mpct;
321 mpfps->length = 1;
322 mpfps->revision = 4;
323 mpfps->checksum = 0;
324 for (i = 0; i < 5; ++i)
325 mpfps->feature[i] = 0;
327 /* compute the checksum for our new table */
328 checksum = 0;
329 for (i = 0; i < sizeof(struct mp_floating_pointer_struct); ++i)
330 checksum += ((uint8_t *)(mpfps))[i];
331 mpfps->checksum = -checksum;
332 }
335 /*
336 * find_mp_table_start - searchs through BIOS memory for '___HVMMP' signature
337 *
338 * The '___HVMMP' signature is created by the ROMBIOS and designates a chunk
339 * of space inside the ROMBIOS that is safe for us to write our MP table info
340 */
341 void* get_mp_table_start(void)
342 {
343 char *bios_mem;
344 for (bios_mem = (char *)ROMBIOS_BEGIN;
345 bios_mem != (char *)ROMBIOS_END;
346 ++bios_mem)
347 if (bios_mem[0] == '_' && bios_mem[1] == '_' &&
348 bios_mem[2] == '_' && bios_mem[3] == 'H' &&
349 bios_mem[4] == 'V' && bios_mem[5] == 'M' &&
350 bios_mem[6] == 'M' && bios_mem[7] == 'P')
351 return bios_mem;
353 return (void *)-1;
354 }
357 /* recalculate the new ROMBIOS checksum after adding MP tables */
358 void reset_bios_checksum(void)
359 {
360 uint32_t i;
361 uint8_t checksum;
363 checksum = 0;
364 for (i = 0; i < ROMBIOS_MAXOFFSET; ++i)
365 checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
367 *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
368 }
371 /* create_mp_tables - creates MP tables for the guest based upon config data */
372 void create_mp_tables(void)
373 {
374 void *mp_table_base;
375 char *p;
376 struct mp_config_table *mp_config_table;
377 int vcpu_nr;
378 int i;
380 vcpu_nr = get_vcpu_nr();
382 puts("Creating MP tables ...\n");
384 /* find the 'safe' place in ROMBIOS for the MP tables */
385 mp_table_base = get_mp_table_start();
386 if (mp_table_base == (void *)-1) {
387 puts("Couldn't find start point for MP tables\n");
388 return;
389 }
390 p = mp_table_base;
392 fill_mp_config_table((struct mp_config_table *)p);
394 /* save the location of the MP config table for a little later*/
395 mp_config_table = (struct mp_config_table *)p;
396 p += sizeof(struct mp_config_table);
398 for (i = 0; i < vcpu_nr; ++i) {
399 fill_mp_proc_entry((struct mp_proc_entry *)p, i);
400 p += sizeof(struct mp_proc_entry);
401 }
403 fill_mp_bus_entry((struct mp_bus_entry *)p, 0, BUS_TYPE_STR_ISA);
404 p += sizeof(struct mp_bus_entry);
406 fill_mp_ioapic_entry((struct mp_ioapic_entry *)p, vcpu_nr);
407 p += sizeof(struct mp_ioapic_entry);
409 for (i = 0; i < INTR_MAX_NR; ++i) {
410 fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
411 i, vcpu_nr, i);
412 p += sizeof(struct mp_io_intr_entry);
413 }
415 /* find the next 16-byte boundary to place the mp floating pointer */
416 while ((unsigned long)p & 0xF)
417 ++p;
419 fill_mpfps((struct mp_floating_pointer_struct *)p,
420 (uint32_t)mp_table_base);
422 /* calculate the MP configuration table's checksum */
423 fill_mp_config_table_checksum(mp_config_table);
425 /* finally, recalculate the ROMBIOS checksum */
426 reset_bios_checksum();
427 }