fix: race condition and partial state issue on injecting signal context into user...
authorMinep <zelong56@gmail.com>
Mon, 27 Jun 2022 00:24:40 +0000 (01:24 +0100)
committerMinep <zelong56@gmail.com>
Mon, 27 Jun 2022 00:24:40 +0000 (01:24 +0100)
refactor: reduce the system timer frequency to 1024.
refactor: make the kprintf re-entrance and reduce the buffer size.
improve: better debugging experience with qemu.
improve: more information when debugging with iret.

lunaix-os/includes/lunaix/timer.h
lunaix-os/kernel/asm/x86/interrupt.S
lunaix-os/kernel/kprintf.c
lunaix-os/kernel/sched.c
lunaix-os/kernel/signal.c
lunaix-os/makefile

index c02d7f6bb49a55b003a8c38a3fdc7d4ed7dd3faf..b499f3fb70402dcd75af5e419a2897b440f885f9 100644 (file)
@@ -4,7 +4,7 @@
 #include <lunaix/ds/llist.h>
 #include <stdint.h>
 
-#define SYS_TIMER_FREQUENCY_HZ 2048
+#define SYS_TIMER_FREQUENCY_HZ 1024
 
 #define TIMER_MODE_PERIODIC 0x1
 
index 8a43aa7467c114d5cd6d7a31e32ad66b6256bf03..dc5c4c395ee750abfb379707cd5c26db5b3193bf 100644 (file)
         movl %eax, %esp
 
 #ifdef __ASM_INTR_DIAGNOSIS
+        movl %eax, (debug_resv + 8)
         movl 56(%esp), %eax
         movl %eax, (debug_resv + 4)
 #endif
index 374fff2993c8f6ef35376883f0a3e5265db18b3d..75b9fc4afaa9b69173c27c0646280abc3ee46de1 100644 (file)
@@ -3,14 +3,13 @@
 #include <lunaix/syslog.h>
 #include <lunaix/tty/tty.h>
 
-#define MAX_KPRINTF_BUF_SIZE 1024
-#define MAX_XFMT_SIZE 1024
-
-static char buf[MAX_KPRINTF_BUF_SIZE];
+#define MAX_KPRINTF_BUF_SIZE 512
+#define MAX_XFMT_SIZE 512
 
 void
 __kprintf(const char* component, const char* fmt, va_list args)
 {
+    char buf[MAX_KPRINTF_BUF_SIZE];
     if (!fmt)
         return;
     char log_level = '0';
@@ -74,16 +73,15 @@ __kprintf(const char* component, const char* fmt, va_list args)
 void
 kprint_panic(const char* fmt, ...)
 {
+    char buf[MAX_KPRINTF_BUF_SIZE];
     va_list args;
     va_start(args, fmt);
 
     tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_RED);
-    tty_clear_line(10);
-    tty_clear_line(11);
-    tty_clear_line(12);
+    tty_clear_line(24);
 
     __sprintf_internal(buf, fmt, MAX_KPRINTF_BUF_SIZE, args);
-    tty_put_str_at(buf, 0, 11);
+    tty_put_str_at(buf, 0, 24);
 
     va_end(args);
 }
\ No newline at end of file
index 5081ccf83ed6c6d03b6ad194ff2e7b2b6c3132a4..8e089d64b976be61ddf22fb77259caf9dea54f5b 100644 (file)
@@ -59,7 +59,8 @@ run(struct proc_info* proc)
     apic_done_servicing();
 
     asm volatile("pushl %0\n"
-                 "jmp switch_to\n" ::"r"(proc)); // kernel/asm/x86/interrupt.S
+                 "jmp switch_to\n" ::"r"(proc)
+                 : "memory"); // kernel/asm/x86/interrupt.S
 }
 
 int
index de83438435ddbfb66ddd3c3cf2d97bb4470c7d26..cb47e8dacfc164548954bde39412c6da75eadf6f 100644 (file)
@@ -22,6 +22,7 @@ void* default_handlers[_SIG_NUM] = {
     [_SIGINT] = default_sighandler_term,
 };
 
+volatile isr_param __temp_save;
 // Referenced in kernel/asm/x86/interrupt.S
 void*
 signal_dispatch()
@@ -58,7 +59,29 @@ signal_dispatch()
     struct proc_sig* sig_ctx =
       (struct proc_sig*)(ustack - sizeof(struct proc_sig));
 
-    sig_ctx->prev_context = __current->intr_ctx;
+    /*
+        这是一个相当恶心的坑。
+        问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面
+        这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。
+
+        由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的
+        注入,而需要走page fault handler进行动态分页。
+
+        竞态条件就出现在这里!
+
+        假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断,
+        那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的
+        上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回,
+        拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系
+        (因为此时的intr_ctx已经不是之前的intr_ctx了!)
+        而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时
+        触发#GP。
+
+        解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
+    */
+    __temp_save = __current->intr_ctx;
+    sig_ctx->prev_context = __temp_save;
+
     sig_ctx->sig_num = sig_selected;
     sig_ctx->signal_handler = __current->sig_handler[sig_selected];
 
index 0666dc4f6a3ee9869c1d1e155e50c4b60d805f87..f1a6dce04c9e7b5d54cdafe0df9cc6c4aa3a5d91 100644 (file)
@@ -51,13 +51,13 @@ clean:
        @sleep 2
 
 run: $(BUILD_DIR)/$(OS_ISO)
-       @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
+       @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) -d cpu_reset -monitor telnet::$(QEMU_MON_PORT),server,nowait &
        @sleep 1
        @telnet 127.0.0.1 $(QEMU_MON_PORT)
 
 debug-qemu: all-debug
        @${TOOLCHAIN}/i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg
-       @qemu-system-i386 -m 1G -rtc base=utc -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
+       @qemu-system-i386 -m 1G -rtc base=utc -d cpu_reset -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
        @sleep 1
        @$(QEMU_MON_TERM) -- telnet 127.0.0.1 $(QEMU_MON_PORT)
        @gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234"