Oficina
11. Interrupções, Exceções e IDTs
Dom 27 Mai 2007 08:55 |
- Detalhes
- Categoria: Sistemas Operacionais
- Atualização: Quarta, 22 Abril 2009 11:38
- Autor: vovó Vicki
- Acessos: 22727
O que é uma exceção e como é disparada
Uma exceção é uma interrupção que ocorre quando alguma coisa dá errado com o código que está sendo executado. Pode ser uma divisão por zero, uma tentativa de acessar um segmento inexistente ou coisa parecida.
Existem 15 tipos de exceções na CPU x86, classificadas como interrupções de 0 a 16, o que significa que existem algumas "falhas" na sequência. Estas falhas correspondem a interrupções reservadas pela Intel, talvez para uso futuro. As interrupções das exceções são as seguintes (mantenho a nomenclatura da Intel entre parênteses):
0 Erro de Divisão (Divide Error) 1 Exceções de Debug (Debug Exceptions) 2 3 Ponto de parada de execução (Breakpoint) 4 Overflow 5 Checagem de Limites (Bounds Check) 6 Código Operacional Inválido (Invalid Opcode) 7 Coprocessador não disponível (Coprocessor Not Available) 8 Falha Dupla (Double Fault) 9 Segmento de Coprocessador Ultrapassado (Coprocessor Segment Overrun) 10 TSS Inválida (Invalid TSS) 11 Segmento Não Presente (Segment Not Present) 12 Exceção da Pilha (Stack Exception) 13 Exceção de Proteção Geral - Falha Tripla (General Protection Exception - Triple Fault) 14 Falha de Página (Page Fault) 15 16 Erro do Coprocessador (Coprocessor Error)
Uma ISR para uma Exceção Simples
O modelo de ISR também serve para tratar exceções, mas falta o código que trata a interrupção. Como exemplo, veja uma ISR completa para a exceção 0. Esta ISR mistura código C e Assembly:
A função _interrupt_0, escrita em C, leva em consideração que temos apenas tarefas do ring 0 (ou seja, que estamos trabalhando em modo real). Se tivéssemos tarefas do ring 3 e uma destas tarefas tivesse causado a exceção, então deveríamos deletar a tarefa do ring 3 e continuar. Se você não tiver idéia do que sejam os rings, dê uma lida em O Sistema Windows de 32 bits que está no Oráculo de Referências.
Existem duas opções: criar uma função para cada tipo de exceção ou criar apenas uma função C, que recebe como parâmetro a exceção ocorrida e com rotinas que tratam de todas as exceções possíveis.
O que é uma IDT
Uma IDT (Interrupt Descriptor Table - Tabela de Descritores de Interrupção) é um array de descritores usado para associar interrupções e exceções às respectivas ISRs. É o mapa da mina para a CPU saber qual rotina precisa ser executada quando receber uma chamada de interrupção. Cada descritor é composto por 8 bytes e a IDT pode conter no máximo 256 descritores (o total de interrupções no PC também é 256). Quando se cria uma IDT, não é necessário que a tabela contenha 256 descritores, basta usar um para cada interrupção que será tratada no sistema operacional. Para informar a localização da IDT para a CPU, usamos a instrução Assembly LIDT.
O formato do descritor IDT
Como já foi mencionado, cada descritor possui 8 bytes, ou seja, 64 bits. O formato dos descritores contidos numa IDT é o seguinte:
|
- O bit 15, Presente: 0 = ausente, 1 = presente. Se Presente não for 1, ocorrerá uma exceção.
- DPL (Descriptor Privilege Level - Nível de Privilégio do Descritor): 00 = ring0, 01 = ring1, 10 = ring2, 11 = ring3
- Seletor: seletor do código que a ISR usará
- Deslocamento: o endereço da ISR. É dividido em dois campos diferentes para manter o processador 386 (e melhores) compatível com o 286.
O melhor é criar um seletor para entender como funciona. No descritor do exemplo o DPL está ajustado para o ring0, é um descritor presente, o seletor é 0x10 e o deslocamento (o endereço da ISR) é 0x200000. Veja abaixo:
|
Conhecendo a estrutura dos descritores de interrupção, fica fácil entender a estrutura de uma IDT. No momento, é o que basta. Acontece que isto não é tudo. Se não soubermos informar onde a CPU pode encontrar a IDT... de nada vale compor a tabela.
Carregando a IDT via LIDT
Informamos a localização da IDT à CPU através da instrução Assembly LIDT. Esta instrução precisa de um parâmetro do tipo ponteiro. Este aponta para uma pequena estrutura que descreve a IDT para que a CPU saiba onde ela começa e quantos descritores contém. Esta estrutura, que chamaremos de ponteiro da IDT, possui os seguintes campos:
|
- Base: endereço do começo da IDT
- Limite: comprimento da IDT em bytes
Com estas informações é possível criar uma pequena IDT com apenas três entradas usando o NASM:
Agora os marcadores inicio_da_idt e fim_da_idt nos fornecem os endereços que devem compor o ponteiro da IDT:
|
Traduzido para o NASM, o ponteiro da IDT é o seguinte:
Tendo o ponteiro da IDT, agora basta usar a instrução LIDT:
Considerações finais
Estamos chegando cada vez mais perto do nosso objetivo que, para ser sincera, não é construir um sistema operacional que faça concorrência aos existentes. O importante nesta série de tutoriais é adquirir conhecimento suficiente para que possamos entender os sistemas operacionais e, se estivermos planejando um grande projeto, sabermos por onde começar. É por isso que textos da qualidade do Interrupts, Exceptions, and IDTs, escrito por K.J. em três partes, são tão valiosos. Como o texto serviu de base para este módulo, agradeço o autor por ter disponibilizado este material na Internet e o coloquei na seção de downloads da Aldeia em Tutoriais / Sistemas Operacionais.
- << Anterior
- Próximo