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

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 $0x67"); //Works fine, code continues executing
asm("int $0xB"); //Calls "test" (interrupt 11 )but code execution stops...
asm("int $0x67"); //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个保留的异常)不会返回。我需要从中返回,每次发生类似页面错误的情况时,计算机都无法崩溃。有见识吗?提前致谢。

附言我使用GCC交叉编译器进行编译和运行,该编译器针对i686-elf。看起来像这样:
i686-elf-gcc -m32 -c kernel.c -o ../bin/kernel.o -O3 -ffreestanding -Wall -Wextra -fno-exceptions

极端更新:仅不会返回通过错误代码的中断。我在这部分做错了吗?这是错误代码中断的宏:
%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 $0xB");调用它们时,需要错误代码(8、10-14)的中断永远不会将错误代码压入堆栈(中断11)。这将调用该函数,而未正确设置堆栈。
宏:

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

如您所见,只有isr号被压入,而另一个宏ISR_NOERRCODE一个空字节被压入。当调用某个中断时,错误代码将由处理器自动推送。我只是手动调用它,而没有这样做。这就是为什么0-7和15及以后的数值仍然有效的原因。实际上,这是很愚蠢的错误,但是感谢大家的帮助!

08-05 12:28