• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
4  * Author: David Gibson & Adam Litke
5  */
6 
7 /*\
8  * [Description]
9  *
10  * On some old ppc64 kernel, when hpage is mmaped on 32 bit boundary and
11  * normal page below it, it triggers the bug caused by off-by-one error.
12  *
13  * WARNING: The offsets and addresses used within are specifically
14  * calculated to trigger the bug as it existed. Don't mess with them
15  * unless you *really* know what you're doing.
16  */
17 
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <sys/mount.h>
21 #include <limits.h>
22 #include <sys/param.h>
23 #include <sys/types.h>
24 
25 #include "hugetlb.h"
26 
27 #define FOURGB (1ULL << 32)
28 #define MNTPOINT "hugetlbfs/"
29 static int  fd = -1;
30 static unsigned long hpage_size;
31 static int page_size;
32 
run_test(void)33 static void run_test(void)
34 {
35 	void *p, *q = NULL;
36 	unsigned long long lowaddr;
37 	unsigned long long below_start;
38 	unsigned long long above_end;
39 
40 	p = mmap((void *)FOURGB, hpage_size, PROT_READ|PROT_WRITE,
41 		 MAP_SHARED | MAP_FIXED, fd, 0);
42 	if (p == MAP_FAILED) {
43 		/* slice 0 (high) spans from 4G-1T */
44 		below_start = FOURGB;
45 		above_end = 1024ULL*1024*1024*1024;
46 
47 		if (range_is_mapped(below_start, above_end) == 1) {
48 			tst_res(TINFO|TERRNO, "region 4G-IT is not free & "
49 					"mmap() failed expected");
50 			tst_res(TPASS, "Successful but inconclusive");
51 		} else
52 			tst_res(TFAIL|TERRNO, "mmap() huge failed unexpected");
53 		goto cleanup;
54 	}
55 	if (p != (void *)FOURGB) {
56 		tst_res(TFAIL, "Wrong address with MAP_FIXED huge");
57 		goto cleanup;
58 	}
59 
60 	tst_res(TINFO, "Mapped hugetlb at %p", p);
61 
62 	memset(p, 0, hpage_size);
63 
64 	/* Test just below 4GB to check for off-by-one errors */
65 	lowaddr = FOURGB - page_size;
66 	q = mmap((void *)lowaddr, page_size, PROT_READ|PROT_WRITE,
67 		 MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0);
68 	if (q == MAP_FAILED) {
69 		below_start = FOURGB - page_size;
70 		above_end = FOURGB;
71 
72 		if (range_is_mapped(below_start, above_end) == 1) {
73 			tst_res(TINFO|TERRNO, "region (4G-page)-4G is not free & "
74 					"mmap() failed expected");
75 			tst_res(TPASS, "Successful but inconclusive");
76 		} else
77 			tst_res(TFAIL|TERRNO, "mmap() normal failed unexpected");
78 		goto cleanup;
79 	}
80 	if (q != (void *)lowaddr) {
81 		tst_res(TFAIL, "Wrong address with MAP_FIXED normal");
82 		goto cleanup;
83 	}
84 
85 	memset(q, 0, page_size);
86 	tst_res(TPASS, "Successful");
87 
88 cleanup:
89 	if (p && p != MAP_FAILED)
90 		SAFE_MUNMAP(p, hpage_size);
91 	if (q && q != MAP_FAILED)
92 		SAFE_MUNMAP(q, page_size);
93 }
94 
setup(void)95 static void setup(void)
96 {
97 	page_size = getpagesize();
98 	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024;
99 
100 	if (sizeof(void *) <= 4)
101 		tst_brk(TCONF, "Machine must be >32 bit");
102 	if (hpage_size > FOURGB)
103 		tst_brk(TCONF, "Huge page size is too large");
104 	fd = tst_creat_unlinked(MNTPOINT, 0);
105 }
106 
cleanup(void)107 static void cleanup(void)
108 {
109 	if (fd > 0)
110 		SAFE_CLOSE(fd);
111 }
112 
113 static struct tst_test test = {
114 	.tags = (struct tst_tag[]) {
115 		{"linux-git", "9a94c5793a7b"},
116 		{}
117 	},
118 	.needs_root = 1,
119 	.mntpoint = MNTPOINT,
120 	.needs_hugetlbfs = 1,
121 	.needs_tmpdir = 1,
122 	.setup = setup,
123 	.cleanup = cleanup,
124 	.test_all = run_test,
125 	.hugepages = {2, TST_NEEDS},
126 };
127