Я реализовал способ регистрации функций обратного вызова для прерываний в своем ядре, которое я разрабатываю с нуля. Это означает, что если программа запустится 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 зарезервированных исключения) не возвращаются. Мне нужно вернуться с этого, я не могу, чтобы компьютер зависал каждый раз, когда происходит что-то вроде сбоя страницы. Любое понимание? Заранее спасибо.
P.S. Я компилирую и запускаю кросс-компилятор 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
Я помещаю здесь фиктивный код ошибки, чтобы сохранить единый кадр стека. Почему прерывания кода ошибки не работают правильно?
int 0x67
? Вы смотрели на стек? Можете ли вы выполнить этот код с помощью отладчика? - person   schedule 11.11.2015int 0x67
работают. попробую отладчиком - person Michael Morrow   schedule 11.11.2015