aboutsummaryrefslogtreecommitdiffstats
path: root/cmcistorm.c
blob: 6a1d2e308873a9e3267ba85b34792a31a2951aa5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 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.
 */

/*
 * Allocate memory - use EINJ to inject a bunch of soft errors,
 * then consume them all as fast a possible.
 */

#include "einj.h"

extern unsigned long long vtop(unsigned long long addr, pid_t pid);
volatile int trigger;
char *progname;
long pagesize;
int Sflag;

#define	BUFSZ	(64 * 1024)

static void inject(int nerrors, double interval)
{
	char	*b, *buf;
	long long paddr;
	int	i;
	unsigned long s, e;
	int	bufsz = nerrors * 4096;
	pid_t pid;

	pid = getpid();
	buf = malloc(bufsz);
	if (buf == NULL) {
		perror("malloc");
		exit(1);
	}
	memset(buf, '*', bufsz);

	for (i = 0; i < nerrors; i++) {
		b = buf + i * 4096;
		paddr = vtop((unsigned long long)b, pid);

		printf("%d: vaddr = %p paddr = %llx\n", i, b, paddr);
		wfile(EINJ_ADDR, paddr);
		wfile(EINJ_DOIT, 1);

		/* wait a bit to make sure SMI is all done on all cpus */
		usleep((int)(interval * 1.0e6));
	}


	/* Trigger error by reading from target location */
	for (i = 0; i < bufsz; i++)
		trigger += *(buf + i);

	/* wait a bit to allow CMCI handlers to complete */
	usleep((int)(interval * 1.0e6));
}

int main(int argc, char **argv)
{
	int nerrors = (argc > 1) ? atoi(argv[1]) : 20;
	double interval = (argc > 2) ? atof(argv[2]) : 1.0;

	progname = argv[0];

	wfile(EINJ_ETYPE, 0x8);
	wfile(EINJ_MASK, ~0x0ul);
	wfile(EINJ_NOTRIGGER, 1);

	inject(nerrors, interval);

	return 0;
}