120 lines
2.3 KiB
C
120 lines
2.3 KiB
C
// 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"
|
|
|
|
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 mask)
|
|
{
|
|
int ret;
|
|
|
|
if ((getauxval(AT_HWCAP2) & hwcap2) != hwcap2) {
|
|
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) == mask) {
|
|
ksft_test_result_pass("%s\n", name);
|
|
} else {
|
|
ksft_print_msg("Got %x, expected %x\n",
|
|
(ret & PR_MTE_TCF_MASK), mask);
|
|
ksft_test_result_fail("%s\n", name);
|
|
}
|
|
}
|
|
|
|
struct mte_mode {
|
|
int mask;
|
|
int hwcap2;
|
|
const char *name;
|
|
} mte_modes[] = {
|
|
{ PR_MTE_TCF_NONE, 0, "NONE" },
|
|
{ PR_MTE_TCF_SYNC, HWCAP2_MTE, "SYNC" },
|
|
{ PR_MTE_TCF_ASYNC, HWCAP2_MTE, "ASYNC" },
|
|
{ PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC, HWCAP2_MTE, "SYNC+ASYNC" },
|
|
};
|
|
|
|
int main(void)
|
|
{
|
|
int i;
|
|
|
|
ksft_print_header();
|
|
ksft_set_plan(5);
|
|
|
|
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].mask);
|
|
|
|
ksft_print_cnts();
|
|
|
|
return 0;
|
|
}
|