Interface Hardware-Software
Modo Protegido de Operação de
Processadores x86 – Interrupções e
Instruções
Interrupções e Exceções em Modo Protegido
O suporte e o mecanismo de tratamento de interrupções e exceções é diferente em relação ao modo real
Registradores específicos Descritores
Tabelas de descritores de interrupções
Contudo a quantidade de vetores de interrupção continua a mesma
– 256 vetores (0 – 255)
Com o modo protegido, alguns números de vetores são consagrados a tipos de exceção/interrupção relacionados a proteção
- 13 – General Protection Fault - 14 – Page Fault
Tipos de Exceção
Fault geralmente pode ser corrigida e permite que o
programa seja reiniciado sem perda de continuidade
- Endereço de retorno para o fault handler(CS e EIP) é
instrução que gerou o fault em vez da instrução que segue
- Exemplo: page fault
Trap é gerada logo em seguida a instrução que a causou e
permite que o programa continue
- Endereço de retorno do trap handler é a instrução seguinte àquela que gerou a trap
- Exemplo: Overflow
Abort não aponta o local preciso da instrução que causou
a exceção e nem permite o reinicio do programa
Suporte a Interrupções/Exceções
Transferência de controle para as rotinas de tratamento (handlers) é feita através de interrupt gates e trap gates
Descritores destes tipos de gates ficam na IDT (Interrupt
Descriptor Table)
IDT
Possui três tipos de descritores:
- Interrupt Gates - Trap Gates - Task Gates
No caso do handler estar em outra tarefa(task), um task gate é utilizado
Cada descritor tem 8 bytes
IDTR
O registrador IDTR tem 48 bits e guarda o endereço base de 32 bits e o limite de 16 bits da IDT
Contudo a IDT só deve ter no máximo 256 entradas de 8 bytes, portanto só seriam necessários 11 bits para o limite
O IDTR é carregado com o endereço base e o limite, geralmente no ato de inicialização do SO
- Instrução LIDT carrega o IDTR
Interrupt Gate x Trap Gate
A diferença entre um interrupt gate e um trap gate é a forma que o processador trata a flag IF no registrador EFLAGS
Interrupt Gate
- Processador coloca IF (Interrupt Flag) para 0 para impedir
que outras interrupções de HW (mascaráveis) interrompam o handler
- Quando é feito um IRET, o processador restaura a flag Trap Gate
Tratando Interrrupções/Exceções
Se o índice para o handler apontar para um descritor do tipo interrupt ou trap gate, o processador trata a
interrupção/exceção de forma semelhante a um CALL para um call gate
Se o índice para o handler apontar para um descritor do tipo task gate, o processador faz um task switch para a
tarefa do handler de forma similar a um CALL para um task gate
Troca de Pilha Durante Tratamento da Interrupção
Quando o handler é localizado em um nível de privilégio maior (numericamente menor), ocorre uma troca de pilha
Não é possível a transferência de execução para um handler com nível de privilégio menor (numericamente maior)
Instruções Privilegiadas
Existem instruções que só podem ser executadas em nível de privilégio zero
Tipicamente são instruções que manipulam registradores e estruturas de dados que dão suporte à proteção
- Registradores de controle (CR0-CR4)
- Registradores de tabela de descritores (GDTR,LDTR,IDTR) - Tabela de descritores
Exemplos de Instruções Privilegiadas
Instrução Descrição Exemplo
LGDT src Carrega endereço base e limite(src) de GDT no registrador
GDTR
lgdt [0x10000]
LSL dst,src Carrega no registrador dst, o limite do segmento dado pelo seletor em
src
mov ebx, cs lsl edx,[ebx]
LIDT src Carrega endereço base e limite (src)de IDT no registrador IDTR
lidt [0x100]
MOV regs de controle,src
Carrega o que está em src em um registrador de controle
mov eax,cr0 or al,1
mov cr0,eax
ARPL dst,src Ajusta (iguala) o RPL do seletor em dst ao RPL do seletor em src
pop dx pop bp
Exemplo do ARPL
Passando de Modo Real para Modo Protegido
O boot começa em modo real e depois ocorre a mudança para modo protegido
- Multi-stage Boot loader
- Permite o carregamento e execução do kernel de 32 bits
Algumas etapas são imperativas para esta mudança:
- Criação e inicialização da GDT - Criação e inicialização da IDT
- Carregamento de registradores de tabelas com os endereços
base das tabelas
- Inibição de interrupções externas
- Alterar registrador de controle para rodar em modo protegido - Inicialização dos registradores de segmentos com seletores
Criando e Inicializando o GDT
gdt_data:
dd 0 ; null descriptor dd 0
; gdt code: ; code descriptor dw 0FFFFh ; limit low dw 0 ; base low db 0 ; base middle db 10011010b ; access db 11001111b ; granularity db 0 ; base high
; gdt data: ; data descriptor dw 0FFFFh ; limit low dw 0 ; base low db 0 ; base middle db 10010010b ; access db 11001111b ; granularity db 0 ; base high end_of_gdt: toc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT) dd gdt_data ; base of GDT
Descritor 0
Descritor 1
Procedimento para Carregar Registrador GDTR
InstallGDT:
cli ; clear interrupts pusha ; save registers
lgdt [toc] ; load GDT into GDTR sti ; enable interrupts
popa ; restore registers ret
Mudança para Modo Protegido e Inicialização dos
Registradores de Segmentos
call InstallGDT cli
mov eax, cr0 ; setar bit 0 (PE) para 1 or eax, 1 mov cr0, eax jmp 08h:Stage3 ... Stage3: mov ax, 10h mov ds, ax mov ss, ax mov es, ax
mov esp, 90000h ; pilha começa no endereço 90000h
Instalando o GDT
Desabilitando interrupções
Mudando Modo da CPU para Protegido
Colocando o seletor 08h no CS
Colocando o seletor 10h no
Entendendo os Valores dos Seletores
(1)
Por que ?
00000000000001000
Seletor para Descritor 1
Entendendo os Valores dos Seletores
(2)
Por que ?
00000000000010000
Seletor para Descritor 2
mov ax,10h mov ds, ax
Modo Protegido: O Que Muda para o
Programador?
Algumas instruções novas são disponíveis para o programador
- Instruções privilegiadas, instruções que dão suporte a escrita
de SO (ou parte) como SGDT (salvar o registrador gdtr em uma posição de memória) e SIDT, e outras de uso geral tal como SYSENTER (32 bits) e SYSCALL (64 bits)
Em vez de se utilizar interrupções da BIOS, utiliza-se
chamadas de sistema que podem ser feitas através:
- Interrupções do SO - Instruções específicas
Utilizando Interrupção 80H do Linux
Ao se utilizar esta interrupção do Linux, deve-se especificar qual é o serviço que se deseja utilizar
- Especifica-se colocando o número do serviço no registrador
EAX
- Parâmetros do serviço devem ser colocados em EBX,ECX e
Alguns Serviços da Interrupção 80H do Linux
%eax Name %ebx %ecx %edx 1 sys_exit int - -
2 sys_fork struct pt_regs
- -
3 sys_read unsigned int char * size_t
4 sys_write unsigned int const char * size_t
5 sys_open const char * int int 6 sys_close unsigned int - -
Hello World Usando INT 80H
section .data
message: db ‘Hello, World!,0 msgLen: equ $-message
section .text
global _start _start:
mov eax, 4 ; system call 4 é escrita
mov ebx, 1 ; deve-se colocar 1 para stdout mov ecx, message ; end da string para saida mov edx, msgLen ; quantidade de bytes int 80h ; chama SO para fazer a escrita mov eax, 1 ; system call 1 é sair
xor ebx, ebx ; exit code é 0
Lendo e Escrevendo uma String com INT 80H
section .data
msgUsr db ‘Entre com numero: '
tamMsgUsr equ $-msgUsr ; O tamanho da mensagem dispMsg db ‘Voce entrou com: '
tamDispMsg equ $-dispMsg section .bss ;Dados não inicializados num resb 5 section .text global _start _start: mov eax, 4 mov ebx, 1
mov ecx, msgUsr mov edx, tamMsgUsr int 80h
Escreve mensagem no display, pedindo para entrar com
mov eax, 3 mov ebx, 0 mov ecx,num
mov edx, 5 ;5 bytes (numerico, 1 para o sinal) int 80h
mov eax, 4 mov ebx, 1
mov ecx, dispMsg mov edx, tamDispMsg int 80h
Lendo e Escrevendo uma String com INT 80H
(cont…)
Lendo o número Imprimindo mensagem “Voce entrou com:”mov eax, 4 mov ebx, 1 mov ecx, num mov edx, 5 int 80h mov eax, 1 mov ebx, 0 int 80h
Lendo e Escrevendo uma String com INT 80H
(cont…)
Imprimindo o número que usuário entrou Saindo do programaUtilizando SYSCALL
A instrução SYSCALL é utilizada para processadores de 64 bits
- Permite acessar mais rapidamente códigos que rodam em
nível de privilégio 0
Ao se utilizar esta instrução, deve-se especificar qual é o serviço que se deseja utilizar (depende do SO utilizado)
- Especifica-se colocando o número do serviço no registrador
RAX
- Parâmetros do serviço devem ser colocados em
Hello World Usando SYSCALL em Linux
section .data
message: db ‘Hello, World!,0 msgLen: equ $-message
section .text
global _start _start:
mov rax, 1 ; system call 1 é escrita
mov rdi, 1 ; deve-se colocar 1 para stdout mov rsi, message ; end da string para saida mov rdx, 13 ; quantidade de bytes
syscall ;chama SO para fazer a escrita
mov rax, 60 ; system call 60 é sair mov rdi, 0 ; exit code é 0
syscall ; chama SO para sair