einj.h: add a header file to declare common EINJ related operations

Lots of files declare the same EINJ related macros like EINJ_ETYPE and
functions like wfile(), include the same header files.

To simplify the code and make it easier to maintain, move all common EINJ
related operations to a header file.

[Tony: Move the code out of einj.h and into new file einj.c]

Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
diff --git a/Makefile b/Makefile
index 3d5ec43..0d18223 100644
--- a/Makefile
+++ b/Makefile
@@ -13,23 +13,23 @@
 vtop: vtop.c
 	cc -o vtop $(CFLAGS) vtop.c
 
-cmcistorm: cmcistorm.o proc_pagemap.o
-	cc -o cmcistorm $(CFLAGS) cmcistorm.o proc_pagemap.o
+cmcistorm: cmcistorm.o proc_pagemap.o einj.o
+	cc -o cmcistorm $(CFLAGS) cmcistorm.o proc_pagemap.o einj.o
 
-rep_ce_page: rep_ce_page.o proc_pagemap.o
-	cc -o rep_ce_page $(CFLAGS) rep_ce_page.o proc_pagemap.o
+rep_ce_page: rep_ce_page.o proc_pagemap.o einj.o
+	cc -o rep_ce_page $(CFLAGS) rep_ce_page.o proc_pagemap.o einj.o
 
-hornet: hornet.c
-	cc -o hornet $(CFLAGS) hornet.c
+hornet: hornet.o einj.o
+	cc -o hornet $(CFLAGS) hornet.o einj.o
 
-einj_mem_uc: einj_mem_uc.o proc_cpuinfo.o proc_interrupt.o proc_pagemap.o do_memcpy.o
-	cc -o einj_mem_uc einj_mem_uc.o proc_cpuinfo.o proc_interrupt.o proc_pagemap.o do_memcpy.o -pthread
+einj_mem_uc: einj_mem_uc.o proc_cpuinfo.o proc_interrupt.o proc_pagemap.o do_memcpy.o einj.o
+	cc -o einj_mem_uc einj_mem_uc.o proc_cpuinfo.o proc_interrupt.o proc_pagemap.o do_memcpy.o einj.o -pthread
 
 lmce: proc_pagemap.o lmce.o
 	cc -o lmce proc_pagemap.o lmce.o -pthread
 
-memattr: memattr.c
-	cc -o memattr $(CFLAGS) memattr.c
+memattr: memattr.o einj.o
+	cc -o memattr $(CFLAGS) memattr.o einj.o
 
 victim: victim.c
 	cc -o victim $(CFLAGS) victim.c
diff --git a/cmcistorm.c b/cmcistorm.c
index ab97162..6a1d2e3 100644
--- a/cmcistorm.c
+++ b/cmcistorm.c
@@ -13,45 +13,17 @@
  * Allocate memory - use EINJ to inject a bunch of soft errors,
  * then consume them all as fast a possible.
  */
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
 
-#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_NOTRIGGER "/sys/kernel/debug/apei/einj/notrigger"
-#define EINJ_DOIT "/sys/kernel/debug/apei/einj/error_inject"
+#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 wfile(char *file, unsigned long val)
-{
-	FILE *fp;
-	static int total_errors;
-
-tryagain:
-	fp = fopen(file, "w");
-	if (fp == NULL) {
-		perror(file);
-		exit(1);
-	}
-	fprintf(fp, "0x%lx\n", val);
-	if (fclose(fp) == EOF) {
-		perror(file);
-		if (++total_errors == 10)
-			exit(1);
-		sleep(3);
-		goto tryagain;
-	}
-}
-
 static void inject(int nerrors, double interval)
 {
 	char	*b, *buf;
@@ -95,6 +67,8 @@
 	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);
diff --git a/einj.c b/einj.c
new file mode 100644
index 0000000..d411570
--- /dev/null
+++ b/einj.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2015 Intel Corporation
+ * Author: Tony Luck
+ */
+
+#include "einj.h"
+
+int check_errortype_available(char *file, unsigned long long val)
+{
+	FILE *fp;
+	int ret = -1;
+	unsigned long long available_error_type;
+
+	if (strcmp(file, EINJ_ETYPE) != 0)
+		return 0;
+
+	fp = fopen(EINJ_ETYPE_AVAILABLE, "r");
+	if (!fp) {
+		fprintf(stderr, "%s: cannot open '%s'\n", progname, file);
+		exit(1);
+	}
+
+	while (fscanf(fp, "%llx%*[^\n]", &available_error_type) == 1) {
+		if (val == available_error_type) {
+			ret = 0;
+			break;
+		}
+	}
+
+	fclose(fp);
+	return ret;
+}
+
+void wfile(char *file, unsigned long long val)
+{
+	FILE *fp;
+
+	if (check_errortype_available(file, val) != 0) {
+		fprintf(stderr, "%s: no support for error type: 0x%llx\n", progname, val);
+		exit(1);
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+	if (!strcmp(file, EINJ_FLAGS))
+		return;
+#endif
+
+	fp = fopen(file, "w");
+	if (fp == NULL) {
+		fprintf(stderr, "%s: cannot open '%s'\n", progname, file);
+		exit(1);
+	}
+	fprintf(fp, "0x%llx\n", val);
+	if (fclose(fp) == EOF) {
+		fprintf(stderr, "%s: write error on '%s'\n", progname, file);
+		exit(1);
+	}
+}
+
+int is_einj_support(void)
+{
+	if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) {
+		fprintf(stderr, "%s: Error injection not supported, check your BIOS settings\n", progname);
+		return 0;
+	}
+	if (access(EINJ_NOTRIGGER, R_OK|W_OK) == -1) {
+		fprintf(stderr, "%s: Is the einj.ko module loaded?\n", progname);
+		return 0;
+	}
+	return 1;
+}
+
+int is_privileged(void)
+{
+	if (getuid() != 0) {
+		fprintf(stderr, "%s: must be root to run error injection tests\n", progname);
+		return 0;
+	}
+	return 1;
+}
+
+void inject_mem_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);
+}
diff --git a/einj.h b/einj.h
new file mode 100644
index 0000000..a5c8e9a
--- /dev/null
+++ b/einj.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2023 Alibaba Corporation
+ * Authors: Shuai Xue
+ *
+ * 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.
+ */
+
+#ifndef EINJ_H
+#define EINJ_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/version.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#define EINJ_ETYPE "/sys/kernel/debug/apei/einj/error_type"
+#define EINJ_ETYPE_AVAILABLE "/sys/kernel/debug/apei/einj/available_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_SBDF "/sys/kernel/debug/apei/einj/param4"
+#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"
+#define EINJ_VENDOR "/sys/kernel/debug/apei/einj/vendor"
+
+#define PRINT_INJECTING printf("injecting ...\n")
+#define PRINT_TRIGGERING printf("triggering ...\n")
+
+extern char *progname;
+extern int Sflag;
+extern long pagesize;
+
+int check_errortype_available(char *file, unsigned long long val);
+
+void wfile(char *file, unsigned long long val);
+
+int is_einj_support(void);
+
+int is_privileged(void);
+
+void inject_mem_uc(unsigned long long addr, void *vaddr, int notrigger);
+
+#endif /* EINJ_H */
diff --git a/einj_mem_uc.c b/einj_mem_uc.c
index 88764d0..16df329 100644
--- a/einj_mem_uc.c
+++ b/einj_mem_uc.c
@@ -9,59 +9,44 @@
  * Free Software Foundation.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include <fcntl.h>
-#include <string.h>
 #include <time.h>
-#include <sys/mman.h>
 #include <sys/time.h>
 #include <setjmp.h>
 #include <signal.h>
 #define _GNU_SOURCE 1
 #define __USE_GNU 1
 #include <sched.h>
-#include <errno.h>
 #include <sys/syscall.h>
 #include <linux/futex.h>
 #include <pthread.h>
 #include <sys/wait.h>
-#include <linux/version.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 char *progname;
 static int nsockets, ncpus, lcpus_persocket;
 static int force_flag;
 static int cmci_skip_flag;
 static int all_flag;
-static int Sflag;
-static long pagesize;
 static int *apicmap;
 static int child_process;
 
 #define	CACHE_LINE_SIZE	64
 #define	DOUBLE_INJECT_OFFSET (pagesize / 4)
 
-#define EINJ_ETYPE "/sys/kernel/debug/apei/einj/error_type"
-#define EINJ_ETYPE_AVAILABLE "/sys/kernel/debug/apei/einj/available_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"
-#define EINJ_VENDOR "/sys/kernel/debug/apei/einj/vendor"
-
 /*
  * Vendor extensions for platform specific operations
  */
@@ -74,78 +59,6 @@
 	int8_t	reserved[3];
 };
 
-#define PRINT_INJECTING printf("injecting ...\n")
-#define PRINT_TRIGGERING printf("triggering ...\n")
-
-static int check_errortype_available(char *file, unsigned long long val)
-{
-	FILE *fp;
-	int ret = -1;
-	unsigned long long available_error_type;
-
-	if (strcmp(file, EINJ_ETYPE) != 0) return 0;
-
-	fp = fopen(EINJ_ETYPE_AVAILABLE, "r");
-	if (!fp) {
-		fprintf(stderr, "%s: cannot open '%s'\n", progname, file);
-		exit(1);
-	}
-
-	while (fscanf(fp, "%llx%*[^\n]", &available_error_type) == 1) {
-		if (val == available_error_type) {
-			ret = 0;
-			break;
-		}
-	}
-
-	fclose(fp);
-	return ret;
-}
-
-static void wfile(char *file, unsigned long long val)
-{
-	FILE *fp;
-
-	if (check_errortype_available(file, val) != 0) {
-		fprintf(stderr, "%s: no support for error type: 0x%llx\n", progname, val);
-		exit(1);
-	}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
-	if (!strcmp(file, EINJ_FLAGS))
-		return;
-#endif
-
-	fp = fopen(file, "w");
-	if (fp == NULL) {
-		fprintf(stderr, "%s: cannot open '%s'\n", progname, file);
-		exit(1);
-	}
-	fprintf(fp, "0x%llx\n", val);
-	if (fclose(fp) == EOF) {
-		fprintf(stderr, "%s: write error on '%s'\n", progname, file);
-		exit(1);
-	}
-}
-
-static void inject_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);
-}
-
 static void inject_double_uc(unsigned long long addr, void *vaddr, int notrigger)
 {
 	PRINT_INJECTING;
@@ -315,27 +228,7 @@
 }
 #endif
 
-static int is_privileged(void)
-{
-	if (getuid() != 0) {
-		fprintf(stderr, "%s: must be root to run error injection tests\n", progname);
-		return 0;
-	}
-	return 1;
-}
 
-static int is_einj_support(void)
-{
-	if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) {
-		fprintf(stderr, "%s: Error injection not supported, check your BIOS settings\n", progname);
-		return 0;
-	}
-	if (access(EINJ_NOTRIGGER, R_OK|W_OK) == -1) {
-		fprintf(stderr, "%s: Is the einj.ko module loaded?\n", progname);
-		return 0;
-	}
-	return 1;
-}
 
 #ifdef __x86_64__
 static int is_advanced_ras(char *model, int modelnum)
@@ -906,27 +799,27 @@
 } tests[] = {
 	{
 		"single", "Single read in pipeline to target address, generates SRAR machine check",
-		data_alloc, inject_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
+		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_uc, 1, trigger_double, F_MCE|F_CMCI|F_SIGBUS,
+		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_uc, 1, trigger_split, F_MCE|F_CMCI|F_SIGBUS|F_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_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
+		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_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
+		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_uc, 1, trigger_write, F_CMCI,
+		data_alloc, inject_mem_uc, 1, trigger_write, F_CMCI,
 	},
 #ifdef __aarch64__
 	{
@@ -971,44 +864,44 @@
 	},
 	{
 		"strbyte", "Write to target address. Should generate a UCNA/CMCI",
-		data_alloc, inject_uc, 1, trigger_write_byte, F_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_uc, 1, trigger_write_word, F_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_uc, 1, trigger_write_dword, F_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_uc, 1, trigger_write_qword, F_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_uc, 1, trigger_prefetch, F_CMCI,
+		data_alloc, inject_mem_uc, 1, trigger_prefetch, F_CMCI,
 	},
 	{
 		"memcpy", "Streaming read from target address. Probably fatal",
-		data_alloc, inject_uc, 1, trigger_memcpy, F_MCE|F_CMCI|F_SIGBUS|F_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_uc, 1, trigger_instr, F_MCE|F_CMCI,
+		instr_alloc, inject_mem_uc, 1, trigger_instr, F_MCE|F_CMCI,
 	},
 	{
 		"patrol", "Patrol scrubber, generates SRAO machine check",
-		data_alloc, inject_uc, 0, trigger_patrol, F_EITHER|F_LONGWAIT,
+		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_uc, 1, trigger_thread, F_MCE|F_CMCI|F_SIGBUS,
+		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_uc, 1, trigger_share, F_MCE|F_CMCI|F_SIGBUS,
+		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",
@@ -1020,23 +913,23 @@
 	},
 	{
 		"copyin", "Kernel copies data from user. Probably fatal",
-		data_alloc, inject_uc, 1, trigger_copyin, F_MCE|F_CMCI|F_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_uc, 1, trigger_copyout, F_MCE|F_CMCI|F_SIGBUS|F_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_uc, 1, trigger_copy_on_write, F_MCE|F_CMCI|F_SIGBUS|F_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_uc, 1, trigger_futex, F_MCE|F_CMCI|F_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_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
+		mlock_data_alloc, inject_mem_uc, 1, trigger_single, F_MCE|F_CMCI|F_SIGBUS,
 	},
 	{
 		"core_ce", "Core corrected error",
diff --git a/hornet.c b/hornet.c
index 9763e5e..6a27697 100644
--- a/hornet.c
+++ b/hornet.c
@@ -15,12 +15,7 @@
  * memory address
  */
 
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <fcntl.h>
-#include <errno.h>
 #include <time.h>
 #include <sys/types.h>
 #include <sys/signal.h>
@@ -30,14 +25,16 @@
 #include <linux/ptrace.h>
 #include <sys/uio.h>
 #include <elf.h>
-
-static char *progname;
+#include "einj.h"
 
 long	addr;
 double	delay;
 int	pid;
 int	tflag, dflag, bflag, sflag, mflag, pflag, vflag;
 int 	trace;
+char	*progname;
+long	pagesize;
+int	Sflag;
 
 static void usage(void)
 {
@@ -48,12 +45,6 @@
 	exit(1);
 }
 
-#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_NOTRIGGER "/sys/kernel/debug/apei/einj/notrigger"
-#define EINJ_DOIT "/sys/kernel/debug/apei/einj/error_inject"
-
 #define check_ptrace(req, pid, addr, data) 				\
 	do {								\
 		if (ptrace(req, pid, addr, data) == -1) {		\
@@ -96,22 +87,6 @@
 	})
 #endif
 
-static void wfile(char *file, unsigned long val)
-{
-	FILE *fp;
-
-	fp = fopen(file, "w");
-	if (fp == NULL) {
-		perror(file);
-		exit(1);
-	}
-	fprintf(fp, "0x%lx\n", val);
-	if (fclose(fp) == EOF) {
-		perror(file);
-		exit(1);
-	}
-}
-
 static int startproc(char **args)
 {
 	int	pid;
diff --git a/memattr.c b/memattr.c
index 3e2dc45..7464a69 100644
--- a/memattr.c
+++ b/memattr.c
@@ -7,11 +7,8 @@
  * Free Software Foundation.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
+
 #include <fcntl.h>
-#include <string.h>
 #include <time.h>
 #include <sys/mman.h>
 #include <sys/time.h>
@@ -20,9 +17,13 @@
 #define _GNU_SOURCE 1
 #define __USE_GNU 1
 #include <sched.h>
-#include <errno.h>
 #include <sys/syscall.h>
 #include <linux/futex.h>
+#include "einj.h"
+
+char *progname;
+long pagesize;
+int Sflag;
 
 typedef struct
 {
@@ -39,54 +40,6 @@
 #define DEV_NAME "/dev/pgprot_drv"
 #define PAGE_SHIFT 12
 static mpgprot_drv_ctx *ctx = NULL;
-static char *progname;
-
-#define EINJ_ETYPE "/sys/kernel/debug/apei/einj/error_type"
-#define EINJ_ETYPE_AVAILABLE "/sys/kernel/debug/apei/einj/available_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"
-#define EINJ_VENDOR "/sys/kernel/debug/apei/einj/vendor"
-
-static int is_privileged(void)
-{
-	if (getuid() != 0) {
-		fprintf(stderr, "%s: must be root to run error injection tests\n", progname);
-		return 0;
-	}
-	return 1;
-}
-
-static void wfile(char *file, unsigned long long val)
-{
-	FILE *fp;
-
-	fp = fopen(file, "w");
-	if (fp == NULL)
-	{
-		fprintf(stderr, "%s: cannot open '%s'\n", progname, file);
-		exit(1);
-	}
-	fprintf(fp, "0x%llx\n", val);
-	if (fclose(fp) == EOF)
-	{
-		fprintf(stderr, "%s: write error on '%s'\n", progname, file);
-		exit(1);
-	}
-}
-
-static void inject_uc(unsigned long long addr, void *vaddr, int notrigger)
-{
-	wfile(EINJ_ETYPE, 0x20);
-	wfile(EINJ_ADDR, addr);
-	wfile(EINJ_MASK, ~0x0ul);
-	wfile(EINJ_FLAGS, 2);
-	wfile(EINJ_NOTRIGGER, notrigger);
-	wfile(EINJ_DOIT, 1);
-}
 
 int trigger_write(char *addr)
 {
@@ -191,7 +144,7 @@
 		/* pick from kernel */
 		long long int paddr = ctx->paddr;
 		printf("vaddr = %p paddr = %llx\n", vaddr, paddr);
-		inject_uc(paddr, vaddr, 1);
+		inject_mem_uc(paddr, vaddr, 1);
 		sleep(3);
 		trigger_write(vaddr);
 	}
diff --git a/rep_ce_page.c b/rep_ce_page.c
index 479ec6f..985ca4a 100644
--- a/rep_ce_page.c
+++ b/rep_ce_page.c
@@ -13,39 +13,17 @@
  * Allocate memory - loop using EINJ to inject a soft error,
  * consuming after each until the page is taken offline.
  */
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <unistd.h>
-
 #include <sys/mman.h>
+#include "einj.h"
 
-#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_NOTRIGGER "/sys/kernel/debug/apei/einj/notrigger"
-#define EINJ_DOIT "/sys/kernel/debug/apei/einj/error_inject"
+char *progname;
+long pagesize;
+int Sflag;
 
 volatile int trigger;
 
 extern unsigned long long vtop(unsigned long long addr, pid_t pid);
 
-static void wfile(char *file, unsigned long val)
-{
-	FILE *fp;
-
-	fp = fopen(file, "w");
-	if (fp == NULL) {
-		perror(file);
-		exit(1);
-	}
-	fprintf(fp, "0x%lx\n", val);
-	if (fclose(fp) == EOF) {
-		perror(file);
-		exit(1);
-	}
-}
-
 #define MAX_TRIES 30
 
 int main(int argc, char **argv)
@@ -56,6 +34,8 @@
 	int i;
 	pid_t pid;
 
+	progname = argv[0];
+
 	if (argc == 2)
 		tries = atoi(argv[1]);