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)
99 uint8_t length; // length in 16 byte chunks (paragraphs)
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 uint8_t reserved; // zero by default
122 // this is followed by entries of the various types indicated below
123 } __attribute__((packed));
125 struct mp_table_processor {
126 uint8_t entry_type; // type 0
127 uint8_t lapic_id; // 0..
128 uint8_t lapic_version; //
132 uint8_t en:1; // 1=processor enabled
133 uint8_t bp:1; // 1=bootstrap processor
146 uint32_t cpu_feature_flags; // result of CPUID
147 uint32_t reserved[2];
148 } __attribute__((packed));
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));
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
164 uint8_t en:1; // 1=ioapic enabled
168 uint32_t ioapic_address; // physical address (same for all procs)
169 } __attribute__((packed));
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)
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;
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));
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)
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;
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));
211 static int check_for_cookie(void *target)
213 return 0==memcmp(target,BIOS_MP_TABLE_COOKIE,BIOS_MP_TABLE_COOKIE_LEN);
216 static int check_table(void *target)
220 struct mp_table_header *header;
223 header=(struct mp_table_header *)target;
225 for (i=0;i<header->base_table_length;i++) {
226 sum+=((uint8_t *)target)[i];
237 static int check_pointer(void *target)
241 struct mp_floating_pointer *p;
243 p=(struct mp_floating_pointer *)target;
245 for (i=0;i<p->length*16;i++) {
246 sum+=((uint8_t *)target)[i];
258 static int write_pointer(void *target, uint32_t mptable_gpa)
262 struct mp_floating_pointer *p=(struct mp_floating_pointer*)target;
264 memset((void*)p,0,sizeof(*p));
266 memcpy((void*)&(p->signature),POINTER_SIGNATURE,4);
268 p->pointer=mptable_gpa;
269 p->length=1; // length in 16 byte chunks
270 p->spec_rev=SPEC_REV;
272 // checksum calculation
276 sum+=((uint8_t *)target)[i];
278 p->checksum=(255-sum)+1;
286 static int write_mptable(void *target, uint32_t numcores)
293 struct mp_table_header *header;
294 struct mp_table_processor *proc;
295 struct mp_table_bus *bus;
296 struct mp_table_ioapic *ioapic;
297 struct mp_table_io_interrupt_assignment *interrupt;
300 cur=(uint8_t *)target;
301 header=(struct mp_table_header *)cur;
302 cur=cur+sizeof(*header);
304 memset((void*)header,0,sizeof(*header));
307 memcpy(&(header->signature),HEADER_SIGNATURE,4);
308 header->spec_rev=SPEC_REV;
309 memcpy(header->oem_id,OEM_ID,8);
310 memcpy(header->prod_id,PROD_ID,12);
312 // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n
313 header->entry_count=numcores+18;
314 header->lapic_addr=LAPIC_ADDR;
316 // now we arrange the processors;
318 for (core=0;core<numcores;core++, cur+=sizeof(*proc)) {
319 proc=(struct mp_table_processor *)cur;
320 memset((void*)proc,0,sizeof(*proc));
321 proc->entry_type=ENTRY_PROC;
323 proc->lapic_version=LAPIC_VERSION;
324 proc->cpu_flags.fields.en=1;
325 proc->cpu_flags.fields.bp = (core==0);
326 proc->cpu_signature.fields.family=PROC_FAMILY;
327 proc->cpu_signature.fields.model=PROC_MODEL;
328 proc->cpu_signature.fields.stepping=PROC_STEPPING;
329 proc->cpu_feature_flags=PROC_FEATURE_FLAGS;
332 // next comes the ISA bas
333 bus=(struct mp_table_bus *)cur;
336 memset((void*)bus,0,sizeof(*bus));
337 bus->entry_type=ENTRY_BUS;
339 memcpy(bus->bus_type,BUS_ISA,6);
341 // next comes the IOAPIC
342 ioapic=(struct mp_table_ioapic *)cur;
343 cur+=sizeof(*ioapic);
345 memset((void*)ioapic,0,sizeof(*ioapic));
346 ioapic->entry_type=ENTRY_IOAPIC;
347 ioapic->ioapic_id=numcores;
348 ioapic->ioapic_version=IOAPIC_VERSION;
349 ioapic->ioapic_flags.fields.en=1;
350 ioapic->ioapic_address=IOAPIC_ADDR;
352 for (irq=0;irq<16;irq++, cur+=sizeof(*interrupt)) {
353 interrupt=(struct mp_table_io_interrupt_assignment *)cur;
354 memset((void*)interrupt,0,sizeof(*interrupt));
355 interrupt->entry_type=ENTRY_IOINT;
356 interrupt->interrupt_type=INT_TYPE_INT;
357 interrupt->io_interrupt_flags.fields.po=INT_POLARITY_DEFAULT;
358 interrupt->io_interrupt_flags.fields.el=INT_TRIGGER_DEFAULT;
359 interrupt->source_bus_id=0;
360 interrupt->source_bus_irq=irq;
361 interrupt->dest_ioapic_id=numcores;
362 interrupt->dest_ioapic_intn=irq;
365 // now we can set the length;
367 header->base_table_length = (cur-(uint8_t*)header);
369 // checksum calculation
372 for (i=0;i<header->base_table_length;i++) {
373 sum+=((uint8_t *)target)[i];
375 header->checksum=(255-sum)+1;
383 int v3_inject_mptable(struct v3_vm_info *vm)
387 if (v3_gpa_to_hva(&(vm->cores[0]),BIOS_MP_TABLE_DEFAULT_LOCATION,(addr_t*)&target)==-1) {
388 PrintError("Cannot inject mptable due to unmapped bios!\n");
392 if (!check_for_cookie(target)) {
393 PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
397 if (vm->num_cores>32) {
398 PrintError("No support for >32 cores in writing MP table, aborting.\n");
402 V3_Print("Constructing mptable for %u cores at %p\n",vm->num_cores,target);
404 if (-1==write_pointer(target,BIOS_MP_TABLE_DEFAULT_LOCATION+sizeof(struct mp_floating_pointer))) {
405 PrintError("Unable to write mptable floating pointer, aborting.\n");
409 if (!check_pointer(target)) {
410 PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
414 if (-1==write_mptable(target+sizeof(struct mp_floating_pointer),vm->num_cores)) {
415 PrintError("Cannot inject mptable configuration header and entries\n");
419 if (!check_table(target+sizeof(struct mp_floating_pointer))) {
420 PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");