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) 2008, The V3VEE Project <http://www.v3vee.org>
11 * All rights reserved.
13 * Copyright (c) 2008, Philip Soltero <psoltero@cs.unm.edu>
14 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
15 * All rights reserved.
17 * Author: Philip Soltero <psoltero@cs.unm.edu>
19 * This is free software. You are permitted to use,
20 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
24 * @file Virtualized machine-check architecture.
26 * @author <a HREF="mailto:psoltero@cs.unm.edu.us">Philip Soltero</a>
29 // TODO: CPUID field add failure.
30 // IF adding CPUID fields fails on the second hook there is no way to back out of the first add.
32 #include <palacios/vm_guest.h>
33 #include <palacios/vmm.h>
34 #include <palacios/vmm_cpuid.h>
35 #include <palacios/vmm_excp.h>
36 #include <palacios/vmm_extensions.h>
37 #include <palacios/vmm_lowlevel.h>
38 #include <palacios/vmm_msr.h>
39 #include <palacios/vmm_string.h>
41 #ifndef V3_CONFIG_DEGUB_EXT_MACH_CHECK
43 #define PrintDebug(fmt, args...)
46 #define MCHECK "MCHECK"
48 #define CPUID_0000_0001 0x00000001
49 #define CPUID_8000_0001 0x80000001
51 // Bit 7 - MCE availability. Bit 14 - MCA availability.
52 #define CPUID_FIELDS 0x00004080
54 // 6 error reporting banks. This may be configurable in the future.
55 #define MC_REG_BANKS 6
56 #define MCE_INTERRUPT 18
58 #define MSG_PRE MCHECK": "
60 #define MCG_CAP 0x0179
61 #define MCG_STAT 0x017A
62 #define MCG_CTRL 0x017B
66 /* I have no idea what Intel was thinking (or maybe they just weren't)
67 * but the MCi registers are completely non-standard across Intel's platforms and are a total mess.
68 * Any derivative of the pentium-M (i.e. all Core CPU lines) completely disregard the
69 * architectural standard that Intel itself created...
70 * For these CPUs: the MC4 MSRs switch locations with the MC3s,
71 * also every MCi below MC3 (including MC4) does not have a MCi_MISC MSR.
73 * So for now, screw it, we'll use AMD's standard
78 Bank 1 : Instruction Cache.
80 Bank 3 : Load Store Unit.
81 Bank 4 : Northbridge and DRAM.
84 static const uint32_t amd_mci_bases[] = {0x0400, 0x0404, 0x0408, 0x040c, 0x0410, 0x0414};
85 static const uint32_t pentium_6_mci_bases[] = {0x0400, 0x0404, 0x0408, 0x040c, 0x0410, 0x0414};
86 static const uint32_t pentium_m_mci_bases[] = {0x0400, 0x0404, 0x0408, 0x0410, 0x040c, 0x0414};
87 static const uint32_t ia32_mci_bases[] = { 0x0400, 0x0404, 0x0408, 0x040c,
88 0x0410, 0x0414, 0x0418, 0x041c,
89 0x0420, 0x0424, 0x0428, 0x042c,
90 0x0430, 0x0434, 0x0438, 0x043c,
91 0x0440, 0x0444, 0x0448, 0x044c,
93 #define MCi_MASK 0xfffffffc
103 * MCA status low and high registers, MC4_STAT, MSR0000_0411.
105 struct mc4_stat_msr {
111 uint_t error_code_ext : 5;
112 uint_t error_code : 16;
117 uint_t mca_stat_sub_cache : 2;
118 uint_t reserved_01 : 1;
121 uint_t syndrome2 : 8;
122 uint_t reserved_02 : 1;
123 uint_t err_cpu_val : 1;
131 }__attribute__((packed));
132 }__attribute__((packed));
133 } __attribute__((packed));
136 * MCA address low and high registers, MC4_ADDR, MSR0000_0412.
138 struct mc4_addr_msr {
143 uint64_t addr32 : 36;
144 uint32_t reserved : 28;
145 } __attribute__((packed));
148 } __attribute__((packed));
149 } __attribute__((packed));
152 * Global machine-check capabilities register, MCG_CAP.
159 uint32_t mcg_ctl_p : 1; // CTRL Present
160 uint64_t reserved : 55;
161 } __attribute__((packed));
162 } __attribute__((packed));
163 } __attribute__((packed));
166 * Global machine-check status register, MCG_STAT.
168 struct mcg_stat_msr {
174 uint32_t mcip : 1; // Machine-check in progress.
175 uint64_t reserved : 61;
176 } __attribute__((packed));
177 } __attribute__((packed));
178 } __attribute__((packed));
181 * Global machine-check control register, MCG_CTRL.
187 uint32_t dce : 1; // Data cache register bank enable
188 uint32_t ice : 1; // Instruction cache register bank enable
189 uint32_t bue : 1; // Bus unit register bank enable
190 uint32_t lse : 1; // Load-store register bank enable
191 uint32_t nbe : 1; // Northbridge register bank enable
192 uint32_t fre : 1; // Fixed issue reorder buffer register bank enable
193 uint64_t unused : 58;
194 } __attribute__((packed));
195 } __attribute__((packed));
196 } __attribute__((packed));
199 * A temporary structure for unimplemented machine-check error reporting banks.
209 struct mcheck_state {
210 struct mcg_cap_msr mcg_cap;
211 struct mcg_stat_msr mcg_stat;
212 struct mcg_ctl_msr mcg_ctl;
214 /* Note that these are in logical order not MSR order */
215 /* So MC4 is always at mci_regs[4] even if the MSR is before MC3's */
216 struct mci_bank mci_regs[MC_REG_BANKS];
221 void init_state(struct mcheck_state * const state) {
224 memset(state, 0, sizeof(struct mcheck_state));
226 // Set the initial MCI reg base values to the current architecture
227 for (i = 0; i < MC_REG_BANKS; i++) {
228 state->mci_regs[i].base = amd_mci_bases[i];
233 * Handles guest writes to MCG MSRs.
236 int mcg_write_handler(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data) {
237 struct mcheck_state * state = (struct mcheck_state *)priv_data;
241 PrintDebug(MSG_PRE "Ignoring write to MCG_CAP MSR.\n");
245 state->mcg_stat.value = 0;
249 if (!state->mcg_cap.mcg_ctl_p) {
250 PrintDebug(MSG_PRE "Ignoring write to control MSR '0x%x'. Control MSRs not supported.\n", msr);
254 // The upper 58 bits are unused and read-only.
255 state->mcg_ctl.value &= ~0x3f;
256 state->mcg_ctl.value |= src.value & 0x3f;
261 PrintError(MSG_PRE "Reading from invalid MSR: %x\n", msr);
270 * Handles guest reads to MCG MSRs.
273 int mcg_read_handler(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data) {
274 struct mcheck_state * state = (struct mcheck_state *)priv_data;
278 dst->value = state->mcg_cap.value;
282 dst->value = state->mcg_stat.value;
286 if (!state->mcg_cap.mcg_ctl_p) {
287 PrintDebug(MSG_PRE "Ignoring read of control MSR '0x%x'. Control MSRs not supported.\n", msr);
291 dst->value = state->mcg_ctl.value;
295 PrintError(MSG_PRE "Reading from invalid MSR: %x\n", msr);
302 static struct mci_bank * get_mci_reg(struct mcheck_state * state, uint32_t msr) {
305 for (i = 0; i < MC_REG_BANKS; i++) {
306 if (state->mci_regs[i].base == (msr & MCi_MASK)) {
307 return &(state->mci_regs[i]);
316 * Handles guest reads to MCi MSRs.
319 int mci_read_handler(struct guest_info * const core,
321 struct v3_msr * const dst,
322 void * const priv_data) {
323 struct mcheck_state * const state = (struct mcheck_state *)priv_data;
324 struct mci_bank * mci = get_mci_reg(state, msr);
326 PrintDebug(MSG_PRE "Reading value '0x%llx' for MSR '0x%x'.\n", dst->value, msr);
329 PrintError(MSG_PRE " MSR read for invalid MCI register 0x%x\n", msr);
333 switch (msr & ~MCi_MASK) {
335 if (!state->mcg_cap.mcg_ctl_p) {
336 PrintDebug(MSG_PRE "Ignoring read of control MSR '0x%x'. Control MSRs not supported.\n", msr);
340 dst->value = mci->ctl.value;
344 dst->value = mci->stat.value;
348 dst->value = mci->addr.value;
352 dst->value = mci->misc.value;
356 PrintError(MSG_PRE "Ignoring read of unhooked MSR '0x%x'. This is a bug.\n", msr);
364 * Handles guest writes to MCi MSRs.
367 int mci_write_handler(struct guest_info * const core,
369 const struct v3_msr src,
370 void * const priv_data) {
371 struct mcheck_state * const state = (struct mcheck_state *)priv_data;
372 struct mci_bank * mci = get_mci_reg(state, msr);
374 PrintDebug(MSG_PRE "Writing value '0x%llx' for MSR '0x%x'.\n", src.value, msr);
376 switch (msr & ~MCi_MASK) {
378 if (!state->mcg_cap.mcg_ctl_p) {
379 PrintDebug(MSG_PRE "Ignoring read of control MSR '0x%x'. Control MSRs not supported.\n", msr);
383 mci->ctl.value = src.value;
387 if (src.value != 0) {
389 PrintError(MSG_PRE "Ignoring write of illegal value '0x%llx'.\n", src.value);
397 mci->addr.value = src.value;
401 V3_Print(MSG_PRE "Ignoring write to read only miscellaneous MSR '0x%x'.\n", msr);
405 PrintError(MSG_PRE "Ignoring write of unhooked MSR '0x%x'. This is a bug.\n", msr);
413 * Add machine-check-related CPUID fields for CPUID functions 0000_0001 and 8000_0001.
415 * @return 0 for success and -1 for failure.
418 int add_cpuid_fields(struct v3_vm_info * const vm,
419 struct mcheck_state * const state) {
422 ret = v3_cpuid_add_fields(vm, CPUID_0000_0001,
426 CPUID_FIELDS, CPUID_FIELDS);
429 PrintError(MSG_PRE "Failed to add CPUID fields for function 0000_0001.\n");
433 // Add bit 7, MCE availability, and bit 14, MCE availability.
434 ret = v3_cpuid_add_fields(vm, CPUID_8000_0001,
438 CPUID_FIELDS, CPUID_FIELDS);
441 PrintError(MSG_PRE "Failed to add CPUID fileds for function 8000_0001.\n");
449 static int deinit_mcheck(struct v3_vm_info * vm, void * priv_data) {
450 struct mcheck_state * state = (struct mcheck_state *)v3_get_extension_state(vm, priv_data);
452 PrintError(MSG_PRE "Failed to get machine-check architecture extension state.\n");
460 static int init_mcheck(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
461 struct mcheck_state * state = NULL;
465 state = (struct mcheck_state *)V3_Malloc(sizeof(struct mcheck_state));
468 PrintError(MSG_PRE "Failed to allocate machine-check architecture state.\n");
475 state->mcg_cap.count = MC_REG_BANKS;
476 state->mcg_cap.mcg_ctl_p = 1;
478 ret |= add_cpuid_fields(vm, state);
481 ret |= v3_hook_msr(vm, MCG_CAP, mcg_read_handler, mcg_write_handler, state);
482 ret |= v3_hook_msr(vm, MCG_STAT, mcg_read_handler, mcg_write_handler, state);
483 ret |= v3_hook_msr(vm, MCG_CTRL, mcg_read_handler, mcg_write_handler, state);
485 for (i = 0; i < MC_REG_BANKS; i++) {
486 ret |= v3_hook_msr(vm, state->mci_regs[i].base, mci_read_handler, mci_write_handler, state);
487 ret |= v3_hook_msr(vm, state->mci_regs[i].base + 1, mci_read_handler, mci_write_handler, state);
488 ret |= v3_hook_msr(vm, state->mci_regs[i].base + 2, mci_read_handler, mci_write_handler, state);
489 ret |= v3_hook_msr(vm, state->mci_regs[i].base + 3, mci_read_handler, mci_write_handler, state);
493 PrintError(MSG_PRE "Error hooking machine-check architecture resources.\n");
500 PrintDebug(MSG_PRE "Initialized machine-check architecture.\n");
505 int v3_mcheck_inject_nb_mce(struct v3_vm_info * const vm, const uint32_t cpu,
506 const struct mc4_stat_msr stat,
507 const struct mc4_addr_msr addr) {
508 struct mcheck_state * state = (struct mcheck_state *)v3_get_extension_state(vm, MCHECK);
512 PrintError(MSG_PRE "Machine-check architecture extension state not found.\n");
516 // For now only MCE injection on cpu 0 is supported.
518 PrintError(MSG_PRE "Injecting MCE on cpu %u not supported.\n", cpu);
522 // Is the Northbridge bank enabled?
523 if (state->mcg_ctl.nbe != 1) {
524 PrintDebug(MSG_PRE "Northbridge register bank disabled. Ignoring Northbridge MCE.\n");
528 state->mci_regs[4].stat.value = stat.value;
529 state->mci_regs[4].addr.value = addr.value;
531 state->mcg_stat.value = 0;
532 state->mcg_stat.ripv = 1;
533 state->mcg_stat.mcip = 1;
535 PrintDebug(MSG_PRE "Injecting NB MCE on core %u.\n", 0);
538 ret = v3_raise_exception(&(vm->cores[0]), MCE_INTERRUPT);
541 PrintError(MSG_PRE "Failed to raise MCE.\n");
548 int v3_mcheck_inject_scrubber_mce(struct v3_vm_info *info, int cpu, uint64_t dst)
550 struct mc4_stat_msr stat;
551 struct mc4_addr_msr addr;
554 stat.error_code = 0x810;
555 stat.error_code_ext = 0x8;
564 return v3_mcheck_inject_nb_mce(info, cpu, stat, addr);
567 static struct v3_extension_impl mcheck_impl = {
570 .deinit = deinit_mcheck,
577 register_extension(&mcheck_impl);