Bootloader de juguete

From Movaxes

(Difference between revisions)
('''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)
-
mov al,0 ;pagina 0 del display
 
-
mov bl,0x07 ;atributos (blanco sobre negro)
 
int 0x10 ;invocamos al BIOS
int 0x10 ;invocamos al BIOS
jmp puts ;siguiente caracter
jmp puts ;siguiente caracter
Line 193: Line 192:
%ENDMACRO
%ENDMACRO
-
;----------------;
 
-
[BITS 16]
 
-
[ORG 0x7c00]
 
;----------------;
;----------------;
;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)

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



Personal tools