aboutsummaryrefslogtreecommitdiff
path: root/tztest/tztest.c
diff options
context:
space:
mode:
Diffstat (limited to 'tztest/tztest.c')
-rw-r--r--tztest/tztest.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/tztest/tztest.c b/tztest/tztest.c
new file mode 100644
index 0000000..1a3b79b
--- /dev/null
+++ b/tztest/tztest.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;
+}