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;
 | 
						|
}
 |