Quien no ha fantaseado alguna vez en programar su propio SO, esta utopía puede llegar a materializarse con unos conocimientos mínimos sobre ensamblador y C, en este artículo se explicará el proceso de arranque de una computadora y como conseguir arrancar nuestro SO super reducido.
Para realizar todas nuestras pruebas necesitaremos un compilador de ASM y el emulador qemu, utilizaremos qemu y no un sistema de virtualización tipo VirtualBox ya que este último ejecutaría instrucciones directamente en nuestra CPU
a favor de un rendimiento superior pero el entorno puede no ser exactamente igual al de una máquina física, en cambio con un emulador si que conseguimos esto.
Dependiendo del SO instalaremos el software de una manera u otra:
FreeBSD:
Gentoo:
El artículo se basa en el siguiente documento colgado en la web de la universidad de Birmingham 2 .
Antes de nada debemos tener en cuenta que cuando una computadora arranca lo primero que hace es cargar la BIOS del chip integrado en la placa a la RAM, acto seguido realiza un chequeo básico de hardware.
Una vez comprobado el hardware queda determinar desde donde arrancar, la BIOS simplemente lee los primeros 512bytes(boot sector) de todos los discos disponibles en el sistema, si alguno contiene los valores AA 55 en los bytes 511 y 512 considera que se trata de un disco bootable.
Estos primeros 512bytes se denominan boot sector, son las instrucciones que se cargarán en RAM para posteriormente ser ejecutadas por la CPU.
Nosotros vamos a crear un boot sector muy sencillo, simplemente marcaremos los bytes 511 y 512 con AA 55 para que la BIOS lo reconozca como un boot sector válido, rellenaremos 510 bytes de 0s para llegar a los 512 en total y nos
quedaremos ejecutando un bucle infinito.
Recordad que la CPU irá leyendo de la RAM ciegamente lo que hayamos cargado de los primeros 512bytes del disco, si no definiesemos el bucle infinito la CPU seguiría leyendo la RAM y ejecutando instrucciones aleatorias, restos de
la carga de programas anteriores, esto puede ser mas o menos peligroso dependiendo de las instrucciones en cuestión.
; Infinite loop (e9 fd ff)
loop:
jmp loop
; Fill with 510 zeros minus the size of the previous code
times 510-($-$$) db 0
; Magic number
dw 0xaa55
Generamos la imagen:
Podemos ver el contenido con xdd:
00000000: ebfe 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000140: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
Lo cargamos en qemu:
SeaBIOS (version rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org)
iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F91410+07EF1410 C980
Booting from Hard Disk...
Impresionante, hemos sido capaces de cargar nuestro SO desde cero.