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.


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