Я пытался создать обработчик ISR, следуя этому уроку Джеймса Моллоя, но я застрял.Всякий раз, когда я генерирую программное прерывание, регистры общего назначения и регистр сегмента данных помещаются в стек с переменными, автоматически передаваемыми ЦП.Затем сегмент данных изменяется на значение 0x10 (дескриптор сегмента данных ядра), поэтому уровни привилегий изменяются.Затем после того, как обработчик возвращает эти значения, pop
ed.Но всякий раз, когда значение в ds
изменяется, генерируется GPE с кодом ошибки 0x2544, и через несколько секунд виртуальная машина перезапускается.(компоновщик и компилятор i386-elf-gcc, nasm на ассемблере)
Я попытался поместить инструкции hlt
между инструкциями, чтобы определить, какая команда выбрасывала GPE.После этого мне удалось выяснить, что такое инструкция «mov ds, ax».Я пробовал разные вещи, такие как удаление стека, который был инициализирован кодом начальной загрузки, для удаления частей кода, изменяющих привилегии.Единственный способ вернуться из общей заглушки - это удалить части моего кода, которые изменяют уровни привилегий, но, поскольку я хочу перейти в режим пользователя, я все еще хочу, чтобы они остались.
Вот моя общая заглушка:
isr_common_stub:
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
xor eax,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler
xor eax,eax
pop eax
mov ds, ax ; This is the instruction everything fails;
mov es, ax
mov fs, ax
mov gs, ax
popa
iret
Макросы моего обработчика ISR:
extern isr_handler
%macro ISR_NOERRCODE 1
global isr%1 ; %1 accesses the first parameter.
isr%1:
cli
push byte 0
push %1
jmp isr_common_stub
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli
push byte %1
jmp isr_common_stub
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
...
Обработчик My C, который приводит к «Полученному прерыванию: 0xD код ошибки 0x2544»
#include <stdio.h>
#include <isr.h>
#include <tty.h>
void isr_handler(registers_t regs) {
printf("ds: %x \n" ,regs.ds);
printf("Received interrupt: %x with err. code: %x \n", regs.int_no, regs.err_code);
}
Имоя основная функция:
void kmain(struct multiboot *mboot_ptr) {
descinit(); // Sets up IDT and GDT
ttyinit(TTY0); // Sets up the VGA Framebuffer
asm volatile ("int $0x1"); // Triggers a software interrupt
printf("Wow"); // After that its supposed to print this
}
Как вы можете видеть, код должен был выводить,
ds: 0x10
Received interrupt: 0x1 with err. code: 0
, но в результате,
...
ds: 0x10
Received interrupt: 0xD with err. code: 0x2544
ds: 0x10
Received interrupt: 0xD with err. code: 0x2544
...
, который продолжается довиртуальная машина перезапускается.
Что я делаю не так?
Я также могу загрузить весь исходный код.