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(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(msg: "Mismatch at %lu\n" , i); |
54 | |
55 | ksft_test_result_pass(msg: "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(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(msg: "%u kB hugepages\n" , 1 << (shift - 10)); |
84 | else |
85 | ksft_print_msg(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(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 | |