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.


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