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.


Working mptable support (Linux correctly recognizes 1,2,4,8,16,32 proc configs)
[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 ((uchar_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     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         } fields;
136     } cpu_flags;
137     union {
138         uint32_t data;
139         struct {
140             uint8_t stepping:4;
141             uint8_t model:4;
142             uint8_t family:4; 
143             uint32_t rest:20;
144         } fields;
145     } cpu_signature;
146     uint32_t cpu_feature_flags;      // result of CPUID
147     uint32_t reserved[2];
148 } __attribute__((packed));
149
150 struct mp_table_bus {
151     uint8_t entry_type;          // type 1
152     uint8_t bus_id;              // 0..
153     uint8_t bus_type[6];         // "PCI" "INTERN", etc
154 } __attribute__((packed));
155
156
157 struct mp_table_ioapic {
158     uint8_t entry_type;          // type 2
159     uint8_t ioapic_id;           // 0..
160     uint8_t ioapic_version;      // bits 0..7 of the version register
161     union {
162         uint8_t data;       
163         struct {
164             uint8_t en:1;        // 1=ioapic enabled
165             uint8_t reserved:7;
166         } fields;
167     } ioapic_flags;
168     uint32_t ioapic_address;     // physical address (same for all procs)
169 } __attribute__((packed));
170
171
172 struct mp_table_io_interrupt_assignment {
173     uint8_t entry_type;          // type 3
174     uint8_t interrupt_type;      // 0=int, 1=nmi, 2=smi, 3=ExtInt(8259)
175     union {
176         uint16_t data;
177         struct {
178             uint8_t po:2;        // polarity (00=default for bus, 01=active high, 10=reserved, 11=active low
179             uint8_t el:2;        // trigger mode (00=default for bus, 01=edge, 10=reserved, 11=level)
180             uint16_t reserved:12;
181         } fields;
182     } io_interrupt_flags;
183     uint8_t source_bus_id;
184     uint8_t source_bus_irq;
185     uint8_t dest_ioapic_id;
186     uint8_t dest_ioapic_intn;
187 } __attribute__((packed));
188
189
190 struct mp_table_local_interrupt_assignment {
191     uint8_t entry_type;          // type 4
192     uint8_t interrupt_type;      // 0=int, 1=nmi, 2=smi, 3=ExtInt(8259)
193     union {
194         uint16_t data;
195         struct {
196             uint8_t po:2;        // polarity (00=default for bus, 01=active high, 10=reserved, 11=active low
197             uint8_t el:2;        // trigger mode (00=default for bus, 01=edge, 10=reserved, 11=level)
198             uint16_t reserved:12;
199         } fields;
200     } io_interrupt_flags;
201     uint8_t source_bus_id;
202     uint8_t source_bus_irq;
203     uint8_t dest_ioapic_id;
204     uint8_t dest_ioapic_intn;
205 } __attribute__((packed));
206
207
208
209
210
211 static int check_for_cookie(void *target)
212 {
213     return 0==memcmp(target,BIOS_MP_TABLE_COOKIE,BIOS_MP_TABLE_COOKIE_LEN);
214 }
215
216 static int check_table(void *target)
217 {
218     uint32_t i;
219     uint8_t sum;
220     struct mp_table_header *header;
221
222     V3_Print("Checksuming mptable header and entries at %p\n",target);
223
224     header=(struct mp_table_header *)target;
225     sum=0;
226     for (i=0;i<header->base_table_length;i++) {
227         sum+=((uint8_t *)target)[i];
228     }
229     if (sum==0) { 
230         V3_Print("Checksum passed\n");
231         return 1;
232     } else {
233         V3_Print("Checksum FAILED\n");
234         return 0;
235     }
236 }
237
238
239 static int check_pointer(void *target)
240 {
241     uint32_t i;
242     uint8_t sum;
243     struct mp_floating_pointer *p;
244
245     V3_Print("Checksuming mptable floating pointer at %p\n",target);
246
247     p=(struct mp_floating_pointer *)target;
248     sum=0;
249     for (i=0;i<p->length*16;i++) {
250         sum+=((uint8_t *)target)[i];
251     }
252     if (sum==0) { 
253         V3_Print("Checksum passed\n");
254         return 1;
255     } else {
256         V3_Print("Checksum FAILED\n");
257         return 0;
258     }
259 }
260     
261
262 static int write_pointer(void *target, uint32_t mptable_gpa)
263 {
264     uint32_t i;
265     uint8_t sum;
266     struct mp_floating_pointer *p=(struct mp_floating_pointer*)target;
267
268     memset((void*)p,0,sizeof(*p));
269     
270     memcpy((void*)&(p->signature),POINTER_SIGNATURE,4);
271     
272     p->pointer=mptable_gpa;
273     p->length=1;             // length in 16 byte chunks
274     p->spec_rev=SPEC_REV;
275     
276     // checksum calculation
277     p->checksum=0;
278     sum=0;
279     for (i=0;i<16;i++) {
280         sum+=((uint8_t *)target)[i];
281     }
282     p->checksum=(255-sum)+1;
283
284     V3_Print("MP Floating Pointer written to %p\n",target);
285
286     return 0;
287 }
288     
289
290     
291
292 static int write_mptable(void *target, uint32_t numcores)
293 {
294     uint32_t i;
295     uint8_t sum;
296     uint8_t core;
297     uint8_t irq;    
298     uint8_t *cur;
299     struct mp_table_header *header;
300     struct mp_table_processor *proc;
301     struct mp_table_bus *bus;
302     struct mp_table_ioapic *ioapic;
303     struct mp_table_io_interrupt_assignment *interrupt;
304
305
306     cur=(uint8_t *)target;
307     header=(struct mp_table_header *)cur;
308     cur=cur+sizeof(*header);
309     
310     memset((void*)header,0,sizeof(*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++, cur+=sizeof(*proc)) { 
325         proc=(struct mp_table_processor *)cur;
326         memset((void*)proc,0,sizeof(*proc));
327         proc->entry_type=ENTRY_PROC;
328         proc->lapic_id=core;
329         proc->lapic_version=LAPIC_VERSION;
330         proc->cpu_flags.fields.en=1;
331         proc->cpu_flags.fields.bp = (core==0);
332         proc->cpu_signature.fields.family=PROC_FAMILY;
333         proc->cpu_signature.fields.model=PROC_MODEL;
334         proc->cpu_signature.fields.stepping=PROC_STEPPING;
335         proc->cpu_feature_flags=PROC_FEATURE_FLAGS;
336     }
337
338     // next comes the ISA bas
339     bus=(struct mp_table_bus *)cur;
340     cur+=sizeof(*bus);
341
342     memset((void*)bus,0,sizeof(*bus));
343     bus->entry_type=ENTRY_BUS;
344     bus->bus_id=0;
345     memcpy(bus->bus_type,BUS_ISA,6);
346
347     // next comes the IOAPIC
348     ioapic=(struct mp_table_ioapic *)cur;
349     cur+=sizeof(*ioapic);
350     
351     memset((void*)ioapic,0,sizeof(*ioapic));
352     ioapic->entry_type=ENTRY_IOAPIC;
353     ioapic->ioapic_id=numcores;
354     ioapic->ioapic_version=IOAPIC_VERSION;
355     ioapic->ioapic_flags.fields.en=1;
356     ioapic->ioapic_address=IOAPIC_ADDR;
357
358     for (irq=0;irq<16;irq++, cur+=sizeof(*interrupt)) { 
359         interrupt=(struct mp_table_io_interrupt_assignment *)cur;
360         memset((void*)interrupt,0,sizeof(*interrupt));
361         interrupt->entry_type=ENTRY_IOINT;
362         interrupt->interrupt_type=INT_TYPE_INT;
363         interrupt->io_interrupt_flags.fields.po=INT_POLARITY_DEFAULT;
364         interrupt->io_interrupt_flags.fields.el=INT_TRIGGER_DEFAULT;
365         interrupt->source_bus_id=0;
366         interrupt->source_bus_irq=irq;
367         interrupt->dest_ioapic_id=1;
368         interrupt->dest_ioapic_intn=irq;
369     }
370
371     // now we can set the length;
372
373     header->base_table_length = (cur-(uint8_t*)header);
374
375     // checksum calculation
376     header->checksum=0;
377     sum=0;
378     for (i=0;i<header->base_table_length;i++) {
379         sum+=((uint8_t *)target)[i];
380     }
381     header->checksum=(255-sum)+1;
382
383
384         
385     return 0;
386 }
387
388
389 int v3_inject_mptable(struct v3_vm_info *vm)
390 {
391     void *target;
392
393     if (v3_gpa_to_hva(&(vm->cores[0]),BIOS_MP_TABLE_DEFAULT_LOCATION,(addr_t*)&target)==-1) { 
394         PrintError("Cannot inject mptable due to unmapped bios!\n");
395         return -1;
396     }
397     
398     if (!check_for_cookie(target)) { 
399         PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
400         return -1;
401     }
402
403     if (vm->num_cores>32) { 
404         PrintError("No support for >32 cores in writing MP table, aborting.\n");
405         return -1;
406     }
407
408     V3_Print("Starting mptable pointer, header, and entry construction for %u cores at %p\n",vm->num_cores,target);
409
410     if (-1==write_pointer(target,BIOS_MP_TABLE_DEFAULT_LOCATION+sizeof(struct mp_floating_pointer))) { 
411         PrintError("Unable to write mptable floating pointer, aborting.\n");
412         return -1;
413     }
414
415     if (!check_pointer(target)) { 
416         PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
417         return -1;
418     }
419
420     if (-1==write_mptable(target+sizeof(struct mp_floating_pointer),vm->num_cores)) {
421         PrintError("Cannot inject mptable configuration header and entries\n");
422         return -1;
423     }
424
425     if (!check_table(target+sizeof(struct mp_floating_pointer))) { 
426         PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");
427         return -1;
428     }
429
430     V3_Print("Done with mptable pointer, header, and entry construction\n");
431
432     return 0;
433     
434 }