162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2022 ARM Limited 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <stdbool.h> 562306a36Sopenharmony_ci#include <stdio.h> 662306a36Sopenharmony_ci#include <string.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <sys/auxv.h> 962306a36Sopenharmony_ci#include <sys/prctl.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/hwcap.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "kselftest.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic int set_tagged_addr_ctrl(int val) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci int ret; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci ret = prctl(PR_SET_TAGGED_ADDR_CTRL, val, 0, 0, 0); 2062306a36Sopenharmony_ci if (ret < 0) 2162306a36Sopenharmony_ci ksft_print_msg("PR_SET_TAGGED_ADDR_CTRL: failed %d %d (%s)\n", 2262306a36Sopenharmony_ci ret, errno, strerror(errno)); 2362306a36Sopenharmony_ci return ret; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic int get_tagged_addr_ctrl(void) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci int ret; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci ret = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); 3162306a36Sopenharmony_ci if (ret < 0) 3262306a36Sopenharmony_ci ksft_print_msg("PR_GET_TAGGED_ADDR_CTRL failed: %d %d (%s)\n", 3362306a36Sopenharmony_ci ret, errno, strerror(errno)); 3462306a36Sopenharmony_ci return ret; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Read the current mode without having done any configuration, should 3962306a36Sopenharmony_ci * run first. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_civoid check_basic_read(void) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci int ret; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci ret = get_tagged_addr_ctrl(); 4662306a36Sopenharmony_ci if (ret < 0) { 4762306a36Sopenharmony_ci ksft_test_result_fail("check_basic_read\n"); 4862306a36Sopenharmony_ci return; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (ret & PR_MTE_TCF_SYNC) 5262306a36Sopenharmony_ci ksft_print_msg("SYNC enabled\n"); 5362306a36Sopenharmony_ci if (ret & PR_MTE_TCF_ASYNC) 5462306a36Sopenharmony_ci ksft_print_msg("ASYNC enabled\n"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* Any configuration is valid */ 5762306a36Sopenharmony_ci ksft_test_result_pass("check_basic_read\n"); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * Attempt to set a specified combination of modes. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_civoid set_mode_test(const char *name, int hwcap2, int mask) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci int ret; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if ((getauxval(AT_HWCAP2) & hwcap2) != hwcap2) { 6862306a36Sopenharmony_ci ksft_test_result_skip("%s\n", name); 6962306a36Sopenharmony_ci return; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci ret = set_tagged_addr_ctrl(mask); 7362306a36Sopenharmony_ci if (ret < 0) { 7462306a36Sopenharmony_ci ksft_test_result_fail("%s\n", name); 7562306a36Sopenharmony_ci return; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ret = get_tagged_addr_ctrl(); 7962306a36Sopenharmony_ci if (ret < 0) { 8062306a36Sopenharmony_ci ksft_test_result_fail("%s\n", name); 8162306a36Sopenharmony_ci return; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if ((ret & PR_MTE_TCF_MASK) == mask) { 8562306a36Sopenharmony_ci ksft_test_result_pass("%s\n", name); 8662306a36Sopenharmony_ci } else { 8762306a36Sopenharmony_ci ksft_print_msg("Got %x, expected %x\n", 8862306a36Sopenharmony_ci (ret & PR_MTE_TCF_MASK), mask); 8962306a36Sopenharmony_ci ksft_test_result_fail("%s\n", name); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistruct mte_mode { 9462306a36Sopenharmony_ci int mask; 9562306a36Sopenharmony_ci int hwcap2; 9662306a36Sopenharmony_ci const char *name; 9762306a36Sopenharmony_ci} mte_modes[] = { 9862306a36Sopenharmony_ci { PR_MTE_TCF_NONE, 0, "NONE" }, 9962306a36Sopenharmony_ci { PR_MTE_TCF_SYNC, HWCAP2_MTE, "SYNC" }, 10062306a36Sopenharmony_ci { PR_MTE_TCF_ASYNC, HWCAP2_MTE, "ASYNC" }, 10162306a36Sopenharmony_ci { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC, HWCAP2_MTE, "SYNC+ASYNC" }, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciint main(void) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int i; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ksft_print_header(); 10962306a36Sopenharmony_ci ksft_set_plan(5); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci check_basic_read(); 11262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mte_modes); i++) 11362306a36Sopenharmony_ci set_mode_test(mte_modes[i].name, mte_modes[i].hwcap2, 11462306a36Sopenharmony_ci mte_modes[i].mask); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci ksft_print_cnts(); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 120