Commit | Line | Data |
---|---|---|
f50a7f3d | 1 | // SPDX-License-Identifier: GPL-2.0-only |
4e5ce33c AK |
2 | /* |
3 | * Copyright 2017, Anshuman Khandual, IBM Corp. | |
4e5ce33c AK |
4 | * |
5 | * Works on architectures which support 128TB virtual | |
6 | * address range and beyond. | |
7 | */ | |
8 | #include <stdio.h> | |
9 | #include <stdlib.h> | |
10 | #include <string.h> | |
11 | #include <unistd.h> | |
12 | #include <errno.h> | |
4e5ce33c AK |
13 | #include <sys/mman.h> |
14 | #include <sys/time.h> | |
15 | ||
16 | /* | |
17 | * Maximum address range mapped with a single mmap() | |
18 | * call is little bit more than 16GB. Hence 16GB is | |
19 | * chosen as the single chunk size for address space | |
20 | * mapping. | |
21 | */ | |
22 | #define MAP_CHUNK_SIZE 17179869184UL /* 16GB */ | |
23 | ||
24 | /* | |
25 | * Address space till 128TB is mapped without any hint | |
26 | * and is enabled by default. Address space beyond 128TB | |
27 | * till 512TB is obtained by passing hint address as the | |
28 | * first argument into mmap() system call. | |
29 | * | |
30 | * The process heap address space is divided into two | |
31 | * different areas one below 128TB and one above 128TB | |
32 | * till it reaches 512TB. One with size 128TB and the | |
33 | * other being 384TB. | |
eff33cfa MS |
34 | * |
35 | * On Arm64 the address space is 256TB and no high mappings | |
36 | * are supported so far. | |
4e5ce33c | 37 | */ |
eff33cfa | 38 | |
4e5ce33c | 39 | #define NR_CHUNKS_128TB 8192UL /* Number of 16GB chunks for 128TB */ |
eff33cfa MS |
40 | #define NR_CHUNKS_256TB (NR_CHUNKS_128TB * 2UL) |
41 | #define NR_CHUNKS_384TB (NR_CHUNKS_128TB * 3UL) | |
4e5ce33c AK |
42 | |
43 | #define ADDR_MARK_128TB (1UL << 47) /* First address beyond 128TB */ | |
eff33cfa MS |
44 | #define ADDR_MARK_256TB (1UL << 48) /* First address beyond 256TB */ |
45 | ||
46 | #ifdef __aarch64__ | |
47 | #define HIGH_ADDR_MARK ADDR_MARK_256TB | |
48 | #define HIGH_ADDR_SHIFT 49 | |
49 | #define NR_CHUNKS_LOW NR_CHUNKS_256TB | |
50 | #define NR_CHUNKS_HIGH 0 | |
51 | #else | |
52 | #define HIGH_ADDR_MARK ADDR_MARK_128TB | |
53 | #define HIGH_ADDR_SHIFT 48 | |
54 | #define NR_CHUNKS_LOW NR_CHUNKS_128TB | |
55 | #define NR_CHUNKS_HIGH NR_CHUNKS_384TB | |
56 | #endif | |
4e5ce33c AK |
57 | |
58 | static char *hind_addr(void) | |
59 | { | |
eff33cfa | 60 | int bits = HIGH_ADDR_SHIFT + rand() % (63 - HIGH_ADDR_SHIFT); |
4e5ce33c AK |
61 | |
62 | return (char *) (1UL << bits); | |
63 | } | |
64 | ||
65 | static int validate_addr(char *ptr, int high_addr) | |
66 | { | |
67 | unsigned long addr = (unsigned long) ptr; | |
68 | ||
69 | if (high_addr) { | |
eff33cfa | 70 | if (addr < HIGH_ADDR_MARK) { |
4e5ce33c AK |
71 | printf("Bad address %lx\n", addr); |
72 | return 1; | |
73 | } | |
74 | return 0; | |
75 | } | |
76 | ||
eff33cfa | 77 | if (addr > HIGH_ADDR_MARK) { |
4e5ce33c AK |
78 | printf("Bad address %lx\n", addr); |
79 | return 1; | |
80 | } | |
81 | return 0; | |
82 | } | |
83 | ||
84 | static int validate_lower_address_hint(void) | |
85 | { | |
86 | char *ptr; | |
87 | ||
88 | ptr = mmap((void *) (1UL << 45), MAP_CHUNK_SIZE, PROT_READ | | |
89 | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
90 | ||
91 | if (ptr == MAP_FAILED) | |
92 | return 0; | |
93 | ||
94 | return 1; | |
95 | } | |
96 | ||
97 | int main(int argc, char *argv[]) | |
98 | { | |
eff33cfa MS |
99 | char *ptr[NR_CHUNKS_LOW]; |
100 | char *hptr[NR_CHUNKS_HIGH]; | |
4e5ce33c AK |
101 | char *hint; |
102 | unsigned long i, lchunks, hchunks; | |
103 | ||
eff33cfa | 104 | for (i = 0; i < NR_CHUNKS_LOW; i++) { |
4e5ce33c AK |
105 | ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE, |
106 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
107 | ||
108 | if (ptr[i] == MAP_FAILED) { | |
109 | if (validate_lower_address_hint()) | |
110 | return 1; | |
111 | break; | |
112 | } | |
113 | ||
114 | if (validate_addr(ptr[i], 0)) | |
115 | return 1; | |
116 | } | |
117 | lchunks = i; | |
118 | ||
eff33cfa | 119 | for (i = 0; i < NR_CHUNKS_HIGH; i++) { |
4e5ce33c AK |
120 | hint = hind_addr(); |
121 | hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE, | |
122 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
123 | ||
124 | if (hptr[i] == MAP_FAILED) | |
125 | break; | |
126 | ||
127 | if (validate_addr(hptr[i], 1)) | |
128 | return 1; | |
129 | } | |
130 | hchunks = i; | |
131 | ||
132 | for (i = 0; i < lchunks; i++) | |
133 | munmap(ptr[i], MAP_CHUNK_SIZE); | |
134 | ||
135 | for (i = 0; i < hchunks; i++) | |
136 | munmap(hptr[i], MAP_CHUNK_SIZE); | |
137 | ||
138 | return 0; | |
139 | } |