1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2022 ARM Limited 3 4 #include <stdbool.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 #include <sys/auxv.h> 9 #include <sys/prctl.h> 10 11 #include <asm/hwcap.h> 12 13 #include "kselftest.h" 14 15 #ifndef AT_HWCAP3 16 #define AT_HWCAP3 29 17 #endif 18 19 static int set_tagged_addr_ctrl(int val) 20 { 21 int ret; 22 23 ret = prctl(PR_SET_TAGGED_ADDR_CTRL, val, 0, 0, 0); 24 if (ret < 0) 25 ksft_print_msg("PR_SET_TAGGED_ADDR_CTRL: failed %d %d (%s)\n", 26 ret, errno, strerror(errno)); 27 return ret; 28 } 29 30 static int get_tagged_addr_ctrl(void) 31 { 32 int ret; 33 34 ret = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); 35 if (ret < 0) 36 ksft_print_msg("PR_GET_TAGGED_ADDR_CTRL failed: %d %d (%s)\n", 37 ret, errno, strerror(errno)); 38 return ret; 39 } 40 41 /* 42 * Read the current mode without having done any configuration, should 43 * run first. 44 */ 45 void check_basic_read(void) 46 { 47 int ret; 48 49 ret = get_tagged_addr_ctrl(); 50 if (ret < 0) { 51 ksft_test_result_fail("check_basic_read\n"); 52 return; 53 } 54 55 if (ret & PR_MTE_TCF_SYNC) 56 ksft_print_msg("SYNC enabled\n"); 57 if (ret & PR_MTE_TCF_ASYNC) 58 ksft_print_msg("ASYNC enabled\n"); 59 60 /* Any configuration is valid */ 61 ksft_test_result_pass("check_basic_read\n"); 62 } 63 64 /* 65 * Attempt to set a specified combination of modes. 66 */ 67 void set_mode_test(const char *name, int hwcap2, int mask) 68 { 69 int ret; 70 71 if ((getauxval(AT_HWCAP2) & hwcap2) != hwcap2) { 72 ksft_test_result_skip("%s\n", name); 73 return; 74 } 75 76 ret = set_tagged_addr_ctrl(mask); 77 if (ret < 0) { 78 ksft_test_result_fail("%s\n", name); 79 return; 80 } 81 82 ret = get_tagged_addr_ctrl(); 83 if (ret < 0) { 84 ksft_test_result_fail("%s\n", name); 85 return; 86 } 87 88 if ((ret & PR_MTE_TCF_MASK) == mask) { 89 ksft_test_result_pass("%s\n", name); 90 } else { 91 ksft_print_msg("Got %x, expected %x\n", 92 (ret & (int)PR_MTE_TCF_MASK), mask); 93 ksft_test_result_fail("%s\n", name); 94 } 95 } 96 97 struct mte_mode { 98 int mask; 99 int hwcap2; 100 const char *name; 101 } mte_modes[] = { 102 { PR_MTE_TCF_NONE, 0, "NONE" }, 103 { PR_MTE_TCF_SYNC, HWCAP2_MTE, "SYNC" }, 104 { PR_MTE_TCF_ASYNC, HWCAP2_MTE, "ASYNC" }, 105 { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC, HWCAP2_MTE, "SYNC+ASYNC" }, 106 }; 107 108 int main(void) 109 { 110 int i; 111 112 ksft_print_header(); 113 ksft_set_plan(5); 114 115 check_basic_read(); 116 for (i = 0; i < ARRAY_SIZE(mte_modes); i++) 117 set_mode_test(mte_modes[i].name, mte_modes[i].hwcap2, 118 mte_modes[i].mask); 119 120 ksft_print_cnts(); 121 122 return 0; 123 } 124