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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Peter Dinda <pdinda@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_mptable.h>
22 #include <palacios/vmm_string.h>
23 #include <palacios/vm_guest_mem.h>
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
32 Currently, we set up n identical processors (based on
33 number of cores in guest info), with apics 0..n-1, and
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
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
49 #define POINTER_SIGNATURE "_MP_"
50 #define HEADER_SIGNATURE "PCMP"
52 #define SPEC_REV ((uchar_t)0x4)
53 #define OEM_ID "V3VEE "
54 #define PROD_ID "PALACIOS 1.3 "
56 #define LAPIC_ADDR 0xfee00000
57 #define LAPIC_VERSION 0x11
61 #define ENTRY_IOAPIC 2
65 #define IOAPIC_ADDR 0xfec00000
66 #define IOAPIC_VERSION 0x11
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
75 #define BUS_ISA "ISA "
77 #define INT_TYPE_INT 0
78 #define INT_TYPE_NMI 1
79 #define INT_TYPE_SMI 2
80 #define INT_TYPE_EXT 3
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
87 #define INT_TRIGGER_DEFAULT 0
88 #define INT_TRIGGER_EDGE 1
89 #define INT_TRIGGER_RESERVED 2
90 #define INT_TRIGGER_LEVEL 3
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)
100 uint8_t spec_rev; // 0x4
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));
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));
124 struct mp_table_processor {
125 uint8_t entry_type; // type 0
126 uint8_t lapic_id; // 0..
127 uint8_t lapic_version; //
131 uint8_t en:1; // 1=processor enabled
132 uint8_t bp:1; // 1=bootstrap processor
145 uint32_t cpu_feature_flags; // result of CPUID
146 uint32_t reserved[2];
147 } __attribute__((packed));
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));
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
163 uint8_t en:1; // 1=ioapic enabled
167 uint32_t ioapic_address; // physical address (same for all procs)
168 } __attribute__((packed));
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)
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;
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));
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)
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;
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));
210 static int check_for_cookie(void *target)
212 return 0==memcmp(target,BIOS_MP_TABLE_COOKIE,BIOS_MP_TABLE_COOKIE_LEN);
215 static int check_table(void *target)
219 struct mp_table_header *header;
221 V3_Print("Checksuming mptable header and entries at %p\n",target);
223 header=(struct mp_table_header *)target;
225 for (i=0;i<header->base_table_length;i++) {
226 sum+=((uint8_t *)target)[i];
229 V3_Print("Checksum passed\n");
232 V3_Print("Checksum FAILED\n");
238 static int check_pointer(void *target)
242 struct mp_floating_pointer *p;
244 V3_Print("Checksuming mptable floating pointer at %p\n",target);
246 p=(struct mp_floating_pointer *)target;
248 for (i=0;i<p->length*16;i++) {
249 sum+=((uint8_t *)target)[i];
252 V3_Print("Checksum passed\n");
255 V3_Print("Checksum FAILED\n");
261 static int write_pointer(void *target, uint32_t mptable_gpa)
265 struct mp_floating_pointer *p=(struct mp_floating_pointer*)target;
267 memset((void*)p,0,sizeof(*p));
269 memcpy((void*)&(p->signature),POINTER_SIGNATURE,4);
271 p->pointer=mptable_gpa;
272 p->length=1; // length in 16 byte chunks
273 p->spec_rev=SPEC_REV;
275 // checksum calculation
279 sum+=((uint8_t *)target)[i];
281 p->checksum=(255-sum)+1;
283 V3_Print("MP Floating Pointer written to %p\n",target);
291 static int write_mptable(void *target, uint32_t numcores)
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;
305 cur=(uint8_t *)target;
306 header=(struct mp_table_header *)cur;
307 cur=cur+sizeof(*header);
309 memset((void*)header,0,sizeof(*header));
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);
317 // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n
318 header->entry_count=numcores+18;
319 header->lapic_addr=LAPIC_ADDR;
321 // now we arrange the processors;
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;
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;
337 // next comes the ISA bas
338 bus=(struct mp_table_bus *)cur;
341 memset((void*)bus,0,sizeof(*bus));
342 bus->entry_type=ENTRY_BUS;
344 memcpy(bus->bus_type,BUS_ISA,6);
346 // next comes the IOAPIC
347 ioapic=(struct mp_table_ioapic *)cur;
348 cur+=sizeof(*ioapic);
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;
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;
370 // now we can set the length;
372 header->base_table_length = (cur-(uint8_t*)header);
374 // checksum calculation
377 for (i=0;i<header->base_table_length;i++) {
378 sum+=((uint8_t *)target)[i];
380 header->checksum=(255-sum)+1;
388 int v3_inject_mptable(struct v3_vm_info *vm)
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");
397 if (!check_for_cookie(target)) {
398 PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
402 if (vm->num_cores>32) {
403 PrintError("No support for >32 cores in writing MP table, aborting.\n");
407 V3_Print("Starting mptable pointer, header, and entry construction for %u cores at %p\n",vm->num_cores,target);
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");
414 if (!check_pointer(target)) {
415 PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
419 if (-1==write_mptable(target+sizeof(struct mp_floating_pointer),vm->num_cores)) {
420 PrintError("Cannot inject mptable configuration header and entries\n");
424 if (!check_table(target+sizeof(struct mp_floating_pointer))) {
425 PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");
429 V3_Print("Done with mptable pointer, header, and entry construction\n");