Skip to content

Commit 27879e8

Browse files
Yang Shictmarinas
authored andcommitted
selftests: arm64: add hugetlb mte tests
The tests cover mmap, mprotect hugetlb with MTE prot and COW. Signed-off-by: Yang Shi <yang@os.amperecomputing.com> Link: https://lore.kernel.org/r/20241001225220.271178-2-yang@os.amperecomputing.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 25c17c4 commit 27879e8

File tree

1 file changed

+285
-0
lines changed

1 file changed

+285
-0
lines changed
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
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);
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);
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);
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+
231+
err = mte_default_setup();
232+
if (err)
233+
return err;
234+
235+
/* Register signal handlers */
236+
mte_register_signal(SIGBUS, mte_default_handler);
237+
mte_register_signal(SIGSEGV, mte_default_handler);
238+
239+
allocate_hugetlb();
240+
241+
if (!is_hugetlb_allocated()) {
242+
ksft_print_msg("ERR: Unable allocate hugetlb pages\n");
243+
return KSFT_FAIL;
244+
}
245+
246+
/* Set test plan */
247+
ksft_set_plan(12);
248+
249+
mte_enable_pstate_tco();
250+
251+
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_OFF),
252+
"Check hugetlb memory with private mapping, sync error mode, mmap memory and tag check off\n");
253+
254+
mte_disable_pstate_tco();
255+
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_OFF),
256+
"Check hugetlb memory with private mapping, no error mode, mmap memory and tag check off\n");
257+
258+
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
259+
"Check hugetlb memory with private mapping, sync error mode, mmap memory and tag check on\n");
260+
evaluate_test(check_hugetlb_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
261+
"Check hugetlb memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
262+
evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
263+
"Check hugetlb memory with private mapping, async error mode, mmap memory and tag check on\n");
264+
evaluate_test(check_hugetlb_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
265+
"Check hugetlb memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
266+
267+
evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
268+
"Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n");
269+
evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
270+
"Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n");
271+
272+
evaluate_test(check_child_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
273+
"Check child hugetlb memory with private mapping, precise mode and mmap memory\n");
274+
evaluate_test(check_child_hugetlb_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
275+
"Check child hugetlb memory with private mapping, precise mode and mmap memory\n");
276+
evaluate_test(check_child_hugetlb_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
277+
"Check child hugetlb memory with private mapping, precise mode and mmap/mprotect memory\n");
278+
evaluate_test(check_child_hugetlb_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
279+
"Check child hugetlb memory with private mapping, precise mode and mmap/mprotect memory\n");
280+
281+
mte_restore_setup();
282+
free_hugetlb();
283+
ksft_print_cnts();
284+
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
285+
}

0 commit comments

Comments
 (0)