Я пытался создать обработчик 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
...
Мой обработчик 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
...
Это продолжается до тех пор, пока виртуальная машина не перезапустится.
Что я делаю неправильно?
registers_t
? Где это определено? - person 1201ProgramAlarm   schedule 06.06.2019