blob: 9608b97d9e7d498f98ddcffb1ddfd39cac25028b [file] [log] [blame]
/*
* Copyright (c) 2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <cdefs.h>
#include <stdbool.h>
#include <stdint.h>
#include <debug.h>
#include <pauth.h>
/*
* This is only a toy implementation to generate a seemingly random
* 128-bit key from sp, x30 and cntpct_el0 values.
*/
uint128_t init_apkey(void)
{
uint64_t return_addr = (uint64_t)__builtin_return_address(0U);
uint64_t frame_addr = (uint64_t)__builtin_frame_address(0U);
uint64_t cntpct = read_cntpct_el0();
uint64_t key_lo = (return_addr << 13) ^ frame_addr ^ cntpct;
uint64_t key_hi = (frame_addr << 15) ^ return_addr ^ cntpct;
return ((uint128_t)(key_hi) << 64) | key_lo;
}
/* Check if ARMv8.3-PAuth key is enabled */
static bool is_pauth_key_enabled(uint64_t key_bit)
{
unsigned int el = (unsigned int)GET_EL(read_CurrentEl());
if (el == 1U) {
return ((read_sctlr_el1() & key_bit) != 0U);
} else if (el == 2U) {
return ((read_sctlr_el2() & key_bit) != 0U);
}
return false;
}
bool pauth_test_lib_compare_template(uint128_t *pauth_keys_before, uint128_t *pauth_keys_after)
{
bool result = true;
pauth_test_lib_read_keys(pauth_keys_after);
for (unsigned int i = 0U; 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] >> 64U),
(uint64_t)(pauth_keys_after[i]),
(uint64_t)(pauth_keys_before[i] >> 64U),
(uint64_t)(pauth_keys_before[i]));
result = false;
}
}
return result;
}
/*
* Program or read ARMv8.3-PAuth keys (if already enabled)
* and store them in <pauth_keys_before> buffer
*/
void pauth_test_lib_fill_regs_and_template(uint128_t *pauth_keys_before)
{
uint128_t plat_key;
(void)memset(pauth_keys_before, 0, NUM_KEYS * sizeof(uint128_t));
if (is_pauth_key_enabled(SCTLR_EnIA_BIT)) {
/* Read APIAKey_EL1 */
plat_key = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64U);
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 >> 64U));
}
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()) << 64U);
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 >> 64U));
}
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()) << 64U);
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 >> 64U));
}
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()) << 64U);
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 >> 64U));
}
pauth_keys_before[3] = plat_key;
pauth_keys_before[4] = read_apgakeylo_el1() |
((uint128_t)(read_apgakeyhi_el1()) << 64U);
if (pauth_keys_before[4] == 0ULL) {
/* Program APGAKey_EL1 */
plat_key = init_apkey();
write_apgakeylo_el1((uint64_t)plat_key);
write_apgakeyhi_el1((uint64_t)(plat_key >> 64U));
pauth_keys_before[4] = plat_key;
}
isb();
}
/*
* Read ARMv8.3-PAuth keys and store them in
* <pauth_keys_arr> buffer
*/
void pauth_test_lib_read_keys(uint128_t *pauth_keys_arr)
{
(void)memset(pauth_keys_arr, 0, NUM_KEYS * sizeof(uint128_t));
/* Read APIAKey_EL1 */
pauth_keys_arr[0] = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64U);
/* Read APIBKey_EL1 */
pauth_keys_arr[1] = read_apibkeylo_el1() |
((uint128_t)(read_apibkeyhi_el1()) << 64U);
/* Read APDAKey_EL1 */
pauth_keys_arr[2] = read_apdakeylo_el1() |
((uint128_t)(read_apdakeyhi_el1()) << 64U);
/* Read APDBKey_EL1 */
pauth_keys_arr[3] = read_apdbkeylo_el1() |
((uint128_t)(read_apdbkeyhi_el1()) << 64U);
/* Read APGAKey_EL1 */
pauth_keys_arr[4] = read_apgakeylo_el1() |
((uint128_t)(read_apgakeyhi_el1()) << 64U);
}
/* Test execution of ARMv8.3-PAuth instructions */
void pauth_test_lib_test_intrs(void)
{
/* Pointer authentication instructions */
__asm__ volatile (
"paciasp\n"
"autiasp\n"
"paciasp\n"
"xpaclri");
}