| // SPDX-License-Identifier: GPL-2.0 | 
 |  | 
 | /* | 
 |  * Copyright (C) 2022 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 - loop using EINJ to inject a soft error, | 
 |  * consuming after each until the page is taken offline. | 
 |  */ | 
 | #include <sys/mman.h> | 
 | #include "einj.h" | 
 |  | 
 | char *progname; | 
 | long pagesize; | 
 | int Sflag; | 
 |  | 
 | volatile int trigger; | 
 |  | 
 | extern unsigned long long vtop(unsigned long long addr, pid_t pid); | 
 |  | 
 | #define MAX_TRIES 30 | 
 |  | 
 | int main(int argc, char **argv) | 
 | { | 
 | 	char *addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); | 
 | 	unsigned long long paddr; | 
 | 	int tries = MAX_TRIES; | 
 | 	int i; | 
 | 	pid_t pid; | 
 |  | 
 | 	progname = argv[0]; | 
 |  | 
 | 	if (argc == 2) | 
 | 		tries = atoi(argv[1]); | 
 |  | 
 | 	if (addr == MAP_FAILED) { | 
 | 		perror("mmap"); | 
 | 		return 1; | 
 | 	} | 
 | 	pid = getpid(); | 
 |  | 
 | 	wfile(EINJ_ETYPE, 0x8); | 
 | 	wfile(EINJ_MASK, ~0x0ul); | 
 | 	wfile(EINJ_NOTRIGGER, 1); | 
 |  | 
 | 	*addr = '*'; | 
 | 	paddr = vtop((unsigned long long)addr, pid); | 
 |  | 
 | 	for (i = 0; i < tries; i++) { | 
 | 		printf("%d: Inject to vaddr=%p paddr=0x%llx\n", i, addr, paddr); | 
 | 		wfile(EINJ_ADDR, paddr); | 
 | 		wfile(EINJ_DOIT, 1); | 
 | 		usleep(250); | 
 | 		trigger += *addr; | 
 | 		sleep(2); | 
 | 		if (paddr != vtop((unsigned long long)addr, pid)) | 
 | 			break; | 
 | 	} | 
 |  | 
 | 	if (i == tries) { | 
 | 		fprintf(stderr, "FAIL: Page was not offline after %d errors\n", i); | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	printf("PASS: page taken offline after %d corrected errors\n", i + 1); | 
 | 	return 0; | 
 | } |