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.


bug fix to check for illegal memory ranges
[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.  The ISA interrupt lines map to pins 0..15
34   of the first ioapic.  PCI bus lines map to pins 16..19
35   of the first ioapic.  The system supports virtual wire
36   compability mode and symmetric mode.   PIC mode is not supported. 
37
38   The expectation is that the target will have 
39   8 bytes (for ___HVMMP signature) followed by 896 bytes of space
40   for a total of 904 bytes of space.
41   We write the floating pointer at target (16 bytes), 
42   immediately followed  by the mp config header, followed by
43   the entries. 
44
45 */
46
47 #define BIOS_MP_TABLE_DEFAULT_LOCATION 0xfcc00   // guest physical (linear)
48 #define BIOS_MP_TABLE_COOKIE         "___HVMMP"
49 #define BIOS_MP_TABLE_COOKIE_LEN     8
50
51 #define POINTER_SIGNATURE "_MP_"
52 #define HEADER_SIGNATURE "PCMP"
53
54 #define SPEC_REV ((uint8_t)0x4)
55 #define OEM_ID   "V3VEE   "
56 #define PROD_ID  "PALACIOS 1.3 "
57
58 #define LAPIC_ADDR 0xfee00000
59 #define LAPIC_VERSION  0x11
60
61 #define ENTRY_PROC 0
62 #define ENTRY_BUS 1
63 #define ENTRY_IOAPIC 2
64 #define ENTRY_IOINT 3
65 #define ENTRY_LOINT 4
66
67 #define IOAPIC_ADDR 0xfec00000
68 #define IOAPIC_VERSION 0x11
69
70 // These are bochs defaults - should really come from cpuid of machne
71 #define PROC_FAMILY 0x6
72 #define PROC_STEPPING 0x0
73 #define PROC_MODEL 0x0
74 #define PROC_FEATURE_FLAGS 0x00000201 
75
76
77 #define BUS_ISA "ISA   "
78 #define BUS_PCI "PCI   "
79
80 #define INT_TYPE_INT 0
81 #define INT_TYPE_NMI 1
82 #define INT_TYPE_SMI 2
83 #define INT_TYPE_EXT 3
84
85 #define INT_POLARITY_DEFAULT     0
86 #define INT_POLARITY_ACTIVE_HIGH 1
87 #define INT_POLARITY_RESERVED    2
88 #define INT_POLARITY_ACTIVE_LOW  3
89
90 #define INT_TRIGGER_DEFAULT      0
91 #define INT_TRIGGER_EDGE         1
92 #define INT_TRIGGER_RESERVED     2
93 #define INT_TRIGGER_LEVEL        3
94
95
96
97
98 // This points to the mp table header
99 struct mp_floating_pointer {
100     uint32_t signature;          /* "_MP_" */
101     uint32_t pointer;            /* gpa of MP table (0xfcc00) */
102     uint8_t  length;             /* length in 16 byte chunks (paragraphs) */
103     uint8_t  spec_rev;           /* 0x4 */
104     uint8_t  checksum;
105     uint8_t  mp_featurebyte[5];  /* zero out to indicate mp config table
106                                     first byte nonzero => default configurations (see spec)
107                                     second byte, bit 7 (top bit) = IMCR if set, virtual wire if zero */
108 } __attribute__((packed));
109
110
111 struct mp_table_header {
112     uint32_t signature;                 /* "PCMP"                                             */
113     uint16_t base_table_length;         /* bytes, starting from header                        */
114     uint8_t  spec_rev;                  /* specification rvision (0x4 is the current rev)     */
115     uint8_t  checksum;                  /* sum of all bytes, including checksum, must be zero */
116     uint8_t  oem_id[8];                 /* OEM ID "V3VEE   "                                  */
117     uint8_t  prod_id[12];               /* Product ID "PALACIOS 1.3"                          */
118     uint32_t oem_table_ptr;             /* oem table, if used (zeroed)                        */
119     uint16_t oem_table_size;            /* oem table length, if used                          */
120     uint16_t entry_count;               /* numnber of entries in this table                   */
121     uint32_t lapic_addr;                /* apic address on all processors                     */
122     uint16_t extended_table_length;     /* zero by default                                    */
123     uint8_t  extended_table_checksum;   /* zero by default                                    */
124     uint8_t  reserved;                  /* zero by default                                    */
125     /* this is followed by entries of the various types indicated below */
126 } __attribute__((packed));
127
128 struct mp_table_processor {
129     uint8_t entry_type;          // type 0
130     uint8_t lapic_id;            // 0..
131     uint8_t lapic_version;       // 
132
133     union {
134         uint8_t data;       
135         struct {
136             uint8_t en          : 1;        /* 1 = processor enabled */
137             uint8_t bp          : 1;        /* 1 = bootstrap processor */
138             uint8_t reserved    : 6;
139         } __attribute__((packed));
140     } __attribute__((packed)) cpu_flags;
141
142     union {
143         uint32_t data;
144         struct {
145             uint8_t stepping    : 4;
146             uint8_t model       : 4;
147             uint8_t family      : 4; 
148             uint32_t rest       : 20;
149         } __attribute__((packed));
150     } __attribute__((packed)) cpu_signature;
151
152     uint32_t cpu_feature_flags;      /* result of CPUID */
153     uint32_t reserved[2];
154 } __attribute__((packed));
155
156 struct mp_table_bus {
157     uint8_t entry_type;          /* type 1              */
158     uint8_t bus_id;              /* 0..                 */
159     uint8_t bus_type[6];         /* "PCI" "INTERN", etc */
160 } __attribute__((packed));
161
162
163 struct mp_table_ioapic {
164     uint8_t entry_type;          /* type 2                            */
165     uint8_t ioapic_id;           /* 0..                               */
166     uint8_t ioapic_version;      /* bits 0..7 of the version register */
167
168     union {
169         uint8_t data;       
170         struct {
171             uint8_t en         : 1;        /* 1=ioapic enabled */
172             uint8_t reserved   : 7;
173         } __attribute__((packed));
174     } __attribute__((packed)) ioapic_flags;
175
176     uint32_t ioapic_address;     /* physical address (same for all procs) */
177 } __attribute__((packed));
178
179
180 struct mp_table_io_interrupt_assignment {
181     uint8_t entry_type;          /* type 3 */
182     uint8_t interrupt_type;      /* 0=int, 1=nmi, 2=smi, 3=ExtInt(8259) */
183  
184    union {
185         uint16_t value;
186         struct {
187             uint8_t po           : 2;        /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
188             uint8_t el           : 2;        /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
189             uint16_t reserved    : 12;
190         } __attribute__((packed));
191    } __attribute__((packed)) flags;
192
193     uint8_t source_bus_id;
194     uint8_t source_bus_irq;
195     uint8_t dest_ioapic_id;
196     uint8_t dest_ioapic_intn;
197 } __attribute__((packed));
198
199
200 struct mp_table_local_interrupt_assignment {
201     uint8_t entry_type;          /* type 4 */
202     uint8_t interrupt_type;      /* 0 = int, 1 = nmi, 2 = smi, 3 = ExtInt(8259) */
203
204     union {
205         uint16_t value;
206         struct {
207             uint8_t po           : 2;        /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
208             uint8_t el           : 2;        /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
209             uint16_t reserved    : 12;
210         } __attribute__((packed));
211     } __attribute__((packed)) flags;
212
213     uint8_t source_bus_id;
214     uint8_t source_bus_irq;
215     uint8_t dest_ioapic_id;
216     uint8_t dest_ioapic_intn;
217 } __attribute__((packed));
218
219
220
221 #define NUM_PCI_SLOTS 8
222
223
224 static inline int check_for_cookie(void * target) {
225     return (memcmp(target, BIOS_MP_TABLE_COOKIE, BIOS_MP_TABLE_COOKIE_LEN) == 0);
226 }
227
228 static inline int check_table(void * target) {
229     uint32_t i;
230     uint8_t sum;
231     struct mp_table_header * header;
232
233     header = (struct mp_table_header *)target;
234     sum = 0;
235
236     for (i = 0; i < header->base_table_length; i++) {
237         sum += ((uint8_t *)target)[i];
238     }
239
240     if (sum == 0) { 
241         return 1;
242     } else {
243         // failed checksum
244         return 0;
245     }
246 }
247
248
249 static inline int check_pointer(void * target) {
250     uint32_t i;
251     uint8_t sum;
252     struct mp_floating_pointer * p;
253
254     p = (struct mp_floating_pointer *)target;
255     sum = 0;
256
257     for (i = 0; i < p->length * 16; i++) {
258         sum += ((uint8_t *)target)[i];
259     }
260
261     if (sum == 0) { 
262         // passed
263         return 1;
264     } else {
265         // failed
266         return 0;
267     }
268 }
269     
270
271 static int write_pointer(void * target, uint32_t mptable_gpa) {
272     uint32_t i;
273     uint8_t sum;
274     struct mp_floating_pointer * p = (struct mp_floating_pointer *)target;
275
276     memset((void *)p, 0, sizeof(struct mp_floating_pointer));
277     
278     memcpy((void *)&(p->signature), POINTER_SIGNATURE, 4);
279     
280     p->pointer = mptable_gpa;
281     p->length = 1;             // length in 16 byte chunks
282     p->spec_rev = SPEC_REV;
283
284     // The remaining zeros indicate that an MP config table is present
285     // and that virtual wire mode is implemented (not PIC mode)
286     // Either virtual wire or PIC must be implemented in addition to
287     // symmetric I/O mode
288     
289     // checksum calculation
290     p->checksum = 0;
291     sum = 0;
292
293     for (i = 0; i < 16; i++) {
294         sum += ((uint8_t *)target)[i];
295     }
296
297     p->checksum = (255 - sum) + 1;
298
299     return 0;
300 }
301     
302
303     
304
305 static int write_mptable(void * target, uint32_t numcores, int have_ioapic, int have_pci) {
306     uint32_t i = 0;
307     uint8_t sum = 0;
308     uint8_t core = 0;
309     uint8_t irq = 0;    
310     struct mp_table_header * header = NULL;
311     struct mp_table_processor * proc = NULL;
312     struct mp_table_bus * bus = NULL;
313     struct mp_table_ioapic * ioapic = NULL;
314     struct mp_table_io_interrupt_assignment * interrupt = NULL;
315     uint8_t * cur = target;
316
317     header = (struct mp_table_header *)cur;
318     cur = cur + sizeof(struct mp_table_header);
319     
320     memset((void *)header, 0, sizeof(struct mp_table_header));
321     
322     
323     memcpy(&(header->signature), HEADER_SIGNATURE, 4);
324     header->spec_rev = SPEC_REV;
325     memcpy(header->oem_id, OEM_ID, 8);
326     memcpy(header->prod_id, PROD_ID, 12);
327
328     // numcores entries for apics, one entry for ioapic (if it exists)
329     // one entry for isa bus (if ioapic exists), one entry for pci bus (if exists),
330     // 16 entries for isa irqs (if ioapic exists) + num_slots*num_intr pci irqs
331     // (if ioapic and pci exist)
332     header->entry_count = numcores + !!have_ioapic + !!have_ioapic + !!have_pci +
333       16*(!!have_ioapic) + NUM_PCI_SLOTS * 4 * (!!have_pci) * (!!have_ioapic);
334
335     header->lapic_addr = LAPIC_ADDR;
336     
337     // now we arrange the processors;
338     for (core = 0; core < numcores; core++) { 
339         proc = (struct mp_table_processor *)cur;
340         memset((void *)proc, 0, sizeof(struct mp_table_processor));
341         proc->entry_type = ENTRY_PROC;
342         proc->lapic_id = core;
343         proc->lapic_version = LAPIC_VERSION;
344         proc->cpu_flags.en = 1;
345
346         if (core == 0) {
347             proc->cpu_flags.bp = 1;
348         } else {
349             proc->cpu_flags.bp = 0;
350         }
351
352         proc->cpu_signature.family = PROC_FAMILY;
353         proc->cpu_signature.model = PROC_MODEL;
354         proc->cpu_signature.stepping = PROC_STEPPING;
355         proc->cpu_feature_flags = PROC_FEATURE_FLAGS;
356
357         cur += sizeof(struct mp_table_processor);
358     }
359
360     // PCI bus is always zero
361     if (have_pci) { 
362       bus = (struct mp_table_bus *)cur;
363       cur += sizeof(struct mp_table_bus);
364       
365       memset((void *)bus, 0, sizeof(struct mp_table_bus));
366       bus->entry_type = ENTRY_BUS;
367       bus->bus_id = 0;
368       memcpy(bus->bus_type, BUS_PCI, 6);
369     }
370
371     // next comes the ISA bus  (bus one)
372     bus = (struct mp_table_bus *)cur;
373     cur += sizeof(struct mp_table_bus);
374
375     memset((void *)bus, 0, sizeof(struct mp_table_bus));
376     bus->entry_type = ENTRY_BUS;
377     bus->bus_id = 1;
378     memcpy(bus->bus_type, BUS_ISA, 6);
379
380
381     // next comes the IOAPIC
382     if (have_ioapic) { 
383       ioapic = (struct mp_table_ioapic *)cur;
384       cur += sizeof(struct mp_table_ioapic);
385       
386       memset((void *)ioapic, 0, sizeof(struct mp_table_ioapic));
387       ioapic->entry_type = ENTRY_IOAPIC;
388       ioapic->ioapic_id = numcores;
389       ioapic->ioapic_version = IOAPIC_VERSION;
390       ioapic->ioapic_flags.en = 1;
391       ioapic->ioapic_address = IOAPIC_ADDR;
392     }
393
394
395     // LEGACY ISA IRQ mappings
396     // The MPTABLE IRQ mappings are kind of odd. 
397     // We don't include a bus IRQ 2, and instead remap Bus IRQ 0 to dest irq 2
398     // The idea here is that the timer hooks to 2, while the PIC hooks
399     // to zero in ExtInt mode.  This makes it possible to do virtual wire
400     // mode via the ioapic.
401     //
402     // Note that the timer connects to pin 2 of the IOAPIC.  Sadly,
403     // the timer is unaware of this and just raises irq 0.  The ioapic
404     // transforms this to a pin 2 interrupt.   If we want the PIC
405     // to be able to channel interrupts via pin 0, we need a separate
406     // path. 
407     if (have_ioapic) {
408       for (irq = 0; irq < 16; irq++) { 
409         uint8_t dst_irq = irq;
410         
411         if (irq == 0) {
412           dst_irq = 2;
413         } else if (irq == 2) {
414           continue;
415         }
416         
417         interrupt = (struct mp_table_io_interrupt_assignment *)cur;
418         memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
419         
420         interrupt->entry_type = ENTRY_IOINT;
421         interrupt->interrupt_type = INT_TYPE_INT;
422         interrupt->flags.po = INT_POLARITY_DEFAULT;
423         interrupt->flags.el = INT_TRIGGER_DEFAULT;
424         interrupt->source_bus_id = 1;
425         interrupt->source_bus_irq = irq;
426         interrupt->dest_ioapic_id = numcores;
427         interrupt->dest_ioapic_intn = dst_irq;
428         
429         cur += sizeof(struct mp_table_io_interrupt_assignment);
430       }
431     }
432       
433     if (have_pci && have_ioapic)     {
434       // Interrupt redirection entries for PCI bus
435       // 
436       // We need an entry for each slot+pci interrupt
437       // There can be 32 slots, each of which can use 4 interrupts
438       // Thus there are 128 entries
439       //
440       // In this simple setup, we map
441       // slot i, intr j (both zero based)  to  pci_irq[(i+j)%4]
442       
443       int slot, intr;
444       static uint8_t pci_irq[4] = {16,17,18,19};
445       
446       for (slot=0;slot<NUM_PCI_SLOTS;slot++) { 
447         for (intr=0;intr<4;intr++) { 
448           
449           uint8_t dst_irq = pci_irq[(slot+intr)%4];
450           
451           interrupt = (struct mp_table_io_interrupt_assignment *)cur;
452           memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
453
454           interrupt->entry_type = ENTRY_IOINT;
455           interrupt->interrupt_type = INT_TYPE_INT;
456           interrupt->flags.po = INT_POLARITY_DEFAULT;
457           interrupt->flags.el = INT_TRIGGER_DEFAULT;
458           interrupt->source_bus_id = 0;
459           // Yes, this is how you encode the slot and pin of a PCI device
460           // As we all know, bits are expensive
461           // We can have as many as 32 slots, but to get that large,
462           // we would need to tweak the bios's landing zone for the mptable
463           interrupt->source_bus_irq = (slot<<2) | intr ;
464           interrupt->dest_ioapic_id = numcores;
465           interrupt->dest_ioapic_intn = dst_irq;
466           
467           cur += sizeof(struct mp_table_io_interrupt_assignment);
468           
469           //V3_Print("PCI0, slot %d, irq %d maps to irq %d\n",slot,intr,dst_irq);
470         }
471       }
472     }
473     
474     // now we can set the length;
475
476     header->base_table_length = (cur - (uint8_t *)header);
477
478     V3_Print("MPtable size: %u\n",header->base_table_length);
479
480     // checksum calculation
481     header->checksum = 0;
482     sum = 0;
483     for (i = 0; i < header->base_table_length; i++) {
484         sum += ((uint8_t *)target)[i];
485     }
486     header->checksum = (255 - sum) + 1;
487         
488     return 0;
489 }
490
491
492 static v3_cfg_tree_t *find_first_peer_device_of_class(v3_cfg_tree_t *themptablenode, char *theclass)
493 {
494   v3_cfg_tree_t *p=themptablenode->parent;
495   v3_cfg_tree_t *c;
496
497
498   if (p==NULL) { 
499     return NULL;
500   }
501
502   for (c=v3_xml_child(p,"device"); 
503        c && strcasecmp(v3_cfg_val(c,"class"),theclass); 
504        c=v3_xml_next(c)) {
505   }
506
507   return c;
508 }
509
510   
511
512
513 static int mptable_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
514     void * target = NULL;
515
516     int have_pci = find_first_peer_device_of_class(cfg,"pci")!=NULL;
517     int have_piix3 = find_first_peer_device_of_class(cfg,"piix3")!=NULL;
518     int have_apic = find_first_peer_device_of_class(cfg,"lapic")!=NULL;
519     int have_ioapic = find_first_peer_device_of_class(cfg,"ioapic")!=NULL;
520
521     if (!have_apic) { 
522       PrintError("Attempt to instantiate MPTABLE but machine has no apics!\n");
523       return -1;
524     }
525
526     if (!have_ioapic) { 
527       PrintError("Attempt to instantiate MPTABLE without ioapic - will try, but this won't end well\n");
528     }
529
530     if (have_pci && (!have_piix3 || !have_ioapic)) { 
531       PrintError("Attempt to instantiate MPTABLE with a PCI Bus, but without either a piix3 or an ioapic\n");
532       return -1;
533     }
534       
535     if (v3_gpa_to_hva(&(vm->cores[0]), BIOS_MP_TABLE_DEFAULT_LOCATION, (addr_t *)&target) == -1) { 
536         PrintError("Cannot inject mptable due to unmapped bios!\n");
537         return -1;
538     }
539     
540     if (!check_for_cookie(target)) { 
541         PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
542         return -1;
543     }
544
545     if (vm->num_cores > 32) { 
546         PrintError("No support for >32 cores in writing MP table, aborting.\n");
547         return -1;
548     }
549
550     V3_Print("Constructing mptable for %u cores at %p\n", vm->num_cores, target);
551
552     if (write_pointer(target, BIOS_MP_TABLE_DEFAULT_LOCATION + sizeof(struct mp_floating_pointer)) == -1) { 
553         PrintError("Unable to write mptable floating pointer, aborting.\n");
554         return -1;
555     }
556
557     if (!check_pointer(target)) { 
558         PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
559         return -1;
560     }
561
562     if (write_mptable(target + sizeof(struct mp_floating_pointer), vm->num_cores, have_ioapic, have_pci)) {
563         PrintError("Cannot inject mptable configuration header and entries\n");
564         return -1;
565     }
566
567     if (!check_table(target + sizeof(struct mp_floating_pointer))) { 
568         PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");
569         return -1;
570     }
571
572
573     return 0;
574 }
575
576
577
578 device_register("MPTABLE", mptable_init)