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 #include <lapi/mmap.h>
25
26 #include "hugetlb.h"
27
28 #define FOURGB (1ULL << 32)
29 #define MNTPOINT "hugetlbfs/"
30 static int fd = -1;
31 static unsigned long hpage_size;
32 static int page_size;
33
run_test(void)34 static void run_test(void)
35 {
36 void *p, *q = NULL;
37 unsigned long long lowaddr;
38 unsigned long long below_start;
39 unsigned long long above_end;
40
41 p = mmap((void *)FOURGB, hpage_size, PROT_READ|PROT_WRITE,
42 MAP_SHARED | MAP_FIXED, fd, 0);
43 if (p == MAP_FAILED) {
44 /* slice 0 (high) spans from 4G-1T */
45 below_start = FOURGB;
46 above_end = 1024ULL*1024*1024*1024;
47
48 if (range_is_mapped(below_start, above_end) == 1) {
49 tst_res(TINFO|TERRNO, "region 4G-IT is not free & "
50 "mmap() failed expected");
51 tst_res(TPASS, "Successful but inconclusive");
52 } else
53 tst_res(TFAIL|TERRNO, "mmap() huge failed unexpected");
54 goto cleanup;
55 }
56 if (p != (void *)FOURGB) {
57 tst_res(TFAIL, "Wrong address with MAP_FIXED huge");
58 goto cleanup;
59 }
60
61 tst_res(TINFO, "Mapped hugetlb at %p", p);
62
63 memset(p, 0, hpage_size);
64
65 /* Test just below 4GB to check for off-by-one errors */
66 lowaddr = FOURGB - MMAP_GRANULARITY;
67 q = mmap((void *)lowaddr, MMAP_GRANULARITY, PROT_READ|PROT_WRITE,
68 MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0);
69 if (q == MAP_FAILED) {
70 below_start = FOURGB - MMAP_GRANULARITY;
71 above_end = FOURGB;
72
73 if (range_is_mapped(below_start, above_end) == 1) {
74 tst_res(TINFO|TERRNO, "region (4G-MMAP_GRANULARITY)-4G is not free & "
75 "mmap() failed expected");
76 tst_res(TPASS, "Successful but inconclusive");
77 } else
78 tst_res(TFAIL|TERRNO, "mmap() normal failed unexpected");
79 goto cleanup;
80 }
81 if (q != (void *)lowaddr) {
82 tst_res(TFAIL, "Wrong address with MAP_FIXED normal");
83 goto cleanup;
84 }
85
86 memset(q, 0, page_size);
87 tst_res(TPASS, "Successful");
88
89 cleanup:
90 if (p && p != MAP_FAILED)
91 SAFE_MUNMAP(p, hpage_size);
92 if (q && q != MAP_FAILED)
93 SAFE_MUNMAP(q, page_size);
94 }
95
setup(void)96 static void setup(void)
97 {
98 page_size = getpagesize();
99 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024;
100
101 if (sizeof(void *) <= 4)
102 tst_brk(TCONF, "Machine must be >32 bit");
103 if (hpage_size > FOURGB)
104 tst_brk(TCONF, "Huge page size is too large");
105 fd = tst_creat_unlinked(MNTPOINT, 0);
106 }
107
cleanup(void)108 static void cleanup(void)
109 {
110 if (fd > 0)
111 SAFE_CLOSE(fd);
112 }
113
114 static struct tst_test test = {
115 .tags = (struct tst_tag[]) {
116 {"linux-git", "9a94c5793a7b"},
117 {}
118 },
119 .needs_root = 1,
120 .mntpoint = MNTPOINT,
121 .needs_hugetlbfs = 1,
122 .needs_tmpdir = 1,
123 .setup = setup,
124 .cleanup = cleanup,
125 .test_all = run_test,
126 .hugepages = {2, TST_NEEDS},
127 };
128