Configurando interrupções no modo protegido (x86)
Qual é o processo de configuração de interrupções no modo protegido?
este O link diz que se deve:
Crie espaço para a tabela do descritor de interrupçãoInforme à CPU onde está esse espaço (consulte o Tutorial do GDT: o lidt funciona da mesma maneira que o lgdt)Diga ao PIC que você não deseja mais usar os padrões do BIOS (consulte Programando os chips PIC)Escreva alguns manipuladores ISR (consulte Interrupt Service Routines) para IRQs e exceçõesColoque os endereços dos manipuladores ISR nos descritores apropriadosHabilite todas as interrupções suportadas na máscara IRQ (do PIC)O terceiro passo não faz sentido para mim (olhei paraesta link, mas não havia nada a dizer ao PIC), então eu o ignorei e concluí as próximas duas etapas, apenas para ficar sem noção mais uma vez quando cheguei à etapa final. No entanto, pelo meu entendimento das interrupções, as duas etapas que eu não entendi estão relacionadas às interrupções de hardware do controlador PIC e não devem afetar as interrupções geradas pelo PIT no IRQ 0. Portanto, eu também ignorei essa etapa.
Quando corri meu código, ele compilou bem e até rodou em uma máquina virtual, mas a interrupção pareceu disparar apenas uma vez. Percebi então que não estava enviando EOI para o PIC, impedindo-o de causar mais interrupções. No entanto, adicionarmov al, 0x20
eout 0x20, al
pouco antes dairet
instrução causa falha na máquina virtual.
Aqui está o meu 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
Aqui está o meu manipulador de interrupção (localizado no local absoluto 0x00 na memória):
ISR_0:
push eax
add [0x300], byte
mov al, 0x20
out 0x20, al
pop eax
iret
times 512-($-$) db 0
Este é o código que eu uso para entrar no modo protegido e carregar o GDT e o IDT na memória:
[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
Minha função principal (que verifica o valor de 0x300) é a seguinte:
void main() {
char iii[15];
int * aa = (int *)0x300;
for (;;)
{
setCursor(0, 0);
print(itoab(*aa, iii));
}
}
A propósito, eu verifiquei usando um despejo de memória que tudo está carregado no endereço correto e tudo está exatamente onde é esperado. Por exemplo, 0x300 é uma parte livre da memória usada simplesmente para simplificar meu código.