Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
19static 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
30static 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 */
45void 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 */
67void 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
102struct 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
117int 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}