ia64/xen-unstable

view tools/firmware/hvmloader/mp_tables.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 d752d8ccd282
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 */
31 #include "config.h"
33 /* FIXME find a header that already has types defined!!! */
34 typedef unsigned char uint8_t;
35 typedef signed char int8_t;
36 typedef unsigned short uint16_t;
37 typedef signed short int16_t;
38 typedef unsigned int uint32_t;
39 typedef signed int int32_t;
40 #ifdef __i386__
41 typedef unsigned long long uint64_t;
42 typedef signed long long int64_t;
43 #else
44 typedef unsigned long uint64_t;
45 typedef signed long int64_t;
46 #endif
48 #define ROMBIOS_SEG 0xF000
49 #define ROMBIOS_BEGIN 0x000F0000
50 #define ROMBIOS_SIZE 0x00010000
51 #define ROMBIOS_MAXOFFSET 0x0000FFFF
52 #define ROMBIOS_END (ROMBIOS_BEGIN + ROMBIOS_SIZE)
54 /* number of non-processor MP table entries */
55 #define NR_NONPROC_ENTRIES 18
57 #define ENTRY_TYPE_PROCESSOR 0
58 #define ENTRY_TYPE_BUS 1
59 #define ENTRY_TYPE_IOAPIC 2
60 #define ENTRY_TYPE_IO_INTR 3
61 #define ENTRY_TYPE_LOCAL_INTR 4
63 #define CPU_FLAG_ENABLED 0x01
64 #define CPU_FLAG_BSP 0x02
66 /* TODO change this to correspond with what the guest's see's from CPUID */
67 #define CPU_SIG_FAMILY 0x06
68 #define CPU_SIG_MODEL 0x00
69 #define CPU_SIG_STEPPING 0x00
70 #define CPU_SIGNATURE ((CPU_SIG_FAMILY << 8) \
71 | (CPU_SIG_MODEL << 4) \
72 | (CPU_SIG_STEPPING))
73 #define CPU_FEATURE_FPU (1U << 0)
74 #define CPU_FEATURE_MCE (1U << 7)
75 #define CPU_FEATURE_CX8 (1U << 8)
76 #define CPU_FEATURE_APIC (1U << 9)
77 #define CPU_FEATURES (CPU_FEATURE_FPU | CPU_FEATURE_APIC)
79 #define BUS_TYPE_LENGTH 6
80 #define BUS_TYPE_STR_ISA "ISA "
81 #define BUS_ID_ISA 0
83 #define INTR_TYPE_INT 0
84 #define INTR_TYPE_NMI 1
85 #define INTR_TYPE_SMI 2
86 #define INTR_TYPE_EXTINT 3
88 #define INTR_MAX_NR 16
90 #include "util.h"
92 extern int get_vcpu_nr(void); /* for the guest's VCPU count */
94 /*
95 * The following structures are defined in the MuliProcessor Specifiation v1.4
96 */
98 /* MP Floating Pointer Structure */
99 struct mp_floating_pointer_struct {
100 uint8_t signature[4];
101 uint32_t mp_table;
102 uint8_t length;
103 uint8_t revision;
104 uint8_t checksum;
105 uint8_t feature[5];
106 };
108 /* MP Configuration Table */
109 struct mp_config_table {
110 uint8_t signature[4];
111 uint16_t length;
112 uint8_t revision;
113 uint8_t checksum;
114 uint8_t oem_id[8];
115 uint8_t vendor_id[12];
116 uint32_t oem_table;
117 uint16_t oem_table_sz;
118 uint16_t nr_entries;
119 uint32_t lapic;
120 uint16_t extended_length;
121 uint8_t extended_checksum;
122 uint8_t reserved;
123 };
125 /* MP Processor Entry */
126 struct mp_proc_entry {
127 uint8_t type;
128 uint8_t lapic_id;
129 uint8_t lapic_version;
130 uint8_t cpu_flags;
131 uint32_t cpu_signature;
132 uint32_t feature_flags;
133 uint8_t reserved[8];
134 };
136 /* MP Bus Entry */
137 struct mp_bus_entry {
138 uint8_t type;
139 uint8_t bus_id;
140 uint8_t bus_type_str[6];
141 };
143 /* MP IOAPIC Entry */
144 struct mp_ioapic_entry {
145 uint8_t type;
146 uint8_t ioapic_id;
147 uint8_t ioapic_version;
148 uint8_t ioapic_flags;
149 uint32_t ioapic_addr;
150 };
152 /* MP IO Interrupt Entry */
153 struct mp_io_intr_entry {
154 uint8_t type;
155 uint8_t intr_type;
156 uint16_t io_intr_flags;
157 uint8_t src_bus_id;
158 uint8_t src_bus_irq;
159 uint8_t dst_ioapic_id;
160 uint8_t dst_ioapic_intin;
161 };
163 /* MP Local Interrupt Entry */
164 struct mp_local_intr_entry {
165 uint8_t type;
166 uint8_t intr_type;
167 uint16_t local_intr_flags;
168 uint8_t src_bus_id;
169 uint8_t src_bus_irq;
170 uint8_t dst_lapic_id;
171 uint8_t dst_lapic_lintin;
172 };
175 void fill_mp_config_table(struct mp_config_table *mpct, int length)
176 {
177 int vcpu_nr, i;
178 uint8_t checksum;
180 vcpu_nr = get_vcpu_nr();
182 /* fill in the MP configuration table signature, "PCMP" */
183 mpct->signature[0] = 'P';
184 mpct->signature[1] = 'C';
185 mpct->signature[2] = 'M';
186 mpct->signature[3] = 'P';
188 mpct->length = length;
190 mpct->revision = 4;
192 /* fill in the OEM ID string, "_HVMCPU_" */
193 mpct->oem_id[0] = '_'; mpct->oem_id[3] = 'M'; mpct->oem_id[6] = 'U';
194 mpct->oem_id[1] = 'H'; mpct->oem_id[4] = 'C'; mpct->oem_id[7] = '_';
195 mpct->oem_id[2] = 'V'; mpct->oem_id[5] = 'P';
197 /* fill in the Vendor ID string, "XEN " */
198 mpct->vendor_id[0] = 'X'; mpct->vendor_id[6] = ' ';
199 mpct->vendor_id[1] = 'E'; mpct->vendor_id[7] = ' ';
200 mpct->vendor_id[2] = 'N'; mpct->vendor_id[8] = ' ';
201 mpct->vendor_id[3] = ' '; mpct->vendor_id[9] = ' ';
202 mpct->vendor_id[4] = ' '; mpct->vendor_id[10] = ' ';
203 mpct->vendor_id[5] = ' '; mpct->vendor_id[11] = ' ';
205 mpct->oem_table = 0;
206 mpct->oem_table_sz = 0;
208 mpct->nr_entries = vcpu_nr + NR_NONPROC_ENTRIES;
210 mpct->lapic = LAPIC_BASE_ADDRESS;
211 mpct->extended_length = 0;
212 mpct->extended_checksum = 0;
214 /* Finally, fill in the checksum. */
215 mpct->checksum = checksum = 0;
216 for ( i = 0; i < length; i++ )
217 checksum += ((uint8_t *)(mpct))[i];
218 mpct->checksum = -checksum;
219 }
221 /* fills in an MP processor entry for VCPU 'vcpu_id' */
222 void fill_mp_proc_entry(struct mp_proc_entry *mppe, int vcpu_id)
223 {
224 mppe->type = ENTRY_TYPE_PROCESSOR;
225 mppe->lapic_id = vcpu_id + 1;
226 mppe->lapic_version = 0x11;
227 mppe->cpu_flags = CPU_FLAG_ENABLED;
228 if ( vcpu_id == 0 )
229 mppe->cpu_flags |= CPU_FLAG_BSP;
230 mppe->cpu_signature = CPU_SIGNATURE;
231 mppe->feature_flags = CPU_FEATURES;
232 }
235 /* fills in an MP bus entry of type 'type' and bus ID 'bus_id' */
236 void fill_mp_bus_entry(struct mp_bus_entry *mpbe, int bus_id, const char *type)
237 {
238 int i;
240 mpbe->type = ENTRY_TYPE_BUS;
241 mpbe->bus_id = bus_id;
242 for ( i = 0; i < BUS_TYPE_LENGTH; i++ )
243 mpbe->bus_type_str[i] = type[i]; /* FIXME length check? */
244 }
247 /* fills in an MP IOAPIC entry for IOAPIC 'ioapic_id' */
248 void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie)
249 {
250 mpie->type = ENTRY_TYPE_IOAPIC;
251 mpie->ioapic_id = IOAPIC_ID;
252 mpie->ioapic_version = IOAPIC_VERSION;
253 mpie->ioapic_flags = 1; /* enabled */
254 mpie->ioapic_addr = IOAPIC_BASE_ADDRESS;
255 }
258 /* fills in an IO interrupt entry for IOAPIC 'ioapic_id' */
259 void fill_mp_io_intr_entry(
260 struct mp_io_intr_entry *mpiie,
261 int src_bus_id, int src_bus_irq, int ioapic_id, int dst_ioapic_intin)
262 {
263 mpiie->type = ENTRY_TYPE_IO_INTR;
264 mpiie->intr_type = INTR_TYPE_INT;
265 mpiie->io_intr_flags = (PCI_ISA_IRQ_MASK & (1U<<src_bus_irq)) ? 0xf : 0x0;
266 mpiie->src_bus_id = src_bus_id;
267 mpiie->src_bus_irq = src_bus_irq;
268 mpiie->dst_ioapic_id = ioapic_id;
269 mpiie->dst_ioapic_intin = dst_ioapic_intin;
270 }
273 /* fill in the mp floating processor structure */
274 void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct)
275 {
276 int i;
277 uint8_t checksum;
280 mpfps->signature[0] = '_';
281 mpfps->signature[1] = 'M';
282 mpfps->signature[2] = 'P';
283 mpfps->signature[3] = '_';
285 mpfps->mp_table = mpct;
286 mpfps->length = 1;
287 mpfps->revision = 4;
288 mpfps->checksum = 0;
289 for (i = 0; i < 5; ++i)
290 mpfps->feature[i] = 0;
292 /* compute the checksum for our new table */
293 checksum = 0;
294 for ( i = 0; i < sizeof(struct mp_floating_pointer_struct); i++ )
295 checksum += ((uint8_t *)(mpfps))[i];
296 mpfps->checksum = -checksum;
297 }
300 /*
301 * find_mp_table_start - searchs through BIOS memory for '___HVMMP' signature
302 *
303 * The '___HVMMP' signature is created by the ROMBIOS and designates a chunk
304 * of space inside the ROMBIOS that is safe for us to write our MP table info
305 */
306 void* get_mp_table_start(void)
307 {
308 char *bios_mem;
310 for ( bios_mem = (char *)ROMBIOS_BEGIN;
311 bios_mem != (char *)ROMBIOS_END;
312 bios_mem++ )
313 {
314 if ( bios_mem[0] == '_' && bios_mem[1] == '_' &&
315 bios_mem[2] == '_' && bios_mem[3] == 'H' &&
316 bios_mem[4] == 'V' && bios_mem[5] == 'M' &&
317 bios_mem[6] == 'M' && bios_mem[7] == 'P' )
318 return bios_mem;
319 }
321 return NULL;
322 }
325 /* recalculate the new ROMBIOS checksum after adding MP tables */
326 void reset_bios_checksum(void)
327 {
328 uint32_t i;
329 uint8_t checksum;
331 checksum = 0;
332 for (i = 0; i < ROMBIOS_MAXOFFSET; ++i)
333 checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
335 *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
336 }
339 /* create_mp_tables - creates MP tables for the guest based upon config data */
340 void create_mp_tables(void)
341 {
342 void *mp_table_base;
343 char *p;
344 int vcpu_nr, i, length;
346 vcpu_nr = get_vcpu_nr();
348 printf("Creating MP tables ...\n");
350 /* Find the 'safe' place in ROMBIOS for the MP tables. */
351 mp_table_base = get_mp_table_start();
352 if ( mp_table_base == NULL )
353 {
354 printf("Couldn't find start point for MP tables\n");
355 return;
356 }
358 p = mp_table_base + sizeof(struct mp_config_table);
360 for ( i = 0; i < vcpu_nr; i++ )
361 {
362 fill_mp_proc_entry((struct mp_proc_entry *)p, i);
363 p += sizeof(struct mp_proc_entry);
364 }
366 fill_mp_bus_entry((struct mp_bus_entry *)p, BUS_ID_ISA, BUS_TYPE_STR_ISA);
367 p += sizeof(struct mp_bus_entry);
369 fill_mp_ioapic_entry((struct mp_ioapic_entry *)p);
370 p += sizeof(struct mp_ioapic_entry);
372 for ( i = 0; i < 16; i++ )
373 {
374 if ( i == 2 ) continue; /* skip the slave PIC connection */
375 fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
376 BUS_ID_ISA, i, IOAPIC_ID, i);
377 p += sizeof(struct mp_io_intr_entry);
378 }
380 length = p - (char *)mp_table_base;
382 /* find the next 16-byte boundary to place the mp floating pointer */
383 while ( (unsigned long)p & 0xF )
384 p++;
386 fill_mpfps((struct mp_floating_pointer_struct *)p,
387 (uint32_t)mp_table_base);
389 fill_mp_config_table((struct mp_config_table *)mp_table_base, length);
390 reset_bios_checksum();
391 }