xref: /linux/tools/testing/selftests/mm/map_hugetlb.c (revision 24168c5e6dfbdd5b414f048f47f75d64533296ca)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Example of using hugepage memory in a user application using the mmap
4  * system call with MAP_HUGETLB flag.  Before running this program make
5  * sure the administrator has allocated enough default sized huge pages
6  * to cover the 256 MB allocation.
7  *
8  * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
9  * That means the addresses starting with 0x800000... will need to be
10  * specified.  Specifying a fixed address is not required on ppc64, i386
11  * or x86_64.
12  */
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #include <fcntl.h>
18 #include "vm_util.h"
19 #include "../kselftest.h"
20 
21 #define LENGTH (256UL*1024*1024)
22 #define PROTECTION (PROT_READ | PROT_WRITE)
23 
24 /* Only ia64 requires this */
25 #ifdef __ia64__
26 #define ADDR (void *)(0x8000000000000000UL)
27 #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
28 #else
29 #define ADDR (void *)(0x0UL)
30 #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
31 #endif
32 
33 static void check_bytes(char *addr)
34 {
35 	ksft_print_msg("First hex is %x\n", *((unsigned int *)addr));
36 }
37 
38 static void write_bytes(char *addr, size_t length)
39 {
40 	unsigned long i;
41 
42 	for (i = 0; i < length; i++)
43 		*(addr + i) = (char)i;
44 }
45 
46 static void read_bytes(char *addr, size_t length)
47 {
48 	unsigned long i;
49 
50 	check_bytes(addr);
51 	for (i = 0; i < length; i++)
52 		if (*(addr + i) != (char)i)
53 			ksft_exit_fail_msg("Mismatch at %lu\n", i);
54 
55 	ksft_test_result_pass("Read correct data\n");
56 }
57 
58 int main(int argc, char **argv)
59 {
60 	void *addr;
61 	size_t hugepage_size;
62 	size_t length = LENGTH;
63 	int flags = FLAGS;
64 	int shift = 0;
65 
66 	hugepage_size = default_huge_page_size();
67 	/* munmap with fail if the length is not page aligned */
68 	if (hugepage_size > length)
69 		length = hugepage_size;
70 
71 	ksft_print_header();
72 	ksft_set_plan(1);
73 
74 	if (argc > 1)
75 		length = atol(argv[1]) << 20;
76 	if (argc > 2) {
77 		shift = atoi(argv[2]);
78 		if (shift)
79 			flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT;
80 	}
81 
82 	if (shift)
83 		ksft_print_msg("%u kB hugepages\n", 1 << (shift - 10));
84 	else
85 		ksft_print_msg("Default size hugepages\n");
86 	ksft_print_msg("Mapping %lu Mbytes\n", (unsigned long)length >> 20);
87 
88 	addr = mmap(ADDR, length, PROTECTION, flags, -1, 0);
89 	if (addr == MAP_FAILED)
90 		ksft_exit_fail_msg("mmap: %s\n", strerror(errno));
91 
92 	ksft_print_msg("Returned address is %p\n", addr);
93 	check_bytes(addr);
94 	write_bytes(addr, length);
95 	read_bytes(addr, length);
96 
97 	/* munmap() length of MAP_HUGETLB memory must be hugepage aligned */
98 	if (munmap(addr, length))
99 		ksft_exit_fail_msg("munmap: %s\n", strerror(errno));
100 
101 	ksft_finished();
102 }
103