Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/mte/check_prctl.c
26296 views
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
134