Browse Source

bugfix: 解决了ignore_int在运行时可能破坏进程执行上下文的问题。 (#61)

login 2 years ago
parent
commit
bf8f61b500

+ 2 - 1
kernel/driver/interrupt/apic/apic.c

@@ -344,7 +344,7 @@ void apic_local_apic_init()
  * @brief 初始化apic控制器
  *
  */
-void apic_init()
+int apic_init()
 {
     // 初始化中断门, 中断使用rsp0防止在软中断时发生嵌套,然后处理器重新加载导致数据被抹掉
     for (int i = 32; i <= 55; ++i)
@@ -386,6 +386,7 @@ void apic_init()
         kwarn("Cannot get RCBA address. RCBA_phys=%#010lx", RCBA_phys);
     }
     sti();
+    return 0;
 }
 /**
  * @brief 中断服务程序

+ 1 - 1
kernel/driver/interrupt/apic/apic.h

@@ -290,7 +290,7 @@ void apic_init_ap_core_local_apic();
  * @brief 初始化apic控制器
  *
  */
-void apic_init();
+int apic_init();
 
 /**
  * @brief 读取指定类型的 Interrupt Control Structure

+ 7 - 0
kernel/exception/entry.S

@@ -351,4 +351,11 @@ ENTRY(syscall_int)
     xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
     jmp Err_Code
 
+// irq模块初始化后的ignore_int入点
+ENTRY(ignore_int)
+    pushq $0
+    pushq %rax
+    leaq ignore_int_handler(%rip), %rax    // 获取ignore处理程序的地址
+    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
+    jmp Err_Code
 

+ 63 - 87
kernel/exception/irq.c

@@ -2,47 +2,47 @@
 #include "irq.h"
 #include <common/errno.h>
 
-
 #if _INTR_8259A_
 #include <driver/interrupt/8259A/8259A.h>
 #else
 #include <driver/interrupt/apic/apic.h>
 #endif
 
+#include "gate.h"
 #include <common/asm.h>
 #include <common/printk.h>
 #include <common/string.h>
-#include "gate.h"
 #include <mm/slab.h>
+extern void ignore_int();
 
 #pragma GCC push_options
 #pragma GCC optimize("O0")
 // 保存函数调用现场的寄存器
-#define SAVE_ALL_REGS       \
-    "cld; \n\t"             \
-    "pushq %rax;    \n\t"   \
-    "pushq %rax;     \n\t"  \
-    "movq %es, %rax; \n\t"  \
-    "pushq %rax;     \n\t"  \
-    "movq %ds, %rax; \n\t"  \
-    "pushq %rax;     \n\t"  \
-    "xorq %rax, %rax;\n\t"  \
-    "pushq %rbp;     \n\t"  \
-    "pushq %rdi;     \n\t"  \
-    "pushq %rsi;     \n\t"  \
-    "pushq %rdx;     \n\t"  \
-    "pushq %rcx;     \n\t"  \
-    "pushq %rbx;     \n\t"  \
-    "pushq %r8 ;    \n\t"   \
-    "pushq %r9 ;    \n\t"   \
-    "pushq %r10;     \n\t"  \
-    "pushq %r11;     \n\t"  \
-    "pushq %r12;     \n\t"  \
-    "pushq %r13;     \n\t"  \
-    "pushq %r14;     \n\t"  \
-    "pushq %r15;     \n\t"  \
-    "movq $0x10, %rdx;\n\t" \
-    "movq %rdx, %ds; \n\t"  \
+#define SAVE_ALL_REGS                                                                                                  \
+    "cld; \n\t"                                                                                                        \
+    "pushq %rax;    \n\t"                                                                                              \
+    "pushq %rax;     \n\t"                                                                                             \
+    "movq %es, %rax; \n\t"                                                                                             \
+    "pushq %rax;     \n\t"                                                                                             \
+    "movq %ds, %rax; \n\t"                                                                                             \
+    "pushq %rax;     \n\t"                                                                                             \
+    "xorq %rax, %rax;\n\t"                                                                                             \
+    "pushq %rbp;     \n\t"                                                                                             \
+    "pushq %rdi;     \n\t"                                                                                             \
+    "pushq %rsi;     \n\t"                                                                                             \
+    "pushq %rdx;     \n\t"                                                                                             \
+    "pushq %rcx;     \n\t"                                                                                             \
+    "pushq %rbx;     \n\t"                                                                                             \
+    "pushq %r8 ;    \n\t"                                                                                              \
+    "pushq %r9 ;    \n\t"                                                                                              \
+    "pushq %r10;     \n\t"                                                                                             \
+    "pushq %r11;     \n\t"                                                                                             \
+    "pushq %r12;     \n\t"                                                                                             \
+    "pushq %r13;     \n\t"                                                                                             \
+    "pushq %r14;     \n\t"                                                                                             \
+    "pushq %r15;     \n\t"                                                                                             \
+    "movq $0x10, %rdx;\n\t"                                                                                            \
+    "movq %rdx, %ds; \n\t"                                                                                             \
     "movq %rdx, %es; \n\t"
 
 // 定义IRQ处理函数的名字格式:IRQ+中断号+interrupt
@@ -52,14 +52,13 @@
 // 构造中断entry
 // 为了复用返回函数的代码,需要压入一个错误码0
 // todo: 将这里改为volatile,也许能解决编译选项为O1时,系统崩溃的问题
-#define Build_IRQ(number)                                                         \
-    void IRQ_NAME(number);                                                        \
-    __asm__(SYMBOL_NAME_STR(IRQ) #number "interrupt:   \n\t"                      \
-                                         "pushq $0x00 \n\t" SAVE_ALL_REGS         \
-                                         "movq %rsp, %rdi   \n\t"                 \
-                                         "leaq ret_from_intr(%rip), %rax    \n\t" \
-                                         "pushq %rax \n\t"                        \
-                                         "movq	$" #number ",	%rsi			\n\t"        \
+#define Build_IRQ(number)                                                                                              \
+    void IRQ_NAME(number);                                                                                             \
+    __asm__(SYMBOL_NAME_STR(IRQ) #number "interrupt:   \n\t"                                                           \
+                                         "pushq $0x00 \n\t" SAVE_ALL_REGS "movq %rsp, %rdi   \n\t"                     \
+                                         "leaq ret_from_intr(%rip), %rax    \n\t"                                      \
+                                         "pushq %rax \n\t"                                                             \
+                                         "movq	$" #number ",	%rsi			\n\t"                                             \
                                          "jmp do_IRQ    \n\t");
 
 // 构造中断入口
@@ -89,32 +88,11 @@ Build_IRQ(0x36);
 Build_IRQ(0x37);
 
 // 初始化中断数组
-void (*interrupt_table[24])(void) =
-    {
-        IRQ0x20interrupt,
-        IRQ0x21interrupt,
-        IRQ0x22interrupt,
-        IRQ0x23interrupt,
-        IRQ0x24interrupt,
-        IRQ0x25interrupt,
-        IRQ0x26interrupt,
-        IRQ0x27interrupt,
-        IRQ0x28interrupt,
-        IRQ0x29interrupt,
-        IRQ0x2ainterrupt,
-        IRQ0x2binterrupt,
-        IRQ0x2cinterrupt,
-        IRQ0x2dinterrupt,
-        IRQ0x2einterrupt,
-        IRQ0x2finterrupt,
-        IRQ0x30interrupt,
-        IRQ0x31interrupt,
-        IRQ0x32interrupt,
-        IRQ0x33interrupt,
-        IRQ0x34interrupt,
-        IRQ0x35interrupt,
-        IRQ0x36interrupt,
-        IRQ0x37interrupt,
+void (*interrupt_table[24])(void) = {
+    IRQ0x20interrupt, IRQ0x21interrupt, IRQ0x22interrupt, IRQ0x23interrupt, IRQ0x24interrupt, IRQ0x25interrupt,
+    IRQ0x26interrupt, IRQ0x27interrupt, IRQ0x28interrupt, IRQ0x29interrupt, IRQ0x2ainterrupt, IRQ0x2binterrupt,
+    IRQ0x2cinterrupt, IRQ0x2dinterrupt, IRQ0x2einterrupt, IRQ0x2finterrupt, IRQ0x30interrupt, IRQ0x31interrupt,
+    IRQ0x32interrupt, IRQ0x33interrupt, IRQ0x34interrupt, IRQ0x35interrupt, IRQ0x36interrupt, IRQ0x37interrupt,
 };
 
 /**
@@ -139,18 +117,9 @@ Build_IRQ(0x80); // 系统调用入口
 void (*syscall_intr_table[1])(void) = {IRQ0x80interrupt};
 
 // 初始化IPI中断服务程序数组
-void (*SMP_interrupt_table[SMP_IRQ_NUM])(void) =
-    {
-        IRQ0xc8interrupt,
-        IRQ0xc9interrupt,
-        IRQ0xcainterrupt,
-        IRQ0xcbinterrupt,
-        IRQ0xccinterrupt,
-        IRQ0xcdinterrupt,
-        IRQ0xceinterrupt,
-        IRQ0xcfinterrupt,
-        IRQ0xd0interrupt,
-        IRQ0xd1interrupt,
+void (*SMP_interrupt_table[SMP_IRQ_NUM])(void) = {
+    IRQ0xc8interrupt, IRQ0xc9interrupt, IRQ0xcainterrupt, IRQ0xcbinterrupt, IRQ0xccinterrupt,
+    IRQ0xcdinterrupt, IRQ0xceinterrupt, IRQ0xcfinterrupt, IRQ0xd0interrupt, IRQ0xd1interrupt,
 };
 
 // 初始化local apic中断服务程序数组
@@ -164,18 +133,9 @@ Build_IRQ(0x9c);
 Build_IRQ(0x9d);
 Build_IRQ(0x9e);
 Build_IRQ(0x9f);
-void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void) =
-    {
-        IRQ0x96interrupt,
-        IRQ0x97interrupt,
-        IRQ0x98interrupt,
-        IRQ0x99interrupt,
-        IRQ0x9ainterrupt,
-        IRQ0x9binterrupt,
-        IRQ0x9cinterrupt,
-        IRQ0x9dinterrupt,
-        IRQ0x9einterrupt,
-        IRQ0x9finterrupt,
+void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void) = {
+    IRQ0x96interrupt, IRQ0x97interrupt, IRQ0x98interrupt, IRQ0x99interrupt, IRQ0x9ainterrupt,
+    IRQ0x9binterrupt, IRQ0x9cinterrupt, IRQ0x9dinterrupt, IRQ0x9einterrupt, IRQ0x9finterrupt,
 };
 
 /**
@@ -189,7 +149,8 @@ void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void) =
  * @param irq_name 中断名
  * @return int
  */
-int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater, hardware_intr_controller *controller, char *irq_name)
+int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater,
+                 hardware_intr_controller *controller, char *irq_name)
 {
     // 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素
     irq_desc_t *p = NULL;
@@ -252,6 +213,10 @@ int irq_unregister(ul irq_num)
  */
 void irq_init()
 {
+    // 将idt重置为新的ignore_int入点(此前在head.S中有设置,
+    // 但是那个不完整,某些版本的编译器的输出,在真机运行时会破坏进程执行环境,从而导致#GP
+    for (int i = 0; i < 256; ++i)
+        set_intr_gate(i, 0, ignore_int);
 #if _INTR_8259A_
     init_8259A();
 #else
@@ -261,4 +226,15 @@ void irq_init()
 
 #endif
 }
-#pragma GCC optimize("O0")
+#pragma GCC optimize("O0")
+
+/**
+ * @brief 当系统收到未知的中断时,执行此处理函数
+ * 
+ * @param regs 
+ * @param error_code 
+ */
+void ignore_int_handler(struct pt_regs *regs, unsigned long error_code)
+{
+    kwarn("Unknown interrupt or fault at RIP.\n");
+}

+ 3 - 1
kernel/head.S

@@ -326,6 +326,7 @@ entry64:
 	jnc	start_smp
 
 setup_IDT:
+    // 该部分代码只在启动初期使用,后面的c文件中会重新设置IDT,
     leaq m_ignore_int(%rip),  %rdx // 将ignore_int的地址暂时存到中段描述符的高8B
     movq $(0x08 << 16), %rax  // 设置段选择子。由IDT结构和段选择子结构可知,本行设置段基地址为0x100000,TI=0,RPL=0
     movw %dx, %ax
@@ -460,6 +461,7 @@ go_to_smp_kernel:
 	.quad	smp_ap_start
 
 // ==== 异常/中断处理模块 ignore int: 忽略中断
+// (该部分代码只在启动初期使用,后面的c文件中会重新设置IDT,从而重设ignore_int的中断入点)
 m_ignore_int:
 // 切换到c语言的ignore_int
     movq go_to_ignore_int(%rip), %rax
@@ -470,7 +472,7 @@ m_ignore_int:
 
 
 go_to_ignore_int:
-    .quad ignore_int
+    .quad ignore_int_handler
 
 
 ENTRY(head_stack_start)

+ 0 - 6
kernel/main.c

@@ -209,10 +209,4 @@ void Start_Kernel(void)
     while (1)
         pause();
 }
-
-void ignore_int()
-{
-    kwarn("Unknown interrupt or fault at RIP.\n");
-    sti();
-}
 #pragma GCC pop_options