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 hwcap3, 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 if ((getauxval(AT_HWCAP3) & hwcap3) != hwcap3) { 77 ksft_test_result_skip("%s\n", name); 78 return; 79 } 80 81 ret = set_tagged_addr_ctrl(mask); 82 if (ret < 0) { 83 ksft_test_result_fail("%s\n", name); 84 return; 85 } 86 87 ret = get_tagged_addr_ctrl(); 88 if (ret < 0) { 89 ksft_test_result_fail("%s\n", name); 90 return; 91 } 92 93 if ((ret & (PR_MTE_TCF_MASK | PR_MTE_STORE_ONLY)) == mask) { 94 ksft_test_result_pass("%s\n", name); 95 } else { 96 ksft_print_msg("Got %x, expected %x\n", 97 (ret & (int)PR_MTE_TCF_MASK), mask); 98 ksft_test_result_fail("%s\n", name); 99 } 100 } 101 102 struct mte_mode { 103 int mask; 104 int hwcap2; 105 int hwcap3; 106 const char *name; 107 } mte_modes[] = { 108 { PR_MTE_TCF_NONE, 0, 0, "NONE" }, 109 { PR_MTE_TCF_SYNC, HWCAP2_MTE, 0, "SYNC" }, 110 { PR_MTE_TCF_ASYNC, HWCAP2_MTE, 0, "ASYNC" }, 111 { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC, HWCAP2_MTE, 0, "SYNC+ASYNC" }, 112 { PR_MTE_TCF_SYNC | PR_MTE_STORE_ONLY, HWCAP2_MTE, HWCAP3_MTE_STORE_ONLY, "SYNC+STONLY" }, 113 { PR_MTE_TCF_ASYNC | PR_MTE_STORE_ONLY, HWCAP2_MTE, HWCAP3_MTE_STORE_ONLY, "ASYNC+STONLY" }, 114 { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC | PR_MTE_STORE_ONLY, HWCAP2_MTE, HWCAP3_MTE_STORE_ONLY, "SYNC+ASYNC+STONLY" }, 115 }; 116 117 int main(void) 118 { 119 int i; 120 121 ksft_print_header(); 122 ksft_set_plan(ARRAY_SIZE(mte_modes)); 123 124 check_basic_read(); 125 for (i = 0; i < ARRAY_SIZE(mte_modes); i++) 126 set_mode_test(mte_modes[i].name, mte_modes[i].hwcap2, mte_modes[i].hwcap3, 127 mte_modes[i].mask); 128 129 ksft_print_cnts(); 130 131 return 0; 132 } 133