From 4830d04c2f167faf81ea8db9b3baa784766b5a55 Mon Sep 17 00:00:00 2001 From: longjin Date: Sun, 16 Oct 2022 18:19:05 +0800 Subject: [PATCH] =?UTF-8?q?bugfix:=20=E8=A7=A3=E5=86=B3=E4=BA=86ignore=5Fi?= =?UTF-8?q?nt=E5=9C=A8=E8=BF=90=E8=A1=8C=E6=97=B6=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E7=A0=B4=E5=9D=8F=E8=BF=9B=E7=A8=8B=E6=89=A7=E8=A1=8C=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/driver/interrupt/apic/apic.c | 3 +- kernel/driver/interrupt/apic/apic.h | 2 +- kernel/exception/entry.S | 7 ++ kernel/exception/irq.c | 150 ++++++++++++---------------- kernel/head.S | 4 +- kernel/main.c | 6 -- 6 files changed, 76 insertions(+), 96 deletions(-) diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index 806fbd72..63c5cd61 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/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 中断服务程序 diff --git a/kernel/driver/interrupt/apic/apic.h b/kernel/driver/interrupt/apic/apic.h index 5d64b105..3a001ce0 100644 --- a/kernel/driver/interrupt/apic/apic.h +++ b/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 diff --git a/kernel/exception/entry.S b/kernel/exception/entry.S index df38194f..2159f5bf 100644 --- a/kernel/exception/entry.S +++ b/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 diff --git a/kernel/exception/irq.c b/kernel/exception/irq.c index eb066eee..d68da32d 100644 --- a/kernel/exception/irq.c +++ b/kernel/exception/irq.c @@ -2,47 +2,47 @@ #include "irq.h" #include - #if _INTR_8259A_ #include #else #include #endif +#include "gate.h" #include #include #include -#include "gate.h" #include +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") \ No newline at end of file +#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"); +} \ No newline at end of file diff --git a/kernel/head.S b/kernel/head.S index cc840da7..1f9e2c78 100644 --- a/kernel/head.S +++ b/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) diff --git a/kernel/main.c b/kernel/main.c index e8f11e2f..b48d505c 100644 --- a/kernel/main.c +++ b/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 \ No newline at end of file