blob: b7434a81c1550b5b012131f13916bcb9a6aeb44d [file] [log] [blame]
/*
* Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <pauth.h>
#include <psci.h>
#include <smccc.h>
#include <test_helpers.h>
#include <tftf_lib.h>
#include <tftf.h>
#include <tsp.h>
#include <string.h>
#ifdef __aarch64__
/* Number of ARMv8.3-PAuth keys */
#define NUM_KEYS 5
static const char * const key_name[] = {"IA", "IB", "DA", "DB", "GA"};
static uint128_t pauth_keys_before[NUM_KEYS];
static uint128_t pauth_keys_after[NUM_KEYS];
/* Check if ARMv8.3-PAuth key is enabled */
static bool is_pauth_key_enabled(uint64_t key_bit)
{
return (IS_IN_EL2() ?
((read_sctlr_el2() & key_bit) != 0U) :
((read_sctlr_el1() & key_bit) != 0U));
}
static test_result_t compare_pauth_keys(void)
{
test_result_t result = TEST_RESULT_SUCCESS;
for (unsigned int i = 0; i < NUM_KEYS; ++i) {
if (pauth_keys_before[i] != pauth_keys_after[i]) {
ERROR("AP%sKey_EL1 read 0x%llx:%llx "
"expected 0x%llx:%llx\n", key_name[i],
(uint64_t)(pauth_keys_after[i] >> 64),
(uint64_t)(pauth_keys_after[i]),
(uint64_t)(pauth_keys_before[i] >> 64),
(uint64_t)(pauth_keys_before[i]));
result = TEST_RESULT_FAIL;
}
}
return result;
}
/*
* Program or read ARMv8.3-PAuth keys (if already enabled)
* and store them in <pauth_keys_before> buffer
*/
static void set_store_pauth_keys(void)
{
uint128_t plat_key;
memset(pauth_keys_before, 0, NUM_KEYS * sizeof(uint128_t));
if (is_armv8_3_pauth_apa_api_apa3_present()) {
if (is_pauth_key_enabled(SCTLR_EnIA_BIT)) {
/* Read APIAKey_EL1 */
plat_key = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64);
INFO("EnIA is set\n");
} else {
/* Program APIAKey_EL1 */
plat_key = init_apkey();
write_apiakeylo_el1((uint64_t)plat_key);
write_apiakeyhi_el1((uint64_t)(plat_key >> 64));
}
pauth_keys_before[0] = plat_key;
if (is_pauth_key_enabled(SCTLR_EnIB_BIT)) {
/* Read APIBKey_EL1 */
plat_key = read_apibkeylo_el1() |
((uint128_t)(read_apibkeyhi_el1()) << 64);
INFO("EnIB is set\n");
} else {
/* Program APIBKey_EL1 */
plat_key = init_apkey();
write_apibkeylo_el1((uint64_t)plat_key);
write_apibkeyhi_el1((uint64_t)(plat_key >> 64));
}
pauth_keys_before[1] = plat_key;
if (is_pauth_key_enabled(SCTLR_EnDA_BIT)) {
/* Read APDAKey_EL1 */
plat_key = read_apdakeylo_el1() |
((uint128_t)(read_apdakeyhi_el1()) << 64);
INFO("EnDA is set\n");
} else {
/* Program APDAKey_EL1 */
plat_key = init_apkey();
write_apdakeylo_el1((uint64_t)plat_key);
write_apdakeyhi_el1((uint64_t)(plat_key >> 64));
}
pauth_keys_before[2] = plat_key;
if (is_pauth_key_enabled(SCTLR_EnDB_BIT)) {
/* Read APDBKey_EL1 */
plat_key = read_apdbkeylo_el1() |
((uint128_t)(read_apdbkeyhi_el1()) << 64);
INFO("EnDB is set\n");
} else {
/* Program APDBKey_EL1 */
plat_key = init_apkey();
write_apdbkeylo_el1((uint64_t)plat_key);
write_apdbkeyhi_el1((uint64_t)(plat_key >> 64));
}
pauth_keys_before[3] = plat_key;
}
/*
* It is safe to assume that Generic Pointer authentication code key
* APGAKey_EL1 can be re-programmed, as this key is not set in
* TF-A Test suite and PACGA instruction is not used.
*/
if (is_armv8_3_pauth_gpa_gpi_gpa3_present()) {
/* Program APGAKey_EL1 */
plat_key = init_apkey();
write_apgakeylo_el1((uint64_t)plat_key);
write_apgakeyhi_el1((uint64_t)(plat_key >> 64));
pauth_keys_before[4] = plat_key;
}
isb();
}
/*
* Read ARMv8.3-PAuth keys and store them in
* <pauth_keys_after> buffer
*/
static void read_pauth_keys(void)
{
memset(pauth_keys_after, 0, NUM_KEYS * sizeof(uint128_t));
if (is_armv8_3_pauth_apa_api_apa3_present()) {
/* Read APIAKey_EL1 */
pauth_keys_after[0] = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64);
/* Read APIBKey_EL1 */
pauth_keys_after[1] = read_apibkeylo_el1() |
((uint128_t)(read_apibkeyhi_el1()) << 64);
/* Read APDAKey_EL1 */
pauth_keys_after[2] = read_apdakeylo_el1() |
((uint128_t)(read_apdakeyhi_el1()) << 64);
/* Read APDBKey_EL1 */
pauth_keys_after[3] = read_apdbkeylo_el1() |
((uint128_t)(read_apdbkeyhi_el1()) << 64);
}
if (is_armv8_3_pauth_gpa_gpi_gpa3_present()) {
/* Read APGAKey_EL1 */
pauth_keys_after[4] = read_apgakeylo_el1() |
((uint128_t)(read_apgakeyhi_el1()) << 64);
}
}
#endif /* __aarch64__ */
/*
* TF-A is expected to allow access to key registers from lower EL's,
* reading the keys excercises this, on failure this will trap to
* EL3 and crash.
*/
test_result_t test_pauth_reg_access(void)
{
SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
read_pauth_keys();
return TEST_RESULT_SUCCESS;
#endif /* __aarch64__ */
}
/*
* Makes a call to PSCI version, and checks that the EL3 pauth keys are not
* leaked when it returns
*/
test_result_t test_pauth_leakage(void)
{
SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
set_store_pauth_keys();
tftf_get_psci_version();
read_pauth_keys();
return compare_pauth_keys();
#endif /* __aarch64__ */
}
/* Test execution of ARMv8.3-PAuth instructions */
test_result_t test_pauth_instructions(void)
{
SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
#if ARM_ARCH_AT_LEAST(8, 3)
/* Pointer authentication instructions */
__asm__ volatile (
"paciasp\n"
"autiasp\n"
"paciasp\n"
"xpaclri"
);
return TEST_RESULT_SUCCESS;
#else
tftf_testcase_printf("Pointer Authentication instructions "
"are not supported on ARMv%u.%u\n",
ARM_ARCH_MAJOR, ARM_ARCH_MINOR);
return TEST_RESULT_SKIPPED;
#endif /* ARM_ARCH_AT_LEAST(8, 3) */
#endif /* __aarch64__ */
}
/*
* Makes a call to TSP ADD, and checks that the checks that the Secure World
* pauth keys are not leaked
*/
test_result_t test_pauth_leakage_tsp(void)
{
SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
smc_args tsp_svc_params;
smc_ret_values tsp_result = {0};
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
SKIP_TEST_IF_TSP_NOT_PRESENT();
set_store_pauth_keys();
/* Standard SMC to ADD two numbers */
tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
tsp_svc_params.arg1 = 4;
tsp_svc_params.arg2 = 6;
tsp_result = tftf_smc(&tsp_svc_params);
/*
* Check the result of the addition-TSP_ADD will add
* the arguments to themselves and return
*/
if (tsp_result.ret0 != 0 || tsp_result.ret1 != 8 ||
tsp_result.ret2 != 12) {
tftf_testcase_printf("TSP add returned wrong result: "
"got %d %d %d expected: 0 8 12\n",
(unsigned int)tsp_result.ret0,
(unsigned int)tsp_result.ret1,
(unsigned int)tsp_result.ret2);
return TEST_RESULT_FAIL;
}
read_pauth_keys();
return compare_pauth_keys();
#endif /* __aarch64__ */
}