为什么我不能从某些处理器异常中 return?玩具内核开发

Why can't I return from certain processor exceptions? Toy kernel dev

我已经实现了一种在我从头开发的内核中注册回调函数以中断的方法。这意味着如果程序 运行s int 0x67 它将调用我内核中的 C 函数来处理系统调用。它 return 就像它应该的那样,内核继续执行代码。但是,当我将函数映射到某些中断时,我无法 return 并且处理器似乎挂起。例如,这是我的一些代码:

void test(registers_t *r) {
    print("Why can't I return from this?\n");
}
void syscall(registers_t *r) {
    print("I can always return from this.\n");
}

在我的主要功能中:

register_int_handler(11, &test); //Also happens on 10 and 11 and 13
register_int_handler(103, &syscall); //a.k.a. 0x67 in hex, this one works.

那我可以打电话给:

asm("int [=13=]x67"); //Works fine, code continues executing
asm("int [=13=]xB"); //Calls "test" (interrupt 11 )but code execution stops...
asm("int [=13=]x67"); //This never gets called.

预期输出:

I can always return from this.
Why can't I return from this?
I can always return from this.

我实际看到的:

I can always return from this.
Why can't I return from this?

下面是实际处理中断的汇编代码:

extern isr_handler

isr_common_stub:
pusha

push ds
push es
push fs
push gs

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

mov eax, esp
push eax
mov eax, isr_handler
call eax
pop eax

pop gs
pop fs
pop es
pop ds

popa
add esp, 8
sti
iret

isr_handler 是一个 C 函数,它在注册处理程序数组中查找并调用我分配给它的函数。

void isr_handler(registers_t *r) {
    if(interrupt_handlers[r->int_no] != 0) {
        isr_t handler = interrupt_handlers[r->int_no];
        handler(r);
    }
}

这部分工作,但一些中断(我相信只有 32 个保留异常)不工作 return。我需要 return ,我不能每次发生页面错误之类的事情时都让计算机崩溃。有什么见解吗?提前致谢。

P.S。我使用 GCC 交叉编译器编译并 运行,编译为目标 i686-elf。它看起来像这样:

i686-elf-gcc -m32 -c kernel.c -o ../bin/kernel.o -O3 -ffreestanding -Wall -Wextra -fno-exceptions

极端更新:只有传递错误代码的中断没有被 returned。我做这部分错了吗?这是错误代码中断的宏:

%macro ISR_ERRCODE 1
    global isr%1
    isr%1:
        cli
        push byte %1
        jmp isr_common_stub
%endmacro

我以为错误代码是自动推送的?这是常规的非错误代码中断的宏:

%macro ISR_NOERRCODE 1
    global isr%1
    isr%1:
        cli
        push byte 0
        push byte %1
        jmp isr_common_stub
%endmacro

我在这里推送一个虚拟错误代码以保持统一的堆栈框架。为什么错误代码中断无法正常工作?

好的,我明白了,其实很简单。当我用 asm("int [=11=]xB");(interrupt 11) 调用需要错误代码 (8, 10-14) 的中断时,它们永远不会将错误代码压入堆栈。这在没有正确设置堆栈的情况下调用了函数。 宏:

%macro ISR_ERRCODE 1
    global isr%1
    isr%1:
        cli
        push byte %1
        jmp isr_common_stub
%endmacro

如您所见,只有 isr 号被推送到另一个宏 ISR_NOERRCODE 的地方,一个虚拟字节被推送。当调用特定中断时,处理器会自动推送错误代码。我只是手动调用它而没有这样做。这就是为什么 0-7 和 15 及以后仍然有效的原因。其实是很愚蠢的错误,但感谢大家的帮助!