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