source: trunk/packages/xen-3.1/xen-3.1/tools/firmware/hvmloader/mp_tables.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

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