Escrevendo meu próprio Sistema Operacional (ou quase...)
Autor: Renan Greinert | Publicado: 2013-01-17T17:03:00-08:00





Uma das coisas mais frustrantes para os
estudantes de engenharia/ciência da computação são as aulas de
Sistemas Operacionais. Você aprende a criar threads, pipes,
schedulers e tudo mais, mas não aprende aquilo que tanto sonhava:
como escrever seu próprio sistema operacional.



Bom, não vou explicar aqui como criar
um Windows ou Linux. Para chegar perto isso, prepare-se para alguns
anos de desenvolvimento. Mas vou mostrar os passos básicos, isto é,
como escrever um Hello World
básico  para rodar no boot
da máquina, independente de Windows, Linux, Solaris, BSD ou seja lá
qual for o SO que você use.



Primeiramente,
precisamos escrever um programa em Assembly puro, sem dependência
nenhuma de nenhum sistema operacional. Estou utilizando o compilador
NASM como exemplo, que pode ser baixado gratuitamente.



(Não vou entrar no mérito de
ensinar Assembly aqui, até porque não sou um especialista na
linguagem. Se quiser se aprofundar mais, existem ótimos tutoriais na
net.)



O seguinte código
imprime um “Ola Mundo” na tela, sem utilizar nenhuma API ou
qualquer outra dependência de um Sistema Operacional:



;os.asm

jmp 0x7C0:main 



main:



mov ax, 0x07C0 
;a MBR eh carregada pela bios em 0x7C0

mov ds, ax

mov es, ax



mov si,
olamundo 

call
print_string ;chama a funcao que imprime o "Ola
Mundo"



mainloop:



jmp mainloop



olamundo db 'Ola
Mundo :P', 0x0D, 0x0A, 0



print_string:

lodsb      
;pega o proximo byte de SI



or al, al  ;
compara o registrador com ele mesmo. 


jz .done   ;
Se o resultado for zero, cai fora



mov ah, 0x0E

int 0x10      ;
Imprime o caracter na tela



jmp print_string



.done:

ret





Para compilá-lo:



nasm os.asm -f
bin -o os.bin



Ótimo, temos o
código compilado, agora precisamos copiá-lo para o setor de boot da
máquina. A menos que você queira que seu computador não faça mais
nada além de mostrar a mensagem “Ola Mundo”, você não vai
querer copiar isso para o setor de boot do seu HD.



Algumas opções
são:

-Copiar para um
pendrive e, para testar, modificar o boot da BIOS para bootar no
pendrive;

-Utilizar uma
máquina virtual.



Para ficar mais
emocionante, vamos copiar para um pendrive (depois da brincadeira,
você precisará formatá-lo para poder voltar a usá-lo normalmente,
então guarde seus arquivos importantes).



Se você estiver no
Linux, pode copiá-lo diretamente utilizando o comando dd:


dd if=os.bin of=/dev/fd#




Sendo # o número do seu dispositivo de pendrive. (Este comando
talvez não funcione, pois algumas BIOS exigem que se coloque os
bytes 0x55aa no fim do setor de boot).



No Windows, podemos
escrever um programinha em C++ para realizar esta cópia. Você
poderá escrever um programa similar para o Linux também, caso o
comando acima não funcione. 




Primeiramente,
precisamos saber qual é o valor do dispositivo que acessa o
pendrive. Não adianta tentar apontar para “d:\”
ou algo do tipo, pois este endereço aponta para a partição fat
dentro do pendrive. Queremos apontar para a MBR.



Para isso, clique
com o botão direito em Meu Computador, vá em Gerenciamento e
então em Gerenciamento de Disco (Disk Management).

Embaixo, você deve
ter alguma coisa do tipo:



Disk 0 - C:

Disk 1 - D:

…



Veja qual é o
disco referente ao seu Pendrive (no meu caso é Disk 2). Aí você
pode apontar para ela pelo caminho:



\\.\PhysicalDrive#



(sendo # o número
do disco).



O código do
programa para copiar o seu código em ASM para a MBR é o seguinte:






#include &lt;cstdio&gt;
#include &lt;cstdlib&gt;
#include &lt;io.h&gt;
#include &lt;windows.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;

int main()
{
&nbsp; FILE* arqAsm = NULL;

&nbsp; unsigned char buf[512]; //A MBR tem tamanho 512

&nbsp; arqAsm = fopen( "os.bin", "r" );

&nbsp; fseek( arqAsm, 0, 0 );

&nbsp; fread( (void*)buf, 1, 510, arqAsm ); //lemos o conteúdo do arquivo para nosso buffer

&nbsp; buf[510] = 0x55; //colocamos o 0x55aa no final da MBR, pois
&nbsp; buf[511] = 0xaa; //algumas BIOS precisam disso


&nbsp; fclose( arqAsm );
&nbsp; //aqui abrimos a MBR do pendrive
&nbsp; HANDLE hFile;

&nbsp; hFile = CreateFile("\\\\.\\PhysicalDrive2", //Apontando para "Disk 2". Mude para o que você for usar
&nbsp; GENERIC_WRITE, // abrindo para escrita
&nbsp; 0,
&nbsp; NULL,
&nbsp; OPEN_EXISTING,
&nbsp; NULL,
&nbsp; NULL);

&nbsp; if (hFile == INVALID_HANDLE_VALUE)
&nbsp; {
&nbsp; &nbsp; printf("Problema abrindo a MBR");
&nbsp; &nbsp; return 0;
&nbsp; }

&nbsp; SetFilePointer( hFile, 0, 0, FILE_BEGIN );

&nbsp; DWORD escritos;
&nbsp; if ( !WriteFile( hFile, buf, 512, &amp;escritos, NULL ) )
&nbsp; {
&nbsp; &nbsp; printf("Problema ao escrever na MBR" );
&nbsp; }

&nbsp; CloseHandle( hFile );

&nbsp; return 0;
}





Antes de
executá-lo, verifique novamente se você colocou o endereço do
disco correto! Se você apontou para o seu HD, não vai mais
conseguir bootar o seu Windows!



Se você quiser
escrever o programa em Linux, em vez da função “CreateFile”
utilize “open”, e em vez de “WriteFile” utilize “write”
(note que os parametros são diferentes). 




Agora é só
compilar e executar. Note que, em algumas versões do Windows, será
necessário executá-lo como administrador.



Agora basta
reiniciar a máquina, entrar na BIOS, colocar o pendrive como boot #1
e ver o seu “Hello World” rodar!



É isso pessoal, em
um próximo post eu explico com mais detalhes como a MBR funciona.





Agora você já
pode sobrescrever a MBR do computador da sua namorada com uma
mensagem do tipo “Eu te amo, minha linda!”. Ela vai adorar.