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