Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/mte/check_hugetlb_options.c
26296 views
1
// SPDX-License-Identifier: GPL-2.0
2
// Copyright (C) 2024 Ampere Computing LLC
3
4
#define _GNU_SOURCE
5
6
#include <errno.h>
7
#include <fcntl.h>
8
#include <signal.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <ucontext.h>
13
#include <sys/mman.h>
14
#include <sys/stat.h>
15
#include <sys/types.h>
16
#include <sys/wait.h>
17
18
#include "kselftest.h"
19
#include "mte_common_util.h"
20
#include "mte_def.h"
21
22
#define TAG_CHECK_ON 0
23
#define TAG_CHECK_OFF 1
24
25
static unsigned long default_huge_page_size(void)
26
{
27
unsigned long hps = 0;
28
char *line = NULL;
29
size_t linelen = 0;
30
FILE *f = fopen("/proc/meminfo", "r");
31
32
if (!f)
33
return 0;
34
while (getline(&line, &linelen, f) > 0) {
35
if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
36
hps <<= 10;
37
break;
38
}
39
}
40
41
free(line);
42
fclose(f);
43
return hps;
44
}
45
46
static bool is_hugetlb_allocated(void)
47
{
48
unsigned long hps = 0;
49
char *line = NULL;
50
size_t linelen = 0;
51
FILE *f = fopen("/proc/meminfo", "r");
52
53
if (!f)
54
return false;
55
while (getline(&line, &linelen, f) > 0) {
56
if (sscanf(line, "Hugetlb: %lu kB", &hps) == 1) {
57
hps <<= 10;
58
break;
59
}
60
}
61
62
free(line);
63
fclose(f);
64
65
if (hps > 0)
66
return true;
67
68
return false;
69
}
70
71
static void write_sysfs(char *str, unsigned long val)
72
{
73
FILE *f;
74
75
f = fopen(str, "w");
76
if (!f) {
77
ksft_print_msg("ERR: missing %s\n", str);
78
return;
79
}
80
fprintf(f, "%lu", val);
81
fclose(f);
82
}
83
84
static void allocate_hugetlb()
85
{
86
write_sysfs("/proc/sys/vm/nr_hugepages", 2);
87
}
88
89
static void free_hugetlb()
90
{
91
write_sysfs("/proc/sys/vm/nr_hugepages", 0);
92
}
93
94
static int check_child_tag_inheritance(char *ptr, int size, int mode)
95
{
96
int i, parent_tag, child_tag, fault, child_status;
97
pid_t child;
98
99
parent_tag = MT_FETCH_TAG((uintptr_t)ptr);
100
fault = 0;
101
102
child = fork();
103
if (child == -1) {
104
ksft_print_msg("FAIL: child process creation\n");
105
return KSFT_FAIL;
106
} else if (child == 0) {
107
mte_initialize_current_context(mode, (uintptr_t)ptr, size);
108
/* Do copy on write */
109
memset(ptr, '1', size);
110
mte_wait_after_trig();
111
if (cur_mte_cxt.fault_valid == true) {
112
fault = 1;
113
goto check_child_tag_inheritance_err;
114
}
115
for (i = 0; i < size; i += MT_GRANULE_SIZE) {
116
child_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));
117
if (parent_tag != child_tag) {
118
ksft_print_msg("FAIL: child mte tag (%d) mismatch\n", i);
119
fault = 1;
120
goto check_child_tag_inheritance_err;
121
}
122
}
123
check_child_tag_inheritance_err:
124
_exit(fault);
125
}
126
/* Wait for child process to terminate */
127
wait(&child_status);
128
if (WIFEXITED(child_status))
129
fault = WEXITSTATUS(child_status);
130
else
131
fault = 1;
132
return (fault) ? KSFT_FAIL : KSFT_PASS;
133
}
134
135
static int check_mte_memory(char *ptr, int size, int mode, int tag_check)
136
{
137
mte_initialize_current_context(mode, (uintptr_t)ptr, size);
138
memset(ptr, '1', size);
139
mte_wait_after_trig();
140
if (cur_mte_cxt.fault_valid == true)
141
return KSFT_FAIL;
142
143
return KSFT_PASS;
144
}
145
146
static int check_hugetlb_memory_mapping(int mem_type, int mode, int mapping, int tag_check)
147
{
148
char *ptr, *map_ptr;
149
int result;
150
unsigned long map_size;
151
152
map_size = default_huge_page_size();
153
154
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
155
map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false);
156
if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS)
157
return KSFT_FAIL;
158
159
mte_initialize_current_context(mode, (uintptr_t)map_ptr, map_size);
160
/* Only mte enabled memory will allow tag insertion */
161
ptr = mte_insert_tags((void *)map_ptr, map_size);
162
if (!ptr || cur_mte_cxt.fault_valid == true) {
163
ksft_print_msg("FAIL: Insert tags on anonymous mmap memory\n");
164
munmap((void *)map_ptr, map_size);
165
return KSFT_FAIL;
166
}
167
result = check_mte_memory(ptr, map_size, mode, tag_check);
168
mte_clear_tags((void *)ptr, map_size);
169
mte_free_memory((void *)map_ptr, map_size, mem_type, false);
170
if (result == KSFT_FAIL)
171
return KSFT_FAIL;
172
173
return KSFT_PASS;
174
}
175
176
static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
177
{
178
char *map_ptr;
179
int prot_flag, result;
180
unsigned long map_size;
181
182
prot_flag = PROT_READ | PROT_WRITE;
183
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
184
map_size = default_huge_page_size();
185
map_ptr = (char *)mte_allocate_memory_tag_range(map_size, mem_type, mapping,
186
0, 0);
187
if (check_allocated_memory_range(map_ptr, map_size, mem_type,
188
0, 0) != KSFT_PASS)
189
return KSFT_FAIL;
190
/* Try to clear PROT_MTE property and verify it by tag checking */
191
if (mprotect(map_ptr, map_size, prot_flag)) {
192
mte_free_memory_tag_range((void *)map_ptr, map_size, mem_type,
193
0, 0);
194
ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n");
195
return KSFT_FAIL;
196
}
197
result = check_mte_memory(map_ptr, map_size, mode, TAG_CHECK_ON);
198
mte_free_memory_tag_range((void *)map_ptr, map_size, mem_type, 0, 0);
199
if (result != KSFT_PASS)
200
return KSFT_FAIL;
201
202
return KSFT_PASS;
203
}
204
205
static int check_child_hugetlb_memory_mapping(int mem_type, int mode, int mapping)
206
{
207
char *ptr;
208
int result;
209
unsigned long map_size;
210
211
map_size = default_huge_page_size();
212
213
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
214
ptr = (char *)mte_allocate_memory_tag_range(map_size, mem_type, mapping,
215
0, 0);
216
if (check_allocated_memory_range(ptr, map_size, mem_type,
217
0, 0) != KSFT_PASS)
218
return KSFT_FAIL;
219
result = check_child_tag_inheritance(ptr, map_size, mode);
220
mte_free_memory_tag_range((void *)ptr, map_size, mem_type, 0, 0);
221
if (result == KSFT_FAIL)
222
return result;
223
224
return KSFT_PASS;
225
}
226
227
int main(int argc, char *argv[])
228
{
229
int err;
230
void *map_ptr;
231
unsigned long map_size;
232
233
err = mte_default_setup();
234
if (err)
235
return err;
236
237
/* Register signal handlers */
238
mte_register_signal(SIGBUS, mte_default_handler, false);
239
mte_register_signal(SIGSEGV, mte_default_handler, false);
240
241
allocate_hugetlb();
242
243
if (!is_hugetlb_allocated()) {
244
ksft_print_msg("ERR: Unable allocate hugetlb pages\n");
245
return KSFT_FAIL;
246
}
247
248
/* Check if MTE supports hugetlb mappings */
249
map_size = default_huge_page_size();
250
map_ptr = mmap(NULL, map_size, PROT_READ | PROT_MTE,
251
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
252
if (map_ptr == MAP_FAILED)
253
ksft_exit_skip("PROT_MTE not supported with MAP_HUGETLB mappings\n");
254
else
255
munmap(map_ptr, map_size);
256
257
/* Set test plan */
258
ksft_set_plan(12);
259
260
mte_enable_pstate_tco();
261
262
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_OFF),
263
"Check hugetlb memory with private mapping, sync error mode, mmap memory and tag check off\n");
264
265
mte_disable_pstate_tco();
266
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_OFF),
267
"Check hugetlb memory with private mapping, no error mode, mmap memory and tag check off\n");
268
269
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
270
"Check hugetlb memory with private mapping, sync error mode, mmap memory and tag check on\n");
271
evaluate_test(check_hugetlb_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
272
"Check hugetlb memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
273
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
274
"Check hugetlb memory with private mapping, async error mode, mmap memory and tag check on\n");
275
evaluate_test(check_hugetlb_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
276
"Check hugetlb memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
277
278
evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
279
"Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n");
280
evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
281
"Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n");
282
283
evaluate_test(check_child_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
284
"Check child hugetlb memory with private mapping, sync error mode and mmap memory\n");
285
evaluate_test(check_child_hugetlb_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
286
"Check child hugetlb memory with private mapping, async error mode and mmap memory\n");
287
evaluate_test(check_child_hugetlb_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
288
"Check child hugetlb memory with private mapping, sync error mode and mmap/mprotect memory\n");
289
evaluate_test(check_child_hugetlb_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
290
"Check child hugetlb memory with private mapping, async error mode and mmap/mprotect memory\n");
291
292
mte_restore_setup();
293
free_hugetlb();
294
ksft_print_cnts();
295
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
296
}
297
298