Como hacer un Bootloader y no morir en el intento
Cuando la computadora es encendida ( arquitectura intel IA32), el microprocesador se ecuentra operando en modo real. En la última etapa del POST el BIOS llama la int 19h, la cual carga el primer sector del disco (duro o flexible) si encuentra en el número 0xAA55 que empieza en el offset ( desplazamiento) 510.
De aparecer ese número la int 19h copia los 512 bytes del sector en la dirección de memoria 7c00:0000, luego realiza un salto incodicional a esa dirección, lo cual significa que el registro cs= 7c00 y ip=0000 por lo que realiza algo como:
mov ax,7c00
mov cs,ax
jmp 0
Una forma realmente sencilla de ver el contenido de tu sector de arranque es con lo siguiente ( como usuario root)
kb@cobalt:/home/labs/src/osdev/miniboot$ dd if=/dev/hda bs=1 count=512 of=mbr.bin
kb@cobalt:/labs/labs/src/osdev/miniboot$cat mbr.bin | od -x
0000000 37ea c000 4307 7261 6167 646e 206f 6c65
0000020 5320 7369 6574 616d 2e20 2e2e 2e2e 2e2e
0000040 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e
0000060 2e2e 2e2e 2e2e 8c00 8ec8 8ed8 bec0 0005
0000100 3cac 7400 b409 bb0e 0007 10cd f2eb 00b8
0000120 8e10 31c0 b4db b002 b501 b100 b602 b200
0000140 cd00 7213 eae9 0000 1000 0000 0000 0000
0000160 0000 0000 0000 0000 0000 0000 0000 0000
0000760 0000 0000 0000 0000 0000 0000 0000 aa55 <-- marca de arranque
La clave esta en que Si la marca de arranque no existe la int19h no copia el sector a memoria e imprime el famoso "Operating System no found"
Entonces hay que cuidar ciertos detalles de la siguiente lista:
Para resolver el problema 1:
La mayoría de los ensambladores poseen una pseudoinstrucción que permite "rellenar" el archivo generado con algun valor un número determinado de veces o hasta que el archivo tenga algun tamaño. En nuestro caso NASM, utiliza una instrucción llamada rep la cual veremos como funciona más adelante. Para resolver el problema 3:
Debemos programar el bootloader en ensamblador, en el caso de nasm la opción para generar un binario plano es llamar nasm sin opciones, ejemplo:
$nasm boot.s -o bootloader.raw
En fin el programa de ejemplo aqui:
;archivo mboot.s
%define BUFFER 0x0600 ; comienzo de la memoria a donde se copiara a si mismo el codigo
%define PART_TABLE 446 ;localizacion de la tabla de particion dentro de este codigo
%define PENTRYSIZE 16 ; tamaoñ de una entrada de la tabla de particion
%define MAGIC 510 ; donde se encuentra AA55
global begtext , begdata , begbss, endtext , enddata , endbss , _main
[org 0x7C00:0000 ]
jmp start
msg db 'Cargando el Sistema .............................',0
.data
begdata:
.bss
begbss:
.text
begtext:
_main:
start:
mov ax,cs
mov ds,ax
mov es,ax
mov si , msg
imprime:
lodsb
cmp al,0
je rellena
mov ah,0Eh
mov bx,7
int 10h
jmp imprime
rellena:
mov ax,1000h
mov es, ax
xor bx,bx
mov ah,2
mov al,1 ; lee 1 sector
mov ch,0 ; cilindro 0
mov cl,2 ; sector 2
mov dh , 0 ; cabeza 0
mov dl , 0 ; drive = 0
int 0x13
jc rellena ; si hay error repite
lgdt [gdt_desc]
jmp PmodeStart
PmodeStart:
jmp 1000h:0000
times 510-($-$$) db 0 ; repetir 0 510-(diferencia_en_bytes_inicio - actual )
dw 0AA55h ; ultimos 2 bytes para completar 512
Este es la segunda parte del bootloader, pero no se puede copiar a memoria
junto con la primera por que int 19h solo copia 512 bytes, esta
copiada inmediatamente en el segundo sector y es ejecutada mediante
al primera parte ( es por eso que grub tiene stage1 y stage2).
;archivo hello.s
mov ah, 9
mov al, '='
mov cx , 10
mov bh, 0 ; pagina de video 0
mov bl , 0xf ; blanco
int 0x10
jmp $ ; salto aqui mismo formando un bucleº
kb@cobalt:/mnt/hda7/labs/src/osdev/miniboot/miniboot$ ls
boot.bin hello.s mboot.s boot.s
kb@cobalt:/mnt/hda7/labs/src/osdev/miniboot/miniboot$ cat boot.bin | od -x
0000000 37ea c000 4307 7261 6167 646e 206f 6c65
0000020 5320 7369 6574 616d 2e20 2e2e 2e2e 2e2e
0000040 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e
0000060 2e2e 2e2e 2e2e 8c00 8ec8 8ed8 bec0 0005
0000100 3cac 7400 b409 bb0e 0007 10cd f2eb 00b8
0000120 8e10 31c0 b4db b002 b501 b100 b602 b200
0000140 cd00 7213 eae9 0000 1000 0000 0000 0000
0000160 0000 0000 0000 0000 0000 0000 0000 0000
*
0000760 0000 0000 0000 0000 0000 0000 0000 aa55
0001000 09b4 3db0 0ab9 b700 b300 cd0f eb10 00fe
0001017
Contenido de boot.s
kb@cobalt:/mnt/hda7/labs/src/osdev/miniboot/miniboot$ cat boot.s
%include mboot.s
%include hello.s
kb@cobalt:/mnt/hda7/labs/src/osdev/miniboot/miniboot$ nasm boot.s -o bootloader.raw
kb@cobalt:/mnt/hda7/labs/src/osdev/miniboot/miniboot$ cat boot.bin2 | od -x
0000000 37ea c000 4307 7261 6167 646e 206f 6c65
0000020 5320 7369 6574 616d 2e20 2e2e 2e2e 2e2e
0000040 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e 2e2e
0000060 2e2e 2e2e 2e2e 8c00 8ec8 8ed8 bec0 0005
0000100 3cac 7400 b409 bb0e 0007 10cd f2eb 00b8
0000120 8e10 31c0 b4db b002 b501 b100 b602 b200
0000140 cd00 7213 eae9 0000 1000 0000 0000 0000
0000160 0000 0000 0000 0000 0000 0000 0000 0000
*
0000760 0000 0000 0000 0000 0000 0000 0000 aa55<--marca que limita los 512 bytes y fin de mboot.s
0001000 09b4 3db0 0ab9 b700 b300 cd0f eb10 00fe<--codigo extra empieza en segundo sector
0001017 |
|------inicio del codigo de archivo hello.s
Obviamente faltan muchas cosas que explicar pero ya puse algo de código asi que pueden guiarse. Por favor si tienes algun comentario hazlo y mandame un mail siempre es grato comunicarse con alguien interesado en lo mismo que a uno.