blob: 835c243dfaedf2d28fdbd0d2ddf04adb66bafa3f [file] [log] [blame]
/*
* 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;
}