1 Star 0 Fork 5

herbertee/ras-tools

forked from anolis/ras-tools 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
einj_mem_uc.c 26.45 KB
一键复制 编辑 原始数据 按行查看 历史
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015 Intel Corporation
* Author: Tony Luck
*
* This software may be redistributed and/or modified under the terms of
* the GNU General Public License ("GPL") version 2 only as published by the
* Free Software Foundation.
*/
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <setjmp.h>
#include <signal.h>
#define _GNU_SOURCE 1
#define __USE_GNU 1
#include <sched.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <pthread.h>
#include <sys/wait.h>
#include "einj.h"
#ifndef MAP_HUGETLB
#define MAP_HUGETLB 0x40000
#endif
char *progname;
long pagesize;
int Sflag;
unsigned long long vtop(unsigned long long addr, pid_t pid);
extern void proc_cpuinfo(int *nsockets, int *ncpus, char *model, int *modelnum, int **apicmap);
extern void proc_interrupts(long *nmce, long *ncmci);
extern void do_memcpy(void *dst, void *src, int cnt);
static void show_help(void);
static int nsockets, ncpus, lcpus_persocket;
static int force_flag;
static int cmci_skip_flag;
static int all_flag;
static int *apicmap;
static int child_process;
#define CACHE_LINE_SIZE 64
#define DOUBLE_INJECT_OFFSET (pagesize / 4)
/*
* Vendor extensions for platform specific operations
*/
struct vendor_error_type_extension {
int32_t length;
int32_t pcie_sbdf;
int16_t vendor_id;
int16_t device_id;
int8_t rev_id;
int8_t reserved[3];
};
static void inject_double_uc(unsigned long long addr, void *vaddr, int notrigger)
{
PRINT_INJECTING;
if (Sflag) {
vaddr = (void *)((long)vaddr & ~(pagesize - 1));
madvise(vaddr, pagesize, MADV_HWPOISON);
return;
}
wfile(EINJ_ETYPE, 0x10);
wfile(EINJ_ADDR, addr);
wfile(EINJ_MASK, ~0x0ul);
wfile(EINJ_FLAGS, 2);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
wfile(EINJ_ADDR, vtop((unsigned long long)(vaddr + DOUBLE_INJECT_OFFSET), getpid()));
wfile(EINJ_DOIT, 1);
}
static void inject_core_ce(unsigned long long addr, void *vaddr, int notrigger)
{
unsigned int cpu;
PRINT_INJECTING;
cpu = sched_getcpu();
wfile(EINJ_ETYPE, 0x1);
wfile(EINJ_APIC, cpu);
wfile(EINJ_FLAGS, 1);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_core_non_fatal(unsigned long long addr, void *vaddr, int notrigger)
{
unsigned int cpu;
PRINT_INJECTING;
cpu = sched_getcpu();
wfile(EINJ_ETYPE, 0x2);
wfile(EINJ_APIC, cpu);
wfile(EINJ_FLAGS, 1);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_core_fatal(unsigned long long addr, void *vaddr, int notrigger)
{
unsigned int cpu;
PRINT_INJECTING;
cpu = sched_getcpu();
wfile(EINJ_ETYPE, 0x4);
wfile(EINJ_APIC, cpu);
wfile(EINJ_FLAGS, 1);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
#ifdef __x86_64__
static void inject_llc(unsigned long long addr, void *vaddr, int notrigger)
{
unsigned cpu;
PRINT_INJECTING;
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);
}
#elif __aarch64__
static void inject_llc(unsigned long long addr, void *vaddr, int notrigger)
{
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x400);
wfile(EINJ_MASK, 0x01);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_cmn_fatal(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x800);
wfile(EINJ_MASK, 0x01);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_gic_ce(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x200);
wfile(EINJ_MASK, 0x02);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_gic_non_fatal(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x400);
wfile(EINJ_MASK, 0x02);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_smmu_tcu_ce(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x200);
wfile(EINJ_MASK, 0x03);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_smmu_tcu_non_fatal(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x400);
wfile(EINJ_MASK, 0x03);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_smmu_tcu_fatal(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x800);
wfile(EINJ_MASK, 0x03);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_smmu_tbu_ce(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x200);
wfile(EINJ_MASK, 0x04);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_smmu_tbu_non_fatal(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x400);
wfile(EINJ_MASK, 0x04);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
static void inject_smmu_tbu_fatal(unsigned long long addr, void *vaddr, int notrigger) {
PRINT_INJECTING;
wfile(EINJ_ETYPE, 0x800);
wfile(EINJ_MASK, 0x04);
wfile(EINJ_FLAGS, 0x01);
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
#endif
#ifdef __x86_64__
static void check_configuration(void)
{
char model[512];
int modelnum;
if (!is_privileged() || !is_einj_support())
exit(1);
model[0] = '\0';
proc_cpuinfo(&nsockets, &ncpus, model, &modelnum, &apicmap);
if (nsockets == 0 || ncpus == 0) {
fprintf(stderr, "%s: could not find number of sockets/cpus\n", progname);
exit(1);
}
if (ncpus % nsockets) {
fprintf(stderr, "%s: strange topology. Are all cpus online?\n", progname);
exit(1);
}
lcpus_persocket = ncpus / nsockets;
}
#elif __aarch64__
static void check_configuration(void)
{
if (!is_privileged() || !is_einj_support())
exit(1);
}
#endif
#define REP9(stmt) stmt;stmt;stmt;stmt;stmt;stmt;stmt;stmt;stmt
volatile int vol;
int dosums(void)
{
vol = 0;
REP9(REP9(REP9(vol++)));
return vol;
}
#define MB(n) ((n) * 1024 * 1024)
static void *thp_data_alloc(void)
{
char *p = malloc(MB(128));
int i;
if (p == NULL) {
fprintf(stderr, "%s: cannot allocate memory\n", progname);
exit(1);
}
srandom(getpid() * time(NULL));
for (i = 0; i < MB(128); i++)
p[i] = random();
return p + MB(64);
}
int get_huge_pagesize(void)
{
FILE *fp;
char *line = NULL;
size_t linelen = 0;
int hpagesize = 0;
if ((fp = fopen("/proc/meminfo", "r")) == NULL) {
fprintf(stderr, "open /proc/meminfo");
exit(1);
}
while (getline(&line, &linelen, fp) > 0) {
if (sscanf(line, "Hugepagesize: %d kB", &hpagesize) >= 1)
break;
}
free(line);
fclose(fp);
return hpagesize * 1024;
}
static void *hugetlb_alloc(void)
{
int HPS = get_huge_pagesize();
char *p = mmap(NULL, HPS, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON|MAP_HUGETLB, -1, 0);
int i;
if (p == MAP_FAILED) {
fprintf(stderr, "%s: cannot allocate memory\n", progname);
exit(1);
}
srandom(getpid() * time(NULL));
for (i = 0; i < HPS; i++)
p[i] = random();
return p + HPS / 4;
}
static void *data_alloc_common(int flag)
{
char *p = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, flag, -1, 0);
int i;
if (p == NULL) {
fprintf(stderr, "%s: cannot allocate memory\n", progname);
exit(1);
}
srandom(getpid() * time(NULL));
for (i = 0; i < pagesize; i++)
p[i] = random();
return p + pagesize / 4;
}
static void *data_alloc(void)
{
return data_alloc_common(MAP_SHARED|MAP_ANON);
}
static void *data_alloc_private(void)
{
return data_alloc_common(MAP_PRIVATE|MAP_ANON);
}
static FILE *pcfile;
static void *map_file_alloc(void)
{
char c, *p;
int i;
pcfile = tmpfile();
for (i = 0; i < pagesize; i++) {
c = random();
fputc(c, pcfile);
}
fflush(pcfile);
p = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(pcfile), 0);
if (p == NULL) {
fprintf(stderr, "%s: cannot mmap tmpfile\n", progname);
exit(1);
}
*p = random();
return p + pagesize / 4;
}
static void *mlock_data_alloc(void)
{
char *p = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
int i;
if (p == NULL) {
fprintf(stderr, "%s: cannot allocate memory\n", progname);
exit(1);
}
srandom(getpid() * time(NULL));
for (i = 0; i < pagesize; i++)
p[i] = random();
if (mlock(p, pagesize) == -1) {
fprintf(stderr, "%s: cannot mlock(2) memory\n", progname);
exit(1);
}
return p + pagesize / 4;
}
static void *instr_alloc(void)
{
char *p = (char *)dosums;
p += 2 * pagesize;
/*pre-load the dosum memory page to prevent vtop conversion failure*/
dosums();
return (void *)((long)p & ~(pagesize - 1));
}
/*
* parameters to the single and write tests.
*/
int trigger_offset = 0; /* where to hit after the poison addr */
int trigger_single(char *addr)
{
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
return target[0];
}
int trigger_double(char *addr)
{
PRINT_TRIGGERING;
return addr[0] + addr[1];
}
int trigger_split(char *addr)
{
long *a = (long *)(addr - 1);
PRINT_TRIGGERING;
return a[0];
}
int trigger_write(char *addr)
{
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
target[0] = 'a';
return 0;
}
#ifdef __aarch64__
#define __put_mem_asm(store, reg, x, addr) \
asm volatile( \
store " " reg "0, [%1]\n" \
: \
: "r" (x), "r" (addr))
int trigger_write_byte(char *addr)
{
int8_t __pu_val = 0x1E;
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
__put_mem_asm("strb", "%w", __pu_val, target);
return 0;
}
int trigger_write_word(char *addr)
{
int16_t __pu_val = 0x1EFF;
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
__put_mem_asm("strh", "%w", __pu_val, target);
return 0;
}
int trigger_write_dword(char *addr)
{
int32_t __pu_val = 0x1FFFEEEE;
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
__put_mem_asm("str", "%w", __pu_val, target);
return 0;
}
int trigger_write_qword(char *addr)
{
int64_t __pu_val = 0x1EEEFFFFFEEEE;
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
__put_mem_asm("str", "%x", __pu_val, target);
return 0;
}
#endif
int thread(char *addr)
{
printf(">> trigger_thread\n");
return addr[0];
}
int trigger_thread(char *addr)
{
unsigned long ret;
pthread_t id1, id2;
ret = pthread_create(&id1, NULL, (void*)thread, addr);
if (ret != 0) {
printf("create pthread error\n");
exit(1);
}
ret = pthread_create(&id2, NULL, (void*)thread, addr);
if (ret != 0) {
printf("create pthread error\n");
exit(1);
}
pthread_join(id1, NULL);
pthread_join(id2, NULL);
return 0;
}
int trigger_share(char *addr)
{
int pid, status;
char *p;
switch (pid = fork()) {
case -1:
fprintf(stderr, "%s: fork failed\n", progname);
return -1;
case 0:
/* mmap share memory */
p = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fileno(pcfile), 0);
if (p == NULL) {
fprintf(stderr, "%s: cannot mmap sharefile\n", progname);
exit(1);
}
PRINT_TRIGGERING;
return *(p + pagesize / 4);
}
while (wait(&status) != pid)
;
PRINT_TRIGGERING;
return addr[0];
}
int trigger_overflow(char *addr)
{
char *target = addr + trigger_offset;
PRINT_TRIGGERING;
return target[0] + (target + DOUBLE_INJECT_OFFSET)[0];
}
/*
* parameters to the memcpy and copyin tests.
*/
int memcpy_runup = 0; /* how much to copy before hitting poison */
int memcpy_size = 512; /* Total amount to copy */
int memcpy_align = 0; /* Relative alignment of src/dst */
/* argument is "runup:size:align" */
void parse_memcpy(char *arg)
{
char *endp;
memcpy_runup = strtol(arg, &endp, 0);
if (*endp != ':')
show_help();
memcpy_size = strtol(endp + 1, &endp, 0);
if (*endp != ':')
show_help();
memcpy_align = strtol(endp + 1, &endp, 0);
if (*endp != '\0')
show_help();
if (memcpy_runup < 0 || memcpy_runup > pagesize / 4) {
fprintf(stderr, "%s: runup out of range\n", progname);
exit(1);
}
if (memcpy_size < 0 || memcpy_size > pagesize / 4) {
fprintf(stderr, "%s: size out of range\n", progname);
exit(1);
}
if (memcpy_runup > memcpy_size) {
fprintf(stderr, "%s: runup must be less than size\n", progname);
exit(1);
}
if (memcpy_align < 0 || memcpy_align >= CACHE_LINE_SIZE) {
fprintf(stderr, "%s: bad alignment\n", progname);
exit(1);
}
}
int trigger_memcpy(char *addr)
{
char *src = addr - memcpy_runup;
char *dst = addr + pagesize / 2;
PRINT_TRIGGERING;
dst -= memcpy_align;
do_memcpy(dst, src, memcpy_size);
return 0;
}
static int copyin_fd = -1;
int trigger_copyin(char *addr)
{
int ret;
char filename[] = "/tmp/einj-XXXXXX";
if ((copyin_fd = mkstemp(filename)) == -1) {
fprintf(stderr, "%s: couldn't make temp file\n", progname);
return -1;
}
(void)unlink(filename);
PRINT_TRIGGERING;
if ((ret = write(copyin_fd, addr - memcpy_runup, memcpy_size)) != memcpy_size) {
if (ret == -1)
fprintf(stderr, "%s: couldn't write temp file (errno=%d)\n", progname, errno);
else
fprintf(stderr, "%s: short (%d bytes) write to temp file\n", progname, ret);
}
return 0;
}
int trigger_copyout(char *addr)
{
char *buf = malloc(pagesize);
int ret;
if (buf == NULL) {
fprintf(stderr, "%s: couldn't allocate memory\n", progname);
return -1;
}
rewind(pcfile);
PRINT_TRIGGERING;
ret = fread(buf, 1, pagesize, pcfile);
fprintf(stderr, "%s: read returned %d\n", progname, ret);
return 0;
}
int trigger_copy_on_write(char *addr)
{
int pid, status;
switch (pid = fork()) {
case -1:
fprintf(stderr, "%s: fork failed\n", progname);
return -1;
case 0:
child_process = 1;
/* force kernel to copy this page */
PRINT_TRIGGERING;
*addr = '*';
exit(0);
}
fprintf(stderr, "%s: COW parent waiting for pid=%d\n", progname, pid);
while (wait(&status) != pid)
;
PRINT_TRIGGERING;
return addr[0];
}
int trigger_patrol(char *addr)
{
PRINT_TRIGGERING;
sleep(1);
}
#ifdef __x86_64__
int trigger_llc(char *addr)
{
PRINT_TRIGGERING;
asm volatile("clflush %0" : "+m" (*addr));
}
int trigger_prefetch(char *addr)
{
PRINT_TRIGGERING;
__builtin_prefetch(addr, 0, 3);
sleep(5);
}
#elif __aarch64__
int trigger_llc(char *addr)
{
asm volatile("dc civac, %0" : : "r" (addr) : "memory");
}
int trigger_prefetch(char *addr)
{
PRINT_TRIGGERING;
asm volatile("prfm pldl1keep, %a0\n" : : "p" (addr));
sleep(5);
}
#endif
int trigger_instr(char *addr)
{
int ret;
PRINT_TRIGGERING;
ret = dosums();
if (ret != 729)
printf("Corruption during instruction fault recovery (%d)\n", ret);
return ret;
}
static int futex(int *uaddr, int futex_op, int val,
const struct timespec *timeout, int *uaddr2, int val3)
{
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3);
}
int trigger_futex(char *addr)
{
int ret;
PRINT_TRIGGERING;
ret = futex((int *)addr, FUTEX_WAIT, 0, NULL, NULL, 0);
if (ret == -1)
printf("futex returned with errno=%d\n", errno);
else
printf("futex return %d\n", ret);
return ret;
}
/* attributes of the test and which events will follow our trigger */
#define F_MCE 1
#define F_CMCI 2
#define F_SIGBUS 4
#define F_FATAL 8
#define F_EITHER 16
#define F_LONGWAIT 32
struct test {
char *testname;
char *testhelp;
void *(*alloc)(void);
void (*inject)(unsigned long long, void *, int);
int notrigger;
int (*trigger)(char *);
int flags;
} tests[] = {
{
"single", "Single read in pipeline to target address, generates SRAR machine check",
data_alloc, inject_mem_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
},
{
"double", "Double read in pipeline to target address, generates SRAR machine check",
data_alloc, inject_mem_uc, 1, trigger_double, F_MCE|F_CMCI|F_SIGBUS,
},
{
"split", "Unaligned read crosses cacheline from good to bad. Probably fatal",
data_alloc, inject_mem_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, inject_mem_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
},
{
"hugetlb", "Try to inject in hugetlb page, generates SRAR machine check",
hugetlb_alloc, inject_mem_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
},
{
"store", "Write to target address. Should generate a UCNA/CMCI",
data_alloc, inject_mem_uc, 1, trigger_write, F_CMCI,
},
#ifdef __aarch64__
{
"cmn_non_fatal", "CMN SLC Data RAM DE. Should generate a UCNA/CMCI",
data_alloc, inject_llc, 1, trigger_single, F_CMCI,
},
{
"cmn_fatal", "CMN SLC Data RAM UE. Should fatal",
data_alloc, inject_cmn_fatal, 1, trigger_single, F_FATAL,
},
{
"gic_ce", "GIC corrected error. Should generate a CMCI",
data_alloc, inject_gic_ce, 1, trigger_single, F_CMCI,
},
{
"gic_non_fatal", "GIC deferred error",
data_alloc, inject_gic_non_fatal, 1, trigger_single, F_CMCI,
},
{
"smmu_tcu_ce", "SMMU TCU corrected error. Should generate a UCNA/CMCI",
data_alloc, inject_smmu_tcu_ce, 1, trigger_single, F_CMCI,
},
{
"smmu_tcu_non_fatal", "SMMU TCU deferred error. Should generate a UCNA/CMCI",
data_alloc, inject_smmu_tcu_non_fatal, 1, trigger_single, F_CMCI,
},
{
"smmu_tcu_fatal", "SMMU TCU uncorrected error. Should fatal",
data_alloc, inject_smmu_tcu_fatal, 1, trigger_single, F_FATAL,
},
{
"smmu_tbu_ce", "SMMU TBU corrected error. Should generate a UCNA/CMCI",
data_alloc, inject_smmu_tbu_ce, 1, trigger_single, F_CMCI,
},
{
"smmu_tbu_non_fatal", "SMMU TBU deferred error. Should generate a UCNA/CMCI",
data_alloc, inject_smmu_tbu_non_fatal, 1, trigger_single, F_CMCI,
},
{
"smmu_tbu_fatal", "SMMU TBU uncorrected error. Should fatal",
data_alloc, inject_smmu_tbu_fatal, 1, trigger_single, F_FATAL,
},
{
"strbyte", "Write to target address. Should generate a UCNA/CMCI",
data_alloc, inject_mem_uc, 1, trigger_write_byte, F_CMCI,
},
{
"strword", "Write to target address. Should generate a UCNA/CMCI",
data_alloc, inject_mem_uc, 1, trigger_write_word, F_CMCI,
},
{
"strdword", "Write to target address. Should generate a UCNA/CMCI",
data_alloc, inject_mem_uc, 1, trigger_write_dword, F_CMCI,
},
{
"strqword", "Write to target address. Should generate a UCNA/CMCI",
data_alloc, inject_mem_uc, 1, trigger_write_qword, F_CMCI,
},
#endif
{
"prefetch", "Prefetch data into L1 cache. Should generate CMCI",
data_alloc, inject_mem_uc, 1, trigger_prefetch, F_CMCI,
},
{
"memcpy", "Streaming read from target address. Probably fatal",
data_alloc, inject_mem_uc, 1, trigger_memcpy, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{
"instr", "Instruction fetch. Generates SRAR that OS should transparently fix",
instr_alloc, inject_mem_uc, 1, trigger_instr, F_MCE|F_CMCI,
},
{
"patrol", "Patrol scrubber, generates SRAO machine check",
data_alloc, inject_mem_uc, 0, trigger_patrol, F_EITHER|F_LONGWAIT,
},
{
"thread", "Single read by two threads to target address at the same time, generates SRAR machine check",
data_alloc, inject_mem_uc, 1, trigger_thread, F_MCE|F_CMCI|F_SIGBUS,
},
{
"share", "Share memory is read by two tasks to target address, generates SRAR machine check",
map_file_alloc, inject_mem_uc, 1, trigger_share, F_MCE|F_CMCI|F_SIGBUS,
},
{
"overflow", "Read to two target addresses at the same time, Probably fatal",
data_alloc, inject_double_uc, 1, trigger_overflow, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{
"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, inject_mem_uc, 1, trigger_copyin, F_MCE|F_CMCI|F_FATAL,
},
{
"copyout", "Kernel copies data to user. Probably fatal",
map_file_alloc, inject_mem_uc, 1, trigger_copyout, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{
"copy-on-write", "Kernel copies user page. Probably fatal",
data_alloc_private, inject_mem_uc, 1, trigger_copy_on_write, F_MCE|F_CMCI|F_SIGBUS|F_FATAL,
},
{
"futex", "Kernel access to futex(2). Probably fatal",
data_alloc, inject_mem_uc, 1, trigger_futex, F_MCE|F_CMCI|F_FATAL,
},
{
"mlock", "mlock target page then inject/read to generates SRAR machine check",
mlock_data_alloc, inject_mem_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
},
{
"core_ce", "Core corrected error",
data_alloc, inject_core_ce, 1, trigger_single, F_CMCI,
},
{
"core_non_fatal", "Core deferred error",
data_alloc, inject_core_non_fatal, 1, trigger_single, F_CMCI,
},
{
"core_fatal", "Core uncorrected error. Should fatal",
data_alloc, inject_core_fatal, 1, trigger_single, F_CMCI|F_FATAL,
},
{ NULL }
};
static void show_help(void)
{
struct test *t;
printf("Usage: %s [-a][-c count][-d delay][-f][-i][j][k] [-m runup:size:align][testname]\n", progname);
printf(" %-8s %-5s %s\n", "Testname", "Fatal", "Description");
for (t = tests; t->testname; t++)
printf(" %-8s %-5s %s\n", t->testname,
(t->flags & F_FATAL) ? "YES" : "no",
t->testhelp);
exit(0);
}
static struct test *lookup_test(char *s)
{
struct test *t;
for (t = tests; t->testname; t++)
if (strcmp(s, t->testname) == 0)
return t;
fprintf(stderr, "%s: unknown test '%s'\n", progname, s);
exit(1);
}
static struct test *next_test(struct test *t)
{
t++;
if (t->testname == NULL)
t = tests;
return t;
}
static jmp_buf env;
static void recover(int sig, siginfo_t *si, void *v)
{
printf("signal %d code %d addr %p\n", sig, si->si_code, si->si_addr);
siglongjmp(env, 1);
}
struct sigaction recover_act = {
.sa_sigaction = recover,
.sa_flags = SA_SIGINFO,
};
void kick_by_file(struct test *t, char *addr) {
const char *trigger = "./trigger_start";
const char *trigger_flag = "trigger";
char trigger_buf[16];
int count = 64*3;
int fd;
errno = 0;
if (unlink(trigger) < 0 && errno != ENOENT) {
fprintf(stderr, "fail to remove trigger file\n");
exit(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);
}
/* trigger now */
t->trigger(addr);
}
int main(int argc, char **argv)
{
int c, i;
int count = 1, kick = 0, inject_skip_flag = 0;
double delay = 1.0;
struct test *t;
void *vaddr;
long long paddr;
pid_t pid;
#ifdef __x86_64__
int cmci_wait_count = 0;
int either;
long b_mce, b_cmci, a_mce, a_cmci;
struct timeval t1, t2;
#endif
progname = argv[0];
pagesize = getpagesize();
pid = getpid();
while ((c = getopt(argc, argv, "ac:d:fhijkm:z:S")) != -1) switch (c) {
case 'a':
all_flag = 1;
break;
case 'c':
count = strtol(optarg, NULL, 0);
break;
case 'd':
delay = strtod(optarg, NULL);
break;
case 'f':
force_flag = 1;
break;
case 'i':
cmci_skip_flag = 1;
break;
case 'j':
inject_skip_flag = 1;
break;
case 'k':
kick = 1;
break;
case 'm':
parse_memcpy(optarg);
break;
case 'z':
trigger_offset = strtod(optarg, NULL);
break;
case 'S':
Sflag = 1;
break;
case 'h': case '?':
show_help();
break;
}
if (Sflag == 0 && inject_skip_flag == 0)
check_configuration();
if (optind < argc)
t = lookup_test(argv[optind]);
else
t = tests;
if ((t->flags & F_FATAL) && !force_flag) {
fprintf(stderr, "%s: selected test may be fatal. Use '-f' flag if you really want to do this\n", progname);
exit(1);
}
sigaction(SIGBUS, &recover_act, NULL);
for (i = 0; i < count; i++) {
vaddr = t->alloc();
paddr = vtop((long long)vaddr, pid);
printf("%d: %-8s vaddr = %p paddr = %llx\n", i, t->testname, vaddr, paddr);
#ifdef __x86_64__
cmci_wait_count = 0;
either = 0;
proc_interrupts(&b_mce, &b_cmci);
gettimeofday(&t1, NULL);
#endif
if (sigsetjmp(env, 1)) {
if ((t->flags & F_SIGBUS) == 0) {
printf("Unexpected SIGBUS\n");
}
} else {
if (!inject_skip_flag)
t->inject(paddr, vaddr, t->notrigger);
sleep(3);
if (kick)
kick_by_file(t, vaddr);
else
t->trigger(vaddr);
if (t->flags & F_SIGBUS) {
printf("Expected SIGBUS, didn't get one\n");
}
}
if (copyin_fd != -1) {
close(copyin_fd);
copyin_fd = -1;
}
if (pcfile) {
fclose(pcfile);
pcfile = NULL;
}
/* if system didn't already take page offline, ask it to do so now */
if (paddr == vtop((long long)vaddr, pid)) {
printf("Manually take page offline\n");
wfile("/sys/devices/system/memory/hard_offline_page", paddr);
}
/* Give system a chance to process on possibly deep C-state idle cpus */
usleep(100);
#ifdef __x86_64__
proc_interrupts(&a_mce, &a_cmci);
#endif
if (t->flags & F_FATAL) {
printf("Big surprise ... still running. Thought that would be fatal\n");
}
#ifdef __x86_64__
if (Sflag == 0 && (t->flags & (F_MCE | F_EITHER))) {
if (a_mce == b_mce) {
if (t->flags & F_EITHER)
goto skip1;
printf("Expected MCE, but none seen\n");
} else if (a_mce == b_mce + 1) {
printf("Saw local machine check\n");
} else if (a_mce == b_mce + ncpus) {
printf("Saw broadcast machine check\n");
} else {
printf("Unusual number of MCEs seen: %ld\n", a_mce - b_mce);
}
either++;
} else {
if (a_mce != b_mce) {
printf("Saw %ld unexpected MCEs (%ld systemwide)\n", b_mce - a_mce, (b_mce - a_mce) / ncpus);
}
}
skip1:
if (Sflag == 0 && (t->flags & (F_CMCI | F_EITHER))) {
int maxwait = (t->flags & F_LONGWAIT) ? 20000 : 500;
while (a_cmci < b_cmci + lcpus_persocket) {
if (cmci_wait_count > maxwait) {
break;
}
usleep(1000);
proc_interrupts(&a_mce, &a_cmci);
cmci_wait_count++;
}
if (a_cmci != b_cmci && cmci_wait_count != 0) {
gettimeofday(&t2, NULL);
printf("CMCIs took ~%.6f secs to be reported.\n",
(t2.tv_sec - t1.tv_sec) +
(t2.tv_usec - t1.tv_usec) /1.0e6);
}
if (a_cmci == b_cmci) {
if (t->flags & F_EITHER)
goto skip2;
if (!cmci_skip_flag) {
printf("Expected CMCI, but none seen\n");
printf("Test failed\n");
return 1;
}
} else if (!cmci_skip_flag && a_cmci < b_cmci + lcpus_persocket) {
printf("Unusual number of CMCIs seen: %ld\n", a_cmci - b_cmci);
printf("Test failed\n");
return 1;
}
either++;
} else {
if (!cmci_skip_flag && a_cmci != b_cmci) {
printf("Saw %ld unexpected CMCIs (%ld per socket)\n", a_cmci - b_cmci, (a_cmci - b_cmci) / lcpus_persocket);
printf("Test failed\n");
return 1;
}
}
skip2:
if (t->flags & F_EITHER) switch (either) {
case 0:
printf("Expected CMCI or MCE, but saw neither\n");
printf("Test failed\n");
return 1;
case 2:
printf("Expected one of CMCI or MCE, but saw both\n");
printf("Test failed\n");
return 1;
}
usleep((useconds_t)(delay * 1.0e6));
if (all_flag) {
t = next_test(t);
while (t->flags & F_FATAL)
t = next_test(t);
}
#endif
if (child_process)
break;
}
printf("Test passed\n");
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/herbertee/ras-tools.git
git@gitee.com:herbertee/ras-tools.git
herbertee
ras-tools
ras-tools
master

搜索帮助

23e8dbc6 1850385 7e0993f3 1850385