Você está na página 1de 14

This is My Fail Code!

Anedotas, Rascunhos e achados meus na internet.

Como criar um sistema operacional – parte 1

7 DE JANEIRO DE 202124 DE MARÇO DE 2022 ⁄ JMALLONE

Montei esse material primeiro no Google Docs, se você quiser acessar o link é esse:

— HTTPS://DOCS.GOOGLE.COM/DOCUMENT/D/1EOBCSNWKII_1XXRNHTYRFWT6DNZC
IHDE1Z2CLZVOASM/EDIT?USP=SHARING
(HTTPS://DOCS.GOOGLE.COM/DOCUMENT/D/1EOBCSNWKII_1XXRNHTYRFWT6DNZCI
HDE1Z2CLZVOASM/EDIT?USP=SHARING)

criando-um-sistema-operacional-parte-1
(https://myfailcode.files.wordpress.com/2022/03/criando-um-sistema-operacional-parte-
1.pdf) Baixar (https://myfailcode.files.wordpress.com/2022/03/criando-um-sistema-
operacional-parte-1.pdf?force_download=true)
Antes de aprendermos a como criar um bootloader, primeiro temos que entender o que
acontece com o computador ao pressionarmos o botão de Ligar.

Quando pressionamos o botão de Ligar, a energia é enviada para a CPU e a mesma trata de
carregar um pequeno programa armazenado em um chip que fica localizado na placa mãe do
computador.

O programa armazenado é chamado de BIOS (Basic Input/Output System), ou seja, Sistema


Básico de Entrada e Saída, em placa mães mais recentes esse sistema é chamado de UEFI
(Unified Extensible Firmware Interface) ou Interface de Firmware Extensível Unificada. O
nosso foco será no desenvolvimento em cima da BIOS ou também chamada de LEGACY BIOS.

Quando executada, a BIOS carrega as configurações iniciais e inicializa o sistema do


hardware, permitindo assim realizar as mais diversas operações, como por exemplo: acessar
o disco, imprimir na tela, acessar o teclado e etc.

Também é feito uma verificação se todos os componentes do computador estão funcionando


corretamente, esse procedimento é chamado de POST (Power on Self Test) Autoteste ao ligar.
Uma vez inicializada corretamente, a BIOS será responsável por encontrar o Bootloader
(Carregador de inicialização) e executá-lo. Discutiremos a respeito mais a frente.

Ambiente e Ferramentas

Neste artigo, estaremos utilizando uma máquina baseada em Linux, essa escolha se deu
pelo fato de que a maioria das ferramentas que utilizaremos já estão nativas nesse tipo de
sistema operacional. As ferramentas utilizadas foram:

Essenciais:

1. NASM version 2.14.02 [1]


2. ld 2.3 [2]
3. QEMU emulator version 4.0.0 [3]
4. gcc 9.2.1

Opcionais:

1. hexdump [4]
2. vim
3. gdb 8.3

Caso esteja em um sistema operacional baseado em linux que não tem essas ferramentas
basta executar o código abaixo para instalar:

$ sudo apt-get install nasm gcc qemu

Meu primeiro bootloader

O bootloader é um pequeno programa de inicialização do sistema que deve estar situado nos
primeiros 512 bytes do disco, sendo que no seu final deverá estar escrito o Magic Number
0xAA55, que é uma ‘assinatura’ pelo qual a BIOS reconhece que se trata de um dispositivo
válido ou não [5]. Basicamente o bootloader tem como objetivo principal fazer 3 coisas:

1. Carregar o kernel para a memória


2. Passar para o modo protegido
3. Passar o controle para o kernel

Ele é o responsável por direcionar o fluxo de execução para o kernel do sistema operacional,
agindo assim como um intermediador. A Figura 1 demonstra o processo simplificado.
Figura 1 – Processo de Boot Simplificado

Layout da memória física

O espaço de endereçamento do computador é dividido em 2 principais regiões.

A primeira região está abaixo de 1MB, conhecida como lower memory, na qual corresponde
todo o endereçamento disponível possível para o chamado modo real, tal modo trabalha no
máximo com 20 bits de endereçamento.

Já a segunda região é situada acima de 1MB, também conhecida como high memory que só
poderá ser acessada no modo protegido, com endereçamentos 32/64 bits.

A BIOS é responsável por carregar o bootloader que terá como destino o endereço de
memória 0x7c00 que corresponde a área chamada Boot Sector Area, percebe-se que esta área
vai de 0x7c00 até 0x7E00, correspondendo a 512 bytes, como pode ser visto na Figura 2.
Figura 2 – Organização da memória de um computador

Criando o arquivo

Agora que sabemos como funciona, podemos prosseguir. Estarei utilizando o editor de texto
vim do linux, mas pode ser empregado qualquer outro editor da sua escolha.

Crie um arquivo de texto em branco chamado bootloader.asm e salve. No terminal iremos


compilar esse arquivo com o programa nasm.
$ nasm bootloader.asm -o bootloader.bin

Nomearemos esse trecho acima como Comando 1. Desse jeito gerando um arquivo de saída
bootloader.bin, agora iremos executar o qemu com o seguinte comando:

$ qemu-system-x86_64 bootloader.bin

Nomearemos esse trecho acima como Comando 2. O resultado pode ser visto na Figura 3.

Figura 3 – Resultado do qemu

Um dos erros ocorrido foi o Boot failed: could not read the boot disk quando tentou fazer o
boot pelo Hard Disk no sistema, isso se deu pelo fato de que o arquivo está vazio e a BIOS não
encontrou o Magic Number.

Para resolver isso iremos abrir novamente o arquivo bootloader.asm e digitar:

times 512 db 0

Depois de escrito, salve o arquivo e execute o Comando 1 e 2 respectivamente. O resultado


pode ser observado na Figura 4.
Figura 4 – Resultado do qemu

Agora a mensagem de erro no Hard Disk mudou para Boot failed: not a bootable disk.

Isso significa que foi encontrado um dispositivo, mas não um que seja válido, pois lembrando,
necessita que no final tenha a assinatura 0xAA55 para ser reconhecido como um dispositivo
válido.

Entendo o binário

Para ter um outro ponto de vista do arquivo binário, iremos utilizar o seguinte comando:

$ hexdump -Cv bootloader.bin

Nomearemos esse trecho acima como Comando 3. A saída do programa você poderá ver na
Figura 5.
Figura 5 – Resultado do comando hexdump

Está preenchido com apenas 0 pois no arquivo só existe uma repetição para incluir o 0 em 512
bytes. Agora Iremos abrir de novo nosso arquivo bootloader.asm e acrescentar:

times 510 db 0

dw 0XAA55

Observe que de 512 foi para 510 pois o comando 0XAA55 corresponde a 2 bytes, sendo 1 byte
0xAA, e outro para 0x55, 510 bytes + 2 bytes totalizando os 512 bytes necessários para o Boot
Sector Area. Execute o Comando 1 e 2 respectivamente e a saída deverá ser como na Figura 6.
Figura 6 – Boot realizado

Se a mensagem que apareceu no qemu foi Booting from Hard Disk, isso indica que foi
realizado o boot corretamente, ou seja, agora temos um dispositivo válido. Se executarmos o
Comando 3 a saída deverá ser igual a da Figura 7.
Figura 7 – Resultado do Comando 3

Agora a BIOS já consegue encontrar o Magic Number, pois observa-se que o 0xAA55 está no
final do Figura 7, na área onde fica os hexadecimais, em forma de 55 aa, está ao contrário por
causa de alguns aspectos peculiares da arquitetura, que pode ser little endian ou big endian.

Escrevendo na Tela

A próxima etapa a ser feita é escrever um texto na tela, ou melhor, escrever

caracteres na tela. Para que isso ocorra você primeiro deverá conhecer o conceito de
interrupções[6].

Como a leitura e escrita é fundamental para o funcionamento de um sistema, as interrupções


vieram para nos auxiliar nisso, fazendo a ponte entre o hardware e o software.

Como demonstra a Figura 2 e com mais detalhes a Figura 8, a memória tem uma região que se
chama IVT (Interrupt Vector Table) ou tabela de vetores de interrupção, que armazena os
endereços onde estão as rotinas de tratamento de cada interrupção chamadas de ISR
(Interrupt Service Routine) ou Rotina dos serviços de interrupção.
Figura 8 – Visualização do IVT na memória
Figura 9 – Fluxo de Execução de uma Interrupção

Ao se chamar a interrupção int 0x10, ocorre o seguinte:

1. A interrupção 0x10 é a décima interrupção, então este número é multiplicado por 4, pois
cada elemento do vetor possui 4 bytes.
2. O endereço 0x40 é acessado na memória do IVT, e o conteúdo existente neste endereço
será um novo endereço onde se encontra o código dessa interrupção no ISR.
3. Pula-se para esse novo endereço.
4. A rotina de tratamento é executada.
5. O controle é retornado para o programa.

## TODO – Registradores

## TODO – ASCII TABLE

Todo esse fluxo pode ser visto na Figura 9. Iremos implementar uma chamada de sistema no
nosso arquivo, então abra o bootloader.asm e digite:

mov ah, 0X0E


mov al, 4Fh

int 10h

times 510-($-$$) db 0

dw 0xAA55

Salve o arquivo e execute o Comando 1 e 2. Deverá aparecer na tela a letra “O” como na
Figura 10.

Pense nos código mov ah, 0X0E e mov al, 4Fh como parâmetros para função de interrupção int
10h, função está responsável pelos procedimentos relacionados ao vídeo, como a escrita de
caracteres na tela ou até mesmo alterar o modo de vídeo.

O valor 0x0E tem que ir para o registrador ah e significa que queremos entrar em modo texto,
já 4Fh é o valor da letra “O” em hexadecimal da tabela ASCII e tem que ir no registrador al.
Essas 3 primeiras linhas poderá ser feito uma analogia em C assim:

void int10(char tipo, char character);

Onde o resultado final é um caractere escrito na tela, ou também similar a função putchar()
já existente do C.

Já a penúltima linha teve que ser modificada, pois como foi inserido mais bytes, se
continuasse a usar 510 bytes provavelmente iria ultrapassar a região do Boot Sector Area, para
resolver esse problemas adicionamos -($-$$) onde o $ significa o endereço de memória atual e
o $$ o endereço do início da seção atual, que no caso é o endereço inicial do arquivo.

Por exemplo, se as 3 primeiras linhas ocupam 5 bytes e o programa chegar no comando -


($-$$) esse comando irá retornar 5 bytes, logo, 510 – 5 = 505 bytes para preencher com 0 + 2
bytes do Magic Number completando assim os 512 bytes.
Figura 10 – Saída do programa depois da chamada da Interrupção

Se quiser escrever mais caracteres é só repetir o mov al, 4Fh e int 10h no código, trocando o
conteúdo de al pela hexadecimal do caractere correspondente na tabela ASCII, e depois
sempre chamando a interrupção, como por exemplo:

mov ah, 0x0E

;; O

mov al, 4Fh

int 10h

;; l

mov al, 6Ch

int 10h

;; a

mov al, 61h

int 10h

times 510-($-$$) db 0

dw 0xAA55
Referências

[1] – “O que é nasm?” https://assembly-area55.github.io/nasm (https://assembly-


area55.github.io/nasm)

[2] – “Utilizando o linker ld” https://www.ic.unicamp.br/~edson/disciplinas/mc404/2016-


2s/abef/labs/lab01/lab01.html (https://www.ic.unicamp.br/~edson/disciplinas/mc404/2016-
2s/abef/labs/lab01/lab01.html)

[3] – “qemu” https://www.qemu.org/ (https://www.qemu.org/)

[4] – “Exemplos de usos do hexdump ” https://www.geeksforgeeks.org/hexdump-command-in-


linux-with-examples/ (https://www.geeksforgeeks.org/hexdump-command-in-linux-with-
examples/)

[5] – “Explicando o MBR” http://mbrwizard.com/thembr.php


(http://mbrwizard.com/thembr.php)

[6] – “Interrupções Básicas”


https://www.cin.ufpe.br/~eaa3/Arquivos/Assembly/interrupcoes_pc.pdf
(https://www.cin.ufpe.br/~eaa3/Arquivos/Assembly/interrupcoes_pc.pdf)

http://www.brackeen.com/vga/ (http://www.brackeen.com/vga/)

Sponsored Content

Categorias: Tutorial Tags: os, sistema operacional, so

Você também pode gostar