Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


3b6a4631b923180e2934922f4c6e9894426f1812
[palacios.git] / palacios / src / devices / mptable.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2010, Peter Dinda <pdinda@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_string.h>
22 #include <palacios/vm_guest_mem.h>
23
24 /* 
25   The guest bios is compiled with blank space for am MP table
26   at a default address.  A cookie value is temporarily placed 
27   there so we can verify it exists.  If it does, we overwrite
28   the MP table based on the configuration we are given in the 
29   guest info.  
30
31   Currently, we set up n identical processors (based on
32   number of cores in guest info), with apics 0..n-1, and
33   ioapic as n.
34
35   The expectation is that the target will have 
36   8 bytes (for ___HVMMP signature) followed by 896 bytes of space
37   for a total of 904 bytes of space.
38   We write the floating pointer at target (16 bytes), 
39   immediately followed  by the mp config header, followed by
40   the entries. 
41
42 */
43
44 #define BIOS_MP_TABLE_DEFAULT_LOCATION 0xfcc00   // guest physical (linear)
45 #define BIOS_MP_TABLE_COOKIE         "___HVMMP"
46 #define BIOS_MP_TABLE_COOKIE_LEN     8
47
48 #define POINTER_SIGNATURE "_MP_"
49 #define HEADER_SIGNATURE "PCMP"
50
51 #define SPEC_REV ((uint8_t)0x4)
52 #define OEM_ID   "V3VEE   "
53 #define PROD_ID  "PALACIOS 1.3 "
54
55 #define LAPIC_ADDR 0xfee00000
56 #define LAPIC_VERSION  0x11
57
58 #define ENTRY_PROC 0
59 #define ENTRY_BUS 1
60 #define ENTRY_IOAPIC 2
61 #define ENTRY_IOINT 3
62 #define ENTRY_LOINT 4
63
64 #define IOAPIC_ADDR 0xfec00000
65 #define IOAPIC_VERSION 0x11
66
67 // These are bochs defaults - should really come from cpuid of machne
68 #define PROC_FAMILY 0x6
69 #define PROC_STEPPING 0x0
70 #define PROC_MODEL 0x0
71 #define PROC_FEATURE_FLAGS 0x00000201 
72
73
74 #define BUS_ISA "ISA   "
75
76 #define INT_TYPE_INT 0
77 #define INT_TYPE_NMI 1
78 #define INT_TYPE_SMI 2
79 #define INT_TYPE_EXT 3
80
81 #define INT_POLARITY_DEFAULT     0
82 #define INT_POLARITY_ACTIVE_HIGH 1
83 #define INT_POLARITY_RESERVED    2
84 #define INT_POLARITY_ACTIVE_LOW  3
85
86 #define INT_TRIGGER_DEFAULT      0
87 #define INT_TRIGGER_EDGE         1
88 #define INT_TRIGGER_RESERVED     2
89 #define INT_TRIGGER_LEVEL        3
90
91
92
93
94 // This points to the mp table header
95 struct mp_floating_pointer {
96     uint32_t signature;          /* "_MP_" */
97     uint32_t pointer;            /* gpa of MP table (0xfcc00) */
98     uint8_t  length;             /* length in 16 byte chunks (paragraphs) */
99     uint8_t  spec_rev;           /* 0x4 */
100     uint8_t  checksum;
101     uint8_t  mp_featurebyte[5];  /* zero out to indicate mp config table
102                                     first byte nonzero => default configurations (see spec)
103                                     second byte, bit 7 (top bit) = IMCR if set, virtual wire if zero */
104 } __attribute__((packed));
105
106
107 struct mp_table_header {
108     uint32_t signature;                 /* "PCMP"                                             */
109     uint16_t base_table_length;         /* bytes, starting from header                        */
110     uint8_t  spec_rev;                  /* specification rvision (0x4 is the current rev)     */
111     uint8_t  checksum;                  /* sum of all bytes, including checksum, must be zero */
112     uint8_t  oem_id[8];                 /* OEM ID "V3VEE   "                                  */
113     uint8_t  prod_id[12];               /* Product ID "PALACIOS 1.3"                          */
114     uint32_t oem_table_ptr;             /* oem table, if used (zeroed)                        */
115     uint16_t oem_table_size;            /* oem table length, if used                          */
116     uint16_t entry_count;               /* numnber of entries in this table                   */
117     uint32_t lapic_addr;                /* apic address on all processors                     */
118     uint16_t extended_table_length;     /* zero by default                                    */
119     uint8_t  extended_table_checksum;   /* zero by default                                    */
120     uint8_t  reserved;                  /* zero by default                                    */
121     /* this is followed by entries of the various types indicated below */
122 } __attribute__((packed));
123
124 struct mp_table_processor {
125     uint8_t entry_type;          // type 0
126     uint8_t lapic_id;            // 0..
127     uint8_t lapic_version;       // 
128
129     union {
130         uint8_t data;       
131         struct {
132             uint8_t en          : 1;        /* 1 = processor enabled */
133             uint8_t bp          : 1;        /* 1 = bootstrap processor */
134             uint8_t reserved    : 6;
135         } __attribute__((packed));
136     } __attribute__((packed)) cpu_flags;
137
138     union {
139         uint32_t data;
140         struct {
141             uint8_t stepping    : 4;
142             uint8_t model       : 4;
143             uint8_t family      : 4; 
144             uint32_t rest       : 20;
145         } __attribute__((packed));
146     } __attribute__((packed)) cpu_signature;
147
148     uint32_t cpu_feature_flags;      /* result of CPUID */
149     uint32_t reserved[2];
150 } __attribute__((packed));
151
152 struct mp_table_bus {
153     uint8_t entry_type;          /* type 1              */
154     uint8_t bus_id;              /* 0..                 */
155     uint8_t bus_type[6];         /* "PCI" "INTERN", etc */
156 } __attribute__((packed));
157
158
159 struct mp_table_ioapic {
160     uint8_t entry_type;          /* type 2                            */
161     uint8_t ioapic_id;           /* 0..                               */
162     uint8_t ioapic_version;      /* bits 0..7 of the version register */
163
164     union {
165         uint8_t data;       
166         struct {
167             uint8_t en         : 1;        /* 1=ioapic enabled */
168             uint8_t reserved   : 7;
169         } __attribute__((packed));
170     } __attribute__((packed)) ioapic_flags;
171
172     uint32_t ioapic_address;     /* physical address (same for all procs) */
173 } __attribute__((packed));
174
175
176 struct mp_table_io_interrupt_assignment {
177     uint8_t entry_type;          /* type 3 */
178     uint8_t interrupt_type;      /* 0=int, 1=nmi, 2=smi, 3=ExtInt(8259) */
179  
180    union {
181         uint16_t value;
182         struct {
183             uint8_t po           : 2;        /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
184             uint8_t el           : 2;        /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
185             uint16_t reserved    : 12;
186         } __attribute__((packed));
187    } __attribute__((packed)) flags;
188
189     uint8_t source_bus_id;
190     uint8_t source_bus_irq;
191     uint8_t dest_ioapic_id;
192     uint8_t dest_ioapic_intn;
193 } __attribute__((packed));
194
195
196 struct mp_table_local_interrupt_assignment {
197     uint8_t entry_type;          /* type 4 */
198     uint8_t interrupt_type;      /* 0 = int, 1 = nmi, 2 = smi, 3 = ExtInt(8259) */
199
200     union {
201         uint16_t value;
202         struct {
203             uint8_t po           : 2;        /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
204             uint8_t el           : 2;        /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
205             uint16_t reserved    : 12;
206         } __attribute__((packed));
207     } __attribute__((packed)) flags;
208
209     uint8_t source_bus_id;
210     uint8_t source_bus_irq;
211     uint8_t dest_ioapic_id;
212     uint8_t dest_ioapic_intn;
213 } __attribute__((packed));
214
215
216
217
218
219 static inline int check_for_cookie(void * target) {
220     return (memcmp(target, BIOS_MP_TABLE_COOKIE, BIOS_MP_TABLE_COOKIE_LEN) == 0);
221 }
222
223 static inline int check_table(void * target) {
224     uint32_t i;
225     uint8_t sum;
226     struct mp_table_header * header;
227
228     header = (struct mp_table_header *)target;
229     sum = 0;
230
231     for (i = 0; i < header->base_table_length; i++) {
232         sum += ((uint8_t *)target)[i];
233     }
234
235     if (sum == 0) { 
236         return 1;
237     } else {
238         // failed checksum
239         return 0;
240     }
241 }
242
243
244 static inline int check_pointer(void * target) {
245     uint32_t i;
246     uint8_t sum;
247     struct mp_floating_pointer * p;
248
249     p = (struct mp_floating_pointer *)target;
250     sum = 0;
251
252     for (i = 0; i < p->length * 16; i++) {
253         sum += ((uint8_t *)target)[i];
254     }
255
256     if (sum == 0) { 
257         // passed
258         return 1;
259     } else {
260         // failed
261         return 0;
262     }
263 }
264     
265
266 static int write_pointer(void * target, uint32_t mptable_gpa) {
267     uint32_t i;
268     uint8_t sum;
269     struct mp_floating_pointer * p = (struct mp_floating_pointer *)target;
270
271     memset((void *)p, 0, sizeof(struct mp_floating_pointer));
272     
273     memcpy((void *)&(p->signature), POINTER_SIGNATURE, 4);
274     
275     p->pointer = mptable_gpa;
276     p->length = 1;             // length in 16 byte chunks
277     p->spec_rev = SPEC_REV;
278     
279     // checksum calculation
280     p->checksum = 0;
281     sum = 0;
282
283     for (i = 0; i < 16; i++) {
284         sum += ((uint8_t *)target)[i];
285     }
286
287     p->checksum = (255 - sum) + 1;
288
289     return 0;
290 }
291     
292
293     
294
295 static int write_mptable(void * target, uint32_t numcores) {
296     uint32_t i = 0;
297     uint8_t sum = 0;
298     uint8_t core = 0;
299     uint8_t irq = 0;    
300     struct mp_table_header * header = NULL;
301     struct mp_table_processor * proc = NULL;
302     struct mp_table_bus * bus = NULL;
303     struct mp_table_ioapic * ioapic = NULL;
304     struct mp_table_io_interrupt_assignment * interrupt = NULL;
305     uint8_t * cur = target;
306
307     header = (struct mp_table_header *)cur;
308     cur = cur + sizeof(struct mp_table_header);
309     
310     memset((void *)header, 0, sizeof(struct mp_table_header));
311     
312     
313     memcpy(&(header->signature), HEADER_SIGNATURE, 4);
314     header->spec_rev = SPEC_REV;
315     memcpy(header->oem_id, OEM_ID, 8);
316     memcpy(header->prod_id, PROD_ID, 12);
317
318     // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n
319     header->entry_count = numcores + 18;
320     header->lapic_addr = LAPIC_ADDR;
321     
322     // now we arrange the processors;
323     
324     for (core = 0; core < numcores; core++) { 
325         proc = (struct mp_table_processor *)cur;
326         memset((void *)proc, 0, sizeof(struct mp_table_processor));
327         proc->entry_type = ENTRY_PROC;
328         proc->lapic_id = core;
329         proc->lapic_version = LAPIC_VERSION;
330         proc->cpu_flags.en = 1;
331
332         if (core == 0) {
333             proc->cpu_flags.bp = 1;
334         } else {
335             proc->cpu_flags.bp = 0;
336         }
337
338         proc->cpu_signature.family = PROC_FAMILY;
339         proc->cpu_signature.model = PROC_MODEL;
340         proc->cpu_signature.stepping = PROC_STEPPING;
341         proc->cpu_feature_flags = PROC_FEATURE_FLAGS;
342
343         cur += sizeof(struct mp_table_processor);
344     }
345
346     // next comes the ISA bas
347     bus = (struct mp_table_bus *)cur;
348     cur += sizeof(struct mp_table_bus);
349
350     memset((void *)bus, 0, sizeof(struct mp_table_bus));
351     bus->entry_type = ENTRY_BUS;
352     bus->bus_id = 0;
353     memcpy(bus->bus_type, BUS_ISA, 6);
354
355     // next comes the IOAPIC
356     ioapic = (struct mp_table_ioapic *)cur;
357     cur += sizeof(struct mp_table_ioapic);
358     
359     memset((void *)ioapic, 0, sizeof(struct mp_table_ioapic));
360     ioapic->entry_type = ENTRY_IOAPIC;
361     ioapic->ioapic_id = numcores;
362     ioapic->ioapic_version = IOAPIC_VERSION;
363     ioapic->ioapic_flags.en = 1;
364     ioapic->ioapic_address = IOAPIC_ADDR;
365
366
367     // The MPTABLE IRQ mappings are kind of odd. 
368     // We don't include a bus IRQ 2, and instead remap Bus IRQ 0 to dest irq 2
369
370
371     for (irq = 0; irq < 16; irq++) { 
372         uint8_t dst_irq = irq;
373
374         if (irq == 0) {
375             dst_irq = 2;
376         } else if (irq == 2) {
377             continue;
378         }
379
380         interrupt = (struct mp_table_io_interrupt_assignment *)cur;
381         memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
382
383         interrupt->entry_type = ENTRY_IOINT;
384         interrupt->interrupt_type = INT_TYPE_INT;
385         interrupt->flags.po = INT_POLARITY_DEFAULT;
386         interrupt->flags.el = INT_TRIGGER_DEFAULT;
387         interrupt->source_bus_id = 0;
388         interrupt->source_bus_irq = irq;
389         interrupt->dest_ioapic_id = numcores;
390         interrupt->dest_ioapic_intn = dst_irq;
391
392         cur += sizeof(struct mp_table_io_interrupt_assignment);
393     }
394
395     // now we can set the length;
396
397     header->base_table_length = (cur - (uint8_t *)header);
398
399     // checksum calculation
400     header->checksum = 0;
401     sum = 0;
402     for (i = 0; i < header->base_table_length; i++) {
403         sum += ((uint8_t *)target)[i];
404     }
405     header->checksum = (255 - sum) + 1;
406
407
408         
409     return 0;
410 }
411
412 static int mptable_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
413     void * target = NULL;
414
415     if (v3_gpa_to_hva(&(vm->cores[0]), BIOS_MP_TABLE_DEFAULT_LOCATION, (addr_t *)&target) == -1) { 
416         PrintError("Cannot inject mptable due to unmapped bios!\n");
417         return -1;
418     }
419     
420     if (!check_for_cookie(target)) { 
421         PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
422         return -1;
423     }
424
425     if (vm->num_cores > 32) { 
426         PrintError("No support for >32 cores in writing MP table, aborting.\n");
427         return -1;
428     }
429
430     V3_Print("Constructing mptable for %u cores at %p\n", vm->num_cores, target);
431
432     if (write_pointer(target, BIOS_MP_TABLE_DEFAULT_LOCATION + sizeof(struct mp_floating_pointer)) == -1) { 
433         PrintError("Unable to write mptable floating pointer, aborting.\n");
434         return -1;
435     }
436
437     if (!check_pointer(target)) { 
438         PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
439         return -1;
440     }
441
442     if (write_mptable(target + sizeof(struct mp_floating_pointer), vm->num_cores) == -1) {
443         PrintError("Cannot inject mptable configuration header and entries\n");
444         return -1;
445     }
446
447     if (!check_table(target + sizeof(struct mp_floating_pointer))) { 
448         PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");
449         return -1;
450     }
451
452
453     return 0;
454 }
455
456
457
458 device_register("MPTABLE", mptable_init)