Настройка прерываний в защищенном режиме (x86)
Как происходит настройка прерываний в защищенном режиме?
это ссылка говорит, что нужно:
Освободить место для таблицы дескрипторов прерыванийСообщите процессору, где находится это пространство (см. Учебное пособие по GDT: lidt работает так же, как lgdt)Скажите PIC, что вы больше не хотите использовать настройки BIOS по умолчанию (см. Программирование микросхем PIC)Напишите пару обработчиков ISR (см. Подпрограммы обработки прерываний) для IRQ и исключенийПоместите адреса обработчиков ISR в соответствующие дескрипторыВключить все поддерживаемые прерывания в маске IRQ (PIC)Третий шаг не имеет смысла для меня (я посмотрел наэтот ссылка, но ничего не было сказано о PIC), поэтому я проигнорировал это и выполнил следующие два шага, только чтобы снова оказаться в неведении, когда я достиг последнего шага. Однако, исходя из моего понимания прерываний, оба шага, которые я не понимал, относятся к аппаратным прерываниям от контроллера PIC и не должны влиять на прерывания, вызванные PIT на IRQ 0. Поэтому я также проигнорировал этот шаг.
Когда я запускал свой код, он прекрасно компилировался и даже работал на виртуальной машине, но прерывание, казалось, срабатывало только один раз. Затем я понял, что не посылаю EOI в PIC, не позволяя ему вызывать больше прерываний. Тем не менее, добавивmov al, 0x20
а такжеout 0x20, al
как раз передiret
инструкция вызывает сбой виртуальной машины.
Вот моя IDT:
; idt
idt_start :
dw 0x00 ; The interrupt handler is located at absolute address 0x00
dw CODE_SEG ; CODE_SEG points to the GDT entry for code
db 0x0 ; The unused byte
db 0b11101001 ; 1110 Defines a 32 bit Interrupt gate, 0 is mandatory, privilege level = 0 (0b00), the last bit is one so that the CPU knows that the interrupt will be used
dw 0x00 ; The higher part of the offset (0x00) is 0x00
idt_end:
idt_descriptor :
dw idt_end - idt_start - 1 ; Size of our idt, always one less than the actual size
dd idt_start ; Start address of our idt
Вот мой обработчик прерываний (расположен в абсолютном месте 0x00 в памяти):
ISR_0:
push eax
add [0x300], byte
mov al, 0x20
out 0x20, al
pop eax
iret
times 512-($-$) db 0
Вот код, который я использую для входа в защищенный режим и загрузки GDT и IDT в память:
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor]
lidt [idt_descriptor]
mov eax, cr0
or eax, 1
mov cr0,eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm :
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
sti
call BEGIN_PM
Моя основная функция (которая проверяет значение 0x300) выглядит следующим образом:
void main() {
char iii[15];
int * aa = (int *)0x300;
for (;;)
{
setCursor(0, 0);
print(itoab(*aa, iii));
}
}
Кстати, я с помощью дампа памяти проверил, что все загружено по правильному адресу и все именно там, где и ожидается. Например, 0x300 - это свободная часть памяти, используемая просто для упрощения моего кода.