BIOS, 2020, 💀 e um bootloader!

Uma das apresentações na UEFI Plugfest deste outono (2017), foi de Brian Richardson, que é Ecosystem Business Planning na Intel. Num dos seus slides, ele revela que a Intel, por fim, irá colocar um término ao suporte da velhinha BIOS. Para os interessados podem ver os slides aqui.

Atenção, UEFI não é perfeita, mas é bem mais moderna e future-proof do que a BIOS. Por isso resolvi escrever este artigo a mostrar como fazer um simples bootloader para correr num PC/emulador com BIOS.

O objetivo é criar um pequeno programa que imprima a mensagem “You have done your job, BIOS!”, que seja corrido diretamente pela BIOS, sem o uso de qualquer sistema operativo.

Antes de começar… 📄

Antes de começar, vamos necessitar de três ferramentas, o NASM, o QEMU e um sistema operativo UNIX. Eu vou estar a usar macOS, mas podem usar qualquer OS Unix-like, como por exemplo Linux.

O Netwide Assembler, ou apenas NASM é um assembler para as arquiteturas 80x86 e x86–64, desenhado para ser altamente portável e modular. Este consegue emitir objetos em diferentes formatos para diferentes plataformas.

O Quick Emulator, mais conhecido por QEMU, é um hypervisor que permite emular diferentes CPUs através de binary translation e através de técnicas de hardware virtualization, por outras palavras o QEMU emula um hardware real na integra.

Como disse acima todos os comandos serão executados em macOS, alguns deles terão que ser modificador para correr em outros sistemas operativos. OK, comecemos por instalar o NASM e o QEMU.

brew install nasm qemu

Como funciona? 👷‍♂️

Para excluir a preocupação com o sistema de ficheiros, discos e afins, o nosso bootloader será escrito como uma imagem de uma disquete. Yap, isso mesmo, aquela tecnologia de ponta dos anos 70 👌

Mas…, bom, afinal o que acontece quando se clica no botão de ligar do PC? Como em quase tudo na vida, existem padrões definidos que produtores de CPUs e de motherboards têm que seguir para que as coisas funcionem como esperado. Quando o PC inicia a Motherboard faz um reset aos diferentes componentes a si ligados, inclusive ao CPU, neste ponto ela define o Program Counter (PC) para a posição de memória no barramento onde o código da BIOS está carregado. O PC, basicamente é o registo do CPU, que armazena o endereço da posição de memória da próxima instrução a ser executada.

A BIOS após se inicializar, começa por fazer um teste ao hardware para ver se existem erros no mesmo, uma operação completamente desnecessárias nos dias de hoje. Isto porque, visto que a qualidade de produção é muito superior do que à 40 anos atrás e por essa razão é que a UEFI não o faz, poupando assim imenso tempo de boot. Após essa verificação, a BIOS carrega 512 bytes para a memória a partir de um dispositivo de media (por exemplo, CD-ROM ou disquete). Se os últimos dois bytes forem iguais a 0xAA55 a BIOS irá saltar para o endereço 0x7C00 e assim passar o controlo para o bootloader.

Neste momento o CPU corre em modo real, um estado do CPU em que este funciona em 16-bits e o código tem liberdade maxima no controlo do hardware. Isso quer dizer que apenas os registers de 16-bit estão disponíveis e que uma vez que a BIOS apenas consegue carregar 512 bytes isso significa que o nosso bootloader não pode passar desse limite, caso contrario caímos em zonas de memória não inicializaras e coisas estranhas acontecem 😅

Vamos a isto. 💪

Agora que já temos um pouco de contexto podemos avançar apara a implementação do nosso bootloader. Para escrevermos a string no ecrã vamos usar o modo “Write Character in TTY Mode” que pode ser encontrado na tabela de interrupções disponibilizadas pela BIOS e para carregar os bytes da string vamos usar a instrução lobsb, que basicamente carrega os bytes em ds:si para al. Let's code:

bits 16       ; informa o NASM para usar código 16 bit
org 0x7c00 ; diz ao NASM para definir o offset inicial do
; programa na localização 0x7c00

entry_point:
mov si, message ; aponta SI para a localização de memória
; onde a mensagem se encontra
mov ah, 0x0e ; 0x0e significa 'Write Character in TTY mode'

.loop:
lodsb
or al, al ; verifica se a al é igual a 0
jz halt ; no caso de ser zero salta para halt
int 0x10 ; executa a interrupção 0x10 - Serviço de Video
jmp .loop ; itera até al ser 0, ou seja o fim da string

halt:
cli ; desativa as interrupções
hlt ; suspende a execução

; mensagem que queremos imprimir, com um null terminator
message: db "You have done your job, BIOS!", 0

times 510 - ($-$$) db 0 ; preenche os restantes 510 bytes com zeros
dw 0xaa55 ; assinatura magica para o booloader. Torna
; os 512 bytes "botaveis"!

Ok, feito! Não foi assim tão difícil, certo? Agora que temos o nosso código escrito temos que o compilar. Eu guardei o ficheiro como sendo bootloader.asm. Para compilar apenas é necessário executar o seguinte comando:

nasm -f bin bootloader.asm -o bootloader.bin

Se fizermos um hexdump bootloader.bin podemos ver que o NASM compilou o código corretamente e nos últimos dois bytes temos o nosso magico 0x55aa:

0000000 be 10 7c b4 0e ac 08 c0 74 04 cd 10 eb f7 fa f4
0000010 59 6f 75 20 68 61 76 65 20 64 6f 6e 65 20 79 6f
0000020 75 72 20 6a 6f 62 2c 20 42 49 4f 53 21 00 00 00
0000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
00001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
0000200

Bota correr 🏃‍♀️

Agora é tempo para correr esta coisa! Para isso vamos usar o QEMU com a flag fba, isto permite carregar a nossa imagem (bootloader.bin) como sendo uma disquete. Para isso vamos executar o comando qemu-system-x86_64 -fda bootloader.bin

O resultado deve ser alguma coisa parecida com o que está a cima. Nice! 😁

O futuro! 🚀

Neste momento ainda existe muito hardware com BIOS, mesmo Motherboards com UEFI têm o Compatibility Support Module (CSM) que permite correr programas legacy em 16-bit. Isto tem que terminar, porque a BIOS tem diversos problemas de segurança, a arquitetura x86 contem demasiadas camadas “desnecessárias” para suportar todo o passado desde o velhinho Intel 8086 e a UEFI tem imensas funcionalidades novas que permite reduzir a code base resultando em binários mais pequenos e mais seguros.

Não te esqueças de apontar na tua agenda, 2020, fim da BIOS! 😉

Like what you read? Give Gil Mendes a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.