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_string.h>
22 #include <palacios/vm_guest_mem.h>
25 The guest bios is compiled with blank space for am MP table
26 at a default address. A cookie value is temporarily placed
27 there so we can verify it exists. If it does, we overwrite
28 the MP table based on the configuration we are given in the
31 Currently, we set up n identical processors (based on
32 number of cores in guest info), with apics 0..n-1, and
35 The expectation is that the target will have
36 8 bytes (for ___HVMMP signature) followed by 896 bytes of space
37 for a total of 904 bytes of space.
38 We write the floating pointer at target (16 bytes),
39 immediately followed by the mp config header, followed by
44 #define BIOS_MP_TABLE_DEFAULT_LOCATION 0xfcc00 // guest physical (linear)
45 #define BIOS_MP_TABLE_COOKIE "___HVMMP"
46 #define BIOS_MP_TABLE_COOKIE_LEN 8
48 #define POINTER_SIGNATURE "_MP_"
49 #define HEADER_SIGNATURE "PCMP"
51 #define SPEC_REV ((uint8_t)0x4)
52 #define OEM_ID "V3VEE "
53 #define PROD_ID "PALACIOS 1.3 "
55 #define LAPIC_ADDR 0xfee00000
56 #define LAPIC_VERSION 0x11
60 #define ENTRY_IOAPIC 2
64 #define IOAPIC_ADDR 0xfec00000
65 #define IOAPIC_VERSION 0x11
67 // These are bochs defaults - should really come from cpuid of machne
68 #define PROC_FAMILY 0x6
69 #define PROC_STEPPING 0x0
70 #define PROC_MODEL 0x0
71 #define PROC_FEATURE_FLAGS 0x00000201
74 #define BUS_ISA "ISA "
76 #define INT_TYPE_INT 0
77 #define INT_TYPE_NMI 1
78 #define INT_TYPE_SMI 2
79 #define INT_TYPE_EXT 3
81 #define INT_POLARITY_DEFAULT 0
82 #define INT_POLARITY_ACTIVE_HIGH 1
83 #define INT_POLARITY_RESERVED 2
84 #define INT_POLARITY_ACTIVE_LOW 3
86 #define INT_TRIGGER_DEFAULT 0
87 #define INT_TRIGGER_EDGE 1
88 #define INT_TRIGGER_RESERVED 2
89 #define INT_TRIGGER_LEVEL 3
94 // This points to the mp table header
95 struct mp_floating_pointer {
96 uint32_t signature; /* "_MP_" */
97 uint32_t pointer; /* gpa of MP table (0xfcc00) */
98 uint8_t length; /* length in 16 byte chunks (paragraphs) */
99 uint8_t spec_rev; /* 0x4 */
101 uint8_t mp_featurebyte[5]; /* zero out to indicate mp config table
102 first byte nonzero => default configurations (see spec)
103 second byte, bit 7 (top bit) = IMCR if set, virtual wire if zero */
104 } __attribute__((packed));
107 struct mp_table_header {
108 uint32_t signature; /* "PCMP" */
109 uint16_t base_table_length; /* bytes, starting from header */
110 uint8_t spec_rev; /* specification rvision (0x4 is the current rev) */
111 uint8_t checksum; /* sum of all bytes, including checksum, must be zero */
112 uint8_t oem_id[8]; /* OEM ID "V3VEE " */
113 uint8_t prod_id[12]; /* Product ID "PALACIOS 1.3" */
114 uint32_t oem_table_ptr; /* oem table, if used (zeroed) */
115 uint16_t oem_table_size; /* oem table length, if used */
116 uint16_t entry_count; /* numnber of entries in this table */
117 uint32_t lapic_addr; /* apic address on all processors */
118 uint16_t extended_table_length; /* zero by default */
119 uint8_t extended_table_checksum; /* zero by default */
120 uint8_t reserved; /* 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; //
132 uint8_t en : 1; /* 1 = processor enabled */
133 uint8_t bp : 1; /* 1 = bootstrap processor */
134 uint8_t reserved : 6;
135 } __attribute__((packed));
136 } __attribute__((packed)) cpu_flags;
141 uint8_t stepping : 4;
145 } __attribute__((packed));
146 } __attribute__((packed)) cpu_signature;
148 uint32_t cpu_feature_flags; /* result of CPUID */
149 uint32_t reserved[2];
150 } __attribute__((packed));
152 struct mp_table_bus {
153 uint8_t entry_type; /* type 1 */
154 uint8_t bus_id; /* 0.. */
155 uint8_t bus_type[6]; /* "PCI" "INTERN", etc */
156 } __attribute__((packed));
159 struct mp_table_ioapic {
160 uint8_t entry_type; /* type 2 */
161 uint8_t ioapic_id; /* 0.. */
162 uint8_t ioapic_version; /* bits 0..7 of the version register */
167 uint8_t en : 1; /* 1=ioapic enabled */
168 uint8_t reserved : 7;
169 } __attribute__((packed));
170 } __attribute__((packed)) ioapic_flags;
172 uint32_t ioapic_address; /* physical address (same for all procs) */
173 } __attribute__((packed));
176 struct mp_table_io_interrupt_assignment {
177 uint8_t entry_type; /* type 3 */
178 uint8_t interrupt_type; /* 0=int, 1=nmi, 2=smi, 3=ExtInt(8259) */
183 uint8_t po : 2; /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
184 uint8_t el : 2; /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
185 uint16_t reserved : 12;
186 } __attribute__((packed));
187 } __attribute__((packed)) flags;
189 uint8_t source_bus_id;
190 uint8_t source_bus_irq;
191 uint8_t dest_ioapic_id;
192 uint8_t dest_ioapic_intn;
193 } __attribute__((packed));
196 struct mp_table_local_interrupt_assignment {
197 uint8_t entry_type; /* type 4 */
198 uint8_t interrupt_type; /* 0 = int, 1 = nmi, 2 = smi, 3 = ExtInt(8259) */
203 uint8_t po : 2; /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
204 uint8_t el : 2; /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
205 uint16_t reserved : 12;
206 } __attribute__((packed));
207 } __attribute__((packed)) flags;
209 uint8_t source_bus_id;
210 uint8_t source_bus_irq;
211 uint8_t dest_ioapic_id;
212 uint8_t dest_ioapic_intn;
213 } __attribute__((packed));
219 static inline int check_for_cookie(void * target) {
220 return (memcmp(target, BIOS_MP_TABLE_COOKIE, BIOS_MP_TABLE_COOKIE_LEN) == 0);
223 static inline int check_table(void * target) {
226 struct mp_table_header * header;
228 header = (struct mp_table_header *)target;
231 for (i = 0; i < header->base_table_length; i++) {
232 sum += ((uint8_t *)target)[i];
244 static inline int check_pointer(void * target) {
247 struct mp_floating_pointer * p;
249 p = (struct mp_floating_pointer *)target;
252 for (i = 0; i < p->length * 16; i++) {
253 sum += ((uint8_t *)target)[i];
266 static int write_pointer(void * target, uint32_t mptable_gpa) {
269 struct mp_floating_pointer * p = (struct mp_floating_pointer *)target;
271 memset((void *)p, 0, sizeof(struct mp_floating_pointer));
273 memcpy((void *)&(p->signature), POINTER_SIGNATURE, 4);
275 p->pointer = mptable_gpa;
276 p->length = 1; // length in 16 byte chunks
277 p->spec_rev = SPEC_REV;
279 // checksum calculation
283 for (i = 0; i < 16; i++) {
284 sum += ((uint8_t *)target)[i];
287 p->checksum = (255 - sum) + 1;
295 static int write_mptable(void * target, uint32_t numcores) {
300 struct mp_table_header * header = NULL;
301 struct mp_table_processor * proc = NULL;
302 struct mp_table_bus * bus = NULL;
303 struct mp_table_ioapic * ioapic = NULL;
304 struct mp_table_io_interrupt_assignment * interrupt = NULL;
305 uint8_t * cur = target;
307 header = (struct mp_table_header *)cur;
308 cur = cur + sizeof(struct mp_table_header);
310 memset((void *)header, 0, sizeof(struct mp_table_header));
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);
318 // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n
319 header->entry_count = numcores + 18;
320 header->lapic_addr = LAPIC_ADDR;
322 // now we arrange the processors;
324 for (core = 0; core < numcores; core++) {
325 proc = (struct mp_table_processor *)cur;
326 memset((void *)proc, 0, sizeof(struct mp_table_processor));
327 proc->entry_type = ENTRY_PROC;
328 proc->lapic_id = core;
329 proc->lapic_version = LAPIC_VERSION;
330 proc->cpu_flags.en = 1;
333 proc->cpu_flags.bp = 1;
335 proc->cpu_flags.bp = 0;
338 proc->cpu_signature.family = PROC_FAMILY;
339 proc->cpu_signature.model = PROC_MODEL;
340 proc->cpu_signature.stepping = PROC_STEPPING;
341 proc->cpu_feature_flags = PROC_FEATURE_FLAGS;
343 cur += sizeof(struct mp_table_processor);
346 // next comes the ISA bas
347 bus = (struct mp_table_bus *)cur;
348 cur += sizeof(struct mp_table_bus);
350 memset((void *)bus, 0, sizeof(struct mp_table_bus));
351 bus->entry_type = ENTRY_BUS;
353 memcpy(bus->bus_type, BUS_ISA, 6);
355 // next comes the IOAPIC
356 ioapic = (struct mp_table_ioapic *)cur;
357 cur += sizeof(struct mp_table_ioapic);
359 memset((void *)ioapic, 0, sizeof(struct mp_table_ioapic));
360 ioapic->entry_type = ENTRY_IOAPIC;
361 ioapic->ioapic_id = numcores;
362 ioapic->ioapic_version = IOAPIC_VERSION;
363 ioapic->ioapic_flags.en = 1;
364 ioapic->ioapic_address = IOAPIC_ADDR;
367 // The MPTABLE IRQ mappings are kind of odd.
368 // We don't include a bus IRQ 2, and instead remap Bus IRQ 0 to dest irq 2
371 for (irq = 0; irq < 16; irq++) {
372 uint8_t dst_irq = irq;
376 } else if (irq == 2) {
380 interrupt = (struct mp_table_io_interrupt_assignment *)cur;
381 memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
383 interrupt->entry_type = ENTRY_IOINT;
384 interrupt->interrupt_type = INT_TYPE_INT;
385 interrupt->flags.po = INT_POLARITY_DEFAULT;
386 interrupt->flags.el = INT_TRIGGER_DEFAULT;
387 interrupt->source_bus_id = 0;
388 interrupt->source_bus_irq = irq;
389 interrupt->dest_ioapic_id = numcores;
390 interrupt->dest_ioapic_intn = dst_irq;
392 cur += sizeof(struct mp_table_io_interrupt_assignment);
395 // now we can set the length;
397 header->base_table_length = (cur - (uint8_t *)header);
399 // checksum calculation
400 header->checksum = 0;
402 for (i = 0; i < header->base_table_length; i++) {
403 sum += ((uint8_t *)target)[i];
405 header->checksum = (255 - sum) + 1;
412 static int mptable_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
413 void * target = NULL;
415 if (v3_gpa_to_hva(&(vm->cores[0]), BIOS_MP_TABLE_DEFAULT_LOCATION, (addr_t *)&target) == -1) {
416 PrintError("Cannot inject mptable due to unmapped bios!\n");
420 if (!check_for_cookie(target)) {
421 PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
425 if (vm->num_cores > 32) {
426 PrintError("No support for >32 cores in writing MP table, aborting.\n");
430 V3_Print("Constructing mptable for %u cores at %p\n", vm->num_cores, target);
432 if (write_pointer(target, BIOS_MP_TABLE_DEFAULT_LOCATION + sizeof(struct mp_floating_pointer)) == -1) {
433 PrintError("Unable to write mptable floating pointer, aborting.\n");
437 if (!check_pointer(target)) {
438 PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
442 if (write_mptable(target + sizeof(struct mp_floating_pointer), vm->num_cores) == -1) {
443 PrintError("Cannot inject mptable configuration header and entries\n");
447 if (!check_table(target + sizeof(struct mp_floating_pointer))) {
448 PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");
458 device_register("MPTABLE", mptable_init)