ia64/xen-unstable

view tools/firmware/hvmloader/mp_tables.c @ 19709:011948e1b5a7

hvmloader: Scan for gpxe-capable NICs until one is found.

Signed-off-by: Akio Takebe <takebe_akio@jp.fujitsu.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jun 03 16:12:34 2009 +0100 (2009-06-03)
parents f20e5039b168
children
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 <stdint.h>
32 #include "config.h"
34 /* number of non-processor MP table entries */
35 #define NR_NONPROC_ENTRIES 18
37 #define ENTRY_TYPE_PROCESSOR 0
38 #define ENTRY_TYPE_BUS 1
39 #define ENTRY_TYPE_IOAPIC 2
40 #define ENTRY_TYPE_IO_INTR 3
41 #define ENTRY_TYPE_LOCAL_INTR 4
43 #define CPU_FLAG_ENABLED 0x01
44 #define CPU_FLAG_BSP 0x02
46 /* TODO change this to correspond with what the guest's see's from CPUID */
47 #define CPU_SIG_FAMILY 0x06
48 #define CPU_SIG_MODEL 0x00
49 #define CPU_SIG_STEPPING 0x00
50 #define CPU_SIGNATURE ((CPU_SIG_FAMILY << 8) \
51 | (CPU_SIG_MODEL << 4) \
52 | (CPU_SIG_STEPPING))
53 #define CPU_FEATURE_FPU (1U << 0)
54 #define CPU_FEATURE_MCE (1U << 7)
55 #define CPU_FEATURE_CX8 (1U << 8)
56 #define CPU_FEATURE_APIC (1U << 9)
57 #define CPU_FEATURES (CPU_FEATURE_FPU | CPU_FEATURE_APIC)
59 #define BUS_TYPE_LENGTH 6
60 #define BUS_TYPE_STR_ISA "ISA "
61 #define BUS_ID_ISA 0
63 #define INTR_TYPE_INT 0
64 #define INTR_TYPE_NMI 1
65 #define INTR_TYPE_SMI 2
66 #define INTR_TYPE_EXTINT 3
68 #define INTR_MAX_NR 16
70 #include "util.h"
72 /*
73 * The following structures are defined in the MuliProcessor Specifiation v1.4
74 */
76 /* MP Floating Pointer Structure */
77 struct mp_floating_pointer_struct {
78 uint8_t signature[4];
79 uint32_t mp_table;
80 uint8_t length;
81 uint8_t revision;
82 uint8_t checksum;
83 uint8_t feature[5];
84 };
86 /* MP Configuration Table */
87 struct mp_config_table {
88 uint8_t signature[4];
89 uint16_t length;
90 uint8_t revision;
91 uint8_t checksum;
92 uint8_t oem_id[8];
93 uint8_t vendor_id[12];
94 uint32_t oem_table;
95 uint16_t oem_table_sz;
96 uint16_t nr_entries;
97 uint32_t lapic;
98 uint16_t extended_length;
99 uint8_t extended_checksum;
100 uint8_t reserved;
101 };
103 /* MP Processor Entry */
104 struct mp_proc_entry {
105 uint8_t type;
106 uint8_t lapic_id;
107 uint8_t lapic_version;
108 uint8_t cpu_flags;
109 uint32_t cpu_signature;
110 uint32_t feature_flags;
111 uint8_t reserved[8];
112 };
114 /* MP Bus Entry */
115 struct mp_bus_entry {
116 uint8_t type;
117 uint8_t bus_id;
118 uint8_t bus_type_str[6];
119 };
121 /* MP IOAPIC Entry */
122 struct mp_ioapic_entry {
123 uint8_t type;
124 uint8_t ioapic_id;
125 uint8_t ioapic_version;
126 uint8_t ioapic_flags;
127 uint32_t ioapic_addr;
128 };
130 /* MP IO Interrupt Entry */
131 struct mp_io_intr_entry {
132 uint8_t type;
133 uint8_t intr_type;
134 uint16_t io_intr_flags;
135 uint8_t src_bus_id;
136 uint8_t src_bus_irq;
137 uint8_t dst_ioapic_id;
138 uint8_t dst_ioapic_intin;
139 };
141 /* MP Local Interrupt Entry */
142 struct mp_local_intr_entry {
143 uint8_t type;
144 uint8_t intr_type;
145 uint16_t local_intr_flags;
146 uint8_t src_bus_id;
147 uint8_t src_bus_irq;
148 uint8_t dst_lapic_id;
149 uint8_t dst_lapic_lintin;
150 };
153 static void fill_mp_config_table(struct mp_config_table *mpct, int length)
154 {
155 int vcpu_nr, i;
156 uint8_t checksum;
158 vcpu_nr = hvm_info->nr_vcpus;
160 /* fill in the MP configuration table signature, "PCMP" */
161 mpct->signature[0] = 'P';
162 mpct->signature[1] = 'C';
163 mpct->signature[2] = 'M';
164 mpct->signature[3] = 'P';
166 mpct->length = length;
168 mpct->revision = 4;
170 /* fill in the OEM ID string, "_HVMCPU_" */
171 mpct->oem_id[0] = '_'; mpct->oem_id[3] = 'M'; mpct->oem_id[6] = 'U';
172 mpct->oem_id[1] = 'H'; mpct->oem_id[4] = 'C'; mpct->oem_id[7] = '_';
173 mpct->oem_id[2] = 'V'; mpct->oem_id[5] = 'P';
175 /* fill in the Vendor ID string, "XEN " */
176 mpct->vendor_id[0] = 'X'; mpct->vendor_id[6] = ' ';
177 mpct->vendor_id[1] = 'E'; mpct->vendor_id[7] = ' ';
178 mpct->vendor_id[2] = 'N'; mpct->vendor_id[8] = ' ';
179 mpct->vendor_id[3] = ' '; mpct->vendor_id[9] = ' ';
180 mpct->vendor_id[4] = ' '; mpct->vendor_id[10] = ' ';
181 mpct->vendor_id[5] = ' '; mpct->vendor_id[11] = ' ';
183 mpct->oem_table = 0;
184 mpct->oem_table_sz = 0;
186 mpct->nr_entries = vcpu_nr + NR_NONPROC_ENTRIES;
188 mpct->lapic = LAPIC_BASE_ADDRESS;
189 mpct->extended_length = 0;
190 mpct->extended_checksum = 0;
192 /* Finally, fill in the checksum. */
193 mpct->checksum = checksum = 0;
194 for ( i = 0; i < length; i++ )
195 checksum += ((uint8_t *)(mpct))[i];
196 mpct->checksum = -checksum;
197 }
199 /* fills in an MP processor entry for VCPU 'vcpu_id' */
200 static void fill_mp_proc_entry(struct mp_proc_entry *mppe, int vcpu_id)
201 {
202 mppe->type = ENTRY_TYPE_PROCESSOR;
203 mppe->lapic_id = LAPIC_ID(vcpu_id);
204 mppe->lapic_version = 0x11;
205 mppe->cpu_flags = CPU_FLAG_ENABLED;
206 if ( vcpu_id == 0 )
207 mppe->cpu_flags |= CPU_FLAG_BSP;
208 mppe->cpu_signature = CPU_SIGNATURE;
209 mppe->feature_flags = CPU_FEATURES;
210 }
213 /* fills in an MP bus entry of type 'type' and bus ID 'bus_id' */
214 static void fill_mp_bus_entry(struct mp_bus_entry *mpbe, int bus_id, const char *type)
215 {
216 int i;
218 mpbe->type = ENTRY_TYPE_BUS;
219 mpbe->bus_id = bus_id;
220 for ( i = 0; i < BUS_TYPE_LENGTH; i++ )
221 mpbe->bus_type_str[i] = type[i]; /* FIXME length check? */
222 }
225 /* fills in an MP IOAPIC entry for IOAPIC 'ioapic_id' */
226 static void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie)
227 {
228 mpie->type = ENTRY_TYPE_IOAPIC;
229 mpie->ioapic_id = IOAPIC_ID;
230 mpie->ioapic_version = IOAPIC_VERSION;
231 mpie->ioapic_flags = 1; /* enabled */
232 mpie->ioapic_addr = IOAPIC_BASE_ADDRESS;
233 }
236 /* fills in an IO interrupt entry for IOAPIC 'ioapic_id' */
237 static void fill_mp_io_intr_entry(
238 struct mp_io_intr_entry *mpiie,
239 int src_bus_id, int src_bus_irq, int ioapic_id, int dst_ioapic_intin)
240 {
241 mpiie->type = ENTRY_TYPE_IO_INTR;
242 mpiie->intr_type = INTR_TYPE_INT;
243 mpiie->io_intr_flags = (PCI_ISA_IRQ_MASK & (1U<<src_bus_irq)) ? 0xf : 0x0;
244 mpiie->src_bus_id = src_bus_id;
245 mpiie->src_bus_irq = src_bus_irq;
246 mpiie->dst_ioapic_id = ioapic_id;
247 mpiie->dst_ioapic_intin = dst_ioapic_intin;
248 }
251 /* fill in the mp floating processor structure */
252 static void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct)
253 {
254 int i;
255 uint8_t checksum;
258 mpfps->signature[0] = '_';
259 mpfps->signature[1] = 'M';
260 mpfps->signature[2] = 'P';
261 mpfps->signature[3] = '_';
263 mpfps->mp_table = mpct;
264 mpfps->length = 1;
265 mpfps->revision = 4;
266 mpfps->checksum = 0;
267 for (i = 0; i < 5; ++i)
268 mpfps->feature[i] = 0;
270 /* compute the checksum for our new table */
271 checksum = 0;
272 for ( i = 0; i < sizeof(struct mp_floating_pointer_struct); i++ )
273 checksum += ((uint8_t *)(mpfps))[i];
274 mpfps->checksum = -checksum;
275 }
278 /*
279 * find_mp_table_start - searchs through BIOS memory for '___HVMMP' signature
280 *
281 * The '___HVMMP' signature is created by the ROMBIOS and designates a chunk
282 * of space inside the ROMBIOS that is safe for us to write our MP table info
283 */
284 static void *get_mp_table_start(void)
285 {
286 char *bios_mem;
288 for ( bios_mem = (char *)ROMBIOS_BEGIN;
289 bios_mem != (char *)ROMBIOS_END;
290 bios_mem++ )
291 {
292 if ( strncmp(bios_mem, "___HVMMP", 8) == 0)
293 return bios_mem;
294 }
296 return NULL;
297 }
300 /* recalculate the new ROMBIOS checksum after adding MP tables */
301 static void reset_bios_checksum(void)
302 {
303 uint32_t i;
304 uint8_t checksum;
306 checksum = 0;
307 for (i = 0; i < ROMBIOS_MAXOFFSET; ++i)
308 checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
310 *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
311 }
313 /* create_mp_tables - creates MP tables for the guest based upon config data */
314 void create_mp_tables(void)
315 {
316 void *mp_table_base;
317 char *p;
318 int vcpu_nr, i, length;
320 vcpu_nr = hvm_info->nr_vcpus;
322 printf("Creating MP tables ...\n");
324 /* Find the 'safe' place in ROMBIOS for the MP tables. */
325 mp_table_base = get_mp_table_start();
326 if ( mp_table_base == NULL )
327 {
328 printf("Couldn't find start point for MP tables\n");
329 return;
330 }
332 p = mp_table_base + sizeof(struct mp_config_table);
334 for ( i = 0; i < vcpu_nr; i++ )
335 {
336 fill_mp_proc_entry((struct mp_proc_entry *)p, i);
337 p += sizeof(struct mp_proc_entry);
338 }
340 fill_mp_bus_entry((struct mp_bus_entry *)p, BUS_ID_ISA, BUS_TYPE_STR_ISA);
341 p += sizeof(struct mp_bus_entry);
343 fill_mp_ioapic_entry((struct mp_ioapic_entry *)p);
344 p += sizeof(struct mp_ioapic_entry);
346 for ( i = 0; i < 16; i++ )
347 {
348 if ( i == 2 ) continue; /* skip the slave PIC connection */
349 fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
350 BUS_ID_ISA, i, IOAPIC_ID, (i == 0) ? 2 : i);
351 p += sizeof(struct mp_io_intr_entry);
352 }
354 length = p - (char *)mp_table_base;
356 /* find the next 16-byte boundary to place the mp floating pointer */
357 while ( (unsigned long)p & 0xF )
358 p++;
360 fill_mpfps((struct mp_floating_pointer_struct *)p,
361 (uint32_t)mp_table_base);
363 fill_mp_config_table((struct mp_config_table *)mp_table_base, length);
364 reset_bios_checksum();
365 }