Browse Source

Improve exception handling.

coderain 5 years ago
parent
commit
b2b59886c7
2 changed files with 38 additions and 18 deletions
  1. 33 15
      kernel/src/exception.c
  2. 5 3
      sdk/exception.h

+ 33 - 15
kernel/src/exception.c

@@ -34,14 +34,13 @@ static const char *exception_names[] = {
     "Memory Access Fault",
 };
 
-static void raise_exception_internal(registers_t *regs, processor_mode_t mode, exception_info_t *info)
+static void raise_exception_internal(thread_t *thread, processor_mode_t mode, exception_info_t *info)
 {
-    thread_t *thread = get_current_thread();
-    if (thread == NULL) KERNEL_CRASH_WITH_REGS(exception_names[info->number], regs);
-
     if (mode == USER_MODE)
     {
+        bool_t current = (thread == get_current_thread());
         thread->user_exception_info = *info;
+        registers_t *regs = (current || (thread->in_kernel > 0)) ? thread->last_context : &thread->state.regs;
 
         if (thread->user_handler.eip)
         {
@@ -52,18 +51,22 @@ static void raise_exception_internal(registers_t *regs, processor_mode_t mode, e
             ASSERT((regs->cs & 0xFFFC) == 0 || SEGMENT_RPL(regs->cs) == 3);
             ASSERT((regs->data_selector & 0xFFFC) == 0 || SEGMENT_RPL(regs->data_selector) == 3);
 
-            registers_ext_t *regs_ext = (registers_ext_t*)regs;
-            regs_ext->esp3 = regs->esp;
+            if (current || (thread->in_kernel > 0))
+            {
+                registers_ext_t *regs_ext = (registers_ext_t*)regs;
+                regs_ext->esp3 = regs->esp;
+            }
         }
         else
         {
-            enable_ints();
-            syscall_terminate(INVALID_HANDLE, 1);
-            ASSERT(FALSE);
+            if (current) enable_ints();
+            terminate_thread_internal(thread, 1);
+            ASSERT(!current);
         }
     }
     else
     {
+        ASSERT(thread == get_current_thread());
         thread->kernel_exception_info = *info;
 
         if (thread->kernel_handler.eip)
@@ -73,7 +76,7 @@ static void raise_exception_internal(registers_t *regs, processor_mode_t mode, e
         }
         else
         {
-            KERNEL_CRASH_WITH_REGS(exception_names[info->number], regs);
+            KERNEL_CRASH_WITH_REGS(exception_names[info->number], thread->last_context);
         }
     }
 }
@@ -152,10 +155,12 @@ static void exception_handler(registers_t *regs, byte_t int_num)
         KERNEL_CRASH_WITH_REGS("Unexpected CPU exception", regs);
     }
 
-    raise_exception_internal(regs, previous_mode, &info);
+    thread_t *thread = get_current_thread();
+    if (thread == NULL) KERNEL_CRASH_WITH_REGS(exception_names[info.number], regs);
+    raise_exception_internal(thread, previous_mode, &info);
 }
 
-sysret_t syscall_raise_exception(exception_info_t *info)
+sysret_t syscall_raise_exception(handle_t thread_handle, const exception_info_t *info)
 {
     exception_info_t safe_info;
 
@@ -172,8 +177,21 @@ sysret_t syscall_raise_exception(exception_info_t *info)
         safe_info = *info;
     }
 
-    thread_t *thread = get_current_thread();
-    raise_exception_internal(&thread->state.regs, get_previous_mode(), &safe_info);
+    thread_t *thread = NULL;
+
+    if (thread_handle == INVALID_HANDLE)
+    {
+        thread = get_current_thread();
+        reference(&thread->header);
+    }
+    else
+    {
+        if (!reference_by_handle(thread_handle, OBJECT_THREAD, (object_t**)&thread)) return ERR_INVALID;
+    }
+
+    raise_exception_internal(thread, USER_MODE, &safe_info);
+
+    dereference(&thread->header);
     return ERR_SUCCESS;
 }
 
@@ -225,7 +243,7 @@ sysret_t syscall_save_exception_handler(exception_handler_t *old_handler)
     return 0;
 }
 
-sysret_t syscall_restore_exception_handler(exception_handler_t *old_handler)
+sysret_t syscall_restore_exception_handler(const exception_handler_t *old_handler)
 {
     thread_t *thread = get_current_thread();
 

+ 5 - 3
sdk/exception.h

@@ -22,11 +22,12 @@
 
 #include "defs.h"
 #include "cpu.h"
+#include "object.h"
 
 #ifdef __MONOLITIHUM_KERNEL_MODE__
 #define EH_TRY if (get_current_thread() != NULL) { exception_handler_t ___handler; if (save_kernel_handler(&___handler) == 0)
 #else
-#define EH_TRY if (TRUE) { exception_handler_t ___handler; if (syscall(SYSCALL_SAVE_EXCEPTION_HANDLER, &__handler) == 0)
+#define EH_TRY if (TRUE) { exception_handler_t ___handler; if (syscall(SYSCALL_SAVE_EXCEPTION_HANDLER, &___handler) == 0)
 #endif
 
 #define EH_CATCH else
@@ -42,6 +43,7 @@ typedef enum
     EXCEPTION_ASSERTION,
     EXCEPTION_BAD_OPERATION,
     EXCEPTION_MEMORY_ACCESS,
+    EXCEPTION_CUSTOM,
 } exception_t;
 
 typedef struct
@@ -52,8 +54,8 @@ typedef struct
 } exception_info_t;
 
 sysret_t syscall_get_exception_info(exception_info_t *info);
-sysret_t syscall_raise_exception(exception_info_t *info);
+sysret_t syscall_raise_exception(handle_t thread, const exception_info_t *info);
 sysret_t syscall_save_exception_handler(exception_handler_t *old_handler);
-sysret_t syscall_restore_exception_handler(exception_handler_t *old_handler);
+sysret_t syscall_restore_exception_handler(const exception_handler_t *old_handler);
 
 #endif