diff options
author | Greg Bellows <greg.bellows@linaro.org> | 2015-04-14 10:37:42 -0500 |
---|---|---|
committer | Greg Bellows <greg.bellows@linaro.org> | 2015-04-14 10:37:42 -0500 |
commit | 7a32277fbcf32bf11c8f3a0319c9e468694ff9e3 (patch) | |
tree | e24801c366de384746d46b9712c594bc333c1d1b | |
parent | d5b1df057fc63bc1c949f83d0536a164cb3f137c (diff) |
Breakout EL0 tests
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
-rw-r--r-- | common/syscntl.h | 5 | ||||
-rw-r--r-- | el0/el0_common.h | 1 | ||||
-rw-r--r-- | el0/nonsecure/Makefile | 10 | ||||
-rw-r--r-- | el0/nonsecure/el0_nsec.c | 34 | ||||
-rw-r--r-- | el0/nonsecure/tztest_nsec.c | 79 | ||||
-rw-r--r-- | el0/secure/Makefile | 10 | ||||
-rw-r--r-- | el0/secure/el0_sec.c (renamed from el0/secure/tztest_sec.c) | 15 | ||||
-rw-r--r-- | tztest/tztest.c | 332 | ||||
-rw-r--r-- | tztest/tztest.h | 124 | ||||
-rw-r--r-- | tztest/tztest_el0.c (renamed from el0/tztest.c) | 25 | ||||
-rw-r--r-- | tztest/tztest_el0.h | 10 | ||||
-rw-r--r-- | tztest/tztest_internal.h (renamed from el0/tztest.h) | 28 | ||||
-rw-r--r-- | tztest/tztest_old.c | 307 | ||||
-rw-r--r-- | tztest/tztest_old.h | 126 |
14 files changed, 559 insertions, 547 deletions
diff --git a/common/syscntl.h b/common/syscntl.h index 75d2637..641fadd 100644 --- a/common/syscntl.h +++ b/common/syscntl.h @@ -1,6 +1,9 @@ #ifndef _SYSCNTL_H #define _SYSCNTL_H +#include <stdint.h> +#include "libcflat.h" + typedef struct { void *buf_pa; void *buf_va; @@ -34,4 +37,6 @@ typedef struct { test_control_t *test_cntl; } sys_control_t; +extern sys_control_t *syscntl; + #endif diff --git a/el0/el0_common.h b/el0/el0_common.h index 8177038..5b91ddf 100644 --- a/el0/el0_common.h +++ b/el0/el0_common.h @@ -7,7 +7,6 @@ #include "arm_builtins.h" #include "el0.h" #include "debug.h" -#include "tztest.h" extern sys_control_t *syscntl; diff --git a/el0/nonsecure/Makefile b/el0/nonsecure/Makefile index d2b45d4..6686683 100644 --- a/el0/nonsecure/Makefile +++ b/el0/nonsecure/Makefile @@ -1,12 +1,13 @@ -VPATH = $(ARCH):../$(ARCH):../../common/$(ARCH):../ +VPATH = $(ARCH):../$(ARCH):../../common/$(ARCH):../:../../tztest EL0_NS_ELF = el0_nsec.elf EL0_NS_IMAGE = el0_nsec.bin EL0_NS_LOAD = el0_nsec.lds -EL0_NS_OBJS = tztest_nsec.o \ - tztest.o \ +EL0_NS_OBJS = el0_nsec.o \ el0.o \ - builtins.o + builtins.o \ + tztest.o \ + tztest_el0.o libgcc := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) FLATLIBS = ../../libcflat/libcflat.a $(libgcc) ../../libcflat/$(ARCH)/libeabi.a @@ -15,6 +16,7 @@ FLATLIBS = ../../libcflat/libcflat.a $(libgcc) ../../libcflat/$(ARCH)/libeabi.a CFLAGS += -I$(ARCH) -I../$(ARCH) -I../ -I../$(ARCH) CFLAGS += -I../../common/$(ARCH) -I../../common/ +CFLAGS += -I../../tztest ################################################################## diff --git a/el0/nonsecure/el0_nsec.c b/el0/nonsecure/el0_nsec.c new file mode 100644 index 0000000..b3676c4 --- /dev/null +++ b/el0/nonsecure/el0_nsec.c @@ -0,0 +1,34 @@ +#include "el0_common.h" +#include "tztest.h" + +const char *sec_state_str = "non-secure"; +sys_control_t *syscntl = NULL; + +int main() +{ + svc_op_desc_t desc; + + printf("EL0 (%s) started...\n", sec_state_str); + + /* Fetch the system-wide control structure */ + __svc(SVC_OP_GET_SYSCNTL, &desc); + syscntl = ((sys_control_t *)desc.get.data); + + /* Allocate and globally map test control descriptor */ + syscntl->test_cntl = (test_control_t*)alloc_mem(0, 0x1000); + map_va(syscntl->test_cntl, 0x1000, OP_MAP_ALL); + + /* If we didn't get a valid control structure then something has already + * gone drastically wrong. + */ + if (!syscntl) { + DEBUG_MSG("Failed to acquire system control structure\n"); + __svc(SVC_OP_EXIT, &desc); + } + + tztest_start(); + + __svc(SVC_OP_EXIT, NULL); + + return 0; +} diff --git a/el0/nonsecure/tztest_nsec.c b/el0/nonsecure/tztest_nsec.c deleted file mode 100644 index b1f3946..0000000 --- a/el0/nonsecure/tztest_nsec.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "el0_common.h" -#include "tztest.h" - -tztest_t tztest[TZTEST_COUNT]; -const char *sec_state_str; - -void interop_test() -{ - op_test_t test; - - test.orig = test.val = 1024; - test.fail = test.count = 0; - printf("\nValidating interop communication between ELs... "); - __svc(SVC_OP_TEST, (svc_op_desc_t *)&test); - TEST_CONDITION(!test.fail && test.val == (test.orig >> test.count)); -} - -void run_test(tztest_func_id_t fid, uint32_t el) -{ - op_dispatch_t disp; - - tztest[fid](el); - - disp.func_id = fid; - __svc(SVC_OP_DISPATCH, (svc_op_desc_t *)&disp); -} - -int main() -{ - svc_op_desc_t desc; - - /* ISSUE: For some reason, static initialization of the global security - * state string fails. The pointer ends up being NULL in some cases, but - * not in others. This likely has something to do with the position - * independence of the EL0 code. The below workaround works fine. - */ - const char *str = "non-secure"; - sec_state_str = str; - - printf("EL0 (%s) started...\n", sec_state_str); - - tztest_init(); - - /* Fetch the system-wide control structure */ - __svc(SVC_OP_GET_SYSCNTL, &desc); - syscntl = ((sys_control_t *)desc.get.data); - - /* Allocate and globally map test control descriptor */ - syscntl->test_cntl = (test_control_t*)alloc_mem(0, 0x1000); - map_va(syscntl->test_cntl, 0x1000, OP_MAP_ALL); - - printf("Starting TZ test...\n"); - - /* Test EL to EL communication */ - interop_test(); - - /* If we didn't get a valid control structure then something has already - * gone drastically wrong. - */ - if (!syscntl) { - DEBUG_MSG("Failed to acquire system control structure\n"); - __svc(SVC_OP_EXIT, &desc); - } - - run_test(TZTEST_SMC, 0); - run_test(TZTEST_REG_ACCESS, 0); -#if AARCH64 - run_test(TZTEST_CPACR_TRAP, 0); - run_test(TZTEST_WFX_TRAP, 0); -#endif - - printf("\nValidation complete. Passed %d of %d tests.\n", - syscntl->test_cntl->test_count - syscntl->test_cntl->fail_count, - syscntl->test_cntl->test_count); - - __svc(SVC_OP_EXIT, NULL); - - return 0; -} diff --git a/el0/secure/Makefile b/el0/secure/Makefile index d08f143..9917c5d 100644 --- a/el0/secure/Makefile +++ b/el0/secure/Makefile @@ -1,12 +1,13 @@ -VPATH = $(ARCH):../$(ARCH):../../common/$(ARCH):../ +VPATH = $(ARCH):../$(ARCH):../../common/$(ARCH):../:../../tztest EL0_S_ELF = el0_sec.elf EL0_S_IMAGE = el0_sec.bin EL0_S_LOAD = el0_sec.lds -EL0_S_OBJS = tztest_sec.o \ - tztest.o \ +EL0_S_OBJS = el0_sec.o \ el0.o \ - builtins.o + builtins.o \ + tztest.o \ + tztest_el0.o libgcc := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) FLATLIBS = ../../libcflat/libcflat.a $(libgcc) ../../libcflat/$(ARCH)/libeabi.a @@ -15,6 +16,7 @@ FLATLIBS = ../../libcflat/libcflat.a $(libgcc) ../../libcflat/$(ARCH)/libeabi.a CFLAGS += -I$(ARCH) -I../$(ARCH) -I../ -I../$(ARCH) CFLAGS += -I../../common/$(ARCH) -I../../common/ +CFLAGS += -I../../tztest ################################################################## diff --git a/el0/secure/tztest_sec.c b/el0/secure/el0_sec.c index 74e0518..43f9e2f 100644 --- a/el0/secure/tztest_sec.c +++ b/el0/secure/el0_sec.c @@ -1,7 +1,8 @@ #include "el0_common.h" +#include "tztest.h" -const char *sec_state_str; -tztest_t tztest[TZTEST_COUNT]; +const char *sec_state_str = "secure"; +sys_control_t *syscntl = NULL; void el0_sec_loop() { @@ -53,18 +54,8 @@ int main() { svc_op_desc_t desc; - /* ISSUE: For some reason, static initialization of the global security - * state string fails. The pointer ends up being NULL in some cases, but - * not in others. This likely has something to do with the position - * independence of the EL0 code. The below workaround works fine. - */ - const char *str = "secure"; - sec_state_str = str; - printf("EL0 (%s) started...\n", sec_state_str); - tztest_init(); - /* Fetch the system-wide control structure */ __svc(SVC_OP_GET_SYSCNTL, &desc); syscntl = (sys_control_t *)desc.get.data; diff --git a/tztest/tztest.c b/tztest/tztest.c index 1a3b79b..71591fc 100644 --- a/tztest/tztest.c +++ b/tztest/tztest.c @@ -1,307 +1,57 @@ -#include "tztest.h" -#include "arch.h" - -extern void test_handshake(); - -/* Make the below globals volatile as found that the compiler uses the - * register value ratherh than the memory value making it look like the writes - * actually happened. - */ -volatile int *tztest_fail_count = &_tztest_fail_count; -volatile int *tztest_test_count = &_tztest_test_count; - -/* Function for dispatching an empty SMC call. Inteded fo use from P0 or P1 - * mode. - */ -static inline uint32_t smc_noop() -{ - asm volatile(".arch_extension sec\n" - "push {lr}\n" - "mov r0, #0\n" - "smc #0\n" - "pop {lr}\n"); - return 0; -} - -uint32_t P0_nonsecure_check_smc() -{ - validate_state(CPSR_MODE_USR, TZTEST_STATE_NONSECURE); - printf("\nValidating non-secure P0 smc behavior:\n"); - printf("\tUnprivileged P0 smc call ... "); - TEST_EXCEPTION(smc_noop(), CPSR_MODE_UND); - - return 0; -} - -uint32_t P0_check_register_access(int state) -{ - char *state_str[2] = {"Secure", "Nonsecure"}; - - /* Set things to non-secure P1 and attempt accesses */ - printf("\nValidating %s P0 restricted register access:\n", - (state == TZTEST_STATE_NONSECURE) ? "nonsecure" : "secure"); - - printf("\t%s P0 SCR read ... ", state_str[state]); - TEST_EXCEPTION(_read_scr(), CPSR_MODE_UND); - - printf("\t%s P0 SCR write ... ", state_str[state]); - TEST_EXCEPTION(_write_scr(0), CPSR_MODE_UND); - - printf("\t%s P0 SDER read ... ", state_str[state]); - TEST_EXCEPTION(_read_sder(), CPSR_MODE_UND); - - printf("\t%s P0 SDER write ... ", state_str[state]); - TEST_EXCEPTION(_write_sder(0), CPSR_MODE_UND); - - printf("\t%s P0 MVBAR read ... ", state_str[state]); - TEST_EXCEPTION(_read_mvbar(), CPSR_MODE_UND); - - printf("\t%s P0 MVBAR write ... ", state_str[state]); - TEST_EXCEPTION(_write_mvbar(0), CPSR_MODE_UND); - - printf("\t%s P0 NSACR write ... ", state_str[state]); - TEST_EXCEPTION(_write_nsacr(0), CPSR_MODE_UND); - - return 0; -} - -uint32_t P0_nonsecure_check_register_access() -{ - validate_state(CPSR_MODE_USR, TZTEST_STATE_NONSECURE); - - P0_check_register_access(TZTEST_STATE_NONSECURE); - - return 0; -} - -uint32_t P0_secure_check_register_access() -{ - validate_state(CPSR_MODE_USR, TZTEST_STATE_SECURE); - - P0_check_register_access(TZTEST_STATE_SECURE); - - return 0; -} -SECURE_USR_FUNC(P0_secure_check_register_access); - -uint32_t P1_nonsecure_check_mask_bits() -{ - uint32_t ret = 0; - - validate_state(CPSR_MODE_SVC, TZTEST_STATE_NONSECURE); - - uint32_t cpsr = _read_cpsr(); - - /* Test: SCR.FW/AW protects access to CPSR.F/Aa when nonsecure - * pg. B1-1151 table B1-2 - */ - printf("\nValidating nonsecure accessiblilty of CPSR:\n"); - - /* It is safe to assume that we are in nonsecure state as we validated - * this on entry. Set the SCR FW and AW bits and preserve the NS bit. - * This SCR setting should allow the CPSR to be written from nonsecure - * state. - */ - DISPATCH_MONITOR(_write_scr, (SCR_AW | SCR_FW | SCR_NS), ret); - - printf("\tChecking CPSR.F with SCR.FW enabled... "); - TEST_FUNCTION(_write_cpsr(cpsr | (1 << 6)), - ((cpsr | (1 << 6)) == _read_cpsr())); - - /* Restore CPSR to its original value before next test. */ - _write_cpsr(cpsr); - - printf("\tChecking CPSR.A with SCR.AW enabled... "); - TEST_FUNCTION(_write_cpsr(cpsr | (1 << 8)), - (cpsr | (1 << 8)) == _read_cpsr()); - - /* Restore CPSR to its original value before next test. */ - _write_cpsr(cpsr); - - /* Switch SCR back to what we likely started with and retry the CPSR - * writes. At this point the setting of these bits should be blocked due - * to the AW and FW bits being clear. - */ - DISPATCH_MONITOR(_write_scr, SCR_NS, ret); - - printf("\tChecking CPSR.F with SCR.FW disabled... "); - TEST_FUNCTION(_write_cpsr(cpsr | (1 << 6)), - (cpsr == _read_cpsr())); - - /* Restore CPSR to its original value before next test. */ - _write_cpsr(cpsr); - - printf("\tChecking CPSR.A with SCR.AW disabled... "); - TEST_FUNCTION(_write_cpsr(cpsr | (1 << 8)), - (cpsr == _read_cpsr())); - - /* Restore CPSR to its original value */ - _write_cpsr(cpsr); - - return ret; -} - -uint32_t MON_check_state() -{ - printf("\nValidating monitor mode:\n"); - - uint32_t cpsr = _read_cpsr(); - - printf("\tChecking monitor mode... "); - TEST_CONDITION(CPSR_MODE_MON == (cpsr & CPSR_MODE_MASK)); - - // Test: Check that CPSR.A/I.F are set to 1 on exception to mon mode - // pg. B1-1182 - printf("\tChecking monitor mode CPSR.F value... "); - TEST_CONDITION(CPSR_F == (CPSR_F & cpsr)); - - printf("\tChecking monitor mode CPSR.I value... "); - TEST_CONDITION(CPSR_I == (CPSR_I & cpsr)); - - printf("\tChecking monitor mode CPSR.A value... "); - TEST_CONDITION(CPSR_A == (CPSR_A & cpsr)); - - return 0; -} - -uint32_t MON_check_exceptions() -{ - printf("\nValidating monitor mode exception:\n"); - - uint32_t scr = _read_scr(); - - /* B1-1211: SMC exceptions from monitor mode cause transition to secure - * state. - * Test: Check that an exception from mon mode, NS cleared to 0 - * pg. B1-1170 - */ - /* Set our starting security state to secure */ - _write_scr(scr & ~SCR_NS); - printf("\tChecking state after secure monitor... "); - TEST_FUNCTION(smc_noop(), !SCR_NS == ((_read_scr() & SCR_NS))); - - /* Set our security state to nonsecure */ - _write_scr(scr | SCR_NS); - printf("\tChecking state after nonsecure monitor... "); - TEST_FUNCTION(smc_noop(), !SCR_NS == ((_read_scr() & SCR_NS))); - - /* Restore the original SCR */ - _write_scr(scr); - - return 0; -} +#include "syscntl.h" +#include "interop.h" +#include "svc.h" +#include "libcflat.h" +#include "tztest_internal.h" +#include "tztest_el0.h" + +tztest_t tztest[TZTEST_COUNT] = +{ + [TZTEST_SMC] = el0_check_smc, + [TZTEST_REG_ACCESS] = el0_check_register_access, +#ifdef AARCH64 + [TZTEST_CPACR_TRAP] = el0_check_cpacr_trap, + [TZTEST_WFX_TRAP] = el0_check_wfx_trap +#endif +}; -uint32_t P1_nonsecure_novirt_behavior() +void interop_test() { - int ret = 0; + op_test_t test; - validate_state(CPSR_MODE_SVC, TZTEST_STATE_NONSECURE); - - printf("\nValidating non-virtualized behavior:\n"); - - DISPATCH_MONITOR(_write_scr, (SCR_SCD | SCR_NS), ret); - - // Check that SCR.SIF/SCD are not restrictive when EL2 not present - // pg. B1-1158 - printf("\tChecking SCR.SCD has no effect... "); - TEST_EXCEPTION(smc_noop(), 0); - - /* Restore SCR to just the nonsecure state */ - DISPATCH_MONITOR(_write_scr, SCR_NS, ret); - - return ret; + test.orig = test.val = 1024; + test.fail = test.count = 0; + printf("\nValidating interop communication between ELs... "); + __svc(SVC_OP_TEST, (svc_op_desc_t *)&test); + TEST_CONDITION(!test.fail && test.val == (test.orig >> test.count)); } -uint32_t MON_check_banked_regs() +void run_test(tztest_func_id_t fid, uint32_t el) { - uint32_t scr = _read_scr(); - uint32_t val = 0; - - printf("\nValidating monitor banked register access:\n"); - - VERIFY_REGISTER_CUSTOM(csselr, 0xF, TZTEST_SVAL, TZTEST_NSVAL); - /* Modifying SCTLR is highly disruptive, so the test is heavily restricted - * to avoid complications. We only flip the V-bit for comparison which is - * safe unless we take an exception which should be low risk. - */ - val = _read_sctlr(); - VERIFY_REGISTER_CUSTOM(sctlr, (1 << 13), val, (val | (1 << 13))); - - /* ACTLR is banked but not supported on Vexpress */ - - /* For testing purposes we switch the secure world to the nonsecure page - * table, so any translations can still be made. Since we are only working - * out of the non-secure mappings we should be safe. This assumption could - * be wrong. - */ - VERIFY_REGISTER_CUSTOM(ttbr0, 0xFFF00000, - (uint32_t)nsec_l1_page_table, TZTEST_NSVAL); - VERIFY_REGISTER(ttbr1); - - /* Modifying TTBCR is highly disruptive, so the test is heavily restricted - * to avoid complications. We only use the PD1-bit for comparison as we - * are not using ttbr1 at this time. - */ - val = _read_ttbcr(); - - VERIFY_REGISTER_CUSTOM(ttbcr, (1 << 5), val, (val | (1 << 5))); - /* Leave the bottom 4 bits alone as they will disrupt address translation - * otherwise. - */ - VERIFY_REGISTER_CUSTOM(dacr, 0xFFFFFFF0, 0x55555555, 0xAAAAAAA5); + op_dispatch_t disp; - VERIFY_REGISTER(dfsr); - VERIFY_REGISTER(ifsr); - VERIFY_REGISTER(dfar); - VERIFY_REGISTER(ifar); - VERIFY_REGISTER_CUSTOM(par, 0xFFFFF000, TZTEST_SVAL, TZTEST_NSVAL); - VERIFY_REGISTER(prrr); - VERIFY_REGISTER(nmrr); + tztest[fid](el); - /* The bottome 5 bits are SBZ */ - VERIFY_REGISTER_CUSTOM(vbar, 0xFFFFFFE0, TZTEST_SVAL, TZTEST_NSVAL); - - VERIFY_REGISTER(fcseidr); - VERIFY_REGISTER(contextidr); - VERIFY_REGISTER(tpidrurw); - VERIFY_REGISTER(tpidruro); - VERIFY_REGISTER(tpidrprw); - - /* Restore the SCR to it's original value */ - _write_scr(scr); - - return 0; + disp.func_id = fid; + __svc(SVC_OP_DISPATCH, (svc_op_desc_t *)&disp); } -uint32_t tztest_nonsecure_usr_main() +void tztest_start() { - uint32_t ret = 0; + printf("Starting TZ test...\n"); - DEBUG_MSG("Entered\n"); - *tztest_test_count = 0; - *tztest_fail_count = 0; + /* Test EL to EL communication */ + interop_test(); - P0_nonsecure_check_smc(); - P0_nonsecure_check_register_access(); - -#ifdef DEBUG - test_handshake(); + run_test(TZTEST_SMC, 0); + run_test(TZTEST_REG_ACCESS, 0); +#if AARCH64 + run_test(TZTEST_CPACR_TRAP, 0); + run_test(TZTEST_WFX_TRAP, 0); #endif - DISPATCH_SECURE_USR(P0_secure_check_register_access, 0, ret); - - DISPATCH_MONITOR(MON_check_state, 0, ret); - DISPATCH_MONITOR(MON_check_exceptions, 0, ret); - DISPATCH_MONITOR(MON_check_banked_regs, 0, ret); - - DISPATCH_NONSECURE_SVC(P1_nonsecure_check_mask_bits, 0, ret); - - DISPATCH_NONSECURE_SVC(P1_nonsecure_novirt_behavior, 0, ret); - - printf("\nValidation complete. Passed %d of %d tests\n", - *tztest_test_count-*tztest_fail_count, *tztest_test_count); - - DEBUG_MSG("Exiting\n"); - - return ret; + printf("\nValidation complete. Passed %d of %d tests.\n", + syscntl->test_cntl->test_count - syscntl->test_cntl->fail_count, + syscntl->test_cntl->test_count); } + diff --git a/tztest/tztest.h b/tztest/tztest.h index 34ced86..e56c911 100644 --- a/tztest/tztest.h +++ b/tztest/tztest.h @@ -1,126 +1,10 @@ #ifndef _TZTEST_H #define _TZTEST_H -#include "common_defs.h" -#include "common_svc.h" +#include <stdint.h> -extern volatile int _tztest_fail_count; -extern volatile int _tztest_test_count; - -#define CALL(_f) __svc(0, _f) -#define RETURN(_r) __svc(0,(_r)) - -#define DISPATCH(_op, _func, _arg, _ret) \ - do { \ - tztest_svc_desc_t _desc; \ - _desc.dispatch.func = (_func); \ - _desc.dispatch.arg = (_arg); \ - __svc((_op), &_desc); \ - (_ret) = _desc.dispatch.ret; \ - } while(0) - -#define SECURE_USR_FUNC(_func) \ - uint32_t _func##_wrapper(uint32_t arg) { RETURN(_func(arg)); return 0; } - -#define DISPATCH_SECURE_USR(_func, _arg, _ret) \ - DISPATCH(SVC_DISPATCH_SECURE_USR, (_func##_wrapper), (_arg), (_ret)) -#define DISPATCH_SECURE_SVC(_func, _arg, _ret) \ - DISPATCH(SVC_DISPATCH_SECURE_SVC, (_func), (_arg), (_ret)) -#define DISPATCH_MONITOR(_func, _arg, _ret) \ - DISPATCH(SVC_DISPATCH_MONITOR, (_func), (_arg), (_ret)) -#define DISPATCH_NONSECURE_SVC(_func, _arg, _ret) \ - DISPATCH(SVC_DISPATCH_NONSECURE_SVC, (_func), (_arg), (_ret)) - -#define INC_TEST_COUNT() (*tztest_test_count += 1) -#define INC_FAIL_COUNT() (*tztest_fail_count += 1) - -#define TEST_CONDITION(_cond) \ - do { \ - if (!(_cond)) { \ - printf("FAILED\n"); \ - INC_FAIL_COUNT(); \ - } else { \ - printf("PASSED\n"); \ - } \ - INC_TEST_COUNT(); \ - } while(0) - -#define TEST_FUNCTION(_fn, _cond) \ - do { \ - _fn; \ - TEST_CONDITION(_cond); \ - } while(0) - -#define TEST_EXCEPTION(_fn, _excp) \ - do { \ - TEST_FUNCTION(_fn, *tztest_exception == (_excp)); \ - *tztest_exception = 0; \ - } while (0) - -#define TZTEST_SVAL 0xaaaaaaaa -#define TZTEST_NSVAL ~TZTEST_SVAL -#define TZTEST_GET_REG_SECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr & ~SCR_NS); \ - (_val) = _read_##_reg(); \ - } while(0) - -#define TZTEST_GET_REG_NONSECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr | SCR_NS); \ - (_val) = _read_##_reg(); \ - } while(0) - -#define TZTEST_SET_REG_SECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr & ~SCR_NS); \ - _write_##_reg(_val); \ - } while(0) - -#define TZTEST_SET_REG_NONSECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr | SCR_NS); \ - _write_##_reg(_val); \ - } while(0) - -#define TZTEST_GET_REG_BANKS(_reg, _sval, _nsval) \ - do { \ - TZTEST_GET_REG_SECURE_BANK(_reg, _sval); \ - TZTEST_GET_REG_NONSECURE_BANK(_reg, _nsval);\ - } while(0) - -#define TZTEST_SET_REG_BANKS(_reg, _sval, _nsval) \ - do { \ - TZTEST_SET_REG_SECURE_BANK(_reg, _sval); \ - TZTEST_SET_REG_NONSECURE_BANK(_reg, _nsval);\ - } while(0) - -#define VERIFY_REGISTER_CUSTOM(_reg, _mask, _sval, _nsval) \ - do { \ - uint32_t sval = 0, nsval = 0; \ - uint32_t _reg[2] = {0,0}; \ - printf("\tChecking %s banks... ", #_reg); \ - TZTEST_GET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ - TZTEST_SET_REG_BANKS(_reg, (_sval), (_nsval)); \ - TZTEST_GET_REG_SECURE_BANK(_reg, sval); \ - TZTEST_GET_REG_NONSECURE_BANK(_reg, nsval); \ - TEST_CONDITION(((sval & (_mask)) != (nsval & (_mask))) && \ - (((_sval) & (_mask)) == (sval & (_mask))) && \ - (((_nsval) & (_mask)) == (nsval & (_mask)))); \ - TZTEST_SET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ - } while(0) - -#define VERIFY_REGISTER(_reg) \ - VERIFY_REGISTER_CUSTOM(_reg, 0xFFFFFFFF, TZTEST_SVAL, TZTEST_NSVAL) - -extern volatile int *tztest_exception; -extern volatile int *tztest_exception_addr; -extern volatile int *tztest_exception_status; -extern volatile int *tztest_fail_count; -extern volatile int *tztest_test_count; -extern void validate_state(uint32_t, uint32_t); -extern uint32_t _shared_memory_heap_base; -extern uint32_t *nsec_l1_page_table; -extern uint32_t *nsec_l2_page_table; +typedef uint32_t (*tztest_t)(uint32_t); +extern tztest_t tztest[]; +extern void tztest_start(); #endif diff --git a/el0/tztest.c b/tztest/tztest_el0.c index bd15505..ce0c60a 100644 --- a/el0/tztest.c +++ b/tztest/tztest_el0.c @@ -5,12 +5,10 @@ #include "exception.h" #include "el0.h" #include "debug.h" -#include "el0_common.h" -#include "tztest.h" +#include "tztest_internal.h" +#include "tztest_el0.h" -sys_control_t *syscntl = NULL; - -uint32_t check_smc(uint32_t el) +uint32_t el0_check_smc(uint32_t el) { TEST_HEAD("smc behavior"); @@ -20,7 +18,7 @@ uint32_t check_smc(uint32_t el) return 0; } -uint32_t check_register_access(uint32_t el) +uint32_t el0_check_register_access(uint32_t el) { /* Set things to non-secure P1 and attempt accesses */ TEST_HEAD("restricted register access"); @@ -60,7 +58,7 @@ uint32_t check_register_access(uint32_t el) } #ifdef AARCH64 -uint32_t check_cpacr_trap(uint32_t el) +uint32_t el0_check_cpacr_trap(uint32_t el) { uint64_t cptr_el3, cpacr; @@ -93,7 +91,7 @@ uint32_t check_cpacr_trap(uint32_t el) return 0; } -uint32_t check_wfx_trap(uint32_t el) +uint32_t el0_check_wfx_trap(uint32_t el) { uint64_t sctlr, scr; @@ -160,14 +158,3 @@ uint32_t check_wfx_trap(uint32_t el) return 0; } #endif - -void tztest_init() -{ - tztest[TZTEST_SMC] = check_smc; - tztest[TZTEST_REG_ACCESS] = check_register_access; -#ifdef AARCH64 - tztest[TZTEST_CPACR_TRAP] = check_cpacr_trap; - tztest[TZTEST_WFX_TRAP] = check_wfx_trap; -#endif -} - diff --git a/tztest/tztest_el0.h b/tztest/tztest_el0.h new file mode 100644 index 0000000..1f85648 --- /dev/null +++ b/tztest/tztest_el0.h @@ -0,0 +1,10 @@ +#ifndef _TZTEST_EL0_H +#define _TZTEST_EL0_H + +extern uint32_t el0_check_smc(uint32_t); +extern uint32_t el0_check_register_access(uint32_t); +extern uint32_t el0_check_cpacr_trap(uint32_t); +extern uint32_t el0_check_wfx_trap(uint32_t); + +#endif + diff --git a/el0/tztest.h b/tztest/tztest_internal.h index be31277..5be8c78 100644 --- a/el0/tztest.h +++ b/tztest/tztest_internal.h @@ -1,14 +1,15 @@ -#ifndef _TZTEST_H -#define _TZTEST_H +#ifndef _TZTEST_INTERNAL_H +#define _TZTEST_INTERNAL_H -typedef uint32_t (*tztest_t)(uint32_t el); -extern tztest_t tztest[]; +#include "tztest.h" -extern void tztest_init(); -extern uint32_t check_smc(uint32_t el); -extern uint32_t check_register_access(uint32_t el); -extern uint32_t check_cpacr_trap(uint32_t el); -extern uint32_t check_wfx_trap(uint32_t el); +typedef enum { + TZTEST_SMC = 0, + TZTEST_REG_ACCESS, + TZTEST_CPACR_TRAP, + TZTEST_WFX_TRAP, + TZTEST_COUNT +} tztest_func_id_t; #define TEST_HEAD(_str, ...) \ printf("\nValidating %s EL%d " _str ":\n", sec_state_str, el, ##__VA_ARGS__) @@ -54,12 +55,5 @@ extern uint32_t check_wfx_trap(uint32_t el); #define TEST_EL3_EXCEPTION(_fn, _excp) \ TEST_EXCEPTION(_fn, _excp, el3_excp) -typedef enum { - TZTEST_SMC = 0, - TZTEST_REG_ACCESS, - TZTEST_CPACR_TRAP, - TZTEST_WFX_TRAP, - TZTEST_COUNT -} tztest_func_id_t; - #endif + diff --git a/tztest/tztest_old.c b/tztest/tztest_old.c new file mode 100644 index 0000000..1a3b79b --- /dev/null +++ b/tztest/tztest_old.c @@ -0,0 +1,307 @@ +#include "tztest.h" +#include "arch.h" + +extern void test_handshake(); + +/* Make the below globals volatile as found that the compiler uses the + * register value ratherh than the memory value making it look like the writes + * actually happened. + */ +volatile int *tztest_fail_count = &_tztest_fail_count; +volatile int *tztest_test_count = &_tztest_test_count; + +/* Function for dispatching an empty SMC call. Inteded fo use from P0 or P1 + * mode. + */ +static inline uint32_t smc_noop() +{ + asm volatile(".arch_extension sec\n" + "push {lr}\n" + "mov r0, #0\n" + "smc #0\n" + "pop {lr}\n"); + return 0; +} + +uint32_t P0_nonsecure_check_smc() +{ + validate_state(CPSR_MODE_USR, TZTEST_STATE_NONSECURE); + printf("\nValidating non-secure P0 smc behavior:\n"); + printf("\tUnprivileged P0 smc call ... "); + TEST_EXCEPTION(smc_noop(), CPSR_MODE_UND); + + return 0; +} + +uint32_t P0_check_register_access(int state) +{ + char *state_str[2] = {"Secure", "Nonsecure"}; + + /* Set things to non-secure P1 and attempt accesses */ + printf("\nValidating %s P0 restricted register access:\n", + (state == TZTEST_STATE_NONSECURE) ? "nonsecure" : "secure"); + + printf("\t%s P0 SCR read ... ", state_str[state]); + TEST_EXCEPTION(_read_scr(), CPSR_MODE_UND); + + printf("\t%s P0 SCR write ... ", state_str[state]); + TEST_EXCEPTION(_write_scr(0), CPSR_MODE_UND); + + printf("\t%s P0 SDER read ... ", state_str[state]); + TEST_EXCEPTION(_read_sder(), CPSR_MODE_UND); + + printf("\t%s P0 SDER write ... ", state_str[state]); + TEST_EXCEPTION(_write_sder(0), CPSR_MODE_UND); + + printf("\t%s P0 MVBAR read ... ", state_str[state]); + TEST_EXCEPTION(_read_mvbar(), CPSR_MODE_UND); + + printf("\t%s P0 MVBAR write ... ", state_str[state]); + TEST_EXCEPTION(_write_mvbar(0), CPSR_MODE_UND); + + printf("\t%s P0 NSACR write ... ", state_str[state]); + TEST_EXCEPTION(_write_nsacr(0), CPSR_MODE_UND); + + return 0; +} + +uint32_t P0_nonsecure_check_register_access() +{ + validate_state(CPSR_MODE_USR, TZTEST_STATE_NONSECURE); + + P0_check_register_access(TZTEST_STATE_NONSECURE); + + return 0; +} + +uint32_t P0_secure_check_register_access() +{ + validate_state(CPSR_MODE_USR, TZTEST_STATE_SECURE); + + P0_check_register_access(TZTEST_STATE_SECURE); + + return 0; +} +SECURE_USR_FUNC(P0_secure_check_register_access); + +uint32_t P1_nonsecure_check_mask_bits() +{ + uint32_t ret = 0; + + validate_state(CPSR_MODE_SVC, TZTEST_STATE_NONSECURE); + + uint32_t cpsr = _read_cpsr(); + + /* Test: SCR.FW/AW protects access to CPSR.F/Aa when nonsecure + * pg. B1-1151 table B1-2 + */ + printf("\nValidating nonsecure accessiblilty of CPSR:\n"); + + /* It is safe to assume that we are in nonsecure state as we validated + * this on entry. Set the SCR FW and AW bits and preserve the NS bit. + * This SCR setting should allow the CPSR to be written from nonsecure + * state. + */ + DISPATCH_MONITOR(_write_scr, (SCR_AW | SCR_FW | SCR_NS), ret); + + printf("\tChecking CPSR.F with SCR.FW enabled... "); + TEST_FUNCTION(_write_cpsr(cpsr | (1 << 6)), + ((cpsr | (1 << 6)) == _read_cpsr())); + + /* Restore CPSR to its original value before next test. */ + _write_cpsr(cpsr); + + printf("\tChecking CPSR.A with SCR.AW enabled... "); + TEST_FUNCTION(_write_cpsr(cpsr | (1 << 8)), + (cpsr | (1 << 8)) == _read_cpsr()); + + /* Restore CPSR to its original value before next test. */ + _write_cpsr(cpsr); + + /* Switch SCR back to what we likely started with and retry the CPSR + * writes. At this point the setting of these bits should be blocked due + * to the AW and FW bits being clear. + */ + DISPATCH_MONITOR(_write_scr, SCR_NS, ret); + + printf("\tChecking CPSR.F with SCR.FW disabled... "); + TEST_FUNCTION(_write_cpsr(cpsr | (1 << 6)), + (cpsr == _read_cpsr())); + + /* Restore CPSR to its original value before next test. */ + _write_cpsr(cpsr); + + printf("\tChecking CPSR.A with SCR.AW disabled... "); + TEST_FUNCTION(_write_cpsr(cpsr | (1 << 8)), + (cpsr == _read_cpsr())); + + /* Restore CPSR to its original value */ + _write_cpsr(cpsr); + + return ret; +} + +uint32_t MON_check_state() +{ + printf("\nValidating monitor mode:\n"); + + uint32_t cpsr = _read_cpsr(); + + printf("\tChecking monitor mode... "); + TEST_CONDITION(CPSR_MODE_MON == (cpsr & CPSR_MODE_MASK)); + + // Test: Check that CPSR.A/I.F are set to 1 on exception to mon mode + // pg. B1-1182 + printf("\tChecking monitor mode CPSR.F value... "); + TEST_CONDITION(CPSR_F == (CPSR_F & cpsr)); + + printf("\tChecking monitor mode CPSR.I value... "); + TEST_CONDITION(CPSR_I == (CPSR_I & cpsr)); + + printf("\tChecking monitor mode CPSR.A value... "); + TEST_CONDITION(CPSR_A == (CPSR_A & cpsr)); + + return 0; +} + +uint32_t MON_check_exceptions() +{ + printf("\nValidating monitor mode exception:\n"); + + uint32_t scr = _read_scr(); + + /* B1-1211: SMC exceptions from monitor mode cause transition to secure + * state. + * Test: Check that an exception from mon mode, NS cleared to 0 + * pg. B1-1170 + */ + /* Set our starting security state to secure */ + _write_scr(scr & ~SCR_NS); + printf("\tChecking state after secure monitor... "); + TEST_FUNCTION(smc_noop(), !SCR_NS == ((_read_scr() & SCR_NS))); + + /* Set our security state to nonsecure */ + _write_scr(scr | SCR_NS); + printf("\tChecking state after nonsecure monitor... "); + TEST_FUNCTION(smc_noop(), !SCR_NS == ((_read_scr() & SCR_NS))); + + /* Restore the original SCR */ + _write_scr(scr); + + return 0; +} + +uint32_t P1_nonsecure_novirt_behavior() +{ + int ret = 0; + + validate_state(CPSR_MODE_SVC, TZTEST_STATE_NONSECURE); + + printf("\nValidating non-virtualized behavior:\n"); + + DISPATCH_MONITOR(_write_scr, (SCR_SCD | SCR_NS), ret); + + // Check that SCR.SIF/SCD are not restrictive when EL2 not present + // pg. B1-1158 + printf("\tChecking SCR.SCD has no effect... "); + TEST_EXCEPTION(smc_noop(), 0); + + /* Restore SCR to just the nonsecure state */ + DISPATCH_MONITOR(_write_scr, SCR_NS, ret); + + return ret; +} + +uint32_t MON_check_banked_regs() +{ + uint32_t scr = _read_scr(); + uint32_t val = 0; + + printf("\nValidating monitor banked register access:\n"); + + VERIFY_REGISTER_CUSTOM(csselr, 0xF, TZTEST_SVAL, TZTEST_NSVAL); + /* Modifying SCTLR is highly disruptive, so the test is heavily restricted + * to avoid complications. We only flip the V-bit for comparison which is + * safe unless we take an exception which should be low risk. + */ + val = _read_sctlr(); + VERIFY_REGISTER_CUSTOM(sctlr, (1 << 13), val, (val | (1 << 13))); + + /* ACTLR is banked but not supported on Vexpress */ + + /* For testing purposes we switch the secure world to the nonsecure page + * table, so any translations can still be made. Since we are only working + * out of the non-secure mappings we should be safe. This assumption could + * be wrong. + */ + VERIFY_REGISTER_CUSTOM(ttbr0, 0xFFF00000, + (uint32_t)nsec_l1_page_table, TZTEST_NSVAL); + VERIFY_REGISTER(ttbr1); + + /* Modifying TTBCR is highly disruptive, so the test is heavily restricted + * to avoid complications. We only use the PD1-bit for comparison as we + * are not using ttbr1 at this time. + */ + val = _read_ttbcr(); + + VERIFY_REGISTER_CUSTOM(ttbcr, (1 << 5), val, (val | (1 << 5))); + /* Leave the bottom 4 bits alone as they will disrupt address translation + * otherwise. + */ + VERIFY_REGISTER_CUSTOM(dacr, 0xFFFFFFF0, 0x55555555, 0xAAAAAAA5); + + VERIFY_REGISTER(dfsr); + VERIFY_REGISTER(ifsr); + VERIFY_REGISTER(dfar); + VERIFY_REGISTER(ifar); + VERIFY_REGISTER_CUSTOM(par, 0xFFFFF000, TZTEST_SVAL, TZTEST_NSVAL); + VERIFY_REGISTER(prrr); + VERIFY_REGISTER(nmrr); + + /* The bottome 5 bits are SBZ */ + VERIFY_REGISTER_CUSTOM(vbar, 0xFFFFFFE0, TZTEST_SVAL, TZTEST_NSVAL); + + VERIFY_REGISTER(fcseidr); + VERIFY_REGISTER(contextidr); + VERIFY_REGISTER(tpidrurw); + VERIFY_REGISTER(tpidruro); + VERIFY_REGISTER(tpidrprw); + + /* Restore the SCR to it's original value */ + _write_scr(scr); + + return 0; +} + +uint32_t tztest_nonsecure_usr_main() +{ + uint32_t ret = 0; + + DEBUG_MSG("Entered\n"); + *tztest_test_count = 0; + *tztest_fail_count = 0; + + P0_nonsecure_check_smc(); + P0_nonsecure_check_register_access(); + +#ifdef DEBUG + test_handshake(); +#endif + + DISPATCH_SECURE_USR(P0_secure_check_register_access, 0, ret); + + DISPATCH_MONITOR(MON_check_state, 0, ret); + DISPATCH_MONITOR(MON_check_exceptions, 0, ret); + DISPATCH_MONITOR(MON_check_banked_regs, 0, ret); + + DISPATCH_NONSECURE_SVC(P1_nonsecure_check_mask_bits, 0, ret); + + DISPATCH_NONSECURE_SVC(P1_nonsecure_novirt_behavior, 0, ret); + + printf("\nValidation complete. Passed %d of %d tests\n", + *tztest_test_count-*tztest_fail_count, *tztest_test_count); + + DEBUG_MSG("Exiting\n"); + + return ret; +} diff --git a/tztest/tztest_old.h b/tztest/tztest_old.h new file mode 100644 index 0000000..34ced86 --- /dev/null +++ b/tztest/tztest_old.h @@ -0,0 +1,126 @@ +#ifndef _TZTEST_H +#define _TZTEST_H + +#include "common_defs.h" +#include "common_svc.h" + +extern volatile int _tztest_fail_count; +extern volatile int _tztest_test_count; + +#define CALL(_f) __svc(0, _f) +#define RETURN(_r) __svc(0,(_r)) + +#define DISPATCH(_op, _func, _arg, _ret) \ + do { \ + tztest_svc_desc_t _desc; \ + _desc.dispatch.func = (_func); \ + _desc.dispatch.arg = (_arg); \ + __svc((_op), &_desc); \ + (_ret) = _desc.dispatch.ret; \ + } while(0) + +#define SECURE_USR_FUNC(_func) \ + uint32_t _func##_wrapper(uint32_t arg) { RETURN(_func(arg)); return 0; } + +#define DISPATCH_SECURE_USR(_func, _arg, _ret) \ + DISPATCH(SVC_DISPATCH_SECURE_USR, (_func##_wrapper), (_arg), (_ret)) +#define DISPATCH_SECURE_SVC(_func, _arg, _ret) \ + DISPATCH(SVC_DISPATCH_SECURE_SVC, (_func), (_arg), (_ret)) +#define DISPATCH_MONITOR(_func, _arg, _ret) \ + DISPATCH(SVC_DISPATCH_MONITOR, (_func), (_arg), (_ret)) +#define DISPATCH_NONSECURE_SVC(_func, _arg, _ret) \ + DISPATCH(SVC_DISPATCH_NONSECURE_SVC, (_func), (_arg), (_ret)) + +#define INC_TEST_COUNT() (*tztest_test_count += 1) +#define INC_FAIL_COUNT() (*tztest_fail_count += 1) + +#define TEST_CONDITION(_cond) \ + do { \ + if (!(_cond)) { \ + printf("FAILED\n"); \ + INC_FAIL_COUNT(); \ + } else { \ + printf("PASSED\n"); \ + } \ + INC_TEST_COUNT(); \ + } while(0) + +#define TEST_FUNCTION(_fn, _cond) \ + do { \ + _fn; \ + TEST_CONDITION(_cond); \ + } while(0) + +#define TEST_EXCEPTION(_fn, _excp) \ + do { \ + TEST_FUNCTION(_fn, *tztest_exception == (_excp)); \ + *tztest_exception = 0; \ + } while (0) + +#define TZTEST_SVAL 0xaaaaaaaa +#define TZTEST_NSVAL ~TZTEST_SVAL +#define TZTEST_GET_REG_SECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr & ~SCR_NS); \ + (_val) = _read_##_reg(); \ + } while(0) + +#define TZTEST_GET_REG_NONSECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr | SCR_NS); \ + (_val) = _read_##_reg(); \ + } while(0) + +#define TZTEST_SET_REG_SECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr & ~SCR_NS); \ + _write_##_reg(_val); \ + } while(0) + +#define TZTEST_SET_REG_NONSECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr | SCR_NS); \ + _write_##_reg(_val); \ + } while(0) + +#define TZTEST_GET_REG_BANKS(_reg, _sval, _nsval) \ + do { \ + TZTEST_GET_REG_SECURE_BANK(_reg, _sval); \ + TZTEST_GET_REG_NONSECURE_BANK(_reg, _nsval);\ + } while(0) + +#define TZTEST_SET_REG_BANKS(_reg, _sval, _nsval) \ + do { \ + TZTEST_SET_REG_SECURE_BANK(_reg, _sval); \ + TZTEST_SET_REG_NONSECURE_BANK(_reg, _nsval);\ + } while(0) + +#define VERIFY_REGISTER_CUSTOM(_reg, _mask, _sval, _nsval) \ + do { \ + uint32_t sval = 0, nsval = 0; \ + uint32_t _reg[2] = {0,0}; \ + printf("\tChecking %s banks... ", #_reg); \ + TZTEST_GET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ + TZTEST_SET_REG_BANKS(_reg, (_sval), (_nsval)); \ + TZTEST_GET_REG_SECURE_BANK(_reg, sval); \ + TZTEST_GET_REG_NONSECURE_BANK(_reg, nsval); \ + TEST_CONDITION(((sval & (_mask)) != (nsval & (_mask))) && \ + (((_sval) & (_mask)) == (sval & (_mask))) && \ + (((_nsval) & (_mask)) == (nsval & (_mask)))); \ + TZTEST_SET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ + } while(0) + +#define VERIFY_REGISTER(_reg) \ + VERIFY_REGISTER_CUSTOM(_reg, 0xFFFFFFFF, TZTEST_SVAL, TZTEST_NSVAL) + +extern volatile int *tztest_exception; +extern volatile int *tztest_exception_addr; +extern volatile int *tztest_exception_status; +extern volatile int *tztest_fail_count; +extern volatile int *tztest_test_count; +extern void validate_state(uint32_t, uint32_t); +extern uint32_t _shared_memory_heap_base; +extern uint32_t *nsec_l1_page_table; +extern uint32_t *nsec_l2_page_table; + +#endif |