aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWen Jin <wenx.jin@intel.com>2015-12-24 11:05:22 +0800
committerAndi Kleen <ak@linux.intel.com>2015-12-25 19:39:09 -0800
commitac82804edef3137aa153838c038d35f7e80f50f9 (patch)
tree6a5df68d7037b2d77508adaf3457f05a6ce99aae
parentfe0b3b24605543ea81b37446cf3abb93f6dc5906 (diff)
downloadmce-test-ac82804edef3137aa153838c038d35f7e80f50f9.tar.gz
Unify test case for error injection
We have two similiar to-be-injected "victim" programs but it is a little bit redundant. Merge them into one. BTW, add a new function to enable to choose if injecting a error by hand. Minor fix by Gong. Signed-off-by: Wen Jin <wenx.jin@intel.com> Signed-off-by: Chen, Gong <gong.chen@linux.intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com>
-rw-r--r--cases/function/Makefile3
-rw-r--r--cases/function/core_recovery/Makefile11
-rw-r--r--cases/function/core_recovery/core_recovery.c182
-rwxr-xr-xcases/function/core_recovery/srar_recovery.sh8
-rw-r--r--tools/victim/victim.c361
5 files changed, 212 insertions, 353 deletions
diff --git a/cases/function/Makefile b/cases/function/Makefile
index a94da1a..6d66c0c 100644
--- a/cases/function/Makefile
+++ b/cases/function/Makefile
@@ -2,20 +2,17 @@ all:
$(MAKE) -C erst-inject
$(MAKE) -C pfa
$(MAKE) -C hwpoison
- $(MAKE) -C core_recovery
# $(MAKE) -C kvm
clean:
$(MAKE) -C erst-inject clean
$(MAKE) -C pfa clean
$(MAKE) -C hwpoison clean
- $(MAKE) -C core_recovery clean
# $(MAKE) -C kvm clean
install:
$(MAKE) -C erst-inject install
$(MAKE) -C pfa install
$(MAKE) -C hwpoison install
- $(MAKE) -C core_recovery install
# $(MAKE) -C kvm install
diff --git a/cases/function/core_recovery/Makefile b/cases/function/core_recovery/Makefile
deleted file mode 100644
index c18edf1..0000000
--- a/cases/function/core_recovery/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# pread needs:
-# _XOPEN_SOURCE >= 500 || /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
-# but this hides MAP_ANONYMOUS which comes back via _BSD_SOURCE
-CFLAGS := -Wall -D _BSD_SOURCE -D _XOPEN_SOURCE=500
-
-core_recovery: core_recovery.o
-
-install: core_recovery
-
-clean:
- rm -f core_recovery *.o
diff --git a/cases/function/core_recovery/core_recovery.c b/cases/function/core_recovery/core_recovery.c
deleted file mode 100644
index 835c243..0000000
--- a/cases/function/core_recovery/core_recovery.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Set up to get zapped by a machine check (injected elsewhere)
- * To use this test case please ensure your SUT(System Under Test)
- * can support MCE/SRAR.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should find a copy of v2 of the GNU General Public License somewhere on
- * your Linux system; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) 2012 Intel corporation
- *
- * Author:
- * Tony Luck <tony.luck@intel.com>
- * Gong Chen <gong.chen@intel.com>
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <sys/mman.h>
-
-/*
- * Definition of /proc/pid/pagemap
- * Bits 0-54 page frame number (PFN) if present
- * Bits 0-4 swap type if swapped
- * Bits 5-54 swap offset if swapped
- * Bits 55-60 page shift (page size = 1<<page shift)
- * Bit 61 reserved for future use
- * Bit 62 page swapped
- * Bit 63 page present
- */
-
-struct pagemaps {
- unsigned long long pfn:55;
- unsigned long long pgshift:6;
- unsigned long long rsvd:1;
- unsigned long long swapped:1;
- unsigned long long present:1;
-};
-
-static int pagesize;
-
-/*
- * dummyfunc size should be less than one page after complied,
- * otherwise, caller will not return from this function
- */
-void dummyfunc(void)
-{
- int fatarray[64];
-
- fatarray[0] = 0xdeadbeaf;
- fatarray[8] = 0xdeadbeaf;
- fatarray[16] = 0xdeadbeaf;
- fatarray[32] = 0xdeadbeaf;
-}
-
-/*
- * get information about address from /proc/{pid}/pagemap
- */
-unsigned long long vtop(unsigned long long addr)
-{
- struct pagemaps pinfo;
- unsigned int pinfo_size = sizeof pinfo;
- long offset = addr / pagesize * pinfo_size;
- int fd, pgmask;
- char pagemapname[64];
-
- sprintf(pagemapname, "/proc/%d/pagemap", getpid());
- fd = open(pagemapname, O_RDONLY);
- if (fd == -1) {
- perror(pagemapname);
- return 0;
- }
- if (pread(fd, (void*)&pinfo, pinfo_size, offset) != pinfo_size) {
- perror(pagemapname);
- close(fd);
- return 0;
- }
- close(fd);
- pgmask = (1 << pinfo.pgshift) - 1;
- return (pinfo.pfn << pinfo.pgshift) | (addr & pgmask);
-}
-
-static void usage(void)
-{
- printf(
-"core_recovery [options]\n"
-" -d|--data Inject data error(DCU error) under user context\n"
-" -i|--instruction Inject instruction error(IFU error) under user context\n"
-" -h|--help Show this usage message\n"
- );
-}
-
-static const struct option opts[] = {
- { "data" , 0, NULL, 'd' },
- { "instruction" , 0, NULL, 'i' },
- { "help" , 0, NULL, 'h' },
- { NULL , 0, NULL, 0 }
-};
-
-int main(int argc, char **argv)
-{
- unsigned long long phys;
- long total;
- char *buf, answer[16];
- int c, i;
- int iflag = 0, dflag = 0;
- time_t now;
-
- if (argc <= 1) {
- usage();
- return 0;
- }
-
- pagesize = getpagesize();
-
- while ((c = getopt_long(argc, argv, "dih", opts, NULL)) != -1) {
- switch (c) {
- case 'd':
- dflag = 1;
- break;
- case 'i':
- iflag = 1;
- break;
- case 'h':
- default:
- usage();
- return 0;
- }
- }
-
- buf = mmap(NULL, pagesize, PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_ANONYMOUS|MAP_PRIVATE|MAP_LOCKED, -1, 0);
-
- if (buf == MAP_FAILED) {
- fprintf(stderr, "Can't get a single page of memory!\n");
- return 1;
- }
- memset(buf, '*', pagesize);
- phys = vtop((unsigned long long)buf);
- if (phys == 0) {
- fprintf(stderr, "Can't get physical address of the page!\n");
- return 1;
- }
-
- if (iflag)
- memcpy(buf, (void*)dummyfunc, pagesize);
-
- printf("physical address of (0x%llx) = 0x%llx\n"
- "Hit any key to trigger error: ", (unsigned long long)buf, phys);
- fflush(stdout);
- read(0, answer, 16);
- now = time(NULL);
- printf("Access time at %s\n", ctime(&now));
-
- if (iflag) {
- void (*f)(void) = (void (*)(void))buf;
-
- while (1) f() ;
- }
-
- if (dflag) {
- while (1) {
- for (i = 0; i < pagesize; i += sizeof(int))
- total += *(int*)(buf + i);
- }
- }
-
- return 0;
-}
diff --git a/cases/function/core_recovery/srar_recovery.sh b/cases/function/core_recovery/srar_recovery.sh
index 7b13b5b..ae64af9 100755
--- a/cases/function/core_recovery/srar_recovery.sh
+++ b/cases/function/core_recovery/srar_recovery.sh
@@ -3,6 +3,8 @@
#set -x
export ROOT=`(cd ../../../; pwd)`
+. $ROOT/lib/functions.sh
+setup_path
. $ROOT/lib/mce.sh
inject_type=0x00000010
@@ -65,15 +67,17 @@ else
fi
rmmod $EDAC_TYPE >/dev/null 2>&1
+[ -e $ROOT/bin/victim ] || invalid "file victim doesn't exist!" \
+"maybe you forget to execute make install under directory $ROOT before test"
touch trigger
-tail -f trigger | ./core_recovery $1 > log &
+tail -f trigger | victim $1 > log &
addr=`cat log |cut -d' ' -f6|head -1`
apei_inj $addr
sleep 1
echo go > trigger
sleep 2
rm -f trigger log
-id=`pgrep core_recovery`
+id=`pgrep victim`
if [ X"$id" != X ]; then
echo $id | xargs kill -9 > /dev/null 2>&1
invalid "The poisoned process can't be killed by kernel automatically. Test fails!"
diff --git a/tools/victim/victim.c b/tools/victim/victim.c
index a381909..a0435e5 100644
--- a/tools/victim/victim.c
+++ b/tools/victim/victim.c
@@ -1,49 +1,31 @@
/*
- * Victim
+ * Set up to get zapped by a machine check (injected elsewhere)
+ * To use this test case please ensure your SUT(System Under Test)
+ * can support MCE/SRAR.
*
- * Victim workes under user context, which provides target memory chunk for
- * error injection. It can be used for all kinds of error types, including
- * Corrected error and Uncorrected error(IFU/DCU).
+ * This file is released under the GPLv2.
*
- * Here is an simple example for DCU:
- * Mmap one page memory and returns starting address, and then translate
- * virtual address to physical address. Caller like shell script can
- * inject UC error (error type 0x10 in EINJ table) on returned physical
- * address. Meanwhile, victim continues to read/write on returned memory
- * space to trigger DCU happening ASAP.
- *
- * Copyright (C) 2015, Intel Corp.
+ * Copyright (C) 2012-2015 Intel corporation
*
* Author:
- * Zhilong Liu <zhilongx.liu@intel.com>
- *
- * Date:
- * 01/15 2015
- *
- * History: Revision history
- * None
+ * Tony Luck <tony.luck@intel.com>
+ * Gong Chen <gong.chen@intel.com>
+ * Wen Jin <wenx.jin@intel.com>
*/
+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <getopt.h>
-#include <string.h>
-#include <time.h>
-
-/*
- * Use below macros to make this a non-trivial sized function.
- */
-#define PLUS10 (ifunc_ret++, ifunc_ret++, ifunc_ret++, ifunc_ret++, \
- ifunc_ret++, ifunc_ret++, ifunc_ret++, ifunc_ret++, \
- ifunc_ret++, ifunc_ret++)
-#define PLUS100 (PLUS10, PLUS10, PLUS10, PLUS10, PLUS10, PLUS10, \
- PLUS10, PLUS10, PLUS10, PLUS10)
-#define PLUS1000 (PLUS100, PLUS100, PLUS100, PLUS100, PLUS100, \
- PLUS100, PLUS100, PLUS100, PLUS100, PLUS100)
-
-static int pagesize;
+#include <errno.h>
/*
* Definition of /proc/pid/pagemap
@@ -55,6 +37,7 @@ static int pagesize;
* Bit 62 page swapped
* Bit 63 page present
*/
+
struct pagemaps {
unsigned long long pfn:55;
unsigned long long pgshift:6;
@@ -63,33 +46,34 @@ struct pagemaps {
unsigned long long present:1;
};
-/* Don't let compiler optimize away access to this */
-volatile int ifunc_ret;
+static int pagesize;
-int ifunc(void)
+/*
+ * dummyfunc size should be less than one page after complied,
+ * otherwise, caller will not return from this function
+ */
+void dummyfunc(void)
{
- ifunc_ret = 0;
-
- PLUS1000;
+ int fatarray[64];
- return ifunc_ret;
+ fatarray[0] = 0xdeadbeaf;
+ fatarray[8] = 0xdeadbeaf;
+ fatarray[16] = 0xdeadbeaf;
+ fatarray[32] = 0xdeadbeaf;
}
/*
* get information about address from /proc/{pid}/pagemap
*/
-unsigned long long vtop(unsigned long long addr)
+unsigned long long vtop(unsigned long long addr, pid_t pid)
{
struct pagemaps pinfo;
unsigned int pinfo_size = sizeof(pinfo);
- long offset;
+ unsigned long long offset = addr / pagesize * pinfo_size;
int fd, pgmask;
char pagemapname[64];
- if (!pagesize)
- pagesize = getpagesize();
- offset = addr / pagesize * pinfo_size;
- sprintf(pagemapname, "/proc/%d/pagemap", getpid());
+ sprintf(pagemapname, "/proc/%d/pagemap", pid);
fd = open(pagemapname, O_RDONLY);
if (fd == -1) {
perror(pagemapname);
@@ -101,113 +85,62 @@ unsigned long long vtop(unsigned long long addr)
return 0;
}
close(fd);
- if (!pinfo.present)
- return ~0ull;
- pgmask = (1 << pinfo.pgshift) - 1;
- return (pinfo.pfn << pinfo.pgshift) | (addr & pgmask);
+ pgmask = pagesize - 1;
+ return (pinfo.pfn * pagesize) | (addr & pgmask);
}
static void usage(void)
{
printf(
"victim [options]\n"
-" -d|--data Inject data error(DCU error) under user context\n"
-" -i|--instruction Inject instruction error(IFU error) under user context\n"
-" -p|--pfa Inject memory CE consecutivelly under user context to trigger pfa\n"
-" -h|--help Show this usage message\n"
+" -a|--address vaddr=val, pid=val Translate process virtual address into physical address\n"
+" -d|--data Inject data error(DCU error) under user context\n"
+" -i|--instruction Inject instruction error(IFU error) under user context\n"
+" -k|--kick 0/1 Kick off trigger. Auto(0), Manual(1, by default)\n"
+" -h|--help Show this usage message\n"
);
}
static const struct option opts[] = {
- { "data", 0, NULL, 'd' },
- { "instruction", 0, NULL, 'i' },
- { "pfa", 0, NULL, 'p' },
- { "help", 0, NULL, 'h' },
- { NULL, 0, NULL, 0 }
+ { "address" , 1, NULL, 'a' },
+ { "data" , 0, NULL, 'd' },
+ { "instruction" , 0, NULL, 'i' },
+ { "help" , 0, NULL, 'h' },
+ { "kick" , 1, NULL, 'k' },
+ { NULL , 0, NULL, 0 }
};
-void trigger_ifu(void)
-{
- time_t now;
- char answer[16];
- unsigned long long phys;
- void (*f)(void) = (void (*)(void))ifunc;
-
- phys = vtop((unsigned long long)f);
- printf("physical address of (%p) = 0x%llx\n"
- "Hit any key to trigger error: ", f, phys);
- fflush(stdout);
- read(0, answer, 16);
- now = time(NULL);
- printf("Access time at %s\n", ctime(&now));
- while (1)
- f();
-}
-
-void trigger_dcu(unsigned long long virt, unsigned long long phys)
+int main(int argc, char **argv)
{
- int i;
+ unsigned long long virt, phys;
long total;
- time_t now;
+ char *buf;
+ int c, i;
+ int iflag = 0, dflag = 0;
+ int kick = 1;
+ pid_t pid;
+ enum {
+ I_VADDR = 0,
+ I_PID
+ };
+ char *const token[] = {
+ [I_VADDR] = "vaddr",
+ [I_PID] = "pid",
+ NULL
+ };
+ char *subopts;
+ char *subval;
+ char *svaddr;
+ char *spid;
+ int err;
+ int index;
+ const char *trigger = "./trigger_start";
+ const char *trigger_flag = "trigger";
+ int fd;
+ int count = 100;
+ char trigger_buf[16];
char answer[16];
-
- printf("physical address of (0x%llx) = 0x%llx\n"
- "Hit any key to trigger error: ", virt, phys);
- fflush(stdout);
- read(0, answer, 16);
- now = time(NULL);
- printf("Access time at %s\n", ctime(&now));
- while (1) {
- for (i = 0; i < pagesize; i += sizeof(int))
- total += *(int *)(virt + i);
- }
-}
-
-/*
- * test PFA when inject CE(0x8) consecutivelly
- */
-void trigger_pfa(unsigned long long virt, unsigned long long phys)
-{
- int i;
- long total;
- unsigned long long newphys;
-
- printf("physical address of (0x%llx) = 0x%llx\n", virt, phys);
- fflush(stdout);
- while (1) {
- for (i = 0; i < pagesize; i += sizeof(int)) {
- total += *(int *)(virt + i);
- *(int *)(virt + i) = total;
- }
-
- newphys = vtop(virt);
- if (phys == newphys) {
- for (i = 0; i < pagesize; i += sizeof(int)) {
- total += *(int *)(virt + i);
- *(int *)(virt + i) = i;
- }
- sleep(2);
- newphys = vtop(virt);
- if (phys != newphys) {
- printf("Page was replaced. New phys addr = 0x%llx\n",
- newphys);
- fflush(stdout);
- phys = newphys;
- }
- } else {
- printf("Page was replaced. New phys addr = 0x%llx\n",
- newphys);
- fflush(stdout);
- phys = newphys;
- }
- }
-}
-
-int main(int argc, char **argv)
-{
- int c;
- char *p;
- unsigned long long phys;
+ time_t now;
if (argc <= 1) {
usage();
@@ -215,27 +148,81 @@ int main(int argc, char **argv)
}
pagesize = getpagesize();
- /* only RD/WR permission needed */
- p = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- if (p == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
- /* make sure that kernel does allocate page */
- memset(p, '*', pagesize);
- phys = vtop((unsigned long long)p);
- while ((c = getopt_long(argc, argv, "diph", opts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "a:dihk:", opts, NULL)) != -1) {
switch (c) {
+ case 'a':
+ err = 0;
+ subopts = optarg;
+ while (*subopts != '\0' && !err) {
+ index = getsubopt(&subopts, token, &subval);
+ switch (index) {
+ case I_VADDR:
+ if (subval != NULL) {
+ svaddr = subval;
+ break;
+ } else {
+ fprintf(stderr,
+ "miss value for %s\n",
+ token[I_VADDR]);
+ err++;
+ continue;
+ }
+ case I_PID:
+ if (subval != NULL) {
+ spid = subval;
+ break;
+ } else {
+ fprintf(stderr,
+ "miss value for %s\n",
+ token[I_PID]);
+ err++;
+ continue;
+ }
+ default:
+ err++;
+ break;
+ }
+ }
+ if (err > 0) {
+ usage();
+ return 0;
+ }
+ errno = 0;
+ virt = strtoull(svaddr, NULL, 0);
+ if ((virt == 0 && svaddr[0] != '0') || errno != 0) {
+ fprintf(stderr, "Invalid virtual address: %s\n",
+ svaddr);
+ return 1;
+ }
+ errno = 0;
+ pid = strtoul(spid, NULL, 0);
+ if ((pid == 0 && spid[0] != '0') || errno != 0) {
+ fprintf(stderr, "Invalid process pid number: %s\n",
+ spid);
+ return 1;
+ }
+ phys = vtop(virt, pid);
+ printf("physical address of (%d,0x%llx) = 0x%llx\n",
+ pid, virt, phys);
+ return 0;
case 'd':
- trigger_dcu((unsigned long long)p, phys);
+ dflag = 1;
break;
case 'i':
- trigger_ifu();
+ iflag = 1;
break;
- case 'p':
- trigger_pfa((unsigned long long)p, phys);
+ case 'k':
+ errno = 0;
+ kick = strtol(optarg, NULL, 0);
+ if ((kick == 0 && optarg[0] != '0') || errno != 0) {
+ fprintf(stderr, "Invalid parameter: %s\n", optarg);
+ return 1;
+ }
+ if (kick != 0 && kick != 1) {
+ fprintf(stderr, "Invalid parameter: %s\n", optarg);
+ return 1;
+ }
break;
case 'h':
default:
@@ -244,5 +231,69 @@ int main(int argc, char **argv)
}
}
+ buf = mmap(NULL, pagesize, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANONYMOUS|MAP_PRIVATE|MAP_LOCKED, -1, 0);
+
+ if (buf == MAP_FAILED) {
+ fprintf(stderr, "Can't get a single page of memory!\n");
+ return 1;
+ }
+ memset(buf, '*', pagesize);
+ pid = getpid();
+ phys = vtop((unsigned long long)buf, pid);
+ if (phys == 0) {
+ fprintf(stderr, "Can't get physical address of the page!\n");
+ return 1;
+ }
+
+ if (iflag)
+ memcpy(buf, (void *)dummyfunc, pagesize);
+
+ printf("physical address of (0x%llx) = 0x%llx\n",
+ (unsigned long long)buf, phys);
+ fflush(stdout);
+ if (kick == 0) {
+ errno = 0;
+ if (unlink(trigger) < 0 && errno != ENOENT) {
+ fprintf(stderr, "fail to remove trigger file\n");
+ return 1;
+ }
+ memset(trigger_buf, 0, sizeof(trigger_buf));
+ while (count--) {
+ if ((fd = open(trigger, O_RDONLY)) < 0) {
+ sleep(1);
+ continue;
+ }
+ if (read(fd, trigger_buf, sizeof(trigger_buf)) > 0 &&
+ strstr(trigger_buf, trigger_flag) != NULL) {
+ break;
+ }
+ sleep(1);
+ }
+ if (count == 0) {
+ fprintf(stderr,
+ "Timeout to get trigger flag file\n");
+ return 1;
+ }
+ } else {
+ printf("Hit any key to trigger error: ");
+ fflush(stdout);
+ read(0, answer, 16);
+ now = time(NULL);
+ printf("Access time at %s\n", ctime(&now));
+ }
+ if (iflag) {
+ void (*f)(void) = (void (*)(void))buf;
+
+ while (1) f();
+ }
+
+ if (dflag) {
+ while (1) {
+ for (i = 0; i < pagesize; i += sizeof(int))
+ total += *(int *)(buf + i);
+ }
+ }
+
return 0;
}