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