Я заметил, что в вашем сообщении об ошибке вы получили следующее исключение:
check_exception old: 0xffffffff new 0xd
1: v=0d e=07c2 i=0 cpl=0 IP=0008:0000000000007c74 ...
Важная часть состоит в том, что это исключение - #GP (General Protection Fault) с кодом ошибки 0x7c2
. В OSdev Wiki есть краткое описание исключений и способы интерпретации кода ошибки для исключения #GP:
The error code 0x7c2 is binary 11111000 01 0
. Bit 0 being clear means that this wasn't an exception with an external cause. Bit 1 and 2 is 01
which means the exception was caused when accessing the IDT. 11111000
is the index of the interrupt vector which ix 0xF8
. This is a red flag. Your PIC remapping code appears to be remapping the master pic to 0x20-0x27 and the slave PIC to 0x28-0x2f. Interrupt 0xF8
makes no sense unless the PIC remapping code is wrong.
Upon reviewing the PIC remapping code I noticed an issue:
mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, 0x20
out 0x21, al
mov al, 0x28
out 0xA1, al
mov al, 4
out 0x21, al
mov al, 2
out 0xA1, al
mov al, 11111101b
out 0x20, al
mov al , 11111101b
out 0x21, al
ret
I have removed the jmp $+2
for clarity and because they aren't needed. If you alternate updating the master and slave PIC ports then the out
instruction will act as the needed delay. The OSDev Wiki has a section on doing the PI C переназначение и инициализация . Ваш код здесь отличается:
mov al, 4
out 0x21, al ; This is Correct
mov al, 2
out 0xA1, al ; This is Correct
mov al, 11111101b
out 0x20, al ; This is Wrong
mov al , 11111101b
out 0x21, al ; This is Wrong
ret
После записи 4 в порт 0x21 и 2 в порт 0xA1 вам нужно записать 1 в порт 0xA1 и 1 в порт 0xA2. Затем вы можете записать маску прерывания в порт 0x21 и порт 0xA1, чтобы включить и отключить необходимые прерывания. Правильный код может выглядеть примерно так:
mov al, 4
out 0x21, al ; This is Correct
mov al, 2
out 0xA1, al ; This is Correct
mov al, 1
out 0xA1, al ; This is Correct
out 0x21, al ; This is Correct
; Now set the PIC masks. Each bit in the mask is 0=enabled interrupt, 1=disabled.
mov al, 0
out 0x21, al ; Enable all interrupts on Slave
out 0xA1, al ; Enable all interrupts on Master
; Now set the PIC masks. Each bit in the mask is 0=enabled interrupt, 1=disabled.
; mov al, 0xfc
; out 0x21, al ; Disable all interrupts on Master except timer and keyboard
; 0xfc = 0b11111100
; mov al, 0xff
; out 0xA1, al ; Disable all interrupts on Slave
ret
Мне удалось воспроизвести ваши исключения и прерывания QEMU, используя ваш неправильный код инициализации. Я бы получил прерывание на 0xF8:
0: v=f8 e=0000 i=0 cpl=0 IP=0008:00007c51 pc=00007c51 ...
За ним следует исключение #GP, так как оно было необработанным и вне моей IDT:
1: v=0d e=07c2 i=0 cpl=0 IP=0008:00007c51 pc=00007c51 ...
После исправления я начинаю получать прерывания, такие как таймер с правильными записями, подобными:
0: v=20 e=0000 i=0 cpl=0 IP=0008:00007c4f pc=00007c4f ...