1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * ttranshuge.c: hwpoison test for THP(Transparent Huge Page).
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Copyright (C) 2011, FUJITSU LIMITED.
5f08c3bdfSopenharmony_ci *   Author: Jin Dongming <jin.dongming@css.cn.fujitsu.com>
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * This program is released under the GPLv2.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This program is based on tinject.c and thugetlb.c in tsrc/ directory
10f08c3bdfSopenharmony_ci * in mcetest tool.
11f08c3bdfSopenharmony_ci */
12f08c3bdfSopenharmony_ci
13f08c3bdfSopenharmony_ci/*
14f08c3bdfSopenharmony_ci * Even if THP is supported by Kernel, it could not be sure all the pages
15f08c3bdfSopenharmony_ci * you gotten belong to THP.
16f08c3bdfSopenharmony_ci *
17f08c3bdfSopenharmony_ci * Following is the structure of the memory mapped by mmap()
18f08c3bdfSopenharmony_ci * when the requested memory size is 8M and the THP's size is 2M,
19f08c3bdfSopenharmony_ci *     O: means page belongs to 4k page;
20f08c3bdfSopenharmony_ci *     T: means page belongs to THP.
21f08c3bdfSopenharmony_ci *             Base             .....                   (Base + Size)
22f08c3bdfSopenharmony_ci *     Size :  0M . . . . . 2M . . . . . 4M . . . . . 6M . . . . . 8M
23f08c3bdfSopenharmony_ci *     case0:  OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
24f08c3bdfSopenharmony_ci *             No THP.
25f08c3bdfSopenharmony_ci *     case1:  OOOOOOOTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTOOOOOO
26f08c3bdfSopenharmony_ci *             Mixed with THP where it is possible.
27f08c3bdfSopenharmony_ci *     case2:  OOOOOOOOOOOOOOOOOOOOOOOOOOTTTTTTTTTTTTTTTTTTTTTTTTTT
28f08c3bdfSopenharmony_ci *             Mixed with THP only some part of where it is possible.
29f08c3bdfSopenharmony_ci *     case3:  TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
30f08c3bdfSopenharmony_ci *             All pages are belong to THP.
31f08c3bdfSopenharmony_ci *
32f08c3bdfSopenharmony_ci * So the function find_thp_addr() could not be sure the calculated
33f08c3bdfSopenharmony_ci * address is the address of THP. And in the above structure,
34f08c3bdfSopenharmony_ci * the right address of THP could not be gotten in case 0 and 2 and
35f08c3bdfSopenharmony_ci * could be gotten in case 1 and 3 only.
36f08c3bdfSopenharmony_ci *
37f08c3bdfSopenharmony_ci * According to my experience, the most case gotten by APL is case 1.
38f08c3bdfSopenharmony_ci * So this program is made based on the case 1.
39f08c3bdfSopenharmony_ci *
40f08c3bdfSopenharmony_ci * To improve the rate of THP mapped by mmap(), it is better to do
41f08c3bdfSopenharmony_ci * hwpoison test:
42f08c3bdfSopenharmony_ci *     - After reboot immediately.
43f08c3bdfSopenharmony_ci *       Because there is a lot of freed memory.
44f08c3bdfSopenharmony_ci *     - In the system which has plenty of memory prepared.
45f08c3bdfSopenharmony_ci *       This can avoid hwpoison test failure caused by not enough memory.
46f08c3bdfSopenharmony_ci */
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ci#define _GNU_SOURCE 1
49f08c3bdfSopenharmony_ci#include <stdlib.h>
50f08c3bdfSopenharmony_ci#include <stdio.h>
51f08c3bdfSopenharmony_ci#include <string.h>
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci#include <unistd.h>
54f08c3bdfSopenharmony_ci#include <getopt.h>
55f08c3bdfSopenharmony_ci#include <signal.h>
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci#include <sys/prctl.h>
58f08c3bdfSopenharmony_ci#include <sys/mman.h>
59f08c3bdfSopenharmony_ci#include <sys/wait.h>
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ci/*
62f08c3bdfSopenharmony_ci * This file supposes the following as default.
63f08c3bdfSopenharmony_ci *     Regular Page Size  :  4K(4096Bytes)
64f08c3bdfSopenharmony_ci *     THP's Size         :  2M(2UL * 1024 *1024Bytes)
65f08c3bdfSopenharmony_ci *     Poisoned Page Size :  4K(4096Bytes)
66f08c3bdfSopenharmony_ci */
67f08c3bdfSopenharmony_ci#define DEFAULT_PS			4096UL
68f08c3bdfSopenharmony_ci#define PS_MASK(ps_size)		((unsigned long)(ps_size -1))
69f08c3bdfSopenharmony_ci#define DEFAULT_THP_SIZE		0x200000UL
70f08c3bdfSopenharmony_ci#define THP_MASK(thp_size)		((unsigned long)(thp_size - 1))
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci#define REQ_MEM_SIZE			(8UL * 1024 * 1024)
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci#define MADV_POISON			100
75f08c3bdfSopenharmony_ci#define MADV_HUGEPAGE			14
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci#define PR_MCE_KILL			33
78f08c3bdfSopenharmony_ci#define PR_MCE_KILL_SET			1
79f08c3bdfSopenharmony_ci#define PR_MCE_KILL_EARLY		1
80f08c3bdfSopenharmony_ci#define PR_MCE_KILL_LATE		0
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_ci#define THP_SUCCESS			0
83f08c3bdfSopenharmony_ci#define THP_FAILURE			-1
84f08c3bdfSopenharmony_ci
85f08c3bdfSopenharmony_ci#define print_err(fmt, ...)		printf("[ERROR] "fmt, ##__VA_ARGS__)
86f08c3bdfSopenharmony_ci#define print_success(fmt, ...)		printf("[SUCCESS] "fmt, ##__VA_ARGS__)
87f08c3bdfSopenharmony_ci#define print_failure(fmt, ...)		printf("[FAILURE] "fmt, ##__VA_ARGS__)
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_cistatic char *corrupt_page_addr;
90f08c3bdfSopenharmony_cistatic char *mem_addr;
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_cistatic unsigned int early_kill = 0;
93f08c3bdfSopenharmony_cistatic unsigned int avoid_touch = 0;
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic int corrupt_page = -1;
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_cistatic unsigned long thp_addr = 0;
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_cistatic void print_prep_info(void)
100f08c3bdfSopenharmony_ci{
101f08c3bdfSopenharmony_ci	printf("\n%s Poison Test of THP.\n\n"
102f08c3bdfSopenharmony_ci		"Information:\n"
103f08c3bdfSopenharmony_ci		"    PID %d\n"
104f08c3bdfSopenharmony_ci		"    PS(page size) 0x%lx\n"
105f08c3bdfSopenharmony_ci		"    mmap()'ed Memory Address %p; size 0x%lx\n"
106f08c3bdfSopenharmony_ci		"    THP(Transparent Huge Page) Address 0x%lx; size 0x%lx\n"
107f08c3bdfSopenharmony_ci		"    %s Page Poison Test At %p\n\n",
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci		early_kill ? "Early Kill" : "Late Kill",
110f08c3bdfSopenharmony_ci		getpid(),
111f08c3bdfSopenharmony_ci		DEFAULT_PS,
112f08c3bdfSopenharmony_ci		mem_addr, REQ_MEM_SIZE,
113f08c3bdfSopenharmony_ci		thp_addr, DEFAULT_THP_SIZE,
114f08c3bdfSopenharmony_ci		(corrupt_page == 0) ? "Head" : "Tail", corrupt_page_addr
115f08c3bdfSopenharmony_ci	);
116f08c3bdfSopenharmony_ci}
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_ci/*
119f08c3bdfSopenharmony_ci * Usage:
120f08c3bdfSopenharmony_ci *     If avoid_flag == 1,
121f08c3bdfSopenharmony_ci *         access all the memory except one DEFAULT_PS size memory
122f08c3bdfSopenharmony_ci *         after the address in global variable corrupt_page_addr;
123f08c3bdfSopenharmony_ci *     else
124f08c3bdfSopenharmony_ci *         access all the memory from addr to (addr + size).
125f08c3bdfSopenharmony_ci */
126f08c3bdfSopenharmony_cistatic int read_mem(char *addr, unsigned long size, int avoid_flag)
127f08c3bdfSopenharmony_ci{
128f08c3bdfSopenharmony_ci	int ret = 0;
129f08c3bdfSopenharmony_ci	unsigned long i = 0;
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci	for (i = 0; i < size; i++) {
132f08c3bdfSopenharmony_ci		if ((avoid_flag) &&
133f08c3bdfSopenharmony_ci		    ((addr + i) >= corrupt_page_addr) &&
134f08c3bdfSopenharmony_ci		    ((addr + i) < (corrupt_page_addr + DEFAULT_PS)))
135f08c3bdfSopenharmony_ci			continue;
136f08c3bdfSopenharmony_ci
137f08c3bdfSopenharmony_ci		if (*(addr + i) != (char)('a' + (i % 26))) {
138f08c3bdfSopenharmony_ci			print_err("Mismatch at 0x%lx.\n",
139f08c3bdfSopenharmony_ci					(unsigned long)(addr + i));
140f08c3bdfSopenharmony_ci			ret = -1;
141f08c3bdfSopenharmony_ci			break;
142f08c3bdfSopenharmony_ci		}
143f08c3bdfSopenharmony_ci	}
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_ci	return ret;
146f08c3bdfSopenharmony_ci}
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_cistatic void write_mem(char *addr, unsigned long size)
149f08c3bdfSopenharmony_ci{
150f08c3bdfSopenharmony_ci	int i = 0;
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci	for (i = 0; i < size; i++) {
153f08c3bdfSopenharmony_ci		*(addr + i) = (char)('a' + (i % 26));
154f08c3bdfSopenharmony_ci	}
155f08c3bdfSopenharmony_ci}
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_ci/*
158f08c3bdfSopenharmony_ci * Usage:
159f08c3bdfSopenharmony_ci *     Use MADV_HUGEPAGE to make sure the page could be mapped as THP
160f08c3bdfSopenharmony_ci *     when /sys/kernel/mm/transparent_hugepage/enabled is set with
161f08c3bdfSopenharmony_ci *     madvise.
162f08c3bdfSopenharmony_ci *
163f08c3bdfSopenharmony_ci * Note:
164f08c3bdfSopenharmony_ci *     MADV_HUGEPAGE must be set between mmap and read/write operation.
165f08c3bdfSopenharmony_ci *     And it must follow mmap(). Please refer to patches of
166f08c3bdfSopenharmony_ci *     MADV_HUGEPAGE about THP for more details.
167f08c3bdfSopenharmony_ci *
168f08c3bdfSopenharmony_ci * Patch Information:
169f08c3bdfSopenharmony_ci *     Title: thp: khugepaged: make khugepaged aware about madvise
170f08c3bdfSopenharmony_ci *     commit 60ab3244ec85c44276c585a2a20d3750402e1cf4
171f08c3bdfSopenharmony_ci */
172f08c3bdfSopenharmony_cistatic int request_thp_with_madvise(unsigned long start)
173f08c3bdfSopenharmony_ci{
174f08c3bdfSopenharmony_ci	unsigned long madvise_addr = start & ~PS_MASK(DEFAULT_PS);
175f08c3bdfSopenharmony_ci	unsigned long madvise_size = REQ_MEM_SIZE - (start % DEFAULT_PS);
176f08c3bdfSopenharmony_ci
177f08c3bdfSopenharmony_ci	return madvise((void *)madvise_addr, madvise_size, MADV_HUGEPAGE);
178f08c3bdfSopenharmony_ci}
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci/*
181f08c3bdfSopenharmony_ci * Usage:
182f08c3bdfSopenharmony_ci *     This function is used for getting the address of first THP.
183f08c3bdfSopenharmony_ci *
184f08c3bdfSopenharmony_ci * Note:
185f08c3bdfSopenharmony_ci *     This function could not make sure the address is the address of THP
186f08c3bdfSopenharmony_ci *     really. Please refer to the explanation of mmap() of THP
187f08c3bdfSopenharmony_ci *     at the head of this file.
188f08c3bdfSopenharmony_ci */
189f08c3bdfSopenharmony_cistatic unsigned long find_thp_addr(unsigned long start, unsigned long size)
190f08c3bdfSopenharmony_ci{
191f08c3bdfSopenharmony_ci	unsigned long thp_align_addr = (start + (DEFAULT_THP_SIZE - 1)) &
192f08c3bdfSopenharmony_ci					~THP_MASK(DEFAULT_THP_SIZE);
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci	if ((thp_align_addr >= start) &&
195f08c3bdfSopenharmony_ci	    ((thp_align_addr + DEFAULT_THP_SIZE) < (start + size)))
196f08c3bdfSopenharmony_ci		return thp_align_addr;
197f08c3bdfSopenharmony_ci
198f08c3bdfSopenharmony_ci	return 0;
199f08c3bdfSopenharmony_ci}
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_cistatic int prep_memory_map(void)
202f08c3bdfSopenharmony_ci{
203f08c3bdfSopenharmony_ci	mem_addr = (char *)mmap(NULL, REQ_MEM_SIZE, PROT_WRITE | PROT_READ,
204f08c3bdfSopenharmony_ci				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
205f08c3bdfSopenharmony_ci	if (mem_addr == NULL) {
206f08c3bdfSopenharmony_ci		print_err("Failed to mmap requested memory: size 0x%lx.\n",
207f08c3bdfSopenharmony_ci				REQ_MEM_SIZE);
208f08c3bdfSopenharmony_ci		return THP_FAILURE;
209f08c3bdfSopenharmony_ci	}
210f08c3bdfSopenharmony_ci
211f08c3bdfSopenharmony_ci	return THP_SUCCESS;
212f08c3bdfSopenharmony_ci}
213f08c3bdfSopenharmony_ci
214f08c3bdfSopenharmony_cistatic int prep_injection(void)
215f08c3bdfSopenharmony_ci{
216f08c3bdfSopenharmony_ci	/* enabled(=madvise) in /sys/kernel/mm/transparent_hugepage/. */
217f08c3bdfSopenharmony_ci	if (request_thp_with_madvise((unsigned long)mem_addr) < 0) {
218f08c3bdfSopenharmony_ci		print_err("Failed to request THP for [madvise] in enabled.\n");
219f08c3bdfSopenharmony_ci		return THP_FAILURE;
220f08c3bdfSopenharmony_ci	}
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_ci	write_mem(mem_addr, REQ_MEM_SIZE);
223f08c3bdfSopenharmony_ci	if (read_mem(mem_addr, REQ_MEM_SIZE, 0) < 0) {
224f08c3bdfSopenharmony_ci		print_err("Data is Mismatched(prep_injection).\n");
225f08c3bdfSopenharmony_ci		return THP_FAILURE;
226f08c3bdfSopenharmony_ci	}
227f08c3bdfSopenharmony_ci
228f08c3bdfSopenharmony_ci	/* find the address of THP. */
229f08c3bdfSopenharmony_ci	thp_addr = find_thp_addr((unsigned long)mem_addr, REQ_MEM_SIZE);
230f08c3bdfSopenharmony_ci	if (!thp_addr) {
231f08c3bdfSopenharmony_ci		print_err("No THP mapped.\n");
232f08c3bdfSopenharmony_ci		return THP_FAILURE;
233f08c3bdfSopenharmony_ci	}
234f08c3bdfSopenharmony_ci
235f08c3bdfSopenharmony_ci	/* Calculate the address of the page which will be poisoned */
236f08c3bdfSopenharmony_ci	if (corrupt_page < 0)
237f08c3bdfSopenharmony_ci		corrupt_page = 0;
238f08c3bdfSopenharmony_ci
239f08c3bdfSopenharmony_ci	corrupt_page_addr = (char *)(thp_addr + corrupt_page * DEFAULT_PS);
240f08c3bdfSopenharmony_ci
241f08c3bdfSopenharmony_ci	/* Process will be killed here by kernel(SIGBUS AO). */
242f08c3bdfSopenharmony_ci	prctl(PR_MCE_KILL, PR_MCE_KILL_SET,
243f08c3bdfSopenharmony_ci		early_kill ? PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE,
244f08c3bdfSopenharmony_ci		NULL, NULL);
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_ci	return THP_SUCCESS;
247f08c3bdfSopenharmony_ci}
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_cistatic int do_injection(void)
250f08c3bdfSopenharmony_ci{
251f08c3bdfSopenharmony_ci	/* Early Kill */
252f08c3bdfSopenharmony_ci	if (madvise((void *)corrupt_page_addr, DEFAULT_PS, MADV_POISON) != 0) {
253f08c3bdfSopenharmony_ci		print_err("Failed to poison at 0x%p.\n", corrupt_page_addr);
254f08c3bdfSopenharmony_ci		printf("[INFO] Please check the authority of current user.\n");
255f08c3bdfSopenharmony_ci		return THP_FAILURE;
256f08c3bdfSopenharmony_ci	}
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci	return THP_SUCCESS;
259f08c3bdfSopenharmony_ci}
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_cistatic int post_injection(void)
262f08c3bdfSopenharmony_ci{
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	if (early_kill) {
265f08c3bdfSopenharmony_ci		print_err("Failed to be killed by SIGBUS(Action Optional).\n");
266f08c3bdfSopenharmony_ci		return THP_FAILURE;
267f08c3bdfSopenharmony_ci	}
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_ci	/* Late Kill */
270f08c3bdfSopenharmony_ci	if (read_mem(mem_addr, REQ_MEM_SIZE, avoid_touch) < 0) {
271f08c3bdfSopenharmony_ci		print_err("Data is Mismatched(do_injection).\n");
272f08c3bdfSopenharmony_ci		return THP_FAILURE;
273f08c3bdfSopenharmony_ci	}
274f08c3bdfSopenharmony_ci
275f08c3bdfSopenharmony_ci	if (!avoid_touch) {
276f08c3bdfSopenharmony_ci		print_err("Failed to be killed by SIGBUS(Action Required).\n");
277f08c3bdfSopenharmony_ci		return THP_FAILURE;
278f08c3bdfSopenharmony_ci	}
279f08c3bdfSopenharmony_ci
280f08c3bdfSopenharmony_ci	return THP_SUCCESS;
281f08c3bdfSopenharmony_ci}
282f08c3bdfSopenharmony_ci
283f08c3bdfSopenharmony_cistatic void post_memory_map()
284f08c3bdfSopenharmony_ci{
285f08c3bdfSopenharmony_ci	munmap(mem_addr, REQ_MEM_SIZE);
286f08c3bdfSopenharmony_ci}
287f08c3bdfSopenharmony_ci
288f08c3bdfSopenharmony_cistatic void usage(char *program)
289f08c3bdfSopenharmony_ci{
290f08c3bdfSopenharmony_ci	printf("%s [-o offset] [-ea]\n"
291f08c3bdfSopenharmony_ci" Usage:\n"
292f08c3bdfSopenharmony_ci"	-o|--offset offset(page unit)	Position of error injection from the first THP.\n"
293f08c3bdfSopenharmony_ci"	-e|--early-kill			Set PR_MCE_KILL_EARLY(default NOT early-kill).\n"
294f08c3bdfSopenharmony_ci"	-a|--avoid-touch		Avoid touching error page(page unit) and\n"
295f08c3bdfSopenharmony_ci"					only used when early-kill is not set.\n"
296f08c3bdfSopenharmony_ci"	-h|--help\n\n"
297f08c3bdfSopenharmony_ci" Examples:\n"
298f08c3bdfSopenharmony_ci"	1. Inject the 2nd page(4k) of THP and early killed.\n"
299f08c3bdfSopenharmony_ci"	%s -o 1 -e\n\n"
300f08c3bdfSopenharmony_ci"	2. Inject the 4th page(4k) of THP, late killed and untouched.\n"
301f08c3bdfSopenharmony_ci"	%s --offset 3 --avoid-touch\n\n"
302f08c3bdfSopenharmony_ci" Note:\n"
303f08c3bdfSopenharmony_ci"	Options				Default set\n"
304f08c3bdfSopenharmony_ci"	early-kill			no\n"
305f08c3bdfSopenharmony_ci"	offset				0(head page)\n"
306f08c3bdfSopenharmony_ci"	avoid-touch			no\n\n"
307f08c3bdfSopenharmony_ci	, program, program, program);
308f08c3bdfSopenharmony_ci}
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_cistatic struct option opts[] = {
311f08c3bdfSopenharmony_ci	{ "offset"		, 1, NULL, 'o' },
312f08c3bdfSopenharmony_ci	{ "avoid-touch"		, 0, NULL, 'a' },
313f08c3bdfSopenharmony_ci	{ "early-kill"		, 0, NULL, 'e' },
314f08c3bdfSopenharmony_ci	{ "help"		, 0, NULL, 'h' },
315f08c3bdfSopenharmony_ci	{ NULL			, 0, NULL,  0  }
316f08c3bdfSopenharmony_ci};
317f08c3bdfSopenharmony_ci
318f08c3bdfSopenharmony_cistatic void get_options_or_die(int argc, char *argv[])
319f08c3bdfSopenharmony_ci{
320f08c3bdfSopenharmony_ci	char c;
321f08c3bdfSopenharmony_ci
322f08c3bdfSopenharmony_ci	while ((c = getopt_long(argc, argv, "o:aeh", opts, NULL)) != -1) {
323f08c3bdfSopenharmony_ci		switch (c) {
324f08c3bdfSopenharmony_ci		case 'o':
325f08c3bdfSopenharmony_ci			corrupt_page = strtol(optarg, NULL, 10);
326f08c3bdfSopenharmony_ci			break;
327f08c3bdfSopenharmony_ci		case 'a':
328f08c3bdfSopenharmony_ci			avoid_touch = 1;
329f08c3bdfSopenharmony_ci			break;
330f08c3bdfSopenharmony_ci		case 'e':
331f08c3bdfSopenharmony_ci			early_kill = 1;
332f08c3bdfSopenharmony_ci			break;
333f08c3bdfSopenharmony_ci		case 'h':
334f08c3bdfSopenharmony_ci			usage(argv[0]);
335f08c3bdfSopenharmony_ci			exit(0);
336f08c3bdfSopenharmony_ci		default:
337f08c3bdfSopenharmony_ci			print_err("Wrong options, please check options!\n");
338f08c3bdfSopenharmony_ci			usage(argv[0]);
339f08c3bdfSopenharmony_ci			exit(1);
340f08c3bdfSopenharmony_ci		}
341f08c3bdfSopenharmony_ci	}
342f08c3bdfSopenharmony_ci
343f08c3bdfSopenharmony_ci	if ((avoid_touch) && (corrupt_page == -1)) {
344f08c3bdfSopenharmony_ci		print_err("Avoid which page?\n");
345f08c3bdfSopenharmony_ci		usage(argv[0]);
346f08c3bdfSopenharmony_ci		exit(1);
347f08c3bdfSopenharmony_ci	}
348f08c3bdfSopenharmony_ci}
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
351f08c3bdfSopenharmony_ci{
352f08c3bdfSopenharmony_ci	int ret = THP_FAILURE;
353f08c3bdfSopenharmony_ci	pid_t child;
354f08c3bdfSopenharmony_ci	siginfo_t sig;
355f08c3bdfSopenharmony_ci
356f08c3bdfSopenharmony_ci	/*
357f08c3bdfSopenharmony_ci	 * 1. Options check.
358f08c3bdfSopenharmony_ci	 */
359f08c3bdfSopenharmony_ci	get_options_or_die(argc, argv);
360f08c3bdfSopenharmony_ci
361f08c3bdfSopenharmony_ci	/* Fork a child process for test */
362f08c3bdfSopenharmony_ci	child = fork();
363f08c3bdfSopenharmony_ci	if (child < 0) {
364f08c3bdfSopenharmony_ci		print_err("Failed to fork child process.\n");
365f08c3bdfSopenharmony_ci		return THP_FAILURE;
366f08c3bdfSopenharmony_ci	}
367f08c3bdfSopenharmony_ci
368f08c3bdfSopenharmony_ci	if (child == 0) {
369f08c3bdfSopenharmony_ci		/* Child process */
370f08c3bdfSopenharmony_ci
371f08c3bdfSopenharmony_ci		int ret = THP_FAILURE;
372f08c3bdfSopenharmony_ci
373f08c3bdfSopenharmony_ci		signal(SIGBUS, SIG_DFL);
374f08c3bdfSopenharmony_ci
375f08c3bdfSopenharmony_ci		/*
376f08c3bdfSopenharmony_ci		 * 2. Groundwork for hwpoison injection.
377f08c3bdfSopenharmony_ci		 */
378f08c3bdfSopenharmony_ci		if (prep_memory_map() == THP_FAILURE)
379f08c3bdfSopenharmony_ci			_exit(1);
380f08c3bdfSopenharmony_ci
381f08c3bdfSopenharmony_ci		if (prep_injection() == THP_FAILURE)
382f08c3bdfSopenharmony_ci			goto free_mem;
383f08c3bdfSopenharmony_ci
384f08c3bdfSopenharmony_ci		/* Print the prepared information before hwpoison injection. */
385f08c3bdfSopenharmony_ci		print_prep_info();
386f08c3bdfSopenharmony_ci
387f08c3bdfSopenharmony_ci		/*
388f08c3bdfSopenharmony_ci		 * 3. Hwpoison Injection.
389f08c3bdfSopenharmony_ci		 */
390f08c3bdfSopenharmony_ci		if (do_injection() == THP_FAILURE)
391f08c3bdfSopenharmony_ci			goto free_mem;
392f08c3bdfSopenharmony_ci
393f08c3bdfSopenharmony_ci		if (post_injection() == THP_FAILURE)
394f08c3bdfSopenharmony_ci			goto free_mem;
395f08c3bdfSopenharmony_ci
396f08c3bdfSopenharmony_ci		ret = THP_SUCCESS;
397f08c3bdfSopenharmony_cifree_mem:
398f08c3bdfSopenharmony_ci		post_memory_map();
399f08c3bdfSopenharmony_ci
400f08c3bdfSopenharmony_ci		if (ret == THP_SUCCESS)
401f08c3bdfSopenharmony_ci			_exit(0);
402f08c3bdfSopenharmony_ci
403f08c3bdfSopenharmony_ci		_exit(1);
404f08c3bdfSopenharmony_ci	}
405f08c3bdfSopenharmony_ci
406f08c3bdfSopenharmony_ci	/* Parent process */
407f08c3bdfSopenharmony_ci
408f08c3bdfSopenharmony_ci	if (waitid(P_PID, child, &sig, WEXITED) < 0) {
409f08c3bdfSopenharmony_ci		print_err("Failed to wait child process.\n");
410f08c3bdfSopenharmony_ci		return THP_FAILURE;
411f08c3bdfSopenharmony_ci	}
412f08c3bdfSopenharmony_ci
413f08c3bdfSopenharmony_ci	/*
414f08c3bdfSopenharmony_ci	 * 4. Check the result of hwpoison injection.
415f08c3bdfSopenharmony_ci	 */
416f08c3bdfSopenharmony_ci	if (avoid_touch) {
417f08c3bdfSopenharmony_ci		if (sig.si_code == CLD_EXITED && sig.si_status == 0) {
418f08c3bdfSopenharmony_ci			print_success("Child process survived.\n");
419f08c3bdfSopenharmony_ci			ret = THP_SUCCESS;
420f08c3bdfSopenharmony_ci		} else
421f08c3bdfSopenharmony_ci			print_failure("Child process could not survive.\n");
422f08c3bdfSopenharmony_ci	} else {
423f08c3bdfSopenharmony_ci		if (sig.si_code == CLD_KILLED && sig.si_status == SIGBUS) {
424f08c3bdfSopenharmony_ci			print_success("Child process was killed by SIGBUS.\n");
425f08c3bdfSopenharmony_ci			ret = THP_SUCCESS;
426f08c3bdfSopenharmony_ci		} else
427f08c3bdfSopenharmony_ci			print_failure("Child process could not be killed"
428f08c3bdfSopenharmony_ci					" by SIGBUS.\n");
429f08c3bdfSopenharmony_ci	}
430f08c3bdfSopenharmony_ci
431f08c3bdfSopenharmony_ci	return ret;
432f08c3bdfSopenharmony_ci}
433