      LockGuard lock(&m_thread_mutex);
      trust_thread->decrease_ref();
      return;
-@@ -454,7 +481,7 @@
+@@ -454,7 +484,7 @@
  
  sgx_status_t CTrustThreadPool::new_thread()
  {

+    {
+        if (m_user_utility_thread)
+        {
+            if (m_user_utility_thread_in_use.exchange(true))
+            {
+                return NULL;
+            }

 {
     if(se_try_rdlock(&m_rwlock))
     {
@@ -273,7 +286,20 @@
 on_fallback:
         //Handle normal ECall or fallback'ed switchless ECall
         //do sgx_ecall
-        CTrustThread *trust_thread = get_tcs(proc);
+        int ecmd = proc;
+        // If a utility tcs is active and its untrusted thread is interrupted by
+        // an exception, the exception is generated from the utility thread and
+        // we should enter the enclave through utility tcs.
+        if (m_user_utility_thread_id == get_thread_id() && proc == ECMD_EXCEPT)
+        {
+            ecmd = ECMD_UTILITY_EXCEPT;
+        }
+        //If this is a utility ecall, use the utility thread.
+        else if (is_utility)
+        {
+            ecmd = ECMD_UTILITY;
+        }
+        CTrustThread *trust_thread = get_tcs(ecmd);
         unsigned ret = SGX_ERROR_OUT_OF_TCS;
 
         if(NULL != trust_thread)
@@ -315,7 +341,20 @@
                 }
             }
 
+            // Entering the enclave through the utility tcs. Set the utility
+            // thread id so that coming exception handlings in the same
+            // untrusted thread will enter the enclave through utility tcs.
+            if (is_utility)
+            {
+                m_user_utility_thread_id = get_thread_id();
+            }
             ret = do_ecall(proc, ocall_table, ms, trust_thread);
+            // Exited the enclave through the utility tcs. Reset the utility
+            // thread id.
+            if (is_utility)
+            {
+                m_user_utility_thread_id = 0;
+            }
         }
         put_tcs(trust_thread);
 
@@ -388,7 +427,15 @@
     return &m_enclave_info;
 }
 
