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

This commit is contained in:
longjin
2022-10-16 18:19:05 +08:00
parent fbe1e23e97
commit 4830d04c2f
6 changed files with 76 additions and 96 deletions

View File

@ -351,4 +351,11 @@ ENTRY(syscall_int)
xchgq %rax, (%rsp) // FUNC
jmp Err_Code
// irqignore_int
ENTRY(ignore_int)
pushq $0
pushq %rax
leaq ignore_int_handler(%rip), %rax // ignore
xchgq %rax, (%rsp) // FUNC
jmp Err_Code

View File

@ -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");
}