1e9b60476SAmit Daniel Kachhap // SPDX-License-Identifier: GPL-2.0
2e9b60476SAmit Daniel Kachhap // Copyright (C) 2020 ARM Limited
3e9b60476SAmit Daniel Kachhap
4e9b60476SAmit Daniel Kachhap #include <fcntl.h>
5e9b60476SAmit Daniel Kachhap #include <sched.h>
6e9b60476SAmit Daniel Kachhap #include <signal.h>
7e9b60476SAmit Daniel Kachhap #include <stdio.h>
8e9b60476SAmit Daniel Kachhap #include <stdlib.h>
9e9b60476SAmit Daniel Kachhap #include <unistd.h>
10e9b60476SAmit Daniel Kachhap
11e9b60476SAmit Daniel Kachhap #include <linux/auxvec.h>
12e9b60476SAmit Daniel Kachhap #include <sys/auxv.h>
13e9b60476SAmit Daniel Kachhap #include <sys/mman.h>
14e9b60476SAmit Daniel Kachhap #include <sys/prctl.h>
15e9b60476SAmit Daniel Kachhap
16e9b60476SAmit Daniel Kachhap #include <asm/hwcap.h>
17e9b60476SAmit Daniel Kachhap
18e9b60476SAmit Daniel Kachhap #include "kselftest.h"
19e9b60476SAmit Daniel Kachhap #include "mte_common_util.h"
20e9b60476SAmit Daniel Kachhap #include "mte_def.h"
21e9b60476SAmit Daniel Kachhap
22e9b60476SAmit Daniel Kachhap #define INIT_BUFFER_SIZE 256
23e9b60476SAmit Daniel Kachhap
24e9b60476SAmit Daniel Kachhap struct mte_fault_cxt cur_mte_cxt;
25e9b60476SAmit Daniel Kachhap static unsigned int mte_cur_mode;
26e9b60476SAmit Daniel Kachhap static unsigned int mte_cur_pstate_tco;
27e9b60476SAmit Daniel Kachhap
mte_default_handler(int signum,siginfo_t * si,void * uc)28e9b60476SAmit Daniel Kachhap void mte_default_handler(int signum, siginfo_t *si, void *uc)
29e9b60476SAmit Daniel Kachhap {
30e9b60476SAmit Daniel Kachhap unsigned long addr = (unsigned long)si->si_addr;
31e9b60476SAmit Daniel Kachhap
32e9b60476SAmit Daniel Kachhap if (signum == SIGSEGV) {
33e9b60476SAmit Daniel Kachhap #ifdef DEBUG
34e9b60476SAmit Daniel Kachhap ksft_print_msg("INFO: SIGSEGV signal at pc=%lx, fault addr=%lx, si_code=%lx\n",
35e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc, addr, si->si_code);
36e9b60476SAmit Daniel Kachhap #endif
37e9b60476SAmit Daniel Kachhap if (si->si_code == SEGV_MTEAERR) {
38e9b60476SAmit Daniel Kachhap if (cur_mte_cxt.trig_si_code == si->si_code)
39e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = true;
40191e678bSMark Brown else
41*b95a1cd2SAndre Przywara ksft_print_msg("Got unexpected SEGV_MTEAERR at pc=%llx, fault addr=%lx\n",
42191e678bSMark Brown ((ucontext_t *)uc)->uc_mcontext.pc,
43191e678bSMark Brown addr);
44e9b60476SAmit Daniel Kachhap return;
45e9b60476SAmit Daniel Kachhap }
46e9b60476SAmit Daniel Kachhap /* Compare the context for precise error */
47e9b60476SAmit Daniel Kachhap else if (si->si_code == SEGV_MTESERR) {
48e9b60476SAmit Daniel Kachhap if (cur_mte_cxt.trig_si_code == si->si_code &&
49e9b60476SAmit Daniel Kachhap ((cur_mte_cxt.trig_range >= 0 &&
50e9b60476SAmit Daniel Kachhap addr >= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
51e9b60476SAmit Daniel Kachhap addr <= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)) ||
52e9b60476SAmit Daniel Kachhap (cur_mte_cxt.trig_range < 0 &&
53e9b60476SAmit Daniel Kachhap addr <= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
54e9b60476SAmit Daniel Kachhap addr >= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)))) {
55e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = true;
56e9b60476SAmit Daniel Kachhap /* Adjust the pc by 4 */
57e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc += 4;
58e9b60476SAmit Daniel Kachhap } else {
59e9b60476SAmit Daniel Kachhap ksft_print_msg("Invalid MTE synchronous exception caught!\n");
60e9b60476SAmit Daniel Kachhap exit(1);
61e9b60476SAmit Daniel Kachhap }
62e9b60476SAmit Daniel Kachhap } else {
63e9b60476SAmit Daniel Kachhap ksft_print_msg("Unknown SIGSEGV exception caught!\n");
64e9b60476SAmit Daniel Kachhap exit(1);
65e9b60476SAmit Daniel Kachhap }
66e9b60476SAmit Daniel Kachhap } else if (signum == SIGBUS) {
67*b95a1cd2SAndre Przywara ksft_print_msg("INFO: SIGBUS signal at pc=%llx, fault addr=%lx, si_code=%x\n",
68e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc, addr, si->si_code);
69e9b60476SAmit Daniel Kachhap if ((cur_mte_cxt.trig_range >= 0 &&
70e9b60476SAmit Daniel Kachhap addr >= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
71e9b60476SAmit Daniel Kachhap addr <= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)) ||
72e9b60476SAmit Daniel Kachhap (cur_mte_cxt.trig_range < 0 &&
73e9b60476SAmit Daniel Kachhap addr <= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
74e9b60476SAmit Daniel Kachhap addr >= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range))) {
75e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = true;
76e9b60476SAmit Daniel Kachhap /* Adjust the pc by 4 */
77e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc += 4;
78e9b60476SAmit Daniel Kachhap }
79e9b60476SAmit Daniel Kachhap }
80e9b60476SAmit Daniel Kachhap }
81e9b60476SAmit Daniel Kachhap
mte_register_signal(int signal,void (* handler)(int,siginfo_t *,void *))82e9b60476SAmit Daniel Kachhap void mte_register_signal(int signal, void (*handler)(int, siginfo_t *, void *))
83e9b60476SAmit Daniel Kachhap {
84e9b60476SAmit Daniel Kachhap struct sigaction sa;
85e9b60476SAmit Daniel Kachhap
86e9b60476SAmit Daniel Kachhap sa.sa_sigaction = handler;
87e9b60476SAmit Daniel Kachhap sa.sa_flags = SA_SIGINFO;
88e9b60476SAmit Daniel Kachhap sigemptyset(&sa.sa_mask);
89e9b60476SAmit Daniel Kachhap sigaction(signal, &sa, NULL);
90e9b60476SAmit Daniel Kachhap }
91e9b60476SAmit Daniel Kachhap
mte_wait_after_trig(void)92e9b60476SAmit Daniel Kachhap void mte_wait_after_trig(void)
93e9b60476SAmit Daniel Kachhap {
94e9b60476SAmit Daniel Kachhap sched_yield();
95e9b60476SAmit Daniel Kachhap }
96e9b60476SAmit Daniel Kachhap
mte_insert_tags(void * ptr,size_t size)97e9b60476SAmit Daniel Kachhap void *mte_insert_tags(void *ptr, size_t size)
98e9b60476SAmit Daniel Kachhap {
99e9b60476SAmit Daniel Kachhap void *tag_ptr;
100e9b60476SAmit Daniel Kachhap int align_size;
101e9b60476SAmit Daniel Kachhap
102e9b60476SAmit Daniel Kachhap if (!ptr || (unsigned long)(ptr) & MT_ALIGN_GRANULE) {
103e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Addr=%lx: invalid\n", ptr);
104e9b60476SAmit Daniel Kachhap return NULL;
105e9b60476SAmit Daniel Kachhap }
106e9b60476SAmit Daniel Kachhap align_size = MT_ALIGN_UP(size);
107e9b60476SAmit Daniel Kachhap tag_ptr = mte_insert_random_tag(ptr);
108e9b60476SAmit Daniel Kachhap mte_set_tag_address_range(tag_ptr, align_size);
109e9b60476SAmit Daniel Kachhap return tag_ptr;
110e9b60476SAmit Daniel Kachhap }
111e9b60476SAmit Daniel Kachhap
mte_clear_tags(void * ptr,size_t size)112e9b60476SAmit Daniel Kachhap void mte_clear_tags(void *ptr, size_t size)
113e9b60476SAmit Daniel Kachhap {
114e9b60476SAmit Daniel Kachhap if (!ptr || (unsigned long)(ptr) & MT_ALIGN_GRANULE) {
115e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Addr=%lx: invalid\n", ptr);
116e9b60476SAmit Daniel Kachhap return;
117e9b60476SAmit Daniel Kachhap }
118e9b60476SAmit Daniel Kachhap size = MT_ALIGN_UP(size);
119e9b60476SAmit Daniel Kachhap ptr = (void *)MT_CLEAR_TAG((unsigned long)ptr);
120e9b60476SAmit Daniel Kachhap mte_clear_tag_address_range(ptr, size);
121e9b60476SAmit Daniel Kachhap }
122e9b60476SAmit Daniel Kachhap
__mte_allocate_memory_range(size_t size,int mem_type,int mapping,size_t range_before,size_t range_after,bool tags,int fd)123e9b60476SAmit Daniel Kachhap static void *__mte_allocate_memory_range(size_t size, int mem_type, int mapping,
124e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after,
125e9b60476SAmit Daniel Kachhap bool tags, int fd)
126e9b60476SAmit Daniel Kachhap {
127e9b60476SAmit Daniel Kachhap void *ptr;
128e9b60476SAmit Daniel Kachhap int prot_flag, map_flag;
129e9b60476SAmit Daniel Kachhap size_t entire_size = size + range_before + range_after;
130e9b60476SAmit Daniel Kachhap
1310639e022SMark Brown switch (mem_type) {
1320639e022SMark Brown case USE_MALLOC:
1330639e022SMark Brown return malloc(entire_size) + range_before;
1340639e022SMark Brown case USE_MMAP:
1350639e022SMark Brown case USE_MPROTECT:
1360639e022SMark Brown break;
1370639e022SMark Brown default:
138e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid allocate request\n");
139e9b60476SAmit Daniel Kachhap return NULL;
140e9b60476SAmit Daniel Kachhap }
141e9b60476SAmit Daniel Kachhap
142e9b60476SAmit Daniel Kachhap prot_flag = PROT_READ | PROT_WRITE;
143e9b60476SAmit Daniel Kachhap if (mem_type == USE_MMAP)
144e9b60476SAmit Daniel Kachhap prot_flag |= PROT_MTE;
145e9b60476SAmit Daniel Kachhap
146e9b60476SAmit Daniel Kachhap map_flag = mapping;
147e9b60476SAmit Daniel Kachhap if (fd == -1)
148e9b60476SAmit Daniel Kachhap map_flag = MAP_ANONYMOUS | map_flag;
149e9b60476SAmit Daniel Kachhap if (!(mapping & MAP_SHARED))
150e9b60476SAmit Daniel Kachhap map_flag |= MAP_PRIVATE;
151e9b60476SAmit Daniel Kachhap ptr = mmap(NULL, entire_size, prot_flag, map_flag, fd, 0);
152e9b60476SAmit Daniel Kachhap if (ptr == MAP_FAILED) {
153e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: mmap allocation\n");
154e9b60476SAmit Daniel Kachhap return NULL;
155e9b60476SAmit Daniel Kachhap }
156e9b60476SAmit Daniel Kachhap if (mem_type == USE_MPROTECT) {
157e9b60476SAmit Daniel Kachhap if (mprotect(ptr, entire_size, prot_flag | PROT_MTE)) {
158e9b60476SAmit Daniel Kachhap munmap(ptr, size);
159e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: mprotect PROT_MTE property\n");
160e9b60476SAmit Daniel Kachhap return NULL;
161e9b60476SAmit Daniel Kachhap }
162e9b60476SAmit Daniel Kachhap }
163e9b60476SAmit Daniel Kachhap if (tags)
164e9b60476SAmit Daniel Kachhap ptr = mte_insert_tags(ptr + range_before, size);
165e9b60476SAmit Daniel Kachhap return ptr;
166e9b60476SAmit Daniel Kachhap }
167e9b60476SAmit Daniel Kachhap
mte_allocate_memory_tag_range(size_t size,int mem_type,int mapping,size_t range_before,size_t range_after)168e9b60476SAmit Daniel Kachhap void *mte_allocate_memory_tag_range(size_t size, int mem_type, int mapping,
169e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after)
170e9b60476SAmit Daniel Kachhap {
171e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, range_before,
172e9b60476SAmit Daniel Kachhap range_after, true, -1);
173e9b60476SAmit Daniel Kachhap }
174e9b60476SAmit Daniel Kachhap
mte_allocate_memory(size_t size,int mem_type,int mapping,bool tags)175e9b60476SAmit Daniel Kachhap void *mte_allocate_memory(size_t size, int mem_type, int mapping, bool tags)
176e9b60476SAmit Daniel Kachhap {
177e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, -1);
178e9b60476SAmit Daniel Kachhap }
179e9b60476SAmit Daniel Kachhap
mte_allocate_file_memory(size_t size,int mem_type,int mapping,bool tags,int fd)180e9b60476SAmit Daniel Kachhap void *mte_allocate_file_memory(size_t size, int mem_type, int mapping, bool tags, int fd)
181e9b60476SAmit Daniel Kachhap {
182e9b60476SAmit Daniel Kachhap int index;
183e9b60476SAmit Daniel Kachhap char buffer[INIT_BUFFER_SIZE];
184e9b60476SAmit Daniel Kachhap
185e9b60476SAmit Daniel Kachhap if (mem_type != USE_MPROTECT && mem_type != USE_MMAP) {
186e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid mmap file request\n");
187e9b60476SAmit Daniel Kachhap return NULL;
188e9b60476SAmit Daniel Kachhap }
189e9b60476SAmit Daniel Kachhap /* Initialize the file for mappable size */
190e9b60476SAmit Daniel Kachhap lseek(fd, 0, SEEK_SET);
191d302a702SAndre Przywara for (index = INIT_BUFFER_SIZE; index < size; index += INIT_BUFFER_SIZE) {
192d302a702SAndre Przywara if (write(fd, buffer, INIT_BUFFER_SIZE) != INIT_BUFFER_SIZE) {
193d302a702SAndre Przywara perror("initialising buffer");
194d302a702SAndre Przywara return NULL;
195d302a702SAndre Przywara }
196d302a702SAndre Przywara }
197e9b60476SAmit Daniel Kachhap index -= INIT_BUFFER_SIZE;
198d302a702SAndre Przywara if (write(fd, buffer, size - index) != size - index) {
199d302a702SAndre Przywara perror("initialising buffer");
200d302a702SAndre Przywara return NULL;
201d302a702SAndre Przywara }
202e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, fd);
203e9b60476SAmit Daniel Kachhap }
204e9b60476SAmit Daniel Kachhap
mte_allocate_file_memory_tag_range(size_t size,int mem_type,int mapping,size_t range_before,size_t range_after,int fd)205e9b60476SAmit Daniel Kachhap void *mte_allocate_file_memory_tag_range(size_t size, int mem_type, int mapping,
206e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after, int fd)
207e9b60476SAmit Daniel Kachhap {
208e9b60476SAmit Daniel Kachhap int index;
209e9b60476SAmit Daniel Kachhap char buffer[INIT_BUFFER_SIZE];
210e9b60476SAmit Daniel Kachhap int map_size = size + range_before + range_after;
211e9b60476SAmit Daniel Kachhap
212e9b60476SAmit Daniel Kachhap if (mem_type != USE_MPROTECT && mem_type != USE_MMAP) {
213e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid mmap file request\n");
214e9b60476SAmit Daniel Kachhap return NULL;
215e9b60476SAmit Daniel Kachhap }
216e9b60476SAmit Daniel Kachhap /* Initialize the file for mappable size */
217e9b60476SAmit Daniel Kachhap lseek(fd, 0, SEEK_SET);
218e9b60476SAmit Daniel Kachhap for (index = INIT_BUFFER_SIZE; index < map_size; index += INIT_BUFFER_SIZE)
219d302a702SAndre Przywara if (write(fd, buffer, INIT_BUFFER_SIZE) != INIT_BUFFER_SIZE) {
220d302a702SAndre Przywara perror("initialising buffer");
221d302a702SAndre Przywara return NULL;
222d302a702SAndre Przywara }
223e9b60476SAmit Daniel Kachhap index -= INIT_BUFFER_SIZE;
224d302a702SAndre Przywara if (write(fd, buffer, map_size - index) != map_size - index) {
225d302a702SAndre Przywara perror("initialising buffer");
226d302a702SAndre Przywara return NULL;
227d302a702SAndre Przywara }
228e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, range_before,
229e9b60476SAmit Daniel Kachhap range_after, true, fd);
230e9b60476SAmit Daniel Kachhap }
231e9b60476SAmit Daniel Kachhap
__mte_free_memory_range(void * ptr,size_t size,int mem_type,size_t range_before,size_t range_after,bool tags)232e9b60476SAmit Daniel Kachhap static void __mte_free_memory_range(void *ptr, size_t size, int mem_type,
233e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after, bool tags)
234e9b60476SAmit Daniel Kachhap {
235e9b60476SAmit Daniel Kachhap switch (mem_type) {
236e9b60476SAmit Daniel Kachhap case USE_MALLOC:
237e9b60476SAmit Daniel Kachhap free(ptr - range_before);
238e9b60476SAmit Daniel Kachhap break;
239e9b60476SAmit Daniel Kachhap case USE_MMAP:
240e9b60476SAmit Daniel Kachhap case USE_MPROTECT:
241e9b60476SAmit Daniel Kachhap if (tags)
242e9b60476SAmit Daniel Kachhap mte_clear_tags(ptr, size);
243e9b60476SAmit Daniel Kachhap munmap(ptr - range_before, size + range_before + range_after);
244e9b60476SAmit Daniel Kachhap break;
245e9b60476SAmit Daniel Kachhap default:
246e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid free request\n");
247e9b60476SAmit Daniel Kachhap break;
248e9b60476SAmit Daniel Kachhap }
249e9b60476SAmit Daniel Kachhap }
250e9b60476SAmit Daniel Kachhap
mte_free_memory_tag_range(void * ptr,size_t size,int mem_type,size_t range_before,size_t range_after)251e9b60476SAmit Daniel Kachhap void mte_free_memory_tag_range(void *ptr, size_t size, int mem_type,
252e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after)
253e9b60476SAmit Daniel Kachhap {
254e9b60476SAmit Daniel Kachhap __mte_free_memory_range(ptr, size, mem_type, range_before, range_after, true);
255e9b60476SAmit Daniel Kachhap }
256e9b60476SAmit Daniel Kachhap
mte_free_memory(void * ptr,size_t size,int mem_type,bool tags)257e9b60476SAmit Daniel Kachhap void mte_free_memory(void *ptr, size_t size, int mem_type, bool tags)
258e9b60476SAmit Daniel Kachhap {
259e9b60476SAmit Daniel Kachhap __mte_free_memory_range(ptr, size, mem_type, 0, 0, tags);
260e9b60476SAmit Daniel Kachhap }
261e9b60476SAmit Daniel Kachhap
mte_initialize_current_context(int mode,uintptr_t ptr,ssize_t range)262e9b60476SAmit Daniel Kachhap void mte_initialize_current_context(int mode, uintptr_t ptr, ssize_t range)
263e9b60476SAmit Daniel Kachhap {
264e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = false;
265e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_addr = ptr;
266e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_range = range;
267e9b60476SAmit Daniel Kachhap if (mode == MTE_SYNC_ERR)
268e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_si_code = SEGV_MTESERR;
269e9b60476SAmit Daniel Kachhap else if (mode == MTE_ASYNC_ERR)
270e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_si_code = SEGV_MTEAERR;
271e9b60476SAmit Daniel Kachhap else
272e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_si_code = 0;
273e9b60476SAmit Daniel Kachhap }
274e9b60476SAmit Daniel Kachhap
mte_switch_mode(int mte_option,unsigned long incl_mask)275e9b60476SAmit Daniel Kachhap int mte_switch_mode(int mte_option, unsigned long incl_mask)
276e9b60476SAmit Daniel Kachhap {
277e9b60476SAmit Daniel Kachhap unsigned long en = 0;
278e9b60476SAmit Daniel Kachhap
279f326c9a6SMark Brown switch (mte_option) {
280f326c9a6SMark Brown case MTE_NONE_ERR:
281f326c9a6SMark Brown case MTE_SYNC_ERR:
282f326c9a6SMark Brown case MTE_ASYNC_ERR:
283f326c9a6SMark Brown break;
284f326c9a6SMark Brown default:
285f326c9a6SMark Brown ksft_print_msg("FAIL: Invalid MTE option %x\n", mte_option);
286f326c9a6SMark Brown return -EINVAL;
287f326c9a6SMark Brown }
288f326c9a6SMark Brown
289ffc8274cSMark Brown if (incl_mask & ~MT_INCLUDE_TAG_MASK) {
290f326c9a6SMark Brown ksft_print_msg("FAIL: Invalid incl_mask %lx\n", incl_mask);
291e9b60476SAmit Daniel Kachhap return -EINVAL;
292e9b60476SAmit Daniel Kachhap }
2930639e022SMark Brown
294e9b60476SAmit Daniel Kachhap en = PR_TAGGED_ADDR_ENABLE;
2950639e022SMark Brown switch (mte_option) {
2960639e022SMark Brown case MTE_SYNC_ERR:
297e9b60476SAmit Daniel Kachhap en |= PR_MTE_TCF_SYNC;
2980639e022SMark Brown break;
2990639e022SMark Brown case MTE_ASYNC_ERR:
300e9b60476SAmit Daniel Kachhap en |= PR_MTE_TCF_ASYNC;
3010639e022SMark Brown break;
3020639e022SMark Brown case MTE_NONE_ERR:
303e9b60476SAmit Daniel Kachhap en |= PR_MTE_TCF_NONE;
3040639e022SMark Brown break;
3050639e022SMark Brown }
306e9b60476SAmit Daniel Kachhap
307e9b60476SAmit Daniel Kachhap en |= (incl_mask << PR_MTE_TAG_SHIFT);
308e9b60476SAmit Daniel Kachhap /* Enable address tagging ABI, mte error reporting mode and tag inclusion mask. */
309b4e1fa22SAndre Przywara if (prctl(PR_SET_TAGGED_ADDR_CTRL, en, 0, 0, 0) != 0) {
310e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL:prctl PR_SET_TAGGED_ADDR_CTRL for mte mode\n");
311e9b60476SAmit Daniel Kachhap return -EINVAL;
312e9b60476SAmit Daniel Kachhap }
313e9b60476SAmit Daniel Kachhap return 0;
314e9b60476SAmit Daniel Kachhap }
315e9b60476SAmit Daniel Kachhap
mte_default_setup(void)316e9b60476SAmit Daniel Kachhap int mte_default_setup(void)
317e9b60476SAmit Daniel Kachhap {
31859243286SAndre Przywara unsigned long hwcaps2 = getauxval(AT_HWCAP2);
319e9b60476SAmit Daniel Kachhap unsigned long en = 0;
320e9b60476SAmit Daniel Kachhap int ret;
321e9b60476SAmit Daniel Kachhap
32259243286SAndre Przywara if (!(hwcaps2 & HWCAP2_MTE)) {
32383e5dcbeSMark Brown ksft_print_msg("SKIP: MTE features unavailable\n");
324e9b60476SAmit Daniel Kachhap return KSFT_SKIP;
325e9b60476SAmit Daniel Kachhap }
326e9b60476SAmit Daniel Kachhap /* Get current mte mode */
327e9b60476SAmit Daniel Kachhap ret = prctl(PR_GET_TAGGED_ADDR_CTRL, en, 0, 0, 0);
328e9b60476SAmit Daniel Kachhap if (ret < 0) {
329e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL:prctl PR_GET_TAGGED_ADDR_CTRL with error =%d\n", ret);
330e9b60476SAmit Daniel Kachhap return KSFT_FAIL;
331e9b60476SAmit Daniel Kachhap }
332e9b60476SAmit Daniel Kachhap if (ret & PR_MTE_TCF_SYNC)
333e9b60476SAmit Daniel Kachhap mte_cur_mode = MTE_SYNC_ERR;
334e9b60476SAmit Daniel Kachhap else if (ret & PR_MTE_TCF_ASYNC)
335e9b60476SAmit Daniel Kachhap mte_cur_mode = MTE_ASYNC_ERR;
336e9b60476SAmit Daniel Kachhap else if (ret & PR_MTE_TCF_NONE)
337e9b60476SAmit Daniel Kachhap mte_cur_mode = MTE_NONE_ERR;
338e9b60476SAmit Daniel Kachhap
339e9b60476SAmit Daniel Kachhap mte_cur_pstate_tco = mte_get_pstate_tco();
340e9b60476SAmit Daniel Kachhap /* Disable PSTATE.TCO */
341e9b60476SAmit Daniel Kachhap mte_disable_pstate_tco();
342e9b60476SAmit Daniel Kachhap return 0;
343e9b60476SAmit Daniel Kachhap }
344e9b60476SAmit Daniel Kachhap
mte_restore_setup(void)345e9b60476SAmit Daniel Kachhap void mte_restore_setup(void)
346e9b60476SAmit Daniel Kachhap {
347e9b60476SAmit Daniel Kachhap mte_switch_mode(mte_cur_mode, MTE_ALLOW_NON_ZERO_TAG);
348e9b60476SAmit Daniel Kachhap if (mte_cur_pstate_tco == MT_PSTATE_TCO_EN)
349e9b60476SAmit Daniel Kachhap mte_enable_pstate_tco();
350e9b60476SAmit Daniel Kachhap else if (mte_cur_pstate_tco == MT_PSTATE_TCO_DIS)
351e9b60476SAmit Daniel Kachhap mte_disable_pstate_tco();
352e9b60476SAmit Daniel Kachhap }
353e9b60476SAmit Daniel Kachhap
create_temp_file(void)354e9b60476SAmit Daniel Kachhap int create_temp_file(void)
355e9b60476SAmit Daniel Kachhap {
356e9b60476SAmit Daniel Kachhap int fd;
357e9b60476SAmit Daniel Kachhap char filename[] = "/dev/shm/tmp_XXXXXX";
358e9b60476SAmit Daniel Kachhap
359e9b60476SAmit Daniel Kachhap /* Create a file in the tmpfs filesystem */
360e9b60476SAmit Daniel Kachhap fd = mkstemp(&filename[0]);
361e9b60476SAmit Daniel Kachhap if (fd == -1) {
36275347addSAndre Przywara perror(filename);
363e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Unable to open temporary file\n");
364e9b60476SAmit Daniel Kachhap return 0;
365e9b60476SAmit Daniel Kachhap }
366e9b60476SAmit Daniel Kachhap unlink(&filename[0]);
367e9b60476SAmit Daniel Kachhap return fd;
368e9b60476SAmit Daniel Kachhap }
369