File Index
Files and directories
Sign in
FILE

check_hugetlb_options.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/arm64/mte/check_hugetlb_options.c C
  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
 25static 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
 46static 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
 71static 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
 84static void allocate_hugetlb()
 85{
 86	write_sysfs("/proc/sys/vm/nr_hugepages", 2);
 87}
 88
 89static void free_hugetlb()
 90{
 91	write_sysfs("/proc/sys/vm/nr_hugepages", 0);
 92}
 93
 94static 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		}
123check_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
135static 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
146static 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
176static 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
205static 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
227int 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}
~/ Read-only file preview.