aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2016-02-17 13:51:03 -0800
committerTony Luck <tony.luck@intel.com>2016-03-01 09:06:32 -0800
commit0be8f43bb0745c93046e73533c4c9187b8dc9e9b (patch)
tree56745e6b7fa981a2309c3f1a62c89b45abcbca71
parent767456f1cf0d32d7f25753c84413517c89455980 (diff)
downloadras-tools-0be8f43bb0745c93046e73533c4c9187b8dc9e9b.tar.gz
Add "llc" option to inject processor uncorrected non-fatal and trigger LLC writeback
-rw-r--r--einj_mem_uc.c56
-rw-r--r--proc_cpuinfo.c19
2 files changed, 61 insertions, 14 deletions
diff --git a/einj_mem_uc.c b/einj_mem_uc.c
index 4c45739..d9d5144 100644
--- a/einj_mem_uc.c
+++ b/einj_mem_uc.c
@@ -17,19 +17,28 @@
#include <sys/time.h>
#include <setjmp.h>
#include <signal.h>
+#define _GNU_SOURCE 1
+#define __USE_GNU 1
+#include <sched.h>
extern long long vtop(long long);
+extern void proc_cpuinfo(int *nsockets, int *ncpus, char *model, int **apicmap);
+extern void proc_interrupts(long *nmce, long *ncmci);
+extern void do_memcpy(void *dst, void *src, int dummy, int cnt);
static char *progname;
static int nsockets, ncpus, lcpus_persocket;
static int force_flag;
static int all_flag;
static long pagesize;
+static int *apicmap;
#define CACHE_LINE_SIZE 64
#define EINJ_ETYPE "/sys/kernel/debug/apei/einj/error_type"
#define EINJ_ADDR "/sys/kernel/debug/apei/einj/param1"
#define EINJ_MASK "/sys/kernel/debug/apei/einj/param2"
+#define EINJ_APIC "/sys/kernel/debug/apei/einj/param3"
+#define EINJ_FLAGS "/sys/kernel/debug/apei/einj/flags"
#define EINJ_NOTRIGGER "/sys/kernel/debug/apei/einj/notrigger"
#define EINJ_DOIT "/sys/kernel/debug/apei/einj/error_inject"
@@ -53,6 +62,21 @@ static void inject_uc(unsigned long long addr, int notrigger)
wfile(EINJ_ETYPE, 0x10);
wfile(EINJ_ADDR, addr);
wfile(EINJ_MASK, ~0x0ul);
+ wfile(EINJ_FLAGS, 2);
+ wfile(EINJ_NOTRIGGER, notrigger);
+ wfile(EINJ_DOIT, 1);
+}
+
+static void inject_llc(unsigned long long addr, int notrigger)
+{
+ unsigned cpu;
+
+ cpu = sched_getcpu();
+ wfile(EINJ_ETYPE, 0x2);
+ wfile(EINJ_ADDR, addr);
+ wfile(EINJ_MASK, ~0x0ul);
+ wfile(EINJ_APIC, apicmap[cpu]);
+ wfile(EINJ_FLAGS, 3);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
@@ -76,7 +100,7 @@ static void check_configuration(void)
exit(1);
}
model[0] = '\0';
- proc_cpuinfo(&nsockets, &ncpus, model);
+ proc_cpuinfo(&nsockets, &ncpus, model, &apicmap);
if (nsockets == 0 || ncpus == 0) {
fprintf(stderr, "%s: could not find number of sockets/cpus\n", progname);
exit(1);
@@ -199,6 +223,11 @@ int trigger_patrol(char *addr)
sleep(1);
}
+int trigger_llc(char *addr)
+{
+ asm volatile("clflush %0" : "+m" (*addr));
+}
+
int trigger_instr(char *addr)
{
int ret = dosums();
@@ -219,45 +248,50 @@ struct test {
char *testname;
char *testhelp;
void *(*alloc)(void);
+ void (*inject)(unsigned long long, int);
int notrigger;
int (*trigger)(char *);
int flags;
} tests[] = {
{
"single", "Single read in pipeline to target address, generates SRAR machine check",
- data_alloc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
+ data_alloc, inject_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
},
{
"double", "Double read in pipeline to target address, generates SRAR machine check",
- data_alloc, 1, trigger_double, F_MCE|F_CMCI|F_SIGBUS,
+ data_alloc, inject_uc, 1, trigger_double, F_MCE|F_CMCI|F_SIGBUS,
},
{
"split", "Unaligned read crosses cacheline from good to bad. Probably fatal",
- data_alloc, 1, trigger_split, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
+ data_alloc, inject_uc, 1, trigger_split, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{
"THP", "Try to inject in transparent huge page, generates SRAR machine check",
- thp_data_alloc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
+ thp_data_alloc, inject_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
},
{
"store", "Write to target address. Should generate a UCNA/CMCI",
- data_alloc, 1, trigger_write, F_CMCI,
+ data_alloc, inject_uc, 1, trigger_write, F_CMCI,
},
{
"memcpy", "Streaming read from target address. Probably fatal",
- data_alloc, 1, trigger_memcpy, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
+ data_alloc, inject_uc, 1, trigger_memcpy, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{
"instr", "Instruction fetch. Generates SRAR that OS should transparently fix",
- instr_alloc, 1, trigger_instr, F_MCE|F_CMCI,
+ instr_alloc, inject_uc, 1, trigger_instr, F_MCE|F_CMCI,
},
{
"patrol", "Patrol scrubber, generates SRAO machine check",
- data_alloc, 0, trigger_patrol, F_MCE,
+ data_alloc, inject_uc, 0, trigger_patrol, F_MCE,
+ },
+ {
+ "llc", "Cache write-back, generates SRAO machine check",
+ data_alloc, inject_llc, 1, trigger_llc, F_MCE,
},
{
"copyin", "Kernel copies data from user. Probably fatal",
- data_alloc, 1, trigger_copyin, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
+ data_alloc, inject_uc, 1, trigger_copyin, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{ NULL }
};
@@ -365,7 +399,7 @@ int main(int argc, char **argv)
printf("Unexpected SIGBUS\n");
}
} else {
- inject_uc(paddr, t->notrigger);
+ t->inject(paddr, t->notrigger);
t->trigger(vaddr);
if (t->flags & F_SIGBUS) {
printf("Expected SIGBUS, didn't get one\n");
diff --git a/proc_cpuinfo.c b/proc_cpuinfo.c
index 540dcd1..7d556b1 100644
--- a/proc_cpuinfo.c
+++ b/proc_cpuinfo.c
@@ -17,16 +17,18 @@
* 1) number of cpu sockets
* 2) Number of logical cpus
* 3) Model name of the cpu
+ * 4) Logical cpu# to apicd mappings
*/
-void proc_cpuinfo(int *nsockets, int *ncpus, char *model)
+void proc_cpuinfo(int *nsockets, int *ncpus, char *model, int **apicmap)
{
FILE *fp = fopen("/proc/cpuinfo", "r");
char *p, line[4096];
- long s, sockmask = 0;
- int i;
+ long apicid, lcpu, s, sockmask = 0;
+ int i, maxcpus = 4;
*nsockets = 0;
*ncpus = 0;
+ *apicmap = (int *)calloc(sizeof (int), maxcpus);
if (fp == NULL)
return;
@@ -42,6 +44,17 @@ void proc_cpuinfo(int *nsockets, int *ncpus, char *model)
p = strchr(&line[10], ':');
s = strtol(p+1, NULL, 10);
sockmask |= 1 << s;
+ } else if (strncmp(line, "processor", 9) == 0) {
+ p = strchr(&line[8], ':');
+ lcpu = strtol(p+1, NULL, 10);
+ } else if (strncmp(line, "apicid", 6) == 0) {
+ p = strchr(&line[5], ':');
+ apicid = strtol(p+1, NULL, 10);
+ if (lcpu >= maxcpus) {
+ maxcpus *= 2;
+ *apicmap = realloc(*apicmap, maxcpus * sizeof (int));
+ }
+ (*apicmap)[lcpu] = apicid;
}
}
for (i = 0; i < 8 * sizeof sockmask; i++)