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