1f3b2a26cSAmit Daniel Kachhap // SPDX-License-Identifier: GPL-2.0
2f3b2a26cSAmit Daniel Kachhap // Copyright (C) 2020 ARM Limited
3f3b2a26cSAmit Daniel Kachhap 
4f3b2a26cSAmit Daniel Kachhap #define _GNU_SOURCE
5f3b2a26cSAmit Daniel Kachhap 
6f3b2a26cSAmit Daniel Kachhap #include <errno.h>
7f3b2a26cSAmit Daniel Kachhap #include <signal.h>
8f3b2a26cSAmit Daniel Kachhap #include <stdio.h>
9f3b2a26cSAmit Daniel Kachhap #include <stdlib.h>
10f3b2a26cSAmit Daniel Kachhap #include <string.h>
11f3b2a26cSAmit Daniel Kachhap #include <ucontext.h>
12f3b2a26cSAmit Daniel Kachhap #include <sys/wait.h>
13f3b2a26cSAmit Daniel Kachhap 
14f3b2a26cSAmit Daniel Kachhap #include "kselftest.h"
15f3b2a26cSAmit Daniel Kachhap #include "mte_common_util.h"
16f3b2a26cSAmit Daniel Kachhap #include "mte_def.h"
17f3b2a26cSAmit Daniel Kachhap 
18f3b2a26cSAmit Daniel Kachhap #define BUFFER_SIZE		(5 * MT_GRANULE_SIZE)
19f3b2a26cSAmit Daniel Kachhap #define RUNS			(MT_TAG_COUNT * 2)
20f3b2a26cSAmit Daniel Kachhap #define MTE_LAST_TAG_MASK	(0x7FFF)
21f3b2a26cSAmit Daniel Kachhap 
22f3b2a26cSAmit Daniel Kachhap static int verify_mte_pointer_validity(char *ptr, int mode)
23f3b2a26cSAmit Daniel Kachhap {
24f3b2a26cSAmit Daniel Kachhap 	mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
25f3b2a26cSAmit Daniel Kachhap 	/* Check the validity of the tagged pointer */
26f3b2a26cSAmit Daniel Kachhap 	memset((void *)ptr, '1', BUFFER_SIZE);
27f3b2a26cSAmit Daniel Kachhap 	mte_wait_after_trig();
28f3b2a26cSAmit Daniel Kachhap 	if (cur_mte_cxt.fault_valid)
29f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
30f3b2a26cSAmit Daniel Kachhap 	/* Proceed further for nonzero tags */
31f3b2a26cSAmit Daniel Kachhap 	if (!MT_FETCH_TAG((uintptr_t)ptr))
32f3b2a26cSAmit Daniel Kachhap 		return KSFT_PASS;
33f3b2a26cSAmit Daniel Kachhap 	mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE + 1);
34f3b2a26cSAmit Daniel Kachhap 	/* Check the validity outside the range */
35f3b2a26cSAmit Daniel Kachhap 	ptr[BUFFER_SIZE] = '2';
36f3b2a26cSAmit Daniel Kachhap 	mte_wait_after_trig();
37f3b2a26cSAmit Daniel Kachhap 	if (!cur_mte_cxt.fault_valid)
38f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
39f3b2a26cSAmit Daniel Kachhap 	else
40f3b2a26cSAmit Daniel Kachhap 		return KSFT_PASS;
41f3b2a26cSAmit Daniel Kachhap }
42f3b2a26cSAmit Daniel Kachhap 
43f3b2a26cSAmit Daniel Kachhap static int check_single_included_tags(int mem_type, int mode)
44f3b2a26cSAmit Daniel Kachhap {
45f3b2a26cSAmit Daniel Kachhap 	char *ptr;
46f3b2a26cSAmit Daniel Kachhap 	int tag, run, result = KSFT_PASS;
47f3b2a26cSAmit Daniel Kachhap 
48f3b2a26cSAmit Daniel Kachhap 	ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
49f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
50f3b2a26cSAmit Daniel Kachhap 				   mem_type, false) != KSFT_PASS)
51f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
52f3b2a26cSAmit Daniel Kachhap 
53f3b2a26cSAmit Daniel Kachhap 	for (tag = 0; (tag < MT_TAG_COUNT) && (result == KSFT_PASS); tag++) {
54f3b2a26cSAmit Daniel Kachhap 		mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag));
55f3b2a26cSAmit Daniel Kachhap 		/* Try to catch a excluded tag by a number of tries. */
56f3b2a26cSAmit Daniel Kachhap 		for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
57f3b2a26cSAmit Daniel Kachhap 			ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
58f3b2a26cSAmit Daniel Kachhap 			/* Check tag value */
59f3b2a26cSAmit Daniel Kachhap 			if (MT_FETCH_TAG((uintptr_t)ptr) == tag) {
60f3b2a26cSAmit Daniel Kachhap 				ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
61f3b2a26cSAmit Daniel Kachhap 					       MT_FETCH_TAG((uintptr_t)ptr),
62f3b2a26cSAmit Daniel Kachhap 					       MT_INCLUDE_VALID_TAG(tag));
63f3b2a26cSAmit Daniel Kachhap 				result = KSFT_FAIL;
64f3b2a26cSAmit Daniel Kachhap 				break;
65f3b2a26cSAmit Daniel Kachhap 			}
66f3b2a26cSAmit Daniel Kachhap 			result = verify_mte_pointer_validity(ptr, mode);
67f3b2a26cSAmit Daniel Kachhap 		}
68f3b2a26cSAmit Daniel Kachhap 	}
69f3b2a26cSAmit Daniel Kachhap 	mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
70f3b2a26cSAmit Daniel Kachhap 	return result;
71f3b2a26cSAmit Daniel Kachhap }
72f3b2a26cSAmit Daniel Kachhap 
73f3b2a26cSAmit Daniel Kachhap static int check_multiple_included_tags(int mem_type, int mode)
74f3b2a26cSAmit Daniel Kachhap {
75f3b2a26cSAmit Daniel Kachhap 	char *ptr;
76f3b2a26cSAmit Daniel Kachhap 	int tag, run, result = KSFT_PASS;
77f3b2a26cSAmit Daniel Kachhap 	unsigned long excl_mask = 0;
78f3b2a26cSAmit Daniel Kachhap 
79f3b2a26cSAmit Daniel Kachhap 	ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
80f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
81f3b2a26cSAmit Daniel Kachhap 				   mem_type, false) != KSFT_PASS)
82f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
83f3b2a26cSAmit Daniel Kachhap 
84f3b2a26cSAmit Daniel Kachhap 	for (tag = 0; (tag < MT_TAG_COUNT - 1) && (result == KSFT_PASS); tag++) {
85f3b2a26cSAmit Daniel Kachhap 		excl_mask |= 1 << tag;
86f3b2a26cSAmit Daniel Kachhap 		mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask));
87f3b2a26cSAmit Daniel Kachhap 		/* Try to catch a excluded tag by a number of tries. */
88f3b2a26cSAmit Daniel Kachhap 		for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
89f3b2a26cSAmit Daniel Kachhap 			ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
90f3b2a26cSAmit Daniel Kachhap 			/* Check tag value */
91f3b2a26cSAmit Daniel Kachhap 			if (MT_FETCH_TAG((uintptr_t)ptr) < tag) {
92f3b2a26cSAmit Daniel Kachhap 				ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
93f3b2a26cSAmit Daniel Kachhap 					       MT_FETCH_TAG((uintptr_t)ptr),
94f3b2a26cSAmit Daniel Kachhap 					       MT_INCLUDE_VALID_TAGS(excl_mask));
95f3b2a26cSAmit Daniel Kachhap 				result = KSFT_FAIL;
96f3b2a26cSAmit Daniel Kachhap 				break;
97f3b2a26cSAmit Daniel Kachhap 			}
98f3b2a26cSAmit Daniel Kachhap 			result = verify_mte_pointer_validity(ptr, mode);
99f3b2a26cSAmit Daniel Kachhap 		}
100f3b2a26cSAmit Daniel Kachhap 	}
101f3b2a26cSAmit Daniel Kachhap 	mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
102f3b2a26cSAmit Daniel Kachhap 	return result;
103f3b2a26cSAmit Daniel Kachhap }
104f3b2a26cSAmit Daniel Kachhap 
105f3b2a26cSAmit Daniel Kachhap static int check_all_included_tags(int mem_type, int mode)
106f3b2a26cSAmit Daniel Kachhap {
107f3b2a26cSAmit Daniel Kachhap 	char *ptr;
108f3b2a26cSAmit Daniel Kachhap 	int run, result = KSFT_PASS;
109f3b2a26cSAmit Daniel Kachhap 
110f3b2a26cSAmit Daniel Kachhap 	ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
111f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
112f3b2a26cSAmit Daniel Kachhap 				   mem_type, false) != KSFT_PASS)
113f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
114f3b2a26cSAmit Daniel Kachhap 
115f3b2a26cSAmit Daniel Kachhap 	mte_switch_mode(mode, MT_INCLUDE_TAG_MASK);
116f3b2a26cSAmit Daniel Kachhap 	/* Try to catch a excluded tag by a number of tries. */
117f3b2a26cSAmit Daniel Kachhap 	for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
118f3b2a26cSAmit Daniel Kachhap 		ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
119f3b2a26cSAmit Daniel Kachhap 		/*
120f3b2a26cSAmit Daniel Kachhap 		 * Here tag byte can be between 0x0 to 0xF (full allowed range)
121f3b2a26cSAmit Daniel Kachhap 		 * so no need to match so just verify if it is writable.
122f3b2a26cSAmit Daniel Kachhap 		 */
123f3b2a26cSAmit Daniel Kachhap 		result = verify_mte_pointer_validity(ptr, mode);
124f3b2a26cSAmit Daniel Kachhap 	}
125f3b2a26cSAmit Daniel Kachhap 	mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
126f3b2a26cSAmit Daniel Kachhap 	return result;
127f3b2a26cSAmit Daniel Kachhap }
128f3b2a26cSAmit Daniel Kachhap 
129f3b2a26cSAmit Daniel Kachhap static int check_none_included_tags(int mem_type, int mode)
130f3b2a26cSAmit Daniel Kachhap {
131f3b2a26cSAmit Daniel Kachhap 	char *ptr;
132f3b2a26cSAmit Daniel Kachhap 	int run;
133f3b2a26cSAmit Daniel Kachhap 
134f3b2a26cSAmit Daniel Kachhap 	ptr = (char *)mte_allocate_memory(BUFFER_SIZE, mem_type, 0, false);
135f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE, mem_type, false) != KSFT_PASS)
136f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
137f3b2a26cSAmit Daniel Kachhap 
138f3b2a26cSAmit Daniel Kachhap 	mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK);
139f3b2a26cSAmit Daniel Kachhap 	/* Try to catch a excluded tag by a number of tries. */
140f3b2a26cSAmit Daniel Kachhap 	for (run = 0; run < RUNS; run++) {
141f3b2a26cSAmit Daniel Kachhap 		ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
142f3b2a26cSAmit Daniel Kachhap 		/* Here all tags exluded so tag value generated should be 0 */
143f3b2a26cSAmit Daniel Kachhap 		if (MT_FETCH_TAG((uintptr_t)ptr)) {
144f3b2a26cSAmit Daniel Kachhap 			ksft_print_msg("FAIL: included tag value found\n");
145f3b2a26cSAmit Daniel Kachhap 			mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, true);
146f3b2a26cSAmit Daniel Kachhap 			return KSFT_FAIL;
147f3b2a26cSAmit Daniel Kachhap 		}
148f3b2a26cSAmit Daniel Kachhap 		mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
149f3b2a26cSAmit Daniel Kachhap 		/* Check the write validity of the untagged pointer */
150f3b2a26cSAmit Daniel Kachhap 		memset((void *)ptr, '1', BUFFER_SIZE);
151f3b2a26cSAmit Daniel Kachhap 		mte_wait_after_trig();
152f3b2a26cSAmit Daniel Kachhap 		if (cur_mte_cxt.fault_valid)
153f3b2a26cSAmit Daniel Kachhap 			break;
154f3b2a26cSAmit Daniel Kachhap 	}
155f3b2a26cSAmit Daniel Kachhap 	mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, false);
156f3b2a26cSAmit Daniel Kachhap 	if (cur_mte_cxt.fault_valid)
157f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
158f3b2a26cSAmit Daniel Kachhap 	else
159f3b2a26cSAmit Daniel Kachhap 		return KSFT_PASS;
160f3b2a26cSAmit Daniel Kachhap }
161f3b2a26cSAmit Daniel Kachhap 
162f3b2a26cSAmit Daniel Kachhap int main(int argc, char *argv[])
163f3b2a26cSAmit Daniel Kachhap {
164f3b2a26cSAmit Daniel Kachhap 	int err;
165f3b2a26cSAmit Daniel Kachhap 
166f3b2a26cSAmit Daniel Kachhap 	err = mte_default_setup();
167f3b2a26cSAmit Daniel Kachhap 	if (err)
168f3b2a26cSAmit Daniel Kachhap 		return err;
169f3b2a26cSAmit Daniel Kachhap 
170f3b2a26cSAmit Daniel Kachhap 	/* Register SIGSEGV handler */
171f3b2a26cSAmit Daniel Kachhap 	mte_register_signal(SIGSEGV, mte_default_handler);
172f3b2a26cSAmit Daniel Kachhap 
173041fa41fSVincenzo Frascino 	/* Set test plan */
174041fa41fSVincenzo Frascino 	ksft_set_plan(4);
175041fa41fSVincenzo Frascino 
176f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_single_included_tags(USE_MMAP, MTE_SYNC_ERR),
177f3b2a26cSAmit Daniel Kachhap 		      "Check an included tag value with sync mode\n");
178f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_multiple_included_tags(USE_MMAP, MTE_SYNC_ERR),
179f3b2a26cSAmit Daniel Kachhap 		      "Check different included tags value with sync mode\n");
180f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_none_included_tags(USE_MMAP, MTE_SYNC_ERR),
181f3b2a26cSAmit Daniel Kachhap 		      "Check none included tags value with sync mode\n");
182f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_all_included_tags(USE_MMAP, MTE_SYNC_ERR),
183f3b2a26cSAmit Daniel Kachhap 		      "Check all included tags value with sync mode\n");
184f3b2a26cSAmit Daniel Kachhap 
185f3b2a26cSAmit Daniel Kachhap 	mte_restore_setup();
186f3b2a26cSAmit Daniel Kachhap 	ksft_print_cnts();
187f3b2a26cSAmit Daniel Kachhap 	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
188f3b2a26cSAmit Daniel Kachhap }
189