aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWen Jin <wenx.jin@intel.com>2016-03-22 15:11:52 +0800
committerAndi Kleen <ak@linux.intel.com>2016-04-11 15:32:38 -0700
commit42399a06a50b3de82c453f527ba8807b7f86f036 (patch)
tree9c2213850f38bd0bbdd47594e80ad4ae38d10ab3
parentf058829ed8a17a2d8f51d435d3f32afcd2704699 (diff)
downloadmce-test-42399a06a50b3de82c453f527ba8807b7f86f036.tar.gz
Merge pfa.c into victim.c
1. Merge pfa.c into victim.c because some functions such as vtop is duplicated 2. run mcelog as daemon to get mcelog information background. 3. rewrite some codes in victim.c 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/pfa/Makefile5
-rw-r--r--cases/function/pfa/pfa.c118
-rwxr-xr-xcases/function/pfa/run_pfa.sh34
-rwxr-xr-xcases/function/pfa/runtest.sh3
-rw-r--r--tools/victim/victim.c184
5 files changed, 140 insertions, 204 deletions
diff --git a/cases/function/pfa/Makefile b/cases/function/pfa/Makefile
index 4bcbf48..1ac3831 100644
--- a/cases/function/pfa/Makefile
+++ b/cases/function/pfa/Makefile
@@ -3,11 +3,10 @@
# but this hides MAP_ANONYMOUS which comes back via _BSD_SOURCE
CFLAGS := -g -Wall -D _BSD_SOURCE -D _XOPEN_SOURCE=500
-all: pfa busy
-pfa: pfa.o
+all: busy
busy: busy.o
install: all
clean:
- rm -f *.o pfa busy
+ rm -f *.o busy
diff --git a/cases/function/pfa/pfa.c b/cases/function/pfa/pfa.c
deleted file mode 100644
index a6df354..0000000
--- a/cases/function/pfa/pfa.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.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;
-
-/*
- * 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;
- int fd, pgmask;
- char pagemapname[64];
-
- if (!pagesize)
- pagesize = getpagesize();
- offset = addr / pagesize * pinfo_size;
- 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);
- if (!pinfo.present)
- return ~0ull;
- pgmask = (1 << pinfo.pgshift) - 1;
- return (pinfo.pfn << pinfo.pgshift) | (addr & pgmask);
-}
-
-int main()
-{
- char *p;
- long total, i;
- unsigned long long phys, newphys;
-
- p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- if (p == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
- *p = '*'; /* make kernel allocate page */
- phys = vtop((unsigned long long)p);
-
- printf("allocated page: virtual = %p physical = 0x%llx\n", p, phys);
- fflush(stdout);
-
- for (;;) {
- for (i = 0; i < pagesize; i += sizeof(int)) {
- total += *(int*)(p + i);
- *(int*)(p + i) = total;
- }
-
- newphys = vtop((unsigned long long)p);
- if (phys == newphys) {
- for (i = 0; i < pagesize; i += sizeof(int)) {
- total += *(int*)(p + i);
- *(int*)(p + i) = i;
- }
- sleep(2);
- newphys = vtop((unsigned long long)p);
- if (phys != newphys) {
- printf("Page was replaced. New physical address = 0x%llx\n", newphys);
- fflush(stdout);
- phys = newphys;
- }
- } else {
- printf("Page was replaced. New physical address = 0x%llx\n", newphys);
- fflush(stdout);
- phys = newphys;
- }
- }
-}
diff --git a/cases/function/pfa/run_pfa.sh b/cases/function/pfa/run_pfa.sh
index d9bd11b..e1e9347 100755
--- a/cases/function/pfa/run_pfa.sh
+++ b/cases/function/pfa/run_pfa.sh
@@ -1,6 +1,10 @@
#!/bin/bash
-. ../../../lib/mce.sh
+export ROOT=`(cd ../../../; pwd)`
+
+. $ROOT/lib/functions.sh
+setup_path
+. $ROOT/lib/mce.sh
INJ_TYPE=0x00000008
APEI_IF=""
@@ -33,13 +37,6 @@ usage()
main()
{
- if [ X"$1" = X -o X"$2" = X ]
- then
- usage
- exit 0
- fi
-
- PFA_BIN=$1
check_debugfs
APEI_IF=`cat /proc/mounts | grep debugfs | cut -d ' ' -f2 | head -1`/apei/einj
@@ -70,19 +67,25 @@ main()
fi
rmmod $EDAC_TYPE >/dev/null 2>&1
- killall $PFA_BIN > /dev/null 2>&1
- $PFA_BIN | tee log &
+ #mcelog must be run in daemon mode.
+ cat /dev/null > /var/log/mcelog
+ kill -9 `pidof mcelog` >/dev/null 2>&1
+ sleep 1
+ mcelog --ignorenodev --daemon
+
+ killall victim &> /dev/null
+ victim -p | tee log &
#wait to flush stdout into log
sleep 1
- addr=`cat log |cut -d' ' -f8|tail -1`
+ addr=`cat log | awk '{print $NF}' | tail -1`
last_addr=$addr
start=`date +%s`
while :
do
echo inject address = $addr
apei_inj $addr
- sleep $2
- addr=`cat log |cut -d' ' -f8|tail -1`
+ sleep 2
+ addr=`cat log | awk '{print $NF}' | tail -1`
end=`date +%s`
timeout=`expr $end - $start`
if [ X"$last_addr" != X"$addr" ]
@@ -97,9 +100,10 @@ main()
cleanup()
{
- rm -f trigger log
+ rm -f log
+ killall victim &> /dev/null
modprobe $EDAC_TYPE >/dev/null 2>&1
}
trap "cleanup" 0
-main "$@"
+main
diff --git a/cases/function/pfa/runtest.sh b/cases/function/pfa/runtest.sh
index 8213e58..9d9d8db 100755
--- a/cases/function/pfa/runtest.sh
+++ b/cases/function/pfa/runtest.sh
@@ -27,9 +27,8 @@ export TMP_DIR
echo 0 > $TMP_DIR/error.$$
pushd `dirname $0` > /dev/null
-./run_pfa.sh ./pfa 8
+./run_pfa.sh
[ $? -eq 0 ] || echo 1 > $TMP_DIR/error.$$
-killall ./pfa
popd > /dev/null
grep -q "1" $TMP_DIR/error.$$
diff --git a/tools/victim/victim.c b/tools/victim/victim.c
index ca70915..31f868a 100644
--- a/tools/victim/victim.c
+++ b/tools/victim/victim.c
@@ -32,7 +32,7 @@
* 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)
+ * Bits 55-60 page shift, the bits definition is legacy.
* Bit 61 reserved for future use
* Bit 62 page swapped
* Bit 63 page present
@@ -40,7 +40,7 @@
struct pagemaps {
unsigned long long pfn:55;
- unsigned long long pgshift:6;
+ unsigned long long pgshift:6; /*legacy*/
unsigned long long rsvd:1;
unsigned long long swapped:1;
unsigned long long present:1;
@@ -97,6 +97,7 @@ static void usage(void)
" -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"
+" -p|--pfa help to test memory PFA(Predictive Failure Analysis) function\n"
" -h|--help Show this usage message\n"
);
}
@@ -107,18 +108,48 @@ static const struct option opts[] = {
{ "instruction" , 0, NULL, 'i' },
{ "help" , 0, NULL, 'h' },
{ "kick" , 1, NULL, 'k' },
+ { "pfa" , 0, NULL, 'p' },
{ NULL , 0, NULL, 0 }
};
-int main(int argc, char **argv)
+static void pfa_helper(char *p, pid_t pid, unsigned long long old_phys)
{
- unsigned long long virt, phys;
- long total;
- char *buf;
- int c, i;
- int iflag = 0, dflag = 0;
- int kick = 1;
- pid_t pid;
+ int i;
+ int total;
+ unsigned long long new_phys;
+
+ for (;;) {
+ for (i = 0; i < pagesize; i += sizeof(int)) {
+ total += *(int*)(p + i);
+ *(int*)(p + i) = total;
+ }
+
+ new_phys = vtop((unsigned long long)p, pid);
+ if (old_phys == new_phys) {
+ for (i = 0; i < pagesize; i += sizeof(int)) {
+ total += *(int*)(p + i);
+ *(int*)(p + i) = i;
+ }
+ sleep(2);
+ new_phys = vtop((unsigned long long)p, pid);
+ if (old_phys != new_phys) {
+ printf("Page was replaced. New physical address = 0x%llx\n", new_phys);
+ fflush(stdout);
+ old_phys = new_phys;
+ }
+ } else {
+ printf("Page was replaced. New physical address = 0x%llx\n", new_phys);
+ fflush(stdout);
+ old_phys = new_phys;
+ }
+ }
+}
+
+static int parse_addr_subopts(char *subopts, unsigned long long *virt,
+ pid_t *pid)
+{
+ int err = 0;
+ int index;
enum {
I_VADDR = 0,
I_PID
@@ -128,12 +159,72 @@ int main(int argc, char **argv)
[I_PID] = "pid",
NULL
};
- char *subopts;
+ char *p = subopts;
char *subval;
char *svaddr;
char *spid;
- int err;
- int index;
+
+ while (*p != '\0' && !err) {
+ index = getsubopt(&p, 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 1;
+ }
+ 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;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned long long virt, phys;
+ long total;
+ char *buf;
+ int c, i;
+ int iflag = 0, dflag = 0;
+ int kick = 1;
+ int pfa = 0;
+ pid_t pid;
const char *trigger = "./trigger_start";
const char *trigger_flag = "trigger";
int fd;
@@ -149,63 +240,16 @@ int main(int argc, char **argv)
pagesize = getpagesize();
- while ((c = getopt_long(argc, argv, "a:dihk:", opts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "a:dihk:p", 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();
+ if (parse_addr_subopts(optarg, &virt, &pid) == 0) {
+ phys = vtop(virt, pid);
+ printf("physical address of (%d,0x%llx) = 0x%llx\n",
+ pid, virt, phys);
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;
+ return 1;
case 'd':
dflag = 1;
break;
@@ -224,6 +268,9 @@ int main(int argc, char **argv)
return 1;
}
break;
+ case 'p':
+ pfa = 1;
+ break;
case 'h':
default:
usage();
@@ -256,6 +303,10 @@ int main(int argc, char **argv)
printf("physical address of (0x%llx) = 0x%llx\n",
(unsigned long long)buf, phys);
fflush(stdout);
+
+ if (pfa == 1)
+ pfa_helper(buf, pid, phys);
+
if (kick == 0) {
errno = 0;
if (unlink(trigger) < 0 && errno != ENOENT) {
@@ -286,6 +337,7 @@ int main(int argc, char **argv)
now = time(NULL);
printf("Access time at %s\n", ctime(&now));
}
+
if (iflag) {
void (*f)(void) = (void (*)(void))buf;