Gerenciador de Boot Simples
Transcrição
Gerenciador de Boot Simples
Gerenciador de Boot Simples Este tutorial é uma simples caminhada através de um Gerenciador de Boot “Hello World”. Este, como qualquer outro gestor, tem que obedecer a algumas regras. Termos utilizados: • BIOS - Um pedaço de código, que é embutido. Isto testa se o hardware está presente e tem algumas funções embutidas que podem ser chamados usando interrupções. • Interrupções - É uma chamada para uma função embutida(building) / procedimento • Hexadecimal – sistema de numeração com base 16. - Refira a números hexadecimais em Asm colocando um "h" depois ou 0x antes. • Decimal – Sistema de numeração normal, mais conhecido. Base 10. Regras: 1) Deve ter 512bytes de tamanho! Isto é porque a BIOS vai automaticamente carregar o primeiro setor do disco na memória. (Disco de inicialização está definido na BIOS, na configuração normal é ter que arrancar a partir do drive de disquete e não que o disco rígido). 2) Deve terminar com a assinatura do bootloader, '55 AA' Onde fica o gerenciador de inicialização carregado na memória? Em hexadecimal, ele é carregado para 7C00. Em decimal é carregado para 31744 (eu acho) Por que isso? Bem, o computador possui uma série de coisas especiais armazenadas no início da memória que você ainda vai conhecer e aprender sobre. Pessoalmente, eu só tenho uma vaga idéia do que fica entre 0 e 4864. INT 0x10: INT 0x10 é a interrupção de vídeo da BIOS. Todas as interrupções relacionadas a tela são feitas com essa interrupção. Então, como você os utiliza? Bem, você tem que ter certos valores em certos registradores para utilizá-los: AH – 0x0E ← Teletype mode (This number must be used to tell the BIOS to put a character on the screen) AL – caractere ASCII para o display BH – Número de página (Para a maior parte de nosso trabalho, será 0x00) BL – Atributo de Texto (Para a maior parte de nosso trabalho, será 0x07) modifique este valor para cores diferentes, etc. Então, assim que os registros estiverem no lugar, você deve chamar a interrupção. Instalando o boot loader: Todos os boot loaders deste documento podem ser copiados e testador por você (exceto o primeiro). Mas sobre sua responsabilidade. É necessário uma CPU compatível com x86. (basicamente AMD/Intel, maioria dos Pcs domésticos 286/286/486... Um disquete para instalar o setor de boot e o compilador NASM. Em nosso caso, necessitaremos de um emulador de arquitetura x86 e o compilador nasm. Os passos são: 1. Criar o arquivo assembler do boot loader e preenche-lo com o conteúdo referente; 2. Compilar com NASM, ex: “nasm arquivo.asm”; 3. Verificar se o arquivo compilado tem exatamente 512bytes; 4. Instalar o boot loader no disquete (no nosso caso, virtual): dd if=arquivo_gerado bs=512 of=floppy.img 5. e bootar a máquina: qemu -fda floppy.img -boot a Exemplos: boot loader que não faz nada: (Não copie e execute este exemplo) ; Início sessão [BITS 16] [ORG 0x7C00] ; ; ; ; Diz ao compilador para fazer isso em geração de código de 16 bits Origem, informa ao compilador onde o código estará na memória depois de ser carregado (em hexadecimal) ; Final sessão times 510-($-$$) db 0 dw 0xAA55 ; Preencha o resto do etor com zeros ; Adicione a assinatura ao final Ok então o que este exemplo faz? Bem, ele não faz nada! Pelo menos nada de importante para comentar. Deixe-me explicar, uma parte que você deve ser capaz de compreender através dos comentários do código. Mesmo assim, o final da sessão é um pouco confuso. times 510-($-$$) db 0 Lê-se assim: 510 vezes – (Início dessa instrução - Início do programa), com 0's $ Representa o início da instrução $$ Representa o início do programa db significa definir byte - um byte é 8 bits, um bit pode ser 0 ou um 1. dw 0xAA55 Por alguma razão, a assinatura tem de ser escrita desta forma! Isto preenche os últimos bytes do gerenciador de inicialização com 55AA (este é um número hexadecimal) Sem essa assinatura, a BIOS não vai reconhecer isso como um disquete de boot! Setor de boot em loop sem final: [BITS 16] ; código de 16 bits [ORG 0x7C00] ; Origem do código definida para 7C00 main: jmp $ ; label principal (Não é realmente necessário agora, porém depois) ; Salta para o início da instrução (nunca terminando o loop) ; Uma alternativa seria 'jmp main' que teria exatamente o mesmo ; efeito. ; Final da sessão times 510-($-$$) db 0 dw 0xAA55 Portanto, agora o que isso representa? Isso coloca o carregador em um loop contínuo. Isto é útil? Mais ou menos. Você vai ver algo na tela? Nada... coisa de BIOS apenas Copie este código e teste, não será interessante ainda, porém é o primeiro passo do gerenciador de boot. Character on the screen boot loader: [BITS 16] [ORG 0x7C00] ; geração de código de 16 bits ; Origem da localização 7C00 ; Programa principal main: ; principal do rótulo do programa mov ah, 0x0E ; Este número é o número da função na BIOS para funcionar. ; Esta função é para colocar caractere na função tela mov bh, 0x00 ; número de página ;deixe-a assim para a maioria do trabalho que vamos fazer mov bl, 0x07 ; ; ; ; ; mov al, 65 int 0x10 jmp $ cor do texto (Controla o fundo e o primeiro plano e possivelmente outras opções) 07 = texto de fundo branco, preto. (Sinta-se livre para brincar com esse valor, pois não deve prejudicar nada) ; Isso deve (em teoria) colocar um valor em ASCII para ser ; exibido. (Este não é o caminho normal para fazer isso) ; Chamada a interrupção de vídeo da BIOS. ; Coloque-o em um loop contínuo para pará-lo correndo dentro ; da memória de execução, limpando qualquer lixo que pode encontrar lá. ; Fim da sessão times 510-($-$$) db 0 ; Preenche o resto do setor com zeros dw 0xAA55 ; assinatura de Boot Agora você verá um caractere aparecendo na tela. Armazenado dados: Se você já usou linguagem de montagem antes deste texto/código e seções de dados. Pois bem, no carregador não temos os mesmos casos. Então onde é que vamos colocar os dados? Bem, nós teremos que encontrar algum lugar que não será executado como parte do programa e colocar os dados lá (e procedimentos). Isto é tanto no início do gerenciador de boot com uma instrução jmp usada para ignorá-los quando quando o boot loader inicia. Ou, no final, onde nunca o gestor de arranque vai. [BITS 16] ; geração de código de 16 bits [ORG 0x7C00]; origem do programa. (Posição inicial) ; Programa principal main: ; Colocando um rótulo que define o início do programa principal call PutChar ; Execute o procedimento jmp $ ; Coloque o programa em um ciclo interminável ; Tudo aqui está fora do programa principal ; Procedimentos PutChar: mov ah, 0x0E mov bh, 0x00 mov bl,0x07 mov al,65 int 0x10 ret ; ; ; ; ; ; ; Label do procedimento Coloque o número da função char (Elevado) número de página (Ignorar por enquanto) atributo normal código de caracteres ASCII Interrupção de execução Voltar ao programa principal ; Esta informação nunca é executada, nem mesmo como um procedimento ; Dados TestHugeNum dd 0x00 TestLargeNum dw 0x00 TestSmallNum db 0x00 ; ; ; ; ; ; Este pode Até o hex Isso pode Até o hex Este pode Até o hex ser um número muito grande (1 palavra dupla) ffffffff ser um bom número bem grande (1 palavra) ffff ser um número pequeno (1 byte) ff TestString db 'Test String',13,10,0 ; Final da sessão times 510-($-$$) db 0 dw 0xAA55 ;Esta é uma string (pode ser bem longa) ; zero para o resto do setor ; assinatura Bootloader Execute este código de boot também. O que ele faz? Exatamente o mesmo de antes, colocando alguns valores na memória, e colocando o código responsável por um caractere na tela por um procedimento. A principal coisa que vai olhar incomum é a linha: TestString db 'Test String ", 13,10,0 Como isso é apenas um db (byte)? Bem, não é, mas TestString armazena apenas a localização de memória e não os dados. E a referência de localização da string pode ser armazenada em um byte. O que acontece com os números no final? 13 – ASCII para Retorno 10 – ASCII para Nova Linha (Os dois juntos fazem iniciar o texto seguinte na linha seguinte) 0 – Não faz nada, mas será mais tarde utilizado como um marcador para o fim da cadeia O resto do código que você deve compreender a partir de seus comentários. Escrevendo toda a string: [BITS 16] [ORG 0x7C00] ; geração de código de 16 bits ; local de origem ; Programa Principal main: ; Label para o programa principal mov ax,0x0000 mov ds,ax ; ; ; ; ; configuração dos dados do registo do segmento Localização dos dados é DS: Offset Isto não pode ser carregado diretamente, tem que ser em 2 passos 'mov ds, 0x0000' não irá funcionar devido a limitações na CPU mov si, HelloWorld ; Carrega a string dentro da posição para o procedimento call PutStr ; Chama/Inicia o procedimento jmp $ ; loop sem final ; Procedimentos PutStr: ; Configura os mov ah,0x0E mov bh,0x00 mov bl,0x07 ; Label/Início do Procedimento registros para a chamada de interrupção ; A função para mostrar o caractere (teletype) ; Número de página ; Atributo normal de texto .nextchar lodsb ; Label interno ; (necessário para continuar o loop para o próximo caractere) ; LOaD String Block ; Checa pelo final 0 da string or al,al ; Define zero para a bandeira se al = 0 jz .return int 0x10 jmp .nextchar .return ret ; ; ; ; ; ; ; Se o sinalizador zero foi definido ir até o fim do processo. bandeira zero fica definido quando uma instrução retorna 0 como resposta. Executa a interrupção de vídeo na BIOS Voltar o ciclo ao topo Label para o final do loop Retorna para o programa principal ; Dados HelloWorld db 'Hello World',13,10,0 ; Final da sessão times 510-($-$$) db 0 dw 0xAA55 ; Preenche o resto com zeros ; Assinatura do Boot loader Ok, agora isso vai colocar 'Olá Mundo' na tela. Fonte: <http://www.osdever.net/tutorials/hello_btldr.php> Autor: Daniel Rowell Faulkner Tradução e Adaptação: Jacson RC Silva