Почему я не могу вернуться из определенных исключений процессора? Разработчик игрушечного ядра

Я реализовал способ регистрации функций обратного вызова для прерываний в своем ядре, которое я разрабатываю с нуля. Это означает, что если программа запустится 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

Я помещаю здесь фиктивный код ошибки, чтобы сохранить единый кадр стека. Почему прерывания кода ошибки не работают правильно?


person Michael Morrow    schedule 10.11.2015    source источник
comment
Какое именно ядро? Ксилкернел? ОСРВ? Пожалуйста, укажите это в своем вопросе.   -  person    schedule 11.11.2015
comment
Мое собственное ядро. Я внесу правку.   -  person Michael Morrow    schedule 11.11.2015
comment
Можете ли вы сделать минимальный автономный пример для вашей проблемы?   -  person fuz    schedule 11.11.2015
comment
Не могли бы вы быть немного более конкретным? Я был бы счастлив сделать это. В каком формате вы хотели бы это?   -  person Michael Morrow    schedule 11.11.2015
comment
Вы пробовали два последовательных int 0x67? Вы смотрели на стек? Можете ли вы выполнить этот код с помощью отладчика?   -  person    schedule 11.11.2015
comment
Да два последовательных int 0x67 работают. попробую отладчиком   -  person Michael Morrow    schedule 11.11.2015
comment
Хорошо, ребята, я узнал кое-какую важную информацию, я добавил ее к своему вопросу.   -  person Michael Morrow    schedule 11.11.2015
comment
Я не могу сказать из вашего вопроса, как вы на самом деле определяете isr9 (я не знаю, какой макрос вы вызвали), но я не верю, что isr9 имеет код ошибки.   -  person Michael Petch    schedule 11.11.2015
comment
Ты прав. Все дело было в кодах ошибок. Я опубликовал ответ, объясняющий мое решение.   -  person Michael Morrow    schedule 11.11.2015
comment
9 было неправильным числом для использования. я ошибся с этим   -  person Michael Morrow    schedule 11.11.2015


Ответы (1)


Хорошо, я понял это, довольно просто на самом деле. Прерывания, которым требуются коды ошибок (8, 10-14), никогда не помещали коды ошибок в стек, когда я вызываю их с помощью asm("int $0xB");(прерывание 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 и выше все еще будут работать. Довольно глупая ошибка на самом деле, но спасибо всем за помощь!

person Michael Morrow    schedule 10.11.2015
comment
Я неправильно тестировал обработчик. Правильным способом было бы неявно инициировать исключение, например, вызвать ошибку страницы, выполнив: uint32_t *ptr = (uint32_t *)0xA0000000; и затем распечатав (прочитав) значение по адресу памяти на экране. Если бы эта память была защищена в таблице страниц, это привело бы к правильному вызову isr14 с правильным кодом ошибки. - person Michael Morrow; 11.11.2015
comment
Рад, что вы разобрались с проблемой. Пока я искал ответ, я подумал, может быть, некоторые инструкции int помещают в стек что-то другое, чем другие. Я, конечно, ничего не нашла, а теперь оказывается наоборот ;) - person ; 11.11.2015
comment
@MichaelMorrow - Будьте осторожны, следуя этому конкретному руководству. Существует ряд известных проблем с уроком Джеймса М. Здесь, если вы еще не видели список: wiki.osdev.org/James_Molloy's_Tutorial_Known_Bugs - person enhzflep; 11.11.2015
comment
Правильно, я планирую реализовать код управления памятью самостоятельно, так как считаю, что так я лучше его изучу. - person Michael Morrow; 11.11.2015