| /* |
| * Copyright (c) 2022, Google Inc. All rights reserved |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files |
| * (the "Software"), to deal in the Software without restriction, |
| * including without limitation the rights to use, copy, modify, merge, |
| * publish, distribute, sublicense, and/or sell copies of the Software, |
| * and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /* Tests for ARM64 FEAT_BTI (Branch Target Identification) |
| * This is a mandatory CPU feature at ARM-A v8.5. Prior to that level, the |
| * BTI instructions are treated as NOPs and there is no enforcement. |
| * The test here will check either case, based on build configuration and |
| * runtime target support. |
| * Since this is an ARM64 feature, this should not be built for other arches. |
| */ |
| #ifndef ARCH_ARM64 |
| #error BTI is an ARM64 feature |
| #endif |
| |
| #include "btitest.h" |
| #include <arch/ops.h> |
| #include <err.h> |
| #include <lib/unittest/unittest.h> |
| #include <lk/init.h> |
| #include <stdio.h> |
| |
| /** Assembly relative function call test of all BTI-relevant calls. |
| */ |
| int btitest_bl(void); |
| |
| /* Assembly indirect call functions, using all BTI-relevant calls. |
| * BR via x16 and x17 is often used by linkers for veneers and has some |
| * additional handling described in the ARM Architecture Reference Manual, |
| * Table D8-36 (IYWFHD). |
| * The passed func_idx should be one of the BTITEST_CALLEE_ macros, which covers |
| * the landing pad instruction types given in the ARM Architecture Reference |
| * Manual, Table D8-37 (ICNBPL). |
| */ |
| int btitest_blr(int func_idx); |
| int btitest_br_x16(int func_idx); |
| int btitest_br_x17(int func_idx); |
| int btitest_br(int func_idx); |
| |
| /* Get the expected return code when a BTI access should be trapped */ |
| static int bti_trap_code(void) { |
| #ifdef KERNEL_BTI_ENABLED |
| if (arch_bti_supported()) { |
| return ERR_FAULT; |
| } |
| #endif |
| /* No BTI, or not enabled - faults are not detected */ |
| return 0; |
| } |
| |
| TEST(btitest, supported) { |
| if (!arch_bti_supported()) { |
| trusty_unittest_printf("[ INFO ] BTI is not supported\n"); |
| GTEST_SKIP(); |
| } |
| EXPECT_EQ(true, arch_bti_supported()); |
| test_abort:; |
| } |
| |
| /* Smoke-test the callee functions; they should return 0 when called with BL */ |
| TEST(btitest, smoke) { |
| EXPECT_EQ(0, btitest_bl()); |
| } |
| |
| TEST(btitest, nop) { |
| /* Fault on jump or call to non-bti target */ |
| EXPECT_EQ(bti_trap_code(), btitest_br(BTITEST_CALLEE_NOP)); |
| EXPECT_EQ(bti_trap_code(), btitest_blr(BTITEST_CALLEE_NOP)); |
| EXPECT_EQ(bti_trap_code(), btitest_br_x16(BTITEST_CALLEE_NOP)); |
| EXPECT_EQ(bti_trap_code(), btitest_br_x17(BTITEST_CALLEE_NOP)); |
| } |
| |
| TEST(btitest, bti) { |
| /* Fault on any jump or call to non-target bti */ |
| EXPECT_EQ(bti_trap_code(), btitest_br(BTITEST_CALLEE_BTI)); |
| EXPECT_EQ(bti_trap_code(), btitest_blr(BTITEST_CALLEE_BTI)); |
| EXPECT_EQ(bti_trap_code(), btitest_br_x16(BTITEST_CALLEE_BTI)); |
| EXPECT_EQ(bti_trap_code(), btitest_br_x17(BTITEST_CALLEE_BTI)); |
| } |
| |
| TEST(btitest, bti_c) { |
| /* Call or branch via x16/17 to a call target is valid */ |
| EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_BTI_C)); |
| EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_BTI_C)); |
| EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_BTI_C)); |
| |
| /* Fault on branch to call target */ |
| EXPECT_EQ(bti_trap_code(), btitest_br(BTITEST_CALLEE_BTI_C)); |
| } |
| |
| TEST(btitest, bti_j) { |
| /* Any branch to jump target is valid */ |
| EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_BTI_J)); |
| EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_BTI_J)); |
| EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_BTI_J)); |
| |
| /* Fault on call to jump target */ |
| EXPECT_EQ(bti_trap_code(), btitest_blr(BTITEST_CALLEE_BTI_J)); |
| } |
| |
| TEST(btitest, bti_jc) { |
| /* Either branch type allowed to call and jump target */ |
| EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_BTI_JC)); |
| EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_BTI_JC)); |
| EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_BTI_JC)); |
| EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_BTI_JC)); |
| } |
| |
| TEST(btitest, pacisp) { |
| if (!arch_pac_address_supported()) { |
| trusty_unittest_printf("[ INFO ] PAC is not supported\n"); |
| GTEST_SKIP(); |
| } |
| |
| /* PACIASP is a valid target for all branch types */ |
| EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_PACIASP)); |
| EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_PACIASP)); |
| EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_PACIASP)); |
| EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_PACIASP)); |
| |
| /* PACIBSP is a valid target for all branch types */ |
| EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_PACIBSP)); |
| EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_PACIBSP)); |
| EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_PACIBSP)); |
| EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_PACIBSP)); |
| test_abort:; |
| } |
| |
| PORT_TEST(btitest, "com.android.kernel.btitest"); |