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 ((uint8_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; //
133 uint8_t en : 1; /* 1 = processor enabled */
134 uint8_t bp : 1; /* 1 = bootstrap processor */
135 uint8_t reserved : 6;
136 } __attribute__((packed));
137 } __attribute__((packed)) cpu_flags;
142 uint8_t stepping : 4;
146 } __attribute__((packed));
147 } __attribute__((packed)) cpu_signature;
149 uint32_t cpu_feature_flags; /* result of CPUID */
150 uint32_t reserved[2];
151 } __attribute__((packed));
153 struct mp_table_bus {
154 uint8_t entry_type; /* type 1 */
155 uint8_t bus_id; /* 0.. */
156 uint8_t bus_type[6]; /* "PCI" "INTERN", etc */
157 } __attribute__((packed));
160 struct mp_table_ioapic {
161 uint8_t entry_type; /* type 2 */
162 uint8_t ioapic_id; /* 0.. */
163 uint8_t ioapic_version; /* bits 0..7 of the version register */
168 uint8_t en : 1; /* 1=ioapic enabled */
169 uint8_t reserved : 7;
170 } __attribute__((packed));
171 } __attribute__((packed)) ioapic_flags;
173 uint32_t ioapic_address; /* physical address (same for all procs) */
174 } __attribute__((packed));
177 struct mp_table_io_interrupt_assignment {
178 uint8_t entry_type; /* type 3 */
179 uint8_t interrupt_type; /* 0=int, 1=nmi, 2=smi, 3=ExtInt(8259) */
184 uint8_t po : 2; /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
185 uint8_t el : 2; /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
186 uint16_t reserved : 12;
187 } __attribute__((packed));
188 } __attribute__((packed)) flags;
190 uint8_t source_bus_id;
191 uint8_t source_bus_irq;
192 uint8_t dest_ioapic_id;
193 uint8_t dest_ioapic_intn;
194 } __attribute__((packed));
197 struct mp_table_local_interrupt_assignment {
198 uint8_t entry_type; /* type 4 */
199 uint8_t interrupt_type; /* 0 = int, 1 = nmi, 2 = smi, 3 = ExtInt(8259) */
204 uint8_t po : 2; /* polarity (00 = default for bus, 01 = active high, 10 = reserved, 11 = active low */
205 uint8_t el : 2; /* trigger mode (00 = default for bus, 01 = edge, 10 = reserved, 11 = level) */
206 uint16_t reserved : 12;
207 } __attribute__((packed));
208 } __attribute__((packed)) flags;
210 uint8_t source_bus_id;
211 uint8_t source_bus_irq;
212 uint8_t dest_ioapic_id;
213 uint8_t dest_ioapic_intn;
214 } __attribute__((packed));
220 static inline int check_for_cookie(void * target) {
221 return (memcmp(target, BIOS_MP_TABLE_COOKIE, BIOS_MP_TABLE_COOKIE_LEN) == 0);
224 static inline int check_table(void * target) {
227 struct mp_table_header * header;
229 header = (struct mp_table_header *)target;
232 for (i = 0; i < header->base_table_length; i++) {
233 sum += ((uint8_t *)target)[i];
245 static inline int check_pointer(void * target) {
248 struct mp_floating_pointer * p;
250 p = (struct mp_floating_pointer *)target;
253 for (i = 0; i < p->length * 16; i++) {
254 sum += ((uint8_t *)target)[i];
267 static int write_pointer(void * target, uint32_t mptable_gpa) {
270 struct mp_floating_pointer * p = (struct mp_floating_pointer *)target;
272 memset((void *)p, 0, sizeof(struct mp_floating_pointer));
274 memcpy((void *)&(p->signature), POINTER_SIGNATURE, 4);
276 p->pointer = mptable_gpa;
277 p->length = 1; // length in 16 byte chunks
278 p->spec_rev = SPEC_REV;
280 // checksum calculation
284 for (i = 0; i < 16; i++) {
285 sum += ((uint8_t *)target)[i];
288 p->checksum = (255 - sum) + 1;
296 static int write_mptable(void * target, uint32_t numcores) {
301 struct mp_table_header * header = NULL;
302 struct mp_table_processor * proc = NULL;
303 struct mp_table_bus * bus = NULL;
304 struct mp_table_ioapic * ioapic = NULL;
305 struct mp_table_io_interrupt_assignment * interrupt = NULL;
306 uint8_t * cur = target;
308 header = (struct mp_table_header *)cur;
309 cur = cur + sizeof(struct mp_table_header);
311 memset((void *)header, 0, sizeof(struct mp_table_header));
314 memcpy(&(header->signature), HEADER_SIGNATURE, 4);
315 header->spec_rev = SPEC_REV;
316 memcpy(header->oem_id, OEM_ID, 8);
317 memcpy(header->prod_id, PROD_ID, 12);
319 // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n
320 header->entry_count = numcores + 18;
321 header->lapic_addr = LAPIC_ADDR;
323 // now we arrange the processors;
325 for (core = 0; core < numcores; core++) {
326 proc = (struct mp_table_processor *)cur;
327 memset((void *)proc, 0, sizeof(struct mp_table_processor));
328 proc->entry_type = ENTRY_PROC;
329 proc->lapic_id = core;
330 proc->lapic_version = LAPIC_VERSION;
331 proc->cpu_flags.en = 1;
334 proc->cpu_flags.bp = 1;
336 proc->cpu_flags.bp = 0;
339 proc->cpu_signature.family = PROC_FAMILY;
340 proc->cpu_signature.model = PROC_MODEL;
341 proc->cpu_signature.stepping = PROC_STEPPING;
342 proc->cpu_feature_flags = PROC_FEATURE_FLAGS;
344 cur += sizeof(struct mp_table_processor);
347 // next comes the ISA bas
348 bus = (struct mp_table_bus *)cur;
349 cur += sizeof(struct mp_table_bus);
351 memset((void *)bus, 0, sizeof(struct mp_table_bus));
352 bus->entry_type = ENTRY_BUS;
354 memcpy(bus->bus_type, BUS_ISA, 6);
356 // next comes the IOAPIC
357 ioapic = (struct mp_table_ioapic *)cur;
358 cur += sizeof(struct mp_table_ioapic);
360 memset((void *)ioapic, 0, sizeof(struct mp_table_ioapic));
361 ioapic->entry_type = ENTRY_IOAPIC;
362 ioapic->ioapic_id = numcores;
363 ioapic->ioapic_version = IOAPIC_VERSION;
364 ioapic->ioapic_flags.en = 1;
365 ioapic->ioapic_address = IOAPIC_ADDR;
367 for (irq = 0; irq < 16; irq++) {
368 interrupt = (struct mp_table_io_interrupt_assignment *)cur;
369 memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
371 interrupt->entry_type = ENTRY_IOINT;
372 interrupt->interrupt_type = INT_TYPE_INT;
373 interrupt->flags.po = INT_POLARITY_DEFAULT;
374 interrupt->flags.el = INT_TRIGGER_DEFAULT;
375 interrupt->source_bus_id = 0;
376 interrupt->source_bus_irq = irq;
377 interrupt->dest_ioapic_id = numcores;
378 interrupt->dest_ioapic_intn = irq;
380 cur += sizeof(struct mp_table_io_interrupt_assignment);
383 // now we can set the length;
385 header->base_table_length = (cur - (uint8_t *)header);
387 // checksum calculation
388 header->checksum = 0;
390 for (i = 0; i < header->base_table_length; i++) {
391 sum += ((uint8_t *)target)[i];
393 header->checksum = (255 - sum) + 1;
401 int v3_inject_mptable(struct v3_vm_info * vm) {
402 void * target = NULL;
404 if (v3_gpa_to_hva(&(vm->cores[0]), BIOS_MP_TABLE_DEFAULT_LOCATION, (addr_t *)&target) == -1) {
405 PrintError("Cannot inject mptable due to unmapped bios!\n");
409 if (!check_for_cookie(target)) {
410 PrintError("Cookie mismatch in writing mptable, aborting (probably wrong guest BIOS).\n");
414 if (vm->num_cores > 32) {
415 PrintError("No support for >32 cores in writing MP table, aborting.\n");
419 V3_Print("Constructing mptable for %u cores at %p\n", vm->num_cores, target);
421 if (write_pointer(target, BIOS_MP_TABLE_DEFAULT_LOCATION + sizeof(struct mp_floating_pointer)) == -1) {
422 PrintError("Unable to write mptable floating pointer, aborting.\n");
426 if (!check_pointer(target)) {
427 PrintError("Failed to inject mptable floating pointer correctly --- checksum fails\n");
431 if (write_mptable(target + sizeof(struct mp_floating_pointer), vm->num_cores) == -1) {
432 PrintError("Cannot inject mptable configuration header and entries\n");
436 if (!check_table(target + sizeof(struct mp_floating_pointer))) {
437 PrintError("Failed to inject mptable configuration header and entries correctly --- checksum fails\n");