Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
Lei Xia [Sun, 6 Feb 2011 06:51:56 +0000 (00:51 -0600)]
palacios/include/palacios/vmm_dev_mgr.h
palacios/include/palacios/vmm_msr.h
palacios/src/devices/Kconfig
palacios/src/devices/Makefile
palacios/src/devices/apic.c
palacios/src/devices/io_apic.c
palacios/src/devices/mcheck.c [new file with mode: 0644]
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_dev_mgr.c
palacios/src/palacios/vmm_msr.c
utils/guest_creator/default.xml

index 2e732cd..1e3f68b 100644 (file)
@@ -26,6 +26,7 @@
 #include <palacios/vmm_list.h>
 #include <palacios/vmm_string.h>
 #include <palacios/vmm_hashtable.h>
+#include <palacios/vmm_msr.h>
 #include <palacios/vmm_config.h>
 #include <palacios/vmm_ethernet.h>
 
@@ -49,9 +50,8 @@ struct vm_device {
 
     struct list_head dev_link;
 
-
-    uint_t num_io_hooks;
-    struct list_head io_hooks;
+    uint_t num_res_hooks;
+    struct list_head res_hooks;
 };
 
 
@@ -116,12 +116,22 @@ struct v3_device_ops {
 
 
 int v3_dev_hook_io(struct vm_device   * dev,
-                  ushort_t            port,
-                  int (*read)(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data),
-                  int (*write)(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data));
+                  uint16_t            port,
+                  int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
+                  int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data));
 
 int v3_dev_unhook_io(struct vm_device   * dev,
-                    ushort_t            port);
+                    uint16_t            port);
+
+
+int v3_dev_hook_msr(struct vm_device * dev, 
+                   uint32_t           msr,
+                   int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data), 
+                   int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data));
+
+int v3_dev_unhook_msr(struct vm_device * dev, 
+                     uint32_t msr);
+           
 
 
 
index 645baa8..0d2391a 100644 (file)
@@ -45,10 +45,10 @@ struct v3_msr {
 typedef struct v3_msr v3_msr_t;
 
 struct v3_msr_hook {
-    uint_t msr;
+    uint32_t msr;
   
-    int (*read)(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
-    int (*write)(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
+    int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data);
+    int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data);
 
     void * priv_data;
 
@@ -63,7 +63,7 @@ struct v3_msr_map {
     uint_t num_hooks;
     struct list_head hook_list;
 
-    int (*update_map)(struct v3_vm_info * vm, uint_t msr, int hook_read, int hook_write);
+    int (*update_map)(struct v3_vm_info * vm, uint32_t msr, int hook_read, int hook_write);
     void * arch_data;
 
 };
@@ -72,15 +72,15 @@ struct v3_msr_map {
 void v3_init_msr_map(struct v3_vm_info * vm);
 int v3_deinit_msr_map(struct v3_vm_info * vm);
 
-int v3_unhook_msr(struct v3_vm_info * vm, uint_t msr);
+int v3_unhook_msr(struct v3_vm_info * vm, uint32_t msr);
 
-int v3_hook_msr(struct v3_vm_info * vm, uint_t msr,
-               int (*read)(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data),
-               int (*write)(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data), 
+int v3_hook_msr(struct v3_vm_info * vm, uint32_t msr,
+               int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
+               int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data), 
                void * priv_data);
 
 
-struct v3_msr_hook * v3_get_msr_hook(struct v3_vm_info * vm, uint_t msr);
+struct v3_msr_hook * v3_get_msr_hook(struct v3_vm_info * vm, uint32_t msr);
 
 void v3_refresh_msr_map(struct v3_vm_info * vm);
 
index 3758e6d..3d157d6 100644 (file)
@@ -374,5 +374,13 @@ config CHAR_STREAM
        help
          Include Stream based character device frontend
 
+
+config MCHECK
+       bool "Machine Check architecture"
+       default n
+       depends on EXPERIMENTAL
+       help 
+         Include Machine Check injection architecture
+
 endmenu
 
index 2c5a066..cdce9ea 100644 (file)
@@ -39,3 +39,5 @@ obj-$(CONFIG_PASSTHROUGH_PCI) += pci_passthrough.o
 
 obj-$(CONFIG_SYMMOD) += lnx_virtio_symmod.o
 obj-$(CONFIG_CHAR_STREAM) += char_stream.o
+
+obj-$(CONFIG_MCHECK) += mcheck.o
index 7f70d9c..1872bb3 100644 (file)
@@ -227,6 +227,8 @@ struct apic_dev_state {
 
 
 
+
+
 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
 
@@ -704,14 +706,15 @@ static int route_ipi(struct apic_dev_state * apic_dev,
     dest_apic =  &(apic_dev->apics[icr->dst]);
 
 
-    PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
+    PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx) (destapic=%p\n",
               deliverymode_str[icr->del_mode], 
               icr->vec, 
               src_apic,               
               (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
               shorthand_str[icr->dst_shorthand], 
               icr->dst,
-              icr->val);
+              icr->val,
+              dest_apic);
 
     switch (icr->dst_shorthand) {
 
@@ -729,7 +732,6 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                // logical delivery
                int i;
                uint8_t mda = icr->dst;
-
                for (i = 0; i < apic_dev->num_apics; i++) { 
                     dest_apic = &(apic_dev->apics[i]);
                     int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
@@ -1297,13 +1299,13 @@ static int apic_get_intr_number(struct guest_info * core, void * private_data) {
 
 
 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
-    struct apic_dev_state * apic_dev = (struct apic_dev_state *)dev_data;
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)
+       (((struct vm_device *)dev_data)->private_data);
     struct int_cmd_reg tmp_icr;
 
     // zero out all the fields
     tmp_icr.val = 0;
 
-
     tmp_icr.vec = ipi->vector;
     tmp_icr.del_mode = ipi->mode;
     tmp_icr.dst_mode = ipi->logical;
@@ -1317,7 +1319,8 @@ int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev
 
 
 int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
-    struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev_data);
+    struct apic_dev_state * apic_dev = (struct apic_dev_state *)
+       (((struct vm_device*)dev_data)->private_data);
     struct apic_state * apic = &(apic_dev->apics[dst]); 
 
     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
@@ -1554,8 +1557,8 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 #ifdef CONFIG_DEBUG_APIC
     for (i = 0; i < vm->num_cores; i++) {
        struct apic_state * apic = &(apic_dev->apics[i]);
-       PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
-                  i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
+       PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
+                  i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
     }
 #endif
 
index a1d3d9f..010f4ab 100644 (file)
@@ -277,7 +277,7 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq
     if (irq_entry->mask == 0) {
        struct v3_gen_ipi ipi;
 
-       PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", 
+       PrintDebug("ioapic %u: IOAPIC Signaling APIC to raise INTR %d\n", 
                   ioapic->ioapic_id.id, irq_entry->vec);
 
 
diff --git a/palacios/src/devices/mcheck.c b/palacios/src/devices/mcheck.c
new file mode 100644 (file)
index 0000000..78ddaa2
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2008, Philip Soltero <psoltero@cs.unm.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Philip Soltero <psoltero@cs.unm.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+/**
+ * @file Virtualized machine-check architecture.
+ *
+ * @author <a HREF="mailto:psoltero@cs.unm.edu.us">Philip Soltero</a>
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
+#include <palacios/vmm_excp.h>
+#include <palacios/vmm_lowlevel.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vmm_string.h>
+#include <palacios/vmm_cpuid.h>
+
+#ifndef CONFIG_DEBUG_MCHECK
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+#define CPUID_0000_0001 0x00000001
+#define CPUID_8000_0001 0x80000001
+
+// 6 error reporting banks. This may be configurable in the future.
+#define MC_REG_BANKS 6
+#define MCE_INTERRUPT 18
+
+#define MSG_PRE "MCHECK: "
+
+#define MCG_CAP  0x0179
+#define MCG_STAT 0x017A
+#define MCG_CTRL  0x017B
+
+
+
+/* I have no idea what Intel was thinking (or maybe they just weren't) 
+ * but the MCi registers are completely non-standard across Intel's platforms and are a total mess.
+ * Any derivative of the pentium-M (i.e. all Core CPU lines) completely disregard the 
+ * architectural standard that Intel itself created...
+ * For these CPUs: the MC4 MSRs switch locations with the MC3s, 
+ * also every MCi below MC3 (including MC4) does not have a MCi_MISC MSR.
+ * 
+ * So for now, screw it, we'll use AMD's standard
+ */
+
+/* AMD MC Banks:
+   Bank 0 : Data Cache.
+   Bank 1 : Instruction Cache.
+   Bank 2 : Bus Unit.
+   Bank 3 : Load Store Unit.
+   Bank 4 : Northbridge and DRAM.
+*/
+
+static const uint32_t amd_mci_bases[] = {0x0400, 0x0404, 0x0408, 0x040c, 0x0410, 0x0414};
+static const uint32_t pentium_6_mci_bases[] = {0x0400, 0x0404, 0x0408, 0x040c, 0x0410, 0x0414};
+static const uint32_t pentium_m_mci_bases[] = {0x0400, 0x0404, 0x0408, 0x0410, 0x040c, 0x0414};
+static const uint32_t ia32_mci_bases[] = { 0x0400, 0x0404, 0x0408, 0x040c, 
+                                          0x0410, 0x0414, 0x0418, 0x041c, 
+                                          0x0420, 0x0424, 0x0428, 0x042c,
+                                          0x0430, 0x0434, 0x0438, 0x043c,
+                                          0x0440, 0x0444, 0x0448, 0x044c,
+                                          0x0450, 0x0454 };
+#define MCi_MASK  0xfffffffc
+#define MCi_CTRL  0x00
+#define MCi_STAT  0x01
+#define MCi_ADDR  0x02
+#define MCi_MISC  0x03
+
+
+
+
+/**
+ * MCA status low and high registers, MC4_STAT, MSR0000_0411.
+ */
+struct mc4_stat_msr {
+     union {
+        uint64_t value;
+        struct {
+           uint_t syndrome            : 8;
+           uint_t reserved            : 3;
+           uint_t error_code_ext      : 5;
+           uint_t error_code          : 16;
+           uint_t err_cpu             : 4;
+           uint_t ltd_link            : 4;
+           uint_t scrub               : 1;
+           uint_t sublink             : 1;
+           uint_t mca_stat_sub_cache  : 2;
+           uint_t reserved_01         : 1;
+           uint_t uecc                : 1;
+           uint_t cecc                : 1;
+           uint_t syndrome2           : 8;
+           uint_t reserved_02         : 1;
+           uint_t err_cpu_val         : 1;
+           uint_t pcc                 : 1;
+           uint_t addr_v              : 1;
+           uint_t misc_v              : 1;
+           uint_t en                  : 1;
+           uint_t uc                  : 1;
+           uint_t over                : 1;
+           uint_t val                 : 1;         
+        }__attribute__((packed));
+     }__attribute__((packed));
+} __attribute__((packed));
+
+/**
+ * MCA address low and high registers, MC4_ADDR, MSR0000_0412.
+ */
+struct mc4_addr_msr {
+    union {
+        uint64_t value;
+
+        struct {
+           uint64_t addr32    : 36;
+           uint32_t reserved  : 28;
+        } __attribute__((packed));
+
+       uint64_t addr64;
+    } __attribute__((packed));
+} __attribute__((packed));
+
+/**
+ * Global machine-check capabilities register, MCG_CAP.
+ */
+struct mcg_cap_msr {
+    union {
+        uint64_t value;
+        struct {
+            uint32_t count            : 8;
+            uint32_t mcg_ctl_p        : 1;  // CTRL Present
+            uint64_t reserved         : 55;
+        } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+/**
+ * Global machine-check status register, MCG_STAT.
+ */
+struct mcg_stat_msr {
+    union {
+        uint64_t value;
+        struct {
+            uint32_t ripv             : 1;
+            uint32_t eipv             : 1;
+            uint32_t mcip             : 1; // Machine-check in progress.
+            uint64_t reserved         : 61;
+        } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+/**
+ * Global machine-check control register, MCG_CTRL.
+ */
+struct mcg_ctl_msr {
+    union {
+        uint64_t value;
+        struct {
+            uint32_t dce          : 1; // Data cache register bank enable
+            uint32_t ice          : 1; // Instruction cache register bank enable
+            uint32_t bue          : 1; // Bus unit register bank enable
+            uint32_t lse          : 1; // Load-store register bank enable
+            uint32_t nbe          : 1; // Northbridge register bank enable
+            uint32_t fre          : 1; // Fixed issue reorder buffer register bank enable
+            uint64_t unused       : 58;
+        } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+/**
+ * A temporary structure for unimplemented machine-check error reporting banks.
+ */
+struct mci_bank {
+    uint32_t base;
+    struct v3_msr ctl;
+    struct v3_msr stat;
+    struct v3_msr addr;
+    struct v3_msr misc;
+};
+
+struct mcheck_state {
+    struct mcg_cap_msr mcg_cap;
+    struct mcg_stat_msr mcg_stat;
+    struct mcg_ctl_msr mcg_ctl;
+  
+    /* Note that these are in logical order not MSR order */
+    /* So MC4 is always at mci_regs[4] even if the MSR is before MC3's */
+    struct mci_bank mci_regs[MC_REG_BANKS];
+};
+
+
+/**
+ * Handles a guest read of cpuid function 0000_0001 and 8000_0001.
+ * All bits are passthrough except for bit 14, the MCA available bit, and bit 7, the MCE available
+ * bit.
+ *
+ * @b<Note:> The virtual MCA only uses two bits in the entire 256 bit "return value". If other VMM
+ * subsystems or devices require the virtualization of other return value bits, it is suggested that
+ * this hook handler be moved to a common source file where all subsystems and devices can
+ * virtualize the bits they need to.
+ */
+static int cpuid_hook_handler(struct guest_info * const info, const uint32_t cpuid, 
+                             uint32_t * const eax, uint32_t * const ebx, 
+                             uint32_t * const ecx, uint32_t * const edx, 
+                             void * const private_data) {
+
+    // Most bits are passthrough.
+    v3_cpuid(cpuid, eax, ebx, ecx, edx);
+
+    // Bit 7, MCE availability
+    // Bit 14, MCA availability
+    *edx |= 0x00004080;
+
+    return 0;
+}
+
+static inline
+void init_state(struct mcheck_state * const state) {
+    int i = 0;
+
+    memset(state, 0, sizeof(struct mcheck_state));
+
+    // Set the initial MCI reg base values to the current architecture
+    for (i = 0; i < MC_REG_BANKS; i++) {
+       state->mci_regs[i].base = amd_mci_bases[i];
+    }
+}
+
+/**
+ * Handles guest writes to MCG MSRs.
+ */
+static
+int mcg_write_handler(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data) {
+    struct mcheck_state * state = (struct mcheck_state *)priv_data;
+
+    switch (msr) {
+       case MCG_CAP:
+           PrintDebug(MSG_PRE "Ignoring write to MCG_CAP MSR.\n");
+           break;
+
+       case MCG_STAT:
+           state->mcg_stat.value = 0;
+           break;
+           
+       case MCG_CTRL:
+           if (!state->mcg_cap.mcg_ctl_p) {
+               PrintDebug(MSG_PRE "Ignoring write to control MSR '0x%x'. Control MSRs not supported.\n", msr);
+               break;
+           }
+           
+           // The upper 58 bits are unused and read-only.
+           state->mcg_ctl.value &= ~0x3f;
+           state->mcg_ctl.value |= src.value & 0x3f;
+
+           break;
+
+       default:
+            PrintError(MSG_PRE "Reading from invalid MSR: %x\n", msr);
+            return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Handles guest reads to MCG MSRs.
+ */
+static
+int mcg_read_handler(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data) {
+    struct mcheck_state * state = (struct mcheck_state *)priv_data;
+
+     switch(msr) {
+       case MCG_CAP:
+           dst->value = state->mcg_cap.value;
+           break;
+
+       case MCG_STAT:
+           dst->value = state->mcg_stat.value;
+           break;
+
+       case MCG_CTRL:
+           if (!state->mcg_cap.mcg_ctl_p) {
+               PrintDebug(MSG_PRE "Ignoring read of control MSR '0x%x'. Control MSRs not supported.\n", msr);
+               break;
+           }
+
+           dst->value = state->mcg_ctl.value;
+           break;
+
+        default:
+            PrintError(MSG_PRE "Reading from invalid MSR: %x\n", msr);
+            return -1;
+     }
+
+     return 0;
+}
+
+static struct mci_bank * get_mci_reg(struct mcheck_state * state, uint32_t msr) {
+    int i = 0;
+
+    for (i = 0; i < MC_REG_BANKS; i++) {
+       if (state->mci_regs[i].base == (msr & MCi_MASK)) {
+           return &(state->mci_regs[i]);
+       }
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Handles guest reads to MCi MSRs.
+ */
+static
+int mci_read_handler(struct guest_info * const core,
+                     const uint32_t msr,
+                     struct v3_msr * const dst,
+                     void * const priv_data) {
+    struct mcheck_state * const state = (struct mcheck_state *)priv_data;
+    struct mci_bank * mci = get_mci_reg(state, msr);
+
+    PrintDebug(MSG_PRE "Reading value '0x%llx' for MSR '0x%x'.\n", dst->value, msr);
+
+    if (mci == NULL) {
+       PrintError(MSG_PRE " MSR read for invalid MCI register 0x%x\n", msr);
+       return -1;
+    }
+
+    switch (msr & ~MCi_MASK) {
+       case MCi_CTRL:
+           if (!state->mcg_cap.mcg_ctl_p) {
+               PrintDebug(MSG_PRE "Ignoring read of control MSR '0x%x'. Control MSRs not supported.\n", msr);
+               break;
+           }
+
+           dst->value = mci->ctl.value;
+           break;
+
+       case MCi_STAT:
+           dst->value = mci->stat.value;
+           break;
+
+       case MCi_ADDR:
+           dst->value = mci->addr.value;
+           break;
+
+       case MCi_MISC:
+           dst->value = mci->misc.value;
+           break;
+
+       default:
+           PrintError(MSG_PRE "Ignoring read of unhooked MSR '0x%x'. This is a bug.\n", msr);
+           break;
+    }
+
+    return 0;
+}
+
+/**
+ * Handles guest writes to MCi MSRs.
+ */
+static
+int mci_write_handler(struct guest_info * const core,
+                     const uint_t msr,
+                     const struct v3_msr src,
+                     void * const priv_data) {
+    struct mcheck_state * const state = (struct mcheck_state *)priv_data;
+    struct mci_bank * mci = get_mci_reg(state, msr);
+
+    PrintDebug(MSG_PRE "Writing value '0x%llx' for MSR '0x%x'.\n", src.value, msr);
+
+    switch (msr & ~MCi_MASK) {
+       case MCi_CTRL:
+           if (!state->mcg_cap.mcg_ctl_p) {
+               PrintDebug(MSG_PRE "Ignoring read of control MSR '0x%x'. Control MSRs not supported.\n", msr);
+               break;
+           }
+
+           mci->ctl.value = src.value;
+           break;
+
+       case MCi_STAT:
+           if (src.value != 0) {
+               // Should be a GPF.
+               PrintError(MSG_PRE "Ignoring write of illegal value '0x%llx'.\n", src.value);
+               return -1;
+           }
+
+           mci->stat.value = 0;
+           break;
+
+       case MCi_ADDR:
+           mci->addr.value = src.value;
+           break;
+
+       case MCi_MISC:
+           V3_Print(MSG_PRE "Ignoring write to read only miscellaneous MSR '0x%x'.\n", msr);
+           break;
+
+       default:
+           PrintError(MSG_PRE "Ignoring write of unhooked MSR '0x%x'. This is a bug.\n", msr);
+           break;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Hook CPUIDs
+ * CPUID functions 0000_0001 and 8000_0001 are hooked to signal MC availability
+ *
+ * @return 0 for success and -1 for failure.
+ */
+static inline
+int hook_cpuids(struct v3_vm_info * const vm,
+               struct mcheck_state * const state) {
+    int ret = 0;
+
+    ret = v3_hook_cpuid(vm, CPUID_0000_0001, cpuid_hook_handler, state);
+
+    if (ret == -1) {
+       PrintError(MSG_PRE "Failed to hook CPUID function 0000_0001.\n");
+       return -1;
+    }
+    
+    ret = v3_hook_cpuid(vm, CPUID_8000_0001, cpuid_hook_handler, state);
+    
+    if (ret == -1) {
+       PrintError(MSG_PRE "Failed to hook CPUID function 8000_0001.\n");
+       v3_unhook_cpuid(vm, CPUID_0000_0001);
+       return -1;
+    }
+    
+    return 0;
+}
+
+
+static int mcheck_free(struct mcheck_state * state) {
+    V3_Free(state);
+    return 0;
+}
+
+static struct v3_device_ops dev_ops = {
+    .free = (int (*)(void *))mcheck_free,
+};
+
+
+
+
+static int mcheck_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+    struct mcheck_state * state = NULL;
+    //  char * dev_id = v3_cfg_val(cfg, "ID");
+    char * dev_id = "MCHECK"; // we hardcode the device ID for now so we can always find it for #MC insertion
+    int ret = 0;
+    int i = 0;
+
+    state = (struct mcheck_state *)V3_Malloc(sizeof(struct mcheck_state));
+
+    if (state == NULL) {
+       PrintError(MSG_PRE "Failed to allocate machine-check architecture state.\n");
+       return -1;
+    }
+
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
+
+    if (dev == NULL) {
+       PrintError("Could not attach device %s\n", dev_id);
+       V3_Free(state);
+       return -1;
+    }
+    
+    init_state(state);
+
+    state->mcg_cap.count = MC_REG_BANKS;
+
+    ret |= hook_cpuids(vm, state);
+
+    /* Hook the MSRs */
+    ret |= v3_dev_hook_msr(dev, MCG_CAP, mcg_read_handler, mcg_write_handler);
+    ret |= v3_dev_hook_msr(dev, MCG_STAT, mcg_read_handler, mcg_write_handler);
+    ret |= v3_dev_hook_msr(dev, MCG_CTRL, mcg_read_handler, mcg_write_handler);
+
+    for (i = 0; i < MC_REG_BANKS; i++) {
+       ret |= v3_dev_hook_msr(dev, state->mci_regs[i].base, mci_read_handler, mci_write_handler);
+       ret |= v3_dev_hook_msr(dev, state->mci_regs[i].base + 1, mci_read_handler, mci_write_handler);
+       ret |= v3_dev_hook_msr(dev, state->mci_regs[i].base + 2, mci_read_handler, mci_write_handler);
+       ret |= v3_dev_hook_msr(dev, state->mci_regs[i].base + 3, mci_read_handler, mci_write_handler);
+    }
+
+    if (ret == -1) {
+       PrintError(MSG_PRE "Error hooking Device resources\n");
+       v3_remove_device(dev);
+       return -1;
+    }
+    
+    return 0;
+}
+
+int v3_mcheck_inject_nb_mce(struct v3_vm_info * const vm, const uint32_t cpu,
+                           const struct mc4_stat_msr stat,
+                           const struct mc4_addr_msr addr) {
+    struct vm_device * dev = v3_find_dev(vm, "MCHECK");
+    struct mcheck_state * state = dev->private_data;
+    int ret;
+
+    // For now only MCE injection on cpu 0 is supported.
+    if (cpu != 0) {
+       PrintError(MSG_PRE "Injecting MCE on cpu %u not supported.\n", cpu);
+       return -1;
+    }
+
+
+    // Is the Northbridge bank enabled?
+    if (state->mcg_ctl.nbe != 1) {
+       PrintDebug(MSG_PRE "Northbridge register bank disabled. Ignoring Northbridge MCE.\n");
+       return 0;
+    }
+
+    state->mci_regs[4].stat.value = stat.value;
+    state->mci_regs[4].addr.value = addr.value;
+
+    state->mcg_stat.value = 0;
+    state->mcg_stat.ripv = 1;
+    state->mcg_stat.mcip = 1;
+
+    PrintDebug(MSG_PRE "Injecting NB MCE on core %u.\n", 0);
+
+    // Raise on core 0.
+    ret = v3_raise_exception(&(vm->cores[0]), MCE_INTERRUPT);
+
+    if (ret == -1) {
+       PrintError(MSG_PRE "Failed to raise MCE.\n");
+       return -1;
+    }
+
+    return 0;
+}
+
+device_register("MCHECK", mcheck_init);
index 0060bc2..dca1018 100644 (file)
@@ -279,6 +279,7 @@ int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
        void * core_thread = NULL;
        struct guest_info * core = &(vm->cores[vcore_id]);
 
+       /* This assumes that the core 0 thread has been mapped to physical core 0 */
        if (i == V3_Get_CPU()) {
            // We skip the local CPU, because it is reserved for vcore 0
            continue;
index f0554ea..5abb57b 100644 (file)
@@ -181,55 +181,108 @@ struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
 /* The remaining functions are called by the devices themselves */
 /****************************************************************/
 
-struct dev_io_hook {
-    uint16_t port;
+typedef enum {DEV_IO_HOOK, DEV_MSR_HOOK, DEV_CPUID_HOOK, DEV_MEM_HOOK, DEV_HCALL_HOOK} dev_rsrc_type_t;
 
-    struct list_head node;
+struct dev_rsrc {
+    dev_rsrc_type_t type;
+    uint64_t rsrc;
 
+    struct list_head node;
 };
 
-/* IO HOOKS */
+
+
+static int add_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
+    struct dev_rsrc * resource = NULL;
+
+    resource = V3_Malloc(sizeof(struct dev_rsrc));
+
+    if (resource == NULL) {
+       PrintError("Error: Could not allocate device resource\n");
+       return -1;
+    }
+
+    resource->rsrc = rsrc_id;
+    resource->type = type;
+
+    list_add(&(resource->node), &(dev->res_hooks));
+    return 0;
+}
+
+static int free_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
+    struct dev_rsrc * resource = NULL;
+    struct dev_rsrc * tmp;
+
+    list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
+       if ((resource->type == type) && 
+           (resource->rsrc == rsrc_id)) {
+
+           list_del(&(resource->node));
+           V3_Free(resource);
+           
+           return 0;
+       }
+    }
+
+    return -1;
+}
+
+
 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
                   int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
                   int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
-    struct dev_io_hook * io_hook = NULL;
     int ret = 0;
     
-   ret = v3_hook_io_port(dev->vm, port, 
-                        (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))read, 
-                        (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))write, 
-                        (void *)dev->private_data);
+    ret = v3_hook_io_port(dev->vm, port, 
+                         (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))read, 
+                         (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))write, 
+                         (void *)dev->private_data);
 
-   if (ret == -1) {
-       return -1;
-   }
+    if (ret == -1) {
+       return -1;
+    }
 
-   io_hook = V3_Malloc(sizeof(struct dev_io_hook));
+    if (add_resource(dev, DEV_IO_HOOK, port) == -1) {
+       v3_unhook_io_port(dev->vm, port);
+       PrintError("Could not allocate io hook dev state\n");
+       return -1;
+    }
+    
+    return 0;
+}
 
-   if (io_hook == NULL) {
-       PrintError("Could not allocate io hook dev state\n");
-       return -1;
-   }
 
-   io_hook->port = port;
-   list_add(&(io_hook->node), &(dev->io_hooks));
+int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
+    if (free_resource(dev, DEV_IO_HOOK, port) == 0) {
+       return v3_unhook_io_port(dev->vm, port);           
+    } 
 
-   return 0;
+    return -1;
 }
 
 
-int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
-    struct dev_io_hook * io_hook = NULL;
-    struct dev_io_hook * tmp;
+int v3_dev_hook_msr(struct vm_device * dev, uint32_t msr,
+                   int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
+                   int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data)) {
+    int ret = 0;
 
-    list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
-       if (io_hook->port == port) {
+    ret = v3_hook_msr(dev->vm, msr, read, write, dev->private_data);
 
-           list_del(&(io_hook->node));
-           V3_Free(io_hook);
-           
-           return v3_unhook_io_port(dev->vm, port);        
-       }
+    if (ret == -1) {
+       return -1;
+    }
+
+    if (add_resource(dev, DEV_MSR_HOOK, msr) == -1) {
+       v3_unhook_msr(dev->vm, msr);
+       return -1;
+    }
+
+    return 0;
+}
+                 
+int v3_dev_unhook_msr(struct vm_device * dev, uint32_t msr) {
+    if (free_resource(dev, DEV_MSR_HOOK, msr) == 0) {
+       return v3_unhook_msr(dev->vm, msr);
     }
 
     return -1;
@@ -237,15 +290,21 @@ int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
 
 
 
+
 int v3_remove_device(struct vm_device * dev) {
     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
-    struct dev_io_hook * io_hook = NULL;
-    struct dev_io_hook * tmp;
+    struct dev_rsrc * resource = NULL;
+    struct dev_rsrc * tmp;
+
+    list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
+       if (resource->type == DEV_IO_HOOK) {
+           v3_unhook_io_port(dev->vm, (uint16_t)(resource->rsrc));
+       } else if (resource->type == DEV_MSR_HOOK) {
+           v3_unhook_msr(dev->vm, (uint32_t)(resource->rsrc));
+       }
 
-    list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
-       v3_unhook_io_port(dev->vm, io_hook->port);          
-       list_del(&(io_hook->node));
-       V3_Free(io_hook);    
+       list_del(&(resource->node));
+       V3_Free(resource);    
     }
 
     if (dev->ops->free) {
@@ -277,7 +336,7 @@ struct vm_device * v3_add_device(struct v3_vm_info * vm,
        return NULL;
     }
 
-    INIT_LIST_HEAD(&(dev->io_hooks));
+    INIT_LIST_HEAD(&(dev->res_hooks));
 
     strncpy(dev->name, name, 32);
     dev->ops = ops;
index 5fe8ecf..68d4767 100644 (file)
@@ -48,7 +48,7 @@ int v3_deinit_msr_map(struct v3_vm_info * vm) {
 }
 
 int v3_handle_msr_write(struct guest_info * info) {
-    uint_t msr_num = info->vm_regs.rcx;
+    uint32_t msr_num = info->vm_regs.rcx;
     struct v3_msr msr_val;
     struct v3_msr_hook * hook = NULL;
 
@@ -77,7 +77,7 @@ int v3_handle_msr_write(struct guest_info * info) {
 
 
 int v3_handle_msr_read(struct guest_info * info) {
-    uint_t msr_num = info->vm_regs.rcx;
+    uint32_t msr_num = info->vm_regs.rcx;
     struct v3_msr msr_val;
     struct v3_msr_hook * hook = NULL;
 
@@ -102,9 +102,9 @@ int v3_handle_msr_read(struct guest_info * info) {
     return 0;
 }
 
-int v3_hook_msr(struct v3_vm_info * vm, uint_t msr, 
-               int (*read)(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data),
-               int (*write)(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data),
+int v3_hook_msr(struct v3_vm_info * vm, uint32_t msr, 
+               int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
+               int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data),
                void * priv_data) {
 
     struct v3_msr_map * msr_map = &(vm->msr_map);
@@ -148,7 +148,7 @@ static int free_hook(struct v3_vm_info * vm, struct v3_msr_hook * hook) {
 }
 
 
-int v3_unhook_msr(struct v3_vm_info * vm, uint_t msr) {
+int v3_unhook_msr(struct v3_vm_info * vm, uint32_t msr) {
     struct v3_msr_hook * hook = v3_get_msr_hook(vm, msr);
 
     if (hook == NULL) {
@@ -163,7 +163,7 @@ int v3_unhook_msr(struct v3_vm_info * vm, uint_t msr) {
 
 
 
-struct v3_msr_hook * v3_get_msr_hook(struct v3_vm_info * vm, uint_t msr) {
+struct v3_msr_hook * v3_get_msr_hook(struct v3_vm_info * vm, uint32_t msr) {
     struct v3_msr_map * msr_map = &(vm->msr_map);
     struct v3_msr_hook * hook = NULL;
 
index fe5e67b..e3b6bca 100644 (file)
                </device>
 -->
 
+       <!-- Machine-check device -->
+<!--
+        <device class="MCHECK" id="MCHECK" />
+-->
+
+
                <device class="NVRAM" id="nvram">
                        <storage>ide</storage>
                </device>