debuggers.hg

changeset 22682:1bc031edae04

Xen MCE test: utilities to inject fake MCE for X86

A software MCE injection tool, which is based on Xen MCE injection
mechanism. It fake MCE error and inject this error to a assigned
Domain Physical Address. Makefile make sure the tool can be built on
Xen. A README explain the usage for this tool.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Haicheng Li<haicheng.li@intel.com>
Signed-off-by: Xudong Hao <xudong.hao@intel.com>
author Keir Fraser <keir@xen.org>
date Fri Dec 24 10:21:27 2010 +0000 (2010-12-24)
parents 97779ffa76f5
children ca0b26180f32
files tools/tests/mce-test/tools/Makefile tools/tests/mce-test/tools/README tools/tests/mce-test/tools/xen-mceinj.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/tests/mce-test/tools/Makefile	Fri Dec 24 10:21:27 2010 +0000
     1.3 @@ -0,0 +1,27 @@
     1.4 +XEN_ROOT=../../../..
     1.5 +include $(XEN_ROOT)/tools/Rules.mk
     1.6 +
     1.7 +CFLAGS   += -Werror
     1.8 +
     1.9 +INCLUDES += -I $(XEN_XC)
    1.10 +INCLUDES += -I $(XEN_LIBXC)
    1.11 +INCLUDES += -I $(XEN_INCLUDE)
    1.12 +CFLAGS   += $(INCLUDES)
    1.13 +
    1.14 +HDRS     = $(wildcard *.h)
    1.15 +
    1.16 +.PHONY: all
    1.17 +all: xen-mceinj
    1.18 +
    1.19 +install: 
    1.20 +	cp xen-mceinj /usr/sbin/
    1.21 +
    1.22 +.PHONY: clean
    1.23 +clean:
    1.24 +	$(RM) *.o xen-mceinj
    1.25 +
    1.26 +%.o: %.c $(HDRS) Makefile
    1.27 +	$(CC) -c $(CFLAGS) -o $@ $<
    1.28 +
    1.29 +xen-mceinj: %: %.o Makefile
    1.30 +	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenstore)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/tests/mce-test/tools/README	Fri Dec 24 10:21:27 2010 +0000
     2.3 @@ -0,0 +1,24 @@
     2.4 +Xen Machine Check Exception(MCE) error inject tool
     2.5 +----------------------------------------------
     2.6 +
     2.7 +xen-mceinj is a software MCE injection tool, which is based on Xen 
     2.8 +MCE injection mechanism. It allows to inject machine check errors on the
     2.9 +software level into a running Xen/dom0/VM. This is intended for
    2.10 +validation of the Xen machine check handler.
    2.11 +
    2.12 +With the help of the Makefile, it is possible to compile a binary file 
    2.13 +named "xen-mceinj".
    2.14 +
    2.15 +Usage
    2.16 +-----
    2.17 +$make (make install) --Note: make sure compile xen/tools before do this step
    2.18 +$./xen-mceinj [OPTION]...
    2.19 +
    2.20 +OPTION arguments can be:
    2.21 +  -D, --dump           dump addr info without error injection
    2.22 +  -c, --cpu=CPU_ID     target CPU, the default is CPU0
    2.23 +  -d, --domain=DomID   target domain, the default is Xen itself
    2.24 +  -p, --page           physical page address, the default is 0x180020
    2.25 +  -t, --type=error     error type
    2.26 +
    2.27 +For detail help, please refer to "./xen-mceinj -h"
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/tests/mce-test/tools/xen-mceinj.c	Fri Dec 24 10:21:27 2010 +0000
     3.3 @@ -0,0 +1,645 @@
     3.4 +/*
     3.5 + * xen-mceinj.c: utilities to inject fake MCE for x86.
     3.6 + * Copyright (c) 2010, Intel Corporation.
     3.7 + *
     3.8 + * This program is free software; you can redistribute it and/or modify it
     3.9 + * under the terms and conditions of the GNU General Public License,
    3.10 + * version 2, as published by the Free Software Foundation.
    3.11 + *
    3.12 + * This program is distributed in the hope it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    3.15 + * more details.
    3.16 + *
    3.17 + * You should have received a copy of the GNU General Public License along with
    3.18 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    3.19 + * Place - Suite 330, Boston, MA 02111-1307 USA.
    3.20 + * 
    3.21 + * Authors: Yunhong Jiang <yunhong.jiang@intel.com>
    3.22 + *          Haicheng Li <haicheng.li@intel.com>
    3.23 + *          Xudong Hao <xudong.hao@intel.com>
    3.24 + */
    3.25 +
    3.26 +
    3.27 +#define _GNU_SOURCE
    3.28 +#include <stdio.h>
    3.29 +#include <stdlib.h>
    3.30 +#include <unistd.h>
    3.31 +#include <string.h>
    3.32 +#include <getopt.h>
    3.33 +#include <errno.h>
    3.34 +#include <signal.h>
    3.35 +#include <stdarg.h>
    3.36 +
    3.37 +#include <xenctrl.h>
    3.38 +#include <xg_private.h>
    3.39 +#include <xenguest.h>
    3.40 +#include <inttypes.h>
    3.41 +#include <sys/time.h>
    3.42 +#include <xen/arch-x86/xen-mca.h>
    3.43 +#include <xg_save_restore.h>
    3.44 +#include <xs.h>
    3.45 +
    3.46 +#define MCi_type_CTL        0x0
    3.47 +#define MCi_type_STATUS     0x1
    3.48 +#define MCi_type_ADDR       0x2
    3.49 +#define MCi_type_MISC       0x3
    3.50 +#define MCi_type_CTL2       0x4
    3.51 +
    3.52 +#define INVALID_MSR         ~0UL
    3.53 +
    3.54 +/* Intel MSRs */
    3.55 +#define MSR_IA32_MCG_CAP         0x00000179
    3.56 +#define MSR_IA32_MCG_STATUS      0x0000017a
    3.57 +#define MSR_IA32_MCG_CTL         0x0000017b
    3.58 +#define MSR_IA32_MC0_CTL         0x00000400
    3.59 +#define MSR_IA32_MC0_STATUS      0x00000401
    3.60 +#define MSR_IA32_MC0_ADDR        0x00000402
    3.61 +#define MSR_IA32_MC0_MISC        0x00000403
    3.62 +#define MSR_IA32_MC0_CTL2        0x00000280
    3.63 +
    3.64 +/* LLC (Last Level Cache) EWB (Explicit Write Back) SRAO MCE */
    3.65 +#define MCG_STATUS_SRAO_LLC_VAL  0x5
    3.66 +#define MCE_SRAO_LLC_BANK        0x7
    3.67 +#define MCi_STATUS_SRAO_LLC_VAL  0xBD2000008000017AUL
    3.68 +#define MCi_MISC_SRAO_LLC_VAL    0x86UL
    3.69 +
    3.70 +/* Memory Patrol Scrub SRAO MCE */
    3.71 +#define MCG_STATUS_SRAO_MEM_VAL  0x5
    3.72 +#define MCE_SRAO_MEM_BANK        0x8
    3.73 +#define MCi_STATUS_SRAO_MEM_VAL  0xBD000000004000CFUL
    3.74 +#define MCi_MISC_SRAO_MEM_VAL    0x86UL
    3.75 +
    3.76 +/* LLC EWB UCNA Error */
    3.77 +#define MCG_STATUS_UCNA_LLC_VAL  0x0
    3.78 +#define CMCI_UCNA_LLC_BANK       0x9
    3.79 +#define MCi_STATUS_UCNA_LLC_VAL  0xBC20000080000136UL
    3.80 +#define MCi_MISC_UCNA_LLC_VAL    0x86UL
    3.81 +
    3.82 +/* Error Types */
    3.83 +#define MCE_SRAO_MEM        0x0
    3.84 +#define MCE_SRAO_LLC        0x1
    3.85 +#define CMCI_UCNA_LLC       0x2
    3.86 +
    3.87 +#define LOGFILE stdout
    3.88 +
    3.89 +int dump;
    3.90 +struct xen_mc_msrinject msr_inj;
    3.91 +
    3.92 +static void Lprintf(const char *fmt, ...)
    3.93 +{
    3.94 +    char *buf;
    3.95 +    va_list args;
    3.96 +
    3.97 +    va_start(args, fmt);
    3.98 +    vasprintf(&buf, fmt, args);
    3.99 +    fprintf(LOGFILE, "%s", buf);
   3.100 +    va_end(args);
   3.101 +    free(buf);
   3.102 +}
   3.103 +
   3.104 +static void err(xc_interface *xc_handle, const char *fmt, ...)
   3.105 +{
   3.106 +    char *buf;
   3.107 +    va_list args;
   3.108 +
   3.109 +    va_start(args, fmt);
   3.110 +    vasprintf(&buf, fmt, args);
   3.111 +    perror(buf);
   3.112 +    va_end(args);
   3.113 +    free(buf);
   3.114 +
   3.115 +    if ( xc_handle )
   3.116 +        xc_interface_close(xc_handle);
   3.117 +    exit(EXIT_FAILURE);
   3.118 +}
   3.119 +
   3.120 +static void init_msr_inj(void)
   3.121 +{
   3.122 +    memset(&msr_inj, 0, sizeof(msr_inj));
   3.123 +}
   3.124 +
   3.125 +static int flush_msr_inj(xc_interface *xc_handle)
   3.126 +{
   3.127 +    struct xen_mc mc;
   3.128 +
   3.129 +    mc.cmd = XEN_MC_msrinject;
   3.130 +    mc.interface_version = XEN_MCA_INTERFACE_VERSION;
   3.131 +    mc.u.mc_msrinject = msr_inj;
   3.132 +
   3.133 +    return xc_mca_op(xc_handle, &mc);
   3.134 +}
   3.135 +
   3.136 +static int mca_cpuinfo(xc_interface *xc_handle)
   3.137 +{
   3.138 +    struct xen_mc mc;
   3.139 +
   3.140 +    mc.cmd = XEN_MC_physcpuinfo;
   3.141 +    if (xc_mca_op(xc_handle, &mc))
   3.142 +        return mc.u.mc_physcpuinfo.ncpus;
   3.143 +    else
   3.144 +        return 0;
   3.145 +}
   3.146 +
   3.147 +static int inject_cmci(xc_interface *xc_handle, int cpu_nr)
   3.148 +{
   3.149 +    struct xen_mc mc;
   3.150 +    int nr_cpus;
   3.151 +
   3.152 +    memset(&mc, 0, sizeof(struct xen_mc));
   3.153 +
   3.154 +    nr_cpus = mca_cpuinfo(xc_handle);
   3.155 +    if (!nr_cpus)
   3.156 +        err(xc_handle, "Failed to get mca_cpuinfo\n");
   3.157 +
   3.158 +    mc.cmd = XEN_MC_inject_v2;
   3.159 +    mc.interface_version = XEN_MCA_INTERFACE_VERSION;
   3.160 +
   3.161 +    mc.u.mc_inject_v2.flags |= XEN_MC_INJECT_CPU_BROADCAST;
   3.162 +    mc.u.mc_inject_v2.flags |= XEN_MC_INJECT_TYPE_CMCI;
   3.163 +    mc.u.mc_inject_v2.cpumap.nr_cpus = nr_cpus;
   3.164 +
   3.165 +    return xc_mca_op(xc_handle, &mc);
   3.166 +}
   3.167 +
   3.168 +static int inject_mce(xc_interface *xc_handle, int cpu_nr)
   3.169 +{
   3.170 +    struct xen_mc mc;
   3.171 +
   3.172 +    memset(&mc, 0, sizeof(struct xen_mc));
   3.173 +
   3.174 +    mc.cmd = XEN_MC_mceinject;
   3.175 +    mc.interface_version = XEN_MCA_INTERFACE_VERSION;
   3.176 +    mc.u.mc_mceinject.mceinj_cpunr = cpu_nr;
   3.177 +
   3.178 +    return xc_mca_op(xc_handle, &mc);
   3.179 +}
   3.180 +
   3.181 +static uint64_t bank_addr(int bank, int type)
   3.182 +{
   3.183 +    uint64_t addr;
   3.184 +
   3.185 +    switch ( type )
   3.186 +    {
   3.187 +        case MCi_type_CTL:
   3.188 +        case MCi_type_STATUS:
   3.189 +        case MCi_type_ADDR:
   3.190 +        case MCi_type_MISC:
   3.191 +            addr = MSR_IA32_MC0_CTL + (bank * 4) + type;
   3.192 +            break;
   3.193 +        case MCi_type_CTL2:
   3.194 +            addr = MSR_IA32_MC0_CTL2 + bank;
   3.195 +            break;
   3.196 +        default:
   3.197 +            addr = INVALID_MSR;
   3.198 +            break;
   3.199 +    }
   3.200 +
   3.201 +    return addr;
   3.202 +}
   3.203 +
   3.204 +static int add_msr_intpose(xc_interface *xc_handle,
   3.205 +                           uint32_t cpu_nr,
   3.206 +                           uint32_t flags,
   3.207 +                           uint64_t msr,
   3.208 +                           uint64_t val)
   3.209 +{
   3.210 +    uint32_t count;
   3.211 +
   3.212 +    if ( (msr_inj.mcinj_count &&
   3.213 +         (cpu_nr != msr_inj.mcinj_cpunr || flags != msr_inj.mcinj_flags)) ||
   3.214 +         msr_inj.mcinj_count == MC_MSRINJ_MAXMSRS )
   3.215 +    {
   3.216 +        flush_msr_inj(xc_handle);
   3.217 +        init_msr_inj();
   3.218 +    }
   3.219 +    count= msr_inj.mcinj_count;
   3.220 +
   3.221 +    if ( !count )
   3.222 +    {
   3.223 +        msr_inj.mcinj_cpunr = cpu_nr;
   3.224 +        msr_inj.mcinj_flags = flags;
   3.225 +    }
   3.226 +    msr_inj.mcinj_msr[count].reg = msr;
   3.227 +    msr_inj.mcinj_msr[count].value = val;
   3.228 +    msr_inj.mcinj_count++;
   3.229 +
   3.230 +    return 0;
   3.231 +}
   3.232 +
   3.233 +static int add_msr_bank_intpose(xc_interface *xc_handle,
   3.234 +                                uint32_t cpu_nr,
   3.235 +                                uint32_t flags,
   3.236 +                                uint32_t type,
   3.237 +                                uint32_t bank,
   3.238 +                                uint64_t val)
   3.239 +{
   3.240 +    uint64_t msr;
   3.241 +
   3.242 +    msr = bank_addr(bank, type);
   3.243 +    if ( msr == INVALID_MSR )
   3.244 +        return -1;
   3.245 +    return add_msr_intpose(xc_handle, cpu_nr, flags, msr, val);
   3.246 +}
   3.247 +
   3.248 +#define MCE_INVALID_MFN ~0UL
   3.249 +#define mfn_valid(_mfn) (_mfn != MCE_INVALID_MFN)
   3.250 +#define mfn_to_pfn(_mfn) (live_m2p[(_mfn)])
   3.251 +static uint64_t guest_mfn(xc_interface *xc_handle,
   3.252 +                               uint32_t domain,
   3.253 +                               uint64_t gpfn)
   3.254 +{
   3.255 +    xen_pfn_t *live_m2p = NULL;
   3.256 +    int ret;
   3.257 +    unsigned long hvirt_start;
   3.258 +    unsigned int pt_levels;
   3.259 +    uint64_t * pfn_buf = NULL;
   3.260 +    unsigned long max_mfn = 0; /* max mfn of the whole machine */
   3.261 +    unsigned long m2p_mfn0;
   3.262 +    unsigned int guest_width;
   3.263 +    long max_gpfn,i;
   3.264 +    uint64_t mfn = MCE_INVALID_MFN;
   3.265 +
   3.266 +    if ( domain > DOMID_FIRST_RESERVED )
   3.267 +        return MCE_INVALID_MFN;
   3.268 +
   3.269 +    /* Get max gpfn */
   3.270 +    max_gpfn = do_memory_op(xc_handle, XENMEM_maximum_gpfn, &domain, 
   3.271 +                               sizeof(domain)) + 1;
   3.272 +    if ( max_gpfn <= 0 )
   3.273 +        err(xc_handle, "Failed to get max_gpfn 0x%lx\n", max_gpfn);
   3.274 +
   3.275 +    Lprintf("Maxium gpfn for dom %d is 0x%lx\n", domain, max_gpfn);
   3.276 +
   3.277 +    /* Get max mfn */
   3.278 +    if ( !get_platform_info(xc_handle, domain,
   3.279 +                            &max_mfn, &hvirt_start,
   3.280 +                            &pt_levels, &guest_width) )
   3.281 +        err(xc_handle, "Failed to get platform information\n");
   3.282 +
   3.283 +    /* Get guest's pfn list */
   3.284 +    pfn_buf = malloc(sizeof(uint64_t) * max_gpfn);
   3.285 +    if ( !pfn_buf )
   3.286 +        err(xc_handle, "Failed to alloc pfn buf\n");
   3.287 +    memset(pfn_buf, 0, sizeof(uint64_t) * max_gpfn);
   3.288 +
   3.289 +    ret = xc_get_pfn_list(xc_handle, domain, pfn_buf, max_gpfn);
   3.290 +    if ( ret < 0 ) {
   3.291 +        free(pfn_buf);
   3.292 +        err(xc_handle, "Failed to get pfn list %x\n", ret);
   3.293 +    }
   3.294 +
   3.295 +    /* Now get the m2p table */
   3.296 +    live_m2p = xc_map_m2p(xc_handle, max_mfn, PROT_READ, &m2p_mfn0);
   3.297 +    if ( !live_m2p )
   3.298 +        err(xc_handle, "Failed to map live M2P table\n");
   3.299 +
   3.300 +    /* match the mapping */
   3.301 +    for ( i = 0; i < max_gpfn; i++ )
   3.302 +    {
   3.303 +        uint64_t tmp;
   3.304 +        tmp = pfn_buf[i];
   3.305 +
   3.306 +        if (mfn_valid(tmp) &&  (mfn_to_pfn(tmp) == gpfn))
   3.307 +        {
   3.308 +            mfn = tmp;
   3.309 +            Lprintf("We get the mfn 0x%lx for this injection\n", mfn);
   3.310 +            break;
   3.311 +        }
   3.312 +    }
   3.313 +
   3.314 +    munmap(live_m2p, M2P_SIZE(max_mfn));
   3.315 +
   3.316 +    free(pfn_buf);
   3.317 +    return mfn;
   3.318 +}
   3.319 +
   3.320 +static uint64_t mca_gpfn_to_mfn(xc_interface *xc_handle,
   3.321 +                                uint32_t domain,
   3.322 +                                uint64_t gfn)
   3.323 +{
   3.324 +    uint64_t index;
   3.325 +    long max_gpfn;
   3.326 +
   3.327 +    /* If domain is xen, means we want pass index directly */
   3.328 +    if ( domain == DOMID_XEN )
   3.329 +        return gfn;
   3.330 +
   3.331 +    max_gpfn = do_memory_op(xc_handle, XENMEM_maximum_gpfn, &domain, 
   3.332 +                               sizeof(domain)) + 1;
   3.333 +    if ( max_gpfn <= 0 )
   3.334 +        err(xc_handle, "Failed to get max_gpfn 0x%lx\n", max_gpfn);
   3.335 +    index = gfn % max_gpfn;
   3.336 +
   3.337 +    return guest_mfn(xc_handle, domain, index);
   3.338 +}
   3.339 +
   3.340 +static int inject_mcg_status(xc_interface *xc_handle,
   3.341 +                             uint32_t cpu_nr,
   3.342 +                             uint64_t val)
   3.343 +{
   3.344 +    return add_msr_intpose(xc_handle, cpu_nr, MC_MSRINJ_F_INTERPOSE,
   3.345 +                               MSR_IA32_MCG_STATUS, val);
   3.346 +}
   3.347 +
   3.348 +static int inject_mci_status(xc_interface *xc_handle,
   3.349 +                             uint32_t cpu_nr,
   3.350 +                             uint64_t bank,
   3.351 +                             uint64_t val)
   3.352 +{
   3.353 +    return add_msr_bank_intpose(xc_handle, cpu_nr, MC_MSRINJ_F_INTERPOSE,
   3.354 +                                    MCi_type_STATUS, bank, val); 
   3.355 +}
   3.356 +
   3.357 +static int inject_mci_misc(xc_interface *xc_handle,
   3.358 +                             uint32_t cpu_nr,
   3.359 +                             uint64_t bank,
   3.360 +                             uint64_t val)
   3.361 +{
   3.362 +    return add_msr_bank_intpose(xc_handle, cpu_nr, MC_MSRINJ_F_INTERPOSE,
   3.363 +                                    MCi_type_MISC, bank, val); 
   3.364 +}
   3.365 +
   3.366 +static int inject_mci_addr(xc_interface *xc_handle,
   3.367 +                             uint32_t cpu_nr,
   3.368 +                             uint64_t bank,
   3.369 +                             uint64_t val)
   3.370 +{
   3.371 +    return add_msr_bank_intpose(xc_handle, cpu_nr, MC_MSRINJ_F_INTERPOSE,
   3.372 +                                    MCi_type_ADDR, bank, val); 
   3.373 +}
   3.374 +
   3.375 +static int inject_llc_srao(xc_interface *xc_handle,
   3.376 +                             uint32_t cpu_nr,
   3.377 +                             uint32_t domain,
   3.378 +                             uint64_t gaddr)
   3.379 +{
   3.380 +    uint64_t gpfn, mfn, haddr;
   3.381 +    int ret = 0;
   3.382 +
   3.383 +    ret = inject_mcg_status(xc_handle, cpu_nr, MCG_STATUS_SRAO_LLC_VAL);
   3.384 +    if ( ret )
   3.385 +        err(xc_handle, "Failed to inject MCG_STATUS MSR\n");
   3.386 +
   3.387 +    ret = inject_mci_status(xc_handle, cpu_nr,
   3.388 +                            MCE_SRAO_LLC_BANK, MCi_STATUS_SRAO_LLC_VAL);
   3.389 +    if ( ret )
   3.390 +        err(xc_handle, "Failed to inject MCi_STATUS MSR\n");
   3.391 +
   3.392 +    ret = inject_mci_misc(xc_handle, cpu_nr,
   3.393 +                          MCE_SRAO_LLC_BANK, MCi_MISC_SRAO_LLC_VAL);
   3.394 +    if ( ret )
   3.395 +        err(xc_handle, "Failed to inject MCi_MISC MSR\n");
   3.396 +
   3.397 +    gpfn = gaddr >> PAGE_SHIFT;
   3.398 +    mfn = mca_gpfn_to_mfn(xc_handle, domain, gpfn);
   3.399 +    if (!mfn_valid(mfn))
   3.400 +        err(xc_handle, "The MFN is not valid\n");
   3.401 +    haddr = (mfn << PAGE_SHIFT) | (gaddr & (PAGE_SIZE - 1));
   3.402 +    ret = inject_mci_addr(xc_handle, cpu_nr, MCE_SRAO_LLC_BANK, haddr);
   3.403 +    if ( ret )
   3.404 +        err(xc_handle, "Failed to inject MCi_ADDR MSR\n");
   3.405 +
   3.406 +    ret = flush_msr_inj(xc_handle);
   3.407 +    if ( ret )
   3.408 +        err(xc_handle, "Failed to inject MSR\n");
   3.409 +    ret = inject_mce(xc_handle, cpu_nr);
   3.410 +    if ( ret )
   3.411 +        err(xc_handle, "Failed to inject MCE error\n");
   3.412 +
   3.413 +    return 0;
   3.414 +}
   3.415 +
   3.416 +static int inject_mem_srao(xc_interface *xc_handle,
   3.417 +                             uint32_t cpu_nr,
   3.418 +                             uint32_t domain,
   3.419 +                             uint64_t gaddr)
   3.420 +{
   3.421 +    uint64_t gpfn, mfn, haddr;
   3.422 +    int ret = 0;
   3.423 +
   3.424 +    ret = inject_mcg_status(xc_handle, cpu_nr, MCG_STATUS_SRAO_MEM_VAL);
   3.425 +    if ( ret )
   3.426 +        err(xc_handle, "Failed to inject MCG_STATUS MSR\n");
   3.427 +
   3.428 +    ret = inject_mci_status(xc_handle, cpu_nr,
   3.429 +                            MCE_SRAO_MEM_BANK, MCi_STATUS_SRAO_MEM_VAL);
   3.430 +    if ( ret )
   3.431 +        err(xc_handle, "Failed to inject MCi_STATUS MSR\n");
   3.432 +
   3.433 +    ret = inject_mci_misc(xc_handle, cpu_nr,
   3.434 +                          MCE_SRAO_MEM_BANK, MCi_MISC_SRAO_MEM_VAL);
   3.435 +    if ( ret )
   3.436 +        err(xc_handle, "Failed to inject MCi_MISC MSR\n");
   3.437 +
   3.438 +    gpfn = gaddr >> PAGE_SHIFT;
   3.439 +    mfn = mca_gpfn_to_mfn(xc_handle, domain, gpfn);
   3.440 +    if (!mfn_valid(mfn))
   3.441 +        err(xc_handle, "The MFN is not valid\n");
   3.442 +    haddr = (mfn << PAGE_SHIFT) | (gaddr & (PAGE_SIZE - 1));
   3.443 +    ret = inject_mci_addr(xc_handle, cpu_nr, MCE_SRAO_MEM_BANK, haddr);
   3.444 +    if ( ret )
   3.445 +        err(xc_handle, "Failed to inject MCi_ADDR MSR\n");
   3.446 +
   3.447 +    ret = flush_msr_inj(xc_handle);
   3.448 +    if ( ret )
   3.449 +        err(xc_handle, "Failed to inject MSR\n");
   3.450 +    ret = inject_mce(xc_handle, cpu_nr);
   3.451 +    if ( ret )
   3.452 +        err(xc_handle, "Failed to inject MCE error\n");
   3.453 +
   3.454 +    return 0;
   3.455 +}
   3.456 +
   3.457 +static int inject_llc_ucna(xc_interface *xc_handle,
   3.458 +                             uint32_t cpu_nr,
   3.459 +                             uint32_t domain,
   3.460 +                             uint64_t gaddr)
   3.461 +{
   3.462 +    uint64_t gpfn, mfn, haddr;
   3.463 +    int ret = 0;
   3.464 +
   3.465 +    ret = inject_mcg_status(xc_handle, cpu_nr, MCG_STATUS_UCNA_LLC_VAL);
   3.466 +    if ( ret )
   3.467 +        err(xc_handle, "Failed to inject MCG_STATUS MSR\n");
   3.468 +
   3.469 +    ret = inject_mci_status(xc_handle, cpu_nr,
   3.470 +                            CMCI_UCNA_LLC_BANK, MCi_STATUS_UCNA_LLC_VAL);
   3.471 +    if ( ret )
   3.472 +        err(xc_handle, "Failed to inject MCi_STATUS MSR\n");
   3.473 +
   3.474 +    ret = inject_mci_misc(xc_handle, cpu_nr,
   3.475 +                          CMCI_UCNA_LLC_BANK, MCi_MISC_UCNA_LLC_VAL);
   3.476 +    if ( ret )
   3.477 +        err(xc_handle, "Failed to inject MCi_MISC MSR\n");
   3.478 +
   3.479 +    gpfn = gaddr >> PAGE_SHIFT;
   3.480 +    mfn = mca_gpfn_to_mfn(xc_handle, domain, gpfn);
   3.481 +    if (!mfn_valid(mfn))
   3.482 +        err(xc_handle, "The MFN is not valid\n");
   3.483 +    haddr = (mfn << PAGE_SHIFT) | (gaddr & (PAGE_SIZE - 1));
   3.484 +    ret = inject_mci_addr(xc_handle, cpu_nr, CMCI_UCNA_LLC_BANK, haddr);
   3.485 +    if ( ret )
   3.486 +        err(xc_handle, "Failed to inject MCi_ADDR MSR\n");
   3.487 +
   3.488 +    ret = flush_msr_inj(xc_handle);
   3.489 +    if ( ret )
   3.490 +        err(xc_handle, "Failed to inject MSR\n");
   3.491 +    ret = inject_cmci(xc_handle, cpu_nr);
   3.492 +    if ( ret )
   3.493 +        err(xc_handle, "Failed to inject MCE error\n");
   3.494 +
   3.495 +    return 0;
   3.496 +}
   3.497 +
   3.498 +static long xs_get_dom_mem(int domid)
   3.499 +{
   3.500 +    char path[128];
   3.501 +    char *memstr;
   3.502 +    uint64_t mem;
   3.503 +    unsigned int plen;
   3.504 +    struct xs_handle *xs;
   3.505 +
   3.506 +    xs = xs_daemon_open();
   3.507 +    if (!xs)
   3.508 +        return -1;
   3.509 +
   3.510 +    sprintf(path, "/local/domain/%d/memory/target", domid);
   3.511 +    memstr = xs_read(xs, XBT_NULL, path, &plen);
   3.512 +    xs_daemon_close(xs);
   3.513 +
   3.514 +    if (!memstr || !plen)
   3.515 +        return -1;
   3.516 +
   3.517 +    mem = atoll(memstr)*1024;
   3.518 +    free(memstr);
   3.519 +
   3.520 +    return mem;
   3.521 +}
   3.522 +
   3.523 +static struct option opts[] = {
   3.524 +    {"cpu", 0, 0, 'c'},
   3.525 +    {"domain", 0, 0, 'd'},
   3.526 +    {"dump", 0, 0, 'D'},
   3.527 +    {"help", 0, 0, 'h'},
   3.528 +    {"log", 0, 0, 'l'},
   3.529 +    {"page", 0, 0, 'p'},
   3.530 +    {"", 0, 0, '\0'}
   3.531 +};
   3.532 +
   3.533 +static void help(void)
   3.534 +{
   3.535 +    printf("Usage: xen-mceinj [OPTION]...\n"
   3.536 +           "\n"
   3.537 +           "Mandatory arguments to long options are mandatory"
   3.538 +           "for short options too.\n"
   3.539 +           "  -D, --dump           dump addr info without error injection\n"
   3.540 +           "  -c, --cpu=CPU_ID     target CPU\n"
   3.541 +           "  -d, --domain=DomID   target domain, the default is Xen itself\n"
   3.542 +           "  -h, --help           print this page\n"
   3.543 +           "  -p, --phyaddr        physical address\n"
   3.544 +           "  -t, --type=error     error type\n"
   3.545 +           "                        0 : MCE_SRAO_MEM\n"
   3.546 +           "                        1 : MCE_SRAO_LLC\n"
   3.547 +           "                        2 : CMCI_UCNA_LLC\n"
   3.548 +           "\n"
   3.549 +           );
   3.550 +}
   3.551 +
   3.552 +int main(int argc, char *argv[])
   3.553 +{
   3.554 +    int type = MCE_SRAO_MEM;
   3.555 +    int c, opt_index;
   3.556 +    uint32_t domid;
   3.557 +    xc_interface *xc_handle;
   3.558 +    int cpu_nr;
   3.559 +    int64_t gaddr, gpfn, mfn, haddr, max_gpa;
   3.560 +
   3.561 +    /* Default Value */
   3.562 +    domid = DOMID_XEN;
   3.563 +    gaddr = 0x180020;
   3.564 +    cpu_nr = 0;
   3.565 +
   3.566 +    init_msr_inj();
   3.567 +    xc_handle = xc_interface_open(0, 0, 0);
   3.568 +    if ( !xc_handle ) {
   3.569 +        Lprintf("Failed to get xc interface\n");
   3.570 +        exit(EXIT_FAILURE);
   3.571 +    }
   3.572 +
   3.573 +    while ( 1 ) {
   3.574 +        c = getopt_long(argc, argv, "c:Dd:t:hp:r", opts, &opt_index);
   3.575 +        if ( c == -1 )
   3.576 +            break;
   3.577 +        switch ( c ) {
   3.578 +        case 'D':
   3.579 +            dump=1;
   3.580 +            break;
   3.581 +        case 'c':
   3.582 +            cpu_nr = strtol(optarg, &optarg, 10);
   3.583 +            if ( strlen(optarg) != 0 )
   3.584 +                err(xc_handle, "Please input a digit parameter for CPU\n");
   3.585 +            break;
   3.586 +        case 'd':
   3.587 +            domid = strtol(optarg, &optarg, 10);
   3.588 +            if ( strlen(optarg) != 0 )
   3.589 +                err(xc_handle, "Please input a digit parameter for domain\n");
   3.590 +            break;
   3.591 +        case 'p':
   3.592 +            gaddr = strtol(optarg, &optarg, 0);
   3.593 +            if ( strlen(optarg) != 0 )
   3.594 +                err(xc_handle, "Please input correct page address\n");
   3.595 +            break;
   3.596 +        case 't':
   3.597 +            type = strtol(optarg, NULL, 0);
   3.598 +            break;
   3.599 +        case 'h':
   3.600 +        default:
   3.601 +            help();
   3.602 +            return 0;
   3.603 +        }
   3.604 +    }
   3.605 +    
   3.606 +    if ( domid != DOMID_XEN ) {
   3.607 +        max_gpa = xs_get_dom_mem(domid);
   3.608 +        Lprintf("get domain %d max gpa is: 0x%lx \n", domid, max_gpa);
   3.609 +        if ( gaddr >= max_gpa )
   3.610 +            err(xc_handle, "Fail: gaddr exceeds max_gpa 0x%lx\n", max_gpa);
   3.611 +    }
   3.612 +    Lprintf("get gaddr of error inject is: 0x%lx \n", gaddr);
   3.613 +
   3.614 +    if ( dump ) {
   3.615 +        gpfn = gaddr >> PAGE_SHIFT;
   3.616 +        mfn = mca_gpfn_to_mfn(xc_handle, domid, gpfn);
   3.617 +        if (!mfn_valid(mfn))
   3.618 +            err(xc_handle, "The MFN is not valid\n");
   3.619 +        haddr = (mfn << PAGE_SHIFT) | (gaddr & (PAGE_SIZE - 1));
   3.620 +        if ( domid == DOMID_XEN )
   3.621 +            Lprintf("Xen: mfn=0x%lx, haddr=0x%lx\n", mfn, haddr);
   3.622 +        else 
   3.623 +            Lprintf("Dom%d: gaddr=0x%lx, gpfn=0x%lx,"
   3.624 +                    "mfn=0x%lx, haddr=0x%lx\n",
   3.625 +                    domid, gaddr, gpfn, mfn, haddr);
   3.626 +        goto out;
   3.627 +    }
   3.628 +
   3.629 +    switch ( type )
   3.630 +    {
   3.631 +    case MCE_SRAO_MEM:
   3.632 +        inject_mem_srao(xc_handle, cpu_nr, domid, gaddr);
   3.633 +        break;
   3.634 +    case MCE_SRAO_LLC:
   3.635 +        inject_llc_srao(xc_handle, cpu_nr, domid, gaddr);
   3.636 +        break;
   3.637 +    case CMCI_UCNA_LLC:
   3.638 +        inject_llc_ucna(xc_handle, cpu_nr, domid, gaddr);
   3.639 +        break;
   3.640 +    default:
   3.641 +        err(xc_handle, "Unsupported error type\n");
   3.642 +        break;
   3.643 +    }
   3.644 +
   3.645 +out:
   3.646 +    xc_interface_close(xc_handle);
   3.647 +    return 0;
   3.648 +}