Bootloader de juguete
From Movaxes
(→'''2: Hola Mundo!!''') |
(→''2: Hola Mundo (2)'') |
||
Line 167: | Line 167: | ||
; Fecha: 8/2/07 ; | ; Fecha: 8/2/07 ; | ||
;--------------------------; | ;--------------------------; | ||
- | + | [BITS 16] | |
+ | [ORG 0x7c00] | ||
;----------------; | ;----------------; | ||
;MACROS ; | ;MACROS ; | ||
;----------------; | ;----------------; | ||
; puts: ; | ; puts: ; | ||
- | ; 1 = string ; | + | ; 1 = string ; |
;----------------; | ;----------------; | ||
%MACRO puts 1 | %MACRO puts 1 | ||
Line 184: | Line 185: | ||
jz q_puts ;salir de la funcion (q por quit) | jz q_puts ;salir de la funcion (q por quit) | ||
mov ah,0x0e ;para pasar a int 0x10 (bios print) | mov ah,0x0e ;para pasar a int 0x10 (bios print) | ||
- | |||
- | |||
int 0x10 ;invocamos al BIOS | int 0x10 ;invocamos al BIOS | ||
jmp puts ;siguiente caracter | jmp puts ;siguiente caracter | ||
Line 193: | Line 192: | ||
%ENDMACRO | %ENDMACRO | ||
- | |||
- | |||
- | |||
;----------------; | ;----------------; | ||
;MAIN ; | ;MAIN ; |
Revision as of 20:22, 9 February 2007
Contents |
Bootloaders de juguete
Introducción
Primero que nada quiero explicar por qué razón he escrito de juguete, la razón es simplemente que no vamos a desarrollar un bootloader completo (real?). Un bootloader completo pondría todo en su lugar para que el kernel cargara sin problemas, un ejemplo de esto es GRUB que es el que usamos en nuestro siguiente tutorial.
En estos tutoriales voy a mencionar mucho la palabra bootloader así que para ahorrarme las teclas que presiono voy a poner en su lugar BL, ahora ya sabes que si dice BL significa 'bootloader'.
nota: estaré usando NASM como compilador.
JUGUETE??
Estos bootloader no son nada más que una escusa para poder aprender assembler (ensamblador) de manera divertida, jugar con el VGA en modo 0x13 de la tarjeta de video, etc. La verdad es que yo creo que no debería se merecen el nombre de bootloaders pero ni modo, en cierta forma eso es lo que son.
Este es mi laboratorio de ASM en cierta forma, si lo que quieres es ir directo a la creación de un Kernel te recomiendo que leas el tutorial sobre el uso de GRUB como bootloader, eso te hará las cosas más fáciles y te permitirá empezar con el kernel.
Y claro que 'juguetes' no significa que sean lo más fácil del mundo.
Resumen de ¿qué es un bootloader?
Cuando se programa un SO se suele empezar por el bootloader, que es el encargado de alistar la computadora para que el kernel del SO sea cargado. Los discos duros y floppys están divididos en sectores de hasta 512 bytes. Si un disco es bootable el primer sector se llama boot sector, que es donde el bootloader está. Cuando el BIOS encuentra un disco bootable carga los primeros 512 bytes (primer sector) en la dirección física de la memoria de 0x7c00 hasta 0x7dff y usa la instrucción 'jmp' (saltar) para poner el CS:IP (CS= Code Segment, IP = Instruction Pointer) en 0000:7c00 y así pasar el control al bootloader. Cuando se trata de un CD el sector del bootloader no es necesariamente de 512 bytes, pero esto ya es otro tema (quiza para más adelante).
El bootloader se encarga de cargar el kernel (que es el nucleo del SO), algunas de las cosas que hace el bootloader hace son:
- Activar la linea A20 (para acceso total al espacio de memoria)
- Entrar en Modo Protegido (PMode) para direccionamiento de 32 bits en sistemas x86, en lugar del de 16bit del Real Mode
- Instalar el GDT para protección basica de la memoria
- Instalar una tabla de interruptores (IDT)
- Inicializar un stack de 32 bits
- Saltar al area en donde está el kernel y darle el control
Las reglas
Hay ciertos requisitos para que nuestros bootloader de juguete puedan corren en una máquina:
- Código de 16bit, ya que estaremos en Modo Real (Real Mode)
- Deben ser de exactamente 512bytes (sector 0 del floppy)
- Deben tener la firma del bootloader que es: 0xAA55
Eso es todo lo que necesitamos :)
Bootloaders de juguete
1: Loop Infinito
Este es quizá el BL más sencillo del mundo:
boot1.asm:
;--------------------------; ; Juguete 1 ; ; Autor: movaxes ; ; Fecha: 7/2/07 ; ;--------------------------; [BITS 16] ;codigo de 16 bits (direccionamiento) [ORG 0x7c00] ;origen del código jmp $ ;loop infinito times 510-($-$$) db 0 ;lo siguiente indica a NASM que llene el sector con ceros dw 0xAA55 ;la firma del bootloader
Este BL no hace nada más que mantener a nuestro CPU ocupado, no verás nada en pantalla, absolutamente nada. Para terminar solo reinicia tu computadora.
Lo que hace detalladamente es:
- [BITS 16] indica a NASM que vamos a usar código de 16 bits ya que estamos en modo real, el modo en que están todas las computadoras al iniciar.
- [ORG 0x7c00] indica a NASM el origen del código en la memoria luego de ser cargado
- jmp es la instrucción de salto de assembler, indica al programa salte a la instrucción que indica, en este caso $
- $ significa: inicio de esta instrucción lo cual hace que se convierta en un loop infinito
- Times indica a NASM que debe repetir esto n numero de veces (indicado a continuación)
- 510-($-$$) es el calculo que hacemos del numero de veces que vamos a repetir, en este caso calculamos:
- 510 son los bytes totales, menos la firma que son 2 (recuerda que el BL debe ser de 512bytes para llenar el sector 0)
- restamos -($-$$) para ocupar solo los bytes que no están en uso
- $ significa: inicio de esta instrucción
- $$ significa: inicio del programa
- db 0 indica que vamos a llenar de ceros
- db significa: define byte
- dw 0xAA55 es la firma del bootloader
- dw significa: define word (word = 2 bytes)
- 510-($-$$) es el calculo que hacemos del numero de veces que vamos a repetir, en este caso calculamos:
Esa es la explicación más completa que se me ocurre, claro que me faltaría haber explicado que los comentarios empiezan con ;, todo lo que sigue en una linea a ; es un comentario, lo que significa que el compilador (en este caso NASM) no lo lee.
Compilando 1
Para compilar nuestro bootloader numero 1 solo escribe en el terminal:
$nasm -o boot boot1.asm
Revisa que el archivo sea de exactamente 512bytes.
Ahora inserta un floppy en tu drive y escribe este comando en el terminal:
$sudo dd if=boot bs=512 of=/dev/fd0
Listo, ahora debes reiniciar tu computadora con el floppy puesto.
2: Hola Mundo!!
El primer BL no servirá para impresionar a nadie, así que vamos a movernos un poco y vamos a crear el BL Hola Mundo!!.
Para poder escribir en pantalla lo primero que necesitamos es indicarle al BIOS en donde se encuentra nuestro segmento de datos (DS), luego apuntamos SI a nuestra cadena, y por último llamamos a 'puts' (put string) que es nuestra función para imprimir cadenas.
El código de boot2.asm ahora se verá así:
;--------------------------; ; Juguete 2 Hola Mundo ; ; Autor: movaxes ; ; Fecha: 8/2/07 ; ;--------------------------; [BITS 16] [ORG 0x7c00] ;----------------; ;MAIN ; ;----------------; xor ax,ax ;limpiamos ax = 0x0000 mov ds,ax ;ponemos el data segment a 0x0000 mov si,hola ;apuntamos a la cadena call puts ;llamamos a puts para poner la cadena jmp $ ;loop infinito ;----------------; ;VARIABLES ; ;----------------; hola db 'Hola Mundo!!',13,10,0 ;----------------; ;FUNCIONES ; ;----------------; ; puts ; ; si = cadena ; ;----------------; puts: ;siguiente caracter lodsb ;cargamos el siguiente caracter de DS:SI or al,al ;si esto es igual a cero significa que terminamos jz q_puts ;salir de la funcion (q por quit) mov ah,0x0E ;bios print int 0x10 ;invocamos al BIOS jmp puts ;siguiente caracter q_puts: ret ;terminamos ;----------------; times 510-($-$$) db 0 ;llenamos el resto de ceros dw 0xAA55 ;firma del bootloader
Creo que no necesito explicar nada ya que lo hice en los comentarios, lo que si voy a hacer es mostrar otras posibilidades de escribir el mismo BL.
2: Hola Mundo (2)
Usando un MACRO en NASM podemos evitar tener que escribir:
mov si,hola call puts
El nuevo código queda (boot2.asm):
;--------------------------; ; Juguete 2 Hola Mundo (2) ; ; Autor: movaxes ; ; Fecha: 8/2/07 ; ;--------------------------; [BITS 16] [ORG 0x7c00] ;----------------; ;MACROS ; ;----------------; ; puts: ; ; 1 = string ; ;----------------; %MACRO puts 1 mov si,word %1 ;apuntamos a la cadena puts: lodsb ;cargamos el siguiente caracter or al,al ;si esto es igual a cero significa que terminamos jz q_puts ;salir de la funcion (q por quit) mov ah,0x0e ;para pasar a int 0x10 (bios print) int 0x10 ;invocamos al BIOS jmp puts ;siguiente caracter q_puts: %ENDMACRO ;----------------; ;MAIN ; ;----------------; main: xor ax,ax ;limpiamos ax = 0 mov ds,ax ;ponemos el data segment puts hola ;llamamos puts (put string) fin: jmp $ ;nuestro loop infinito ;----------------; ;VARIABLES ; ;----------------; hola db 'Hola Mundo!!!',13,10,0 ;----------------; times 510-($-$$) db 0 ;llenamos de ceros dw 0xAA55 ;firma del bootloader
Ten en cuenta que cada vez que usas un macro se agrega ese código en el lugar de la llamada, lo cual hace que el tamaño de tu ejecutable aumente.
La única desventaja de la versión anterior es que debes recordar apuntar a la cadena con el si.
Compilando Hola Mundo
Para compilar nuestro BL solo debes usar estos dos comandos teniendo tu floppy en el drive.
$nasm -o boot boot2.asm $sudo dd if=boot bs=512 of=/dev/fd0