xref: /aosp_15_r20/external/ltp/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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