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 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; 40e9b60476SAmit Daniel Kachhap return; 41e9b60476SAmit Daniel Kachhap } 42e9b60476SAmit Daniel Kachhap /* Compare the context for precise error */ 43e9b60476SAmit Daniel Kachhap else if (si->si_code == SEGV_MTESERR) { 44e9b60476SAmit Daniel Kachhap if (cur_mte_cxt.trig_si_code == si->si_code && 45e9b60476SAmit Daniel Kachhap ((cur_mte_cxt.trig_range >= 0 && 46e9b60476SAmit Daniel Kachhap addr >= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) && 47e9b60476SAmit Daniel Kachhap addr <= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)) || 48e9b60476SAmit Daniel Kachhap (cur_mte_cxt.trig_range < 0 && 49e9b60476SAmit Daniel Kachhap addr <= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) && 50e9b60476SAmit Daniel Kachhap addr >= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)))) { 51e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = true; 52e9b60476SAmit Daniel Kachhap /* Adjust the pc by 4 */ 53e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc += 4; 54e9b60476SAmit Daniel Kachhap } else { 55e9b60476SAmit Daniel Kachhap ksft_print_msg("Invalid MTE synchronous exception caught!\n"); 56e9b60476SAmit Daniel Kachhap exit(1); 57e9b60476SAmit Daniel Kachhap } 58e9b60476SAmit Daniel Kachhap } else { 59e9b60476SAmit Daniel Kachhap ksft_print_msg("Unknown SIGSEGV exception caught!\n"); 60e9b60476SAmit Daniel Kachhap exit(1); 61e9b60476SAmit Daniel Kachhap } 62e9b60476SAmit Daniel Kachhap } else if (signum == SIGBUS) { 63e9b60476SAmit Daniel Kachhap ksft_print_msg("INFO: SIGBUS signal at pc=%lx, fault addr=%lx, si_code=%lx\n", 64e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc, addr, si->si_code); 65e9b60476SAmit Daniel Kachhap if ((cur_mte_cxt.trig_range >= 0 && 66e9b60476SAmit Daniel Kachhap addr >= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) && 67e9b60476SAmit Daniel Kachhap addr <= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)) || 68e9b60476SAmit Daniel Kachhap (cur_mte_cxt.trig_range < 0 && 69e9b60476SAmit Daniel Kachhap addr <= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) && 70e9b60476SAmit Daniel Kachhap addr >= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range))) { 71e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = true; 72e9b60476SAmit Daniel Kachhap /* Adjust the pc by 4 */ 73e9b60476SAmit Daniel Kachhap ((ucontext_t *)uc)->uc_mcontext.pc += 4; 74e9b60476SAmit Daniel Kachhap } 75e9b60476SAmit Daniel Kachhap } 76e9b60476SAmit Daniel Kachhap } 77e9b60476SAmit Daniel Kachhap 78e9b60476SAmit Daniel Kachhap void mte_register_signal(int signal, void (*handler)(int, siginfo_t *, void *)) 79e9b60476SAmit Daniel Kachhap { 80e9b60476SAmit Daniel Kachhap struct sigaction sa; 81e9b60476SAmit Daniel Kachhap 82e9b60476SAmit Daniel Kachhap sa.sa_sigaction = handler; 83e9b60476SAmit Daniel Kachhap sa.sa_flags = SA_SIGINFO; 84e9b60476SAmit Daniel Kachhap sigemptyset(&sa.sa_mask); 85e9b60476SAmit Daniel Kachhap sigaction(signal, &sa, NULL); 86e9b60476SAmit Daniel Kachhap } 87e9b60476SAmit Daniel Kachhap 88e9b60476SAmit Daniel Kachhap void mte_wait_after_trig(void) 89e9b60476SAmit Daniel Kachhap { 90e9b60476SAmit Daniel Kachhap sched_yield(); 91e9b60476SAmit Daniel Kachhap } 92e9b60476SAmit Daniel Kachhap 93e9b60476SAmit Daniel Kachhap void *mte_insert_tags(void *ptr, size_t size) 94e9b60476SAmit Daniel Kachhap { 95e9b60476SAmit Daniel Kachhap void *tag_ptr; 96e9b60476SAmit Daniel Kachhap int align_size; 97e9b60476SAmit Daniel Kachhap 98e9b60476SAmit Daniel Kachhap if (!ptr || (unsigned long)(ptr) & MT_ALIGN_GRANULE) { 99e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Addr=%lx: invalid\n", ptr); 100e9b60476SAmit Daniel Kachhap return NULL; 101e9b60476SAmit Daniel Kachhap } 102e9b60476SAmit Daniel Kachhap align_size = MT_ALIGN_UP(size); 103e9b60476SAmit Daniel Kachhap tag_ptr = mte_insert_random_tag(ptr); 104e9b60476SAmit Daniel Kachhap mte_set_tag_address_range(tag_ptr, align_size); 105e9b60476SAmit Daniel Kachhap return tag_ptr; 106e9b60476SAmit Daniel Kachhap } 107e9b60476SAmit Daniel Kachhap 108e9b60476SAmit Daniel Kachhap void mte_clear_tags(void *ptr, size_t size) 109e9b60476SAmit Daniel Kachhap { 110e9b60476SAmit Daniel Kachhap if (!ptr || (unsigned long)(ptr) & MT_ALIGN_GRANULE) { 111e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Addr=%lx: invalid\n", ptr); 112e9b60476SAmit Daniel Kachhap return; 113e9b60476SAmit Daniel Kachhap } 114e9b60476SAmit Daniel Kachhap size = MT_ALIGN_UP(size); 115e9b60476SAmit Daniel Kachhap ptr = (void *)MT_CLEAR_TAG((unsigned long)ptr); 116e9b60476SAmit Daniel Kachhap mte_clear_tag_address_range(ptr, size); 117e9b60476SAmit Daniel Kachhap } 118e9b60476SAmit Daniel Kachhap 119e9b60476SAmit Daniel Kachhap static void *__mte_allocate_memory_range(size_t size, int mem_type, int mapping, 120e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after, 121e9b60476SAmit Daniel Kachhap bool tags, int fd) 122e9b60476SAmit Daniel Kachhap { 123e9b60476SAmit Daniel Kachhap void *ptr; 124e9b60476SAmit Daniel Kachhap int prot_flag, map_flag; 125e9b60476SAmit Daniel Kachhap size_t entire_size = size + range_before + range_after; 126e9b60476SAmit Daniel Kachhap 127e9b60476SAmit Daniel Kachhap if (mem_type != USE_MALLOC && mem_type != USE_MMAP && 128e9b60476SAmit Daniel Kachhap mem_type != USE_MPROTECT) { 129e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid allocate request\n"); 130e9b60476SAmit Daniel Kachhap return NULL; 131e9b60476SAmit Daniel Kachhap } 132e9b60476SAmit Daniel Kachhap if (mem_type == USE_MALLOC) 133e9b60476SAmit Daniel Kachhap return malloc(entire_size) + range_before; 134e9b60476SAmit Daniel Kachhap 135e9b60476SAmit Daniel Kachhap prot_flag = PROT_READ | PROT_WRITE; 136e9b60476SAmit Daniel Kachhap if (mem_type == USE_MMAP) 137e9b60476SAmit Daniel Kachhap prot_flag |= PROT_MTE; 138e9b60476SAmit Daniel Kachhap 139e9b60476SAmit Daniel Kachhap map_flag = mapping; 140e9b60476SAmit Daniel Kachhap if (fd == -1) 141e9b60476SAmit Daniel Kachhap map_flag = MAP_ANONYMOUS | map_flag; 142e9b60476SAmit Daniel Kachhap if (!(mapping & MAP_SHARED)) 143e9b60476SAmit Daniel Kachhap map_flag |= MAP_PRIVATE; 144e9b60476SAmit Daniel Kachhap ptr = mmap(NULL, entire_size, prot_flag, map_flag, fd, 0); 145e9b60476SAmit Daniel Kachhap if (ptr == MAP_FAILED) { 146e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: mmap allocation\n"); 147e9b60476SAmit Daniel Kachhap return NULL; 148e9b60476SAmit Daniel Kachhap } 149e9b60476SAmit Daniel Kachhap if (mem_type == USE_MPROTECT) { 150e9b60476SAmit Daniel Kachhap if (mprotect(ptr, entire_size, prot_flag | PROT_MTE)) { 151e9b60476SAmit Daniel Kachhap munmap(ptr, size); 152e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: mprotect PROT_MTE property\n"); 153e9b60476SAmit Daniel Kachhap return NULL; 154e9b60476SAmit Daniel Kachhap } 155e9b60476SAmit Daniel Kachhap } 156e9b60476SAmit Daniel Kachhap if (tags) 157e9b60476SAmit Daniel Kachhap ptr = mte_insert_tags(ptr + range_before, size); 158e9b60476SAmit Daniel Kachhap return ptr; 159e9b60476SAmit Daniel Kachhap } 160e9b60476SAmit Daniel Kachhap 161e9b60476SAmit Daniel Kachhap void *mte_allocate_memory_tag_range(size_t size, int mem_type, int mapping, 162e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after) 163e9b60476SAmit Daniel Kachhap { 164e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, range_before, 165e9b60476SAmit Daniel Kachhap range_after, true, -1); 166e9b60476SAmit Daniel Kachhap } 167e9b60476SAmit Daniel Kachhap 168e9b60476SAmit Daniel Kachhap void *mte_allocate_memory(size_t size, int mem_type, int mapping, bool tags) 169e9b60476SAmit Daniel Kachhap { 170e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, -1); 171e9b60476SAmit Daniel Kachhap } 172e9b60476SAmit Daniel Kachhap 173e9b60476SAmit Daniel Kachhap void *mte_allocate_file_memory(size_t size, int mem_type, int mapping, bool tags, int fd) 174e9b60476SAmit Daniel Kachhap { 175e9b60476SAmit Daniel Kachhap int index; 176e9b60476SAmit Daniel Kachhap char buffer[INIT_BUFFER_SIZE]; 177e9b60476SAmit Daniel Kachhap 178e9b60476SAmit Daniel Kachhap if (mem_type != USE_MPROTECT && mem_type != USE_MMAP) { 179e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid mmap file request\n"); 180e9b60476SAmit Daniel Kachhap return NULL; 181e9b60476SAmit Daniel Kachhap } 182e9b60476SAmit Daniel Kachhap /* Initialize the file for mappable size */ 183e9b60476SAmit Daniel Kachhap lseek(fd, 0, SEEK_SET); 184e9b60476SAmit Daniel Kachhap for (index = INIT_BUFFER_SIZE; index < size; index += INIT_BUFFER_SIZE) 185e9b60476SAmit Daniel Kachhap write(fd, buffer, INIT_BUFFER_SIZE); 186e9b60476SAmit Daniel Kachhap index -= INIT_BUFFER_SIZE; 187e9b60476SAmit Daniel Kachhap write(fd, buffer, size - index); 188e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, fd); 189e9b60476SAmit Daniel Kachhap } 190e9b60476SAmit Daniel Kachhap 191e9b60476SAmit Daniel Kachhap void *mte_allocate_file_memory_tag_range(size_t size, int mem_type, int mapping, 192e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after, int fd) 193e9b60476SAmit Daniel Kachhap { 194e9b60476SAmit Daniel Kachhap int index; 195e9b60476SAmit Daniel Kachhap char buffer[INIT_BUFFER_SIZE]; 196e9b60476SAmit Daniel Kachhap int map_size = size + range_before + range_after; 197e9b60476SAmit Daniel Kachhap 198e9b60476SAmit Daniel Kachhap if (mem_type != USE_MPROTECT && mem_type != USE_MMAP) { 199e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid mmap file request\n"); 200e9b60476SAmit Daniel Kachhap return NULL; 201e9b60476SAmit Daniel Kachhap } 202e9b60476SAmit Daniel Kachhap /* Initialize the file for mappable size */ 203e9b60476SAmit Daniel Kachhap lseek(fd, 0, SEEK_SET); 204e9b60476SAmit Daniel Kachhap for (index = INIT_BUFFER_SIZE; index < map_size; index += INIT_BUFFER_SIZE) 205e9b60476SAmit Daniel Kachhap write(fd, buffer, INIT_BUFFER_SIZE); 206e9b60476SAmit Daniel Kachhap index -= INIT_BUFFER_SIZE; 207e9b60476SAmit Daniel Kachhap write(fd, buffer, map_size - index); 208e9b60476SAmit Daniel Kachhap return __mte_allocate_memory_range(size, mem_type, mapping, range_before, 209e9b60476SAmit Daniel Kachhap range_after, true, fd); 210e9b60476SAmit Daniel Kachhap } 211e9b60476SAmit Daniel Kachhap 212e9b60476SAmit Daniel Kachhap static void __mte_free_memory_range(void *ptr, size_t size, int mem_type, 213e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after, bool tags) 214e9b60476SAmit Daniel Kachhap { 215e9b60476SAmit Daniel Kachhap switch (mem_type) { 216e9b60476SAmit Daniel Kachhap case USE_MALLOC: 217e9b60476SAmit Daniel Kachhap free(ptr - range_before); 218e9b60476SAmit Daniel Kachhap break; 219e9b60476SAmit Daniel Kachhap case USE_MMAP: 220e9b60476SAmit Daniel Kachhap case USE_MPROTECT: 221e9b60476SAmit Daniel Kachhap if (tags) 222e9b60476SAmit Daniel Kachhap mte_clear_tags(ptr, size); 223e9b60476SAmit Daniel Kachhap munmap(ptr - range_before, size + range_before + range_after); 224e9b60476SAmit Daniel Kachhap break; 225e9b60476SAmit Daniel Kachhap default: 226e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid free request\n"); 227e9b60476SAmit Daniel Kachhap break; 228e9b60476SAmit Daniel Kachhap } 229e9b60476SAmit Daniel Kachhap } 230e9b60476SAmit Daniel Kachhap 231e9b60476SAmit Daniel Kachhap void mte_free_memory_tag_range(void *ptr, size_t size, int mem_type, 232e9b60476SAmit Daniel Kachhap size_t range_before, size_t range_after) 233e9b60476SAmit Daniel Kachhap { 234e9b60476SAmit Daniel Kachhap __mte_free_memory_range(ptr, size, mem_type, range_before, range_after, true); 235e9b60476SAmit Daniel Kachhap } 236e9b60476SAmit Daniel Kachhap 237e9b60476SAmit Daniel Kachhap void mte_free_memory(void *ptr, size_t size, int mem_type, bool tags) 238e9b60476SAmit Daniel Kachhap { 239e9b60476SAmit Daniel Kachhap __mte_free_memory_range(ptr, size, mem_type, 0, 0, tags); 240e9b60476SAmit Daniel Kachhap } 241e9b60476SAmit Daniel Kachhap 242e9b60476SAmit Daniel Kachhap void mte_initialize_current_context(int mode, uintptr_t ptr, ssize_t range) 243e9b60476SAmit Daniel Kachhap { 244e9b60476SAmit Daniel Kachhap cur_mte_cxt.fault_valid = false; 245e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_addr = ptr; 246e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_range = range; 247e9b60476SAmit Daniel Kachhap if (mode == MTE_SYNC_ERR) 248e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_si_code = SEGV_MTESERR; 249e9b60476SAmit Daniel Kachhap else if (mode == MTE_ASYNC_ERR) 250e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_si_code = SEGV_MTEAERR; 251e9b60476SAmit Daniel Kachhap else 252e9b60476SAmit Daniel Kachhap cur_mte_cxt.trig_si_code = 0; 253e9b60476SAmit Daniel Kachhap } 254e9b60476SAmit Daniel Kachhap 255e9b60476SAmit Daniel Kachhap int mte_switch_mode(int mte_option, unsigned long incl_mask) 256e9b60476SAmit Daniel Kachhap { 257e9b60476SAmit Daniel Kachhap unsigned long en = 0; 258e9b60476SAmit Daniel Kachhap 259e9b60476SAmit Daniel Kachhap if (!(mte_option == MTE_SYNC_ERR || mte_option == MTE_ASYNC_ERR || 260e9b60476SAmit Daniel Kachhap mte_option == MTE_NONE_ERR || incl_mask <= MTE_ALLOW_NON_ZERO_TAG)) { 261e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Invalid mte config option\n"); 262e9b60476SAmit Daniel Kachhap return -EINVAL; 263e9b60476SAmit Daniel Kachhap } 264e9b60476SAmit Daniel Kachhap en = PR_TAGGED_ADDR_ENABLE; 265e9b60476SAmit Daniel Kachhap if (mte_option == MTE_SYNC_ERR) 266e9b60476SAmit Daniel Kachhap en |= PR_MTE_TCF_SYNC; 267e9b60476SAmit Daniel Kachhap else if (mte_option == MTE_ASYNC_ERR) 268e9b60476SAmit Daniel Kachhap en |= PR_MTE_TCF_ASYNC; 269e9b60476SAmit Daniel Kachhap else if (mte_option == MTE_NONE_ERR) 270e9b60476SAmit Daniel Kachhap en |= PR_MTE_TCF_NONE; 271e9b60476SAmit Daniel Kachhap 272e9b60476SAmit Daniel Kachhap en |= (incl_mask << PR_MTE_TAG_SHIFT); 273e9b60476SAmit Daniel Kachhap /* Enable address tagging ABI, mte error reporting mode and tag inclusion mask. */ 274e9b60476SAmit Daniel Kachhap if (!prctl(PR_SET_TAGGED_ADDR_CTRL, en, 0, 0, 0) == 0) { 275e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL:prctl PR_SET_TAGGED_ADDR_CTRL for mte mode\n"); 276e9b60476SAmit Daniel Kachhap return -EINVAL; 277e9b60476SAmit Daniel Kachhap } 278e9b60476SAmit Daniel Kachhap return 0; 279e9b60476SAmit Daniel Kachhap } 280e9b60476SAmit Daniel Kachhap 281e9b60476SAmit Daniel Kachhap #define ID_AA64PFR1_MTE_SHIFT 8 282e9b60476SAmit Daniel Kachhap #define ID_AA64PFR1_MTE 2 283e9b60476SAmit Daniel Kachhap 284e9b60476SAmit Daniel Kachhap int mte_default_setup(void) 285e9b60476SAmit Daniel Kachhap { 286e9b60476SAmit Daniel Kachhap unsigned long hwcaps = getauxval(AT_HWCAP); 287e9b60476SAmit Daniel Kachhap unsigned long en = 0; 288e9b60476SAmit Daniel Kachhap int ret; 289e9b60476SAmit Daniel Kachhap 290e9b60476SAmit Daniel Kachhap if (!(hwcaps & HWCAP_CPUID)) { 291e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: CPUID registers unavailable\n"); 292e9b60476SAmit Daniel Kachhap return KSFT_FAIL; 293e9b60476SAmit Daniel Kachhap } 294e9b60476SAmit Daniel Kachhap /* Read ID_AA64PFR1_EL1 register */ 295e9b60476SAmit Daniel Kachhap asm volatile("mrs %0, id_aa64pfr1_el1" : "=r"(hwcaps) : : "memory"); 296e9b60476SAmit Daniel Kachhap if (((hwcaps >> ID_AA64PFR1_MTE_SHIFT) & MT_TAG_MASK) != ID_AA64PFR1_MTE) { 297e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: MTE features unavailable\n"); 298e9b60476SAmit Daniel Kachhap return KSFT_SKIP; 299e9b60476SAmit Daniel Kachhap } 300e9b60476SAmit Daniel Kachhap /* Get current mte mode */ 301e9b60476SAmit Daniel Kachhap ret = prctl(PR_GET_TAGGED_ADDR_CTRL, en, 0, 0, 0); 302e9b60476SAmit Daniel Kachhap if (ret < 0) { 303e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL:prctl PR_GET_TAGGED_ADDR_CTRL with error =%d\n", ret); 304e9b60476SAmit Daniel Kachhap return KSFT_FAIL; 305e9b60476SAmit Daniel Kachhap } 306e9b60476SAmit Daniel Kachhap if (ret & PR_MTE_TCF_SYNC) 307e9b60476SAmit Daniel Kachhap mte_cur_mode = MTE_SYNC_ERR; 308e9b60476SAmit Daniel Kachhap else if (ret & PR_MTE_TCF_ASYNC) 309e9b60476SAmit Daniel Kachhap mte_cur_mode = MTE_ASYNC_ERR; 310e9b60476SAmit Daniel Kachhap else if (ret & PR_MTE_TCF_NONE) 311e9b60476SAmit Daniel Kachhap mte_cur_mode = MTE_NONE_ERR; 312e9b60476SAmit Daniel Kachhap 313e9b60476SAmit Daniel Kachhap mte_cur_pstate_tco = mte_get_pstate_tco(); 314e9b60476SAmit Daniel Kachhap /* Disable PSTATE.TCO */ 315e9b60476SAmit Daniel Kachhap mte_disable_pstate_tco(); 316e9b60476SAmit Daniel Kachhap return 0; 317e9b60476SAmit Daniel Kachhap } 318e9b60476SAmit Daniel Kachhap 319e9b60476SAmit Daniel Kachhap void mte_restore_setup(void) 320e9b60476SAmit Daniel Kachhap { 321e9b60476SAmit Daniel Kachhap mte_switch_mode(mte_cur_mode, MTE_ALLOW_NON_ZERO_TAG); 322e9b60476SAmit Daniel Kachhap if (mte_cur_pstate_tco == MT_PSTATE_TCO_EN) 323e9b60476SAmit Daniel Kachhap mte_enable_pstate_tco(); 324e9b60476SAmit Daniel Kachhap else if (mte_cur_pstate_tco == MT_PSTATE_TCO_DIS) 325e9b60476SAmit Daniel Kachhap mte_disable_pstate_tco(); 326e9b60476SAmit Daniel Kachhap } 327e9b60476SAmit Daniel Kachhap 328e9b60476SAmit Daniel Kachhap int create_temp_file(void) 329e9b60476SAmit Daniel Kachhap { 330e9b60476SAmit Daniel Kachhap int fd; 331e9b60476SAmit Daniel Kachhap char filename[] = "/dev/shm/tmp_XXXXXX"; 332e9b60476SAmit Daniel Kachhap 333e9b60476SAmit Daniel Kachhap /* Create a file in the tmpfs filesystem */ 334e9b60476SAmit Daniel Kachhap fd = mkstemp(&filename[0]); 335e9b60476SAmit Daniel Kachhap if (fd == -1) { 336e9b60476SAmit Daniel Kachhap ksft_print_msg("FAIL: Unable to open temporary file\n"); 337e9b60476SAmit Daniel Kachhap return 0; 338e9b60476SAmit Daniel Kachhap } 339e9b60476SAmit Daniel Kachhap unlink(&filename[0]); 340e9b60476SAmit Daniel Kachhap return fd; 341e9b60476SAmit Daniel Kachhap } 342