Add SRAR DCU/IFU functional test case

This patch adds two SRAR functinal test cases (DCU & IFU). The
SRAR test is highly BIOS dependent so if BIOS is bogus, system
will be hang or panic. By default these two test cases are
disabled, if one wants to test SRAR, please open them.

Signed-off-by: Chen Gong <gong.chen@linux.intel.com>
diff --git a/cases/function/Makefile b/cases/function/Makefile
index 6d66c0c..a94da1a 100644
--- a/cases/function/Makefile
+++ b/cases/function/Makefile
@@ -2,17 +2,20 @@
 	$(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
new file mode 100644
index 0000000..1b59dd1
--- /dev/null
+++ b/cases/function/core_recovery/Makefile
@@ -0,0 +1,8 @@
+CFLAGS := -Wall
+
+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
new file mode 100644
index 0000000..835c243
--- /dev/null
+++ b/cases/function/core_recovery/core_recovery.c
@@ -0,0 +1,182 @@
+/*
+ * 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/runtest_dcu.sh b/cases/function/core_recovery/runtest_dcu.sh
new file mode 100755
index 0000000..00040e7
--- /dev/null
+++ b/cases/function/core_recovery/runtest_dcu.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# This test is the SRAR/DCU functional test.
+#
+
+cat <<-EOF
+
+***************************************************************************
+Pay attention:
+
+This test is SRAR functional test. It is for DCU part(L1 Data Cache). The
+test highly depends on BIOS implementation, which means if BIOS is bogus,
+it is possible to cause system hang/crash. If meeting this situation,
+please test again after rebooot or just skip this test.
+***************************************************************************
+
+
+EOF
+
+echo 0 > $TMP_DIR/error.$$
+
+pushd `dirname $0` > /dev/null
+./srar_recovery.sh -d
+[ $? -eq 0 ] || echo 1 > $TMP_DIR/error.$$
+popd > /dev/null
+
+grep -q "1" $TMP_DIR/error.$$
+if [ $? -eq 0 ]
+then
+        exit 1
+else
+        exit 0
+fi
+
diff --git a/cases/function/core_recovery/runtest_ifu.sh b/cases/function/core_recovery/runtest_ifu.sh
new file mode 100755
index 0000000..bb49a5b
--- /dev/null
+++ b/cases/function/core_recovery/runtest_ifu.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# This test is the SRAR/DCU functional test.
+#
+
+cat <<-EOF
+
+***************************************************************************
+Pay attention:
+
+This test is SRAR functional test. It is for IFU part(L1 Instruction Cache).
+The test highly depends on BIOS implementation, which means if BIOS is bogus,
+it is possible to cause system hang/crash. If meeting this situation,
+please test again after rebooot or just skip this test.
+***************************************************************************
+
+
+EOF
+
+echo 0 > $TMP_DIR/error.$$
+
+pushd `dirname $0` > /dev/null
+./srar_recovery.sh -i
+[ $? -eq 0 ] || echo 1 > $TMP_DIR/error.$$
+popd > /dev/null
+
+grep -q "1" $TMP_DIR/error.$$
+if [ $? -eq 0 ]
+then
+        exit 1
+else
+        exit 0
+fi
+
diff --git a/cases/function/core_recovery/srar_recovery.sh b/cases/function/core_recovery/srar_recovery.sh
new file mode 100755
index 0000000..2b30a99
--- /dev/null
+++ b/cases/function/core_recovery/srar_recovery.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+#set -x
+export ROOT=`(cd ../../../; pwd)`
+
+. $ROOT/lib/mce.sh
+
+inject_type=0x00000010
+
+invalid()
+{
+	echo $*
+	exit 1
+}
+
+apei_inj()
+{
+	echo $inject_type > $g_debugfs/apei/einj/error_type
+	echo $1 > $g_debugfs/apei/einj/param1
+	echo 0xfffffffffffff000 > $g_debugfs/apei/einj/param2
+	echo 1 > $g_debugfs/apei/einj/notrigger
+	echo 1 > $g_debugfs/apei/einj/error_inject
+}
+
+print_usage()
+{
+	echo -e "usage:
+\t./srar_recovery.sh -d\t\tDCU error injection under user context
+\t./srar_recovery.sh -i\t\tIFU error injection under user context"
+}
+
+if [ "$1" != "-d" -a "$1" != "-i" ]; then
+	print_usage
+	exit 1
+fi
+check_debugfs
+
+g_debugfs=`cat /proc/mounts | grep debugfs | cut -d ' ' -f2 | head -1`
+#if einj is not builtin, just insmod it
+if [ ! -d $g_debugfs/apei/einj ]; then
+	#if einj is a module, it is ensured to have been loaded
+	modprobe einj param_extension=1 > /dev/null 2>&1
+	[ $? -eq 0 ] || invalid "module einj isn't supported?"
+fi
+[ -f $g_debugfs/apei/einj/param1 ] || invalid "no BIOS extension support for APEI on this platform"
+
+#check if the platform supports Uncorrectable non-fatal Memory Error injection
+cat $g_debugfs/apei/einj/available_error_type | grep -q $inject_type
+if [ $? -ne 0 ]; then
+	invalid "Uncorrectable non-fatal Memory Error is not supported"
+fi
+
+touch trigger
+tail -f trigger | ./core_recovery $1 > log &
+addr=`cat log |cut -d' '  -f6|head -1`
+apei_inj $addr
+sleep 1
+echo go > trigger
+sleep 2
+rm -f trigger log
+pgrep core_recovery > /dev/null 2>&1 | xargs kill -9 > /dev/null 2>&1
+[ $? -eq 0 ] && invalid "The poisoned process can't be killed by kernel. Test fails!"
+
+if [ $1 == "-d" ]; then
+	echo "SRAR/DCU test passes!"
+elif [ $1 == "-i" ]; then
+	echo "SRAR/IFU test passes!"
+fi
+
diff --git a/groups/function b/groups/function
index 1361121..f6c0d70 100644
--- a/groups/function
+++ b/groups/function
@@ -2,6 +2,9 @@
 ERST-INJ cases/function/erst-inject/runtest.sh on
 #PFA test depends on correct BIOS/mcelog setting
 PFA cases/function/pfa/runtest.sh on
+#SRAR test highly depends on BIOS implementation
+SRAR-DCU cases/function/core_recovery/runtest_dcu.sh off
+SRAR-IFU cases/function/core_recovery/runtest_ifu.sh off
 #HWpoison
 HWPOISON-SOFT cases/function/hwpoison/run_soft.sh on
 HWPOISON-HARD cases/function/hwpoison/run_hard.sh on