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

This commit is contained in:
login 2022-10-16 19:38:46 +08:00 committed by GitHub
parent fbe1e23e97
commit bf8f61b500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 96 deletions

View File

@ -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

View File

@ -290,7 +290,7 @@ void apic_init_ap_core_local_apic();
* @brief apic控制器
*
*/
void apic_init();
int apic_init();
/**
* @brief Interrupt Control Structure

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

View File

@ -326,6 +326,7 @@ entry64:
jnc start_smp
setup_IDT:
// 使cIDT
leaq m_ignore_int(%rip), %rdx // ignore_int8B
movq $(0x08 << 16), %rax // IDT0x100000TI=0,RPL=0
movw %dx, %ax
@ -460,6 +461,7 @@ go_to_smp_kernel:
.quad smp_ap_start
// ==== / ignore int
// (使cIDTignore_int)
m_ignore_int:
// cignore_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)

View File

@ -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