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 
verify_mte_pointer_validity(char * ptr,int mode)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 */
26*541235deSMark Brown 	memset(ptr, '1', BUFFER_SIZE);
27f3b2a26cSAmit Daniel Kachhap 	mte_wait_after_trig();
289a568171SMark Brown 	if (cur_mte_cxt.fault_valid) {
299a568171SMark Brown 		ksft_print_msg("Unexpected fault recorded for %p-%p in mode %x\n",
309a568171SMark Brown 			       ptr, ptr + BUFFER_SIZE, mode);
31f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
329a568171SMark Brown 	}
33f3b2a26cSAmit Daniel Kachhap 	/* Proceed further for nonzero tags */
34f3b2a26cSAmit Daniel Kachhap 	if (!MT_FETCH_TAG((uintptr_t)ptr))
35f3b2a26cSAmit Daniel Kachhap 		return KSFT_PASS;
36f3b2a26cSAmit Daniel Kachhap 	mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE + 1);
37f3b2a26cSAmit Daniel Kachhap 	/* Check the validity outside the range */
38f3b2a26cSAmit Daniel Kachhap 	ptr[BUFFER_SIZE] = '2';
39f3b2a26cSAmit Daniel Kachhap 	mte_wait_after_trig();
409a568171SMark Brown 	if (!cur_mte_cxt.fault_valid) {
419a568171SMark Brown 		ksft_print_msg("No valid fault recorded for %p in mode %x\n",
429a568171SMark Brown 			       ptr, mode);
43f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
449a568171SMark Brown 	} else {
45f3b2a26cSAmit Daniel Kachhap 		return KSFT_PASS;
46f3b2a26cSAmit Daniel Kachhap 	}
479a568171SMark Brown }
48f3b2a26cSAmit Daniel Kachhap 
check_single_included_tags(int mem_type,int mode)49f3b2a26cSAmit Daniel Kachhap static int check_single_included_tags(int mem_type, int mode)
50f3b2a26cSAmit Daniel Kachhap {
51f3b2a26cSAmit Daniel Kachhap 	char *ptr;
5272d6771cSMark Brown 	int tag, run, ret, result = KSFT_PASS;
53f3b2a26cSAmit Daniel Kachhap 
54*541235deSMark Brown 	ptr = mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
55f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
56f3b2a26cSAmit Daniel Kachhap 				   mem_type, false) != KSFT_PASS)
57f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
58f3b2a26cSAmit Daniel Kachhap 
59f3b2a26cSAmit Daniel Kachhap 	for (tag = 0; (tag < MT_TAG_COUNT) && (result == KSFT_PASS); tag++) {
6072d6771cSMark Brown 		ret = mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag));
6172d6771cSMark Brown 		if (ret != 0)
6272d6771cSMark Brown 			result = KSFT_FAIL;
63f3b2a26cSAmit Daniel Kachhap 		/* Try to catch a excluded tag by a number of tries. */
64f3b2a26cSAmit Daniel Kachhap 		for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
65*541235deSMark Brown 			ptr = mte_insert_tags(ptr, BUFFER_SIZE);
66f3b2a26cSAmit Daniel Kachhap 			/* Check tag value */
67f3b2a26cSAmit Daniel Kachhap 			if (MT_FETCH_TAG((uintptr_t)ptr) == tag) {
68f3b2a26cSAmit Daniel Kachhap 				ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
69f3b2a26cSAmit Daniel Kachhap 					       MT_FETCH_TAG((uintptr_t)ptr),
70f3b2a26cSAmit Daniel Kachhap 					       MT_INCLUDE_VALID_TAG(tag));
71f3b2a26cSAmit Daniel Kachhap 				result = KSFT_FAIL;
72f3b2a26cSAmit Daniel Kachhap 				break;
73f3b2a26cSAmit Daniel Kachhap 			}
74f3b2a26cSAmit Daniel Kachhap 			result = verify_mte_pointer_validity(ptr, mode);
75f3b2a26cSAmit Daniel Kachhap 		}
76f3b2a26cSAmit Daniel Kachhap 	}
77*541235deSMark Brown 	mte_free_memory_tag_range(ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
78f3b2a26cSAmit Daniel Kachhap 	return result;
79f3b2a26cSAmit Daniel Kachhap }
80f3b2a26cSAmit Daniel Kachhap 
check_multiple_included_tags(int mem_type,int mode)81f3b2a26cSAmit Daniel Kachhap static int check_multiple_included_tags(int mem_type, int mode)
82f3b2a26cSAmit Daniel Kachhap {
83f3b2a26cSAmit Daniel Kachhap 	char *ptr;
84f3b2a26cSAmit Daniel Kachhap 	int tag, run, result = KSFT_PASS;
85f3b2a26cSAmit Daniel Kachhap 	unsigned long excl_mask = 0;
86f3b2a26cSAmit Daniel Kachhap 
87*541235deSMark Brown 	ptr = mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
88f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
89f3b2a26cSAmit Daniel Kachhap 				   mem_type, false) != KSFT_PASS)
90f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
91f3b2a26cSAmit Daniel Kachhap 
92f3b2a26cSAmit Daniel Kachhap 	for (tag = 0; (tag < MT_TAG_COUNT - 1) && (result == KSFT_PASS); tag++) {
93f3b2a26cSAmit Daniel Kachhap 		excl_mask |= 1 << tag;
94f3b2a26cSAmit Daniel Kachhap 		mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask));
95f3b2a26cSAmit Daniel Kachhap 		/* Try to catch a excluded tag by a number of tries. */
96f3b2a26cSAmit Daniel Kachhap 		for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
97*541235deSMark Brown 			ptr = mte_insert_tags(ptr, BUFFER_SIZE);
98f3b2a26cSAmit Daniel Kachhap 			/* Check tag value */
99f3b2a26cSAmit Daniel Kachhap 			if (MT_FETCH_TAG((uintptr_t)ptr) < tag) {
100f3b2a26cSAmit Daniel Kachhap 				ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
101f3b2a26cSAmit Daniel Kachhap 					       MT_FETCH_TAG((uintptr_t)ptr),
102f3b2a26cSAmit Daniel Kachhap 					       MT_INCLUDE_VALID_TAGS(excl_mask));
103f3b2a26cSAmit Daniel Kachhap 				result = KSFT_FAIL;
104f3b2a26cSAmit Daniel Kachhap 				break;
105f3b2a26cSAmit Daniel Kachhap 			}
106f3b2a26cSAmit Daniel Kachhap 			result = verify_mte_pointer_validity(ptr, mode);
107f3b2a26cSAmit Daniel Kachhap 		}
108f3b2a26cSAmit Daniel Kachhap 	}
109*541235deSMark Brown 	mte_free_memory_tag_range(ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
110f3b2a26cSAmit Daniel Kachhap 	return result;
111f3b2a26cSAmit Daniel Kachhap }
112f3b2a26cSAmit Daniel Kachhap 
check_all_included_tags(int mem_type,int mode)113f3b2a26cSAmit Daniel Kachhap static int check_all_included_tags(int mem_type, int mode)
114f3b2a26cSAmit Daniel Kachhap {
115f3b2a26cSAmit Daniel Kachhap 	char *ptr;
11672d6771cSMark Brown 	int run, ret, result = KSFT_PASS;
117f3b2a26cSAmit Daniel Kachhap 
118*541235deSMark Brown 	ptr = mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
119f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
120f3b2a26cSAmit Daniel Kachhap 				   mem_type, false) != KSFT_PASS)
121f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
122f3b2a26cSAmit Daniel Kachhap 
12372d6771cSMark Brown 	ret = mte_switch_mode(mode, MT_INCLUDE_TAG_MASK);
12472d6771cSMark Brown 	if (ret != 0)
12572d6771cSMark Brown 		return KSFT_FAIL;
126f3b2a26cSAmit Daniel Kachhap 	/* Try to catch a excluded tag by a number of tries. */
127f3b2a26cSAmit Daniel Kachhap 	for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
128f3b2a26cSAmit Daniel Kachhap 		ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
129f3b2a26cSAmit Daniel Kachhap 		/*
130f3b2a26cSAmit Daniel Kachhap 		 * Here tag byte can be between 0x0 to 0xF (full allowed range)
131f3b2a26cSAmit Daniel Kachhap 		 * so no need to match so just verify if it is writable.
132f3b2a26cSAmit Daniel Kachhap 		 */
133f3b2a26cSAmit Daniel Kachhap 		result = verify_mte_pointer_validity(ptr, mode);
134f3b2a26cSAmit Daniel Kachhap 	}
135*541235deSMark Brown 	mte_free_memory_tag_range(ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
136f3b2a26cSAmit Daniel Kachhap 	return result;
137f3b2a26cSAmit Daniel Kachhap }
138f3b2a26cSAmit Daniel Kachhap 
check_none_included_tags(int mem_type,int mode)139f3b2a26cSAmit Daniel Kachhap static int check_none_included_tags(int mem_type, int mode)
140f3b2a26cSAmit Daniel Kachhap {
141f3b2a26cSAmit Daniel Kachhap 	char *ptr;
14272d6771cSMark Brown 	int run, ret;
143f3b2a26cSAmit Daniel Kachhap 
144*541235deSMark Brown 	ptr = mte_allocate_memory(BUFFER_SIZE, mem_type, 0, false);
145f3b2a26cSAmit Daniel Kachhap 	if (check_allocated_memory(ptr, BUFFER_SIZE, mem_type, false) != KSFT_PASS)
146f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
147f3b2a26cSAmit Daniel Kachhap 
14872d6771cSMark Brown 	ret = mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK);
14972d6771cSMark Brown 	if (ret != 0)
15072d6771cSMark Brown 		return KSFT_FAIL;
151f3b2a26cSAmit Daniel Kachhap 	/* Try to catch a excluded tag by a number of tries. */
152f3b2a26cSAmit Daniel Kachhap 	for (run = 0; run < RUNS; run++) {
153f3b2a26cSAmit Daniel Kachhap 		ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
154f3b2a26cSAmit Daniel Kachhap 		/* Here all tags exluded so tag value generated should be 0 */
155f3b2a26cSAmit Daniel Kachhap 		if (MT_FETCH_TAG((uintptr_t)ptr)) {
156f3b2a26cSAmit Daniel Kachhap 			ksft_print_msg("FAIL: included tag value found\n");
157f3b2a26cSAmit Daniel Kachhap 			mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, true);
158f3b2a26cSAmit Daniel Kachhap 			return KSFT_FAIL;
159f3b2a26cSAmit Daniel Kachhap 		}
160f3b2a26cSAmit Daniel Kachhap 		mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
161f3b2a26cSAmit Daniel Kachhap 		/* Check the write validity of the untagged pointer */
162*541235deSMark Brown 		memset(ptr, '1', BUFFER_SIZE);
163f3b2a26cSAmit Daniel Kachhap 		mte_wait_after_trig();
164f3b2a26cSAmit Daniel Kachhap 		if (cur_mte_cxt.fault_valid)
165f3b2a26cSAmit Daniel Kachhap 			break;
166f3b2a26cSAmit Daniel Kachhap 	}
167*541235deSMark Brown 	mte_free_memory(ptr, BUFFER_SIZE, mem_type, false);
168f3b2a26cSAmit Daniel Kachhap 	if (cur_mte_cxt.fault_valid)
169f3b2a26cSAmit Daniel Kachhap 		return KSFT_FAIL;
170f3b2a26cSAmit Daniel Kachhap 	else
171f3b2a26cSAmit Daniel Kachhap 		return KSFT_PASS;
172f3b2a26cSAmit Daniel Kachhap }
173f3b2a26cSAmit Daniel Kachhap 
main(int argc,char * argv[])174f3b2a26cSAmit Daniel Kachhap int main(int argc, char *argv[])
175f3b2a26cSAmit Daniel Kachhap {
176f3b2a26cSAmit Daniel Kachhap 	int err;
177f3b2a26cSAmit Daniel Kachhap 
178f3b2a26cSAmit Daniel Kachhap 	err = mte_default_setup();
179f3b2a26cSAmit Daniel Kachhap 	if (err)
180f3b2a26cSAmit Daniel Kachhap 		return err;
181f3b2a26cSAmit Daniel Kachhap 
182f3b2a26cSAmit Daniel Kachhap 	/* Register SIGSEGV handler */
183f3b2a26cSAmit Daniel Kachhap 	mte_register_signal(SIGSEGV, mte_default_handler);
184f3b2a26cSAmit Daniel Kachhap 
185041fa41fSVincenzo Frascino 	/* Set test plan */
186041fa41fSVincenzo Frascino 	ksft_set_plan(4);
187041fa41fSVincenzo Frascino 
188f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_single_included_tags(USE_MMAP, MTE_SYNC_ERR),
189f3b2a26cSAmit Daniel Kachhap 		      "Check an included tag value with sync mode\n");
190f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_multiple_included_tags(USE_MMAP, MTE_SYNC_ERR),
191f3b2a26cSAmit Daniel Kachhap 		      "Check different included tags value with sync mode\n");
192f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_none_included_tags(USE_MMAP, MTE_SYNC_ERR),
193f3b2a26cSAmit Daniel Kachhap 		      "Check none included tags value with sync mode\n");
194f3b2a26cSAmit Daniel Kachhap 	evaluate_test(check_all_included_tags(USE_MMAP, MTE_SYNC_ERR),
195f3b2a26cSAmit Daniel Kachhap 		      "Check all included tags value with sync mode\n");
196f3b2a26cSAmit Daniel Kachhap 
197f3b2a26cSAmit Daniel Kachhap 	mte_restore_setup();
198f3b2a26cSAmit Daniel Kachhap 	ksft_print_cnts();
199f3b2a26cSAmit Daniel Kachhap 	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
200f3b2a26cSAmit Daniel Kachhap }
201