fix(optee): set interrupt handler before kernel boot

When loading OPTEE via an SMC after we start Linux, we end up changing
the interrupt settings which is a violation of the Linux kernel's
policies. This change sets the interrupt handler before we proceed to
starting the kernel and ignores any incoming interrupts that occur
before OPTEE is loaded.

Signed-off-by: Jeffrey Kardatzke<jkardatzke@google.com>
Change-Id: I7da5334498e14f4a703e8cc3eeff386e3ecc0882
diff --git a/services/spd/opteed/opteed_main.c b/services/spd/opteed/opteed_main.c
index 83b001a..d6c0040 100644
--- a/services/spd/opteed/opteed_main.c
+++ b/services/spd/opteed/opteed_main.c
@@ -87,6 +87,13 @@
 	uint32_t linear_id;
 	optee_context_t *optee_ctx;
 
+#if OPTEE_ALLOW_SMC_LOAD
+	if (optee_vector_table == NULL) {
+		/* OPTEE is not loaded yet, ignore this interrupt */
+		SMC_RET0(handle);
+	}
+#endif
+
 	/* Check the security state when the exception was generated */
 	assert(get_interrupt_src_ss(flags) == NON_SECURE);
 
@@ -115,6 +122,24 @@
 	SMC_RET1(&optee_ctx->cpu_ctx, read_elr_el3());
 }
 
+/*
+ * Registers an interrupt handler for S-EL1 interrupts when generated during
+ * code executing in the non-secure state. Panics if it fails to do so.
+ */
+static void register_opteed_interrupt_handler(void)
+{
+	u_register_t flags;
+	uint64_t rc;
+
+	flags = 0;
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+			opteed_sel1_interrupt_handler,
+			flags);
+	if (rc)
+		panic();
+}
+
 /*******************************************************************************
  * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type
  * (aarch32/aarch64) if not already known and initialises the context for entry
@@ -125,6 +150,11 @@
 #if OPTEE_ALLOW_SMC_LOAD
 	opteed_allow_load = true;
 	INFO("Delaying OP-TEE setup until we receive an SMC call to load it\n");
+	/*
+	 * We must register the interrupt handler now so that the interrupt
+	 * priorities are not changed after starting the linux kernel.
+	 */
+	register_opteed_interrupt_handler();
 	return 0;
 #else
 	entry_point_info_t *optee_ep_info;
@@ -575,7 +605,6 @@
 	cpu_context_t *ns_cpu_context;
 	uint32_t linear_id = plat_my_core_pos();
 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
-	uint64_t rc;
 
 	/*
 	 * Determine which security state this SMC originated from
@@ -709,18 +738,9 @@
 			 */
 			psci_register_spd_pm_hook(&opteed_pm);
 
-			/*
-			 * Register an interrupt handler for S-EL1 interrupts
-			 * when generated during code executing in the
-			 * non-secure state.
-			 */
-			flags = 0;
-			set_interrupt_rm_flag(flags, NON_SECURE);
-			rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
-						opteed_sel1_interrupt_handler,
-						flags);
-			if (rc)
-				panic();
+#if !OPTEE_ALLOW_SMC_LOAD
+			register_opteed_interrupt_handler();
+#endif
 		}
 
 		/*