Secuencia de arranque de un núcleo Linux

Publicado por Diego Córdoba en

En este artículo aprenderemos la secuencia de arranque completa de un sistema operativo GNU/Linux desde que presionamos el botón de encendido de la computadora, hasta que completa la carga del núcleo Linux y comienzan a levantarse los procesos de usuario.

A modo de auto-documentación para grabar algunas clases de mi curso de sysadmin GNU/Linux (LPIC-1) surgió este artículo, espero lo disfruten!

Una computadora es un conjunto de muchos componentes electrónicos que trabajan juntos, pero no todos conocen cómo es que estos elementos interactúan entre si.

Aquí aprenderemos la secuencia de arranque de un sistema operativo libre y de código abierto, GNU/Linux, lo que nos va a remitir también a conocer y entender algunos de los componentes de la computadora, y su función.

Entender el proceso de arranque nos permite entender también mucho del hardware de la computadora, y cómo interactúa con el software, y además nos brindará conocimientos para depurar el inicio del sistema y permitirnos solucionar cualquier problema relacionado.

La secuencia de arranque de Linux puede dividirse en varias etapas:

  1. La fuente de energía de la computadora envía un OK al timer de la placa madre.
  2. «Bootstrap» y el proceso de arranque del hardware.
  3. El BIOS y el proceso de inicio.
  4. El MBR (Master Boot Record) y el GRUB.
  5. Carga de la imagen del kernel Linux (initrd)
  6. Carga de los servicios de inicio (SysVinit, systemd, upstart, etc.)

A continuación iré explicando cada uno de estos pasos en detalle, exceptuando el último que lo dejo para mi siguiente artículo.

1. Suministro eléctrico

Uno de los componentes principales de la computadora es la fuente de energía, y su principal objetivo es el de proveer el nivel de voltaje necesario a la placa madre y demás componentes. Este voltaje trabaja con corriente contínua (DC), por lo que la fuente también transforma la corriente alterna domiciliaria (AC) en corriente continua.

Más allá de esto, la fuente informa sobre un buen suministro eléctrico a la computadora enviando una señal acorde, POWER GOOD, a la placa madre. Si la placa madre no recibe dicha señal de la fuente todo el tiempo, a su vez enviará una señal de reset al procesador y no podrá iniciar.

2. Bootstrap y secuencia de arranque

El bootstrap consiste en que el procesador busque en una ROM (Read Only Memory) de la placa madre las instrucciones para arrancar. Estas direcciones de memoria en la que se encuentran las instrucciones son por lo general 0xFFFF:0000 en procesadores x86.

Estas instrucciones contienen un JUMP o salto a otra dirección de memoria, la del programa BIOS (Basic Input/Output System) de la placa madre.

3. BIOS

Aquí comienza realmente el proceso de inicio lógico de la computadora. Una de las primeras tareas que lleva a cabo el BIOS es denominada POST (Power on Self Test). El POST realiza una serie de verificaciones dirigidas por la BIOS que permiten determinar el estado del hardware y con él, saber si la computadora puede iniciar o no.

El POST es muy importante en la secuencia de arranque, y es un paso previo a la carga del sistema operativo, ya que verifica, entre otras cosas, la placa madre, el teclado, puertos de periféricos como el teclado, los discos, la integridad de la memoria, la CPU, la ROM de video, etc.

En general hay dos tipos de inicio de la computadora, Warm Start y Cold Start. El Cold Start ejecuta el POST conducido por el BIOS cuando inicia la computadora desde su estado apagado, mientras que el Warm Start no ejecuta el post, y se da cuando iniciamos la computadora presionando el botón de Reset del gabinete.

Una confusión generalizada en pensar que el BIOS y el CMOS son la misma cosa. El BIOS, como dijimos, es un componente de software almacenado en una memoria ROM. El CMOS por su parte es una pequeña memoria RAM (Random Access Memory) alojada en la placa madre. Esta memoria almacena las configuraciones que efectuemos en el programa BIOS.

No confundir tampoco esta RAM CMOS con la memoria RAM principal de la computadora.

RAM CMOS y la persistencia

Recordemos que una memoria ROM es persistente y no puede modificarse directamente, por lo que NO podemos modificar el BIOS, mientras que la RAM es volátil, puede modificarse, pero su contenido se pierde al perder energía eléctrica. El contenido del CMOS en general se mantiene gracias una batería que se encuentra en la placa madre (¿quién no habrá sacado esa pila de la placa para resetear las configuraciones del BIOS? 🙂)

Al quitar la pila que mantiene el CMOS se perderá información como la fecha y hora configuradas en la BIOS, o la password de acceso a la misma.

Dispositivos de arranque

Volviendo a la secuencia de arranque, entre las configuraciones almacenadas en el CMOS se encuentra el orden de inicio de los dispositivos de almacenamiento donde se buscará un sistema operativo al finalizar la carga del BIOS. Estos dispositivos son, por lo general:

  • CD / DVD ROM
  • Disco Rígido / SSD
  • Dispositivos USB
  • Disquettes / Floppy

Según el orden en el que lo hayamos configurado en el CMOS, al iniciar buscará en uno u otro dispositivo hasta encontrar uno que disponga un sistema operativo instalado utilizable.

4. MBR y el gestor de arranque (GRUB)

Si estamos iniciando desde un disco rígido o SSD, o USB por ejemplo, el BIOS buscará en el dispositivo, en una región de memoria denominada Boot Sector, o sector de inicio, las siguientes instrucciones a ejecutar, correspondientes al gestor de arranque del sistema operativo. De ahí en adelante ya es el sistema operativo instalado el que se encarga de continuar la secuencia de arranque.

Ese área del disco en que se encuentra el Boot Sector es el primer sector del disco, y suele denominárselo Master Boot Record, o MBR. Ese sector corresponde con solo 512 bytes y permiten iniciar la primer etapa del boot loader, o el gestor de arranque, como Grub o el viejo Lilo. De esos 512B, solo 440B se utilizan para el cargador de arranque, el resto almacena la tabla de particiones del disco.

Dicho sea de paso, podemos guardar en un archivo binario todo el MBR con un simple comando en una terminal GNU/Linux: dd. Este comando permitirá copiar un bloque de 512B del disco en un archivo que llamaremos mbr.img.

sudo dd if=/dev/sda of=/tmp/mbr.img bs=512 count=1

Podemos analizar el contenido de dicho sector de arranque con fdisk de esta forma:

cpio sysv sysvinit upstart systemd secuencia de arranque linux gnu kernel nucleo

Aquí yo tengo tres particiones, una para el swap, otra de tipo Linux (ahí tengo un sistema de archivos ext4) y una última extendida. Cabe aclarar que tengo dos discos en mi computadora, este es el MBR del disco en el que tengo Linux instalado y funcional. El asterisco en la segunda columna indica qué partición está activa para el inicio, en la que se encuentra el sistema instalado.

GRUB – GRand Unified Bootloader

El primer sector del disco, el sector 0 mencionado anteriormente, contiene lo que se denomina Stage 1, la primera etapa del cargador de arranque. El cargador de arranque GRUB tiene en total tres etapas o «stages», a saber:

  • GRUB Stage 1
  • GRUB Stage 1.5
  • GRUB Stage 2

Normalmente las particiones no comienzan antes del sector 63 del disco, por lo que los sectores 1-63 están vacíos (recordemos que el sector 0 contiene el MBR). Este espacio es utilizado para almacenar lo que se denomina Stage 1.5. A este espacio también se lo denomina MBR GAP.

Y la pregunta es: ¿por qué es necesaria una supuesta Stage 1.5 en GRUB?

Quienes trabajamos en GNU/Linux sabemos que la configuración del GRUB se encuentra en un archivo llamado (generalmente) /boot/grub/grub.cfg… pero este archivo está en el disco, en una partición (que puede ser una partición aislada para /boot, o la misma partición donde tenemos el sistema operativo instalado.

¿Cómo puede el GRUB acceder a dicho archivo si no se ha montado la partición, ni dispone de los drivers o controladores? Puede porque estos controladores de sistema de archivos se encuentran en estos sectores, del 1 al 63.

Aquí es cuando el GRUB carga dicha configuración y nos muestra un menú en terminal donde podemos elegir qué sistema operativo iniciar. Esto corresponde con el Stage 2 del GRUB.

5. Cargando la imagen del kernel Linux

Una vez que elegimos un sistema operativo GNU/Linux para iniciar, el GRUB le pasa el control del arranque al sistema operativo mediante la carga de una imagen comprimida del núcleo del mismo.

De manera similar al GRUB, el kernel Linux también se carga en etapas o Stages. El kernel cabe aclarar que es quien administra la planificación de procesos, memoria, sistemas de archivos, dispositivos periféricos de E/S, mecanismos de comunicación entre procesos (IPC), e interfaces de red, entre otros.

El kernel nunca es utilizado por los usuarios, sino que representa una capa de abstracción entre el resto del sistema operativo y el hardware, monta un entorno en el que puede correr todo el resto del sistema.

El kernel es un archivo comprimido de imagen que generalmente se encuentra dentro del directorio /boot, ubicación que está configurada en el archivo de configuración del GRUB2. Básicamente es un archivo de imagen bzImage ejecutable. Su nombre característico contiene la palabra «vmlinuz«:

cpio sysv sysvinit upstart systemd secuencia de arranque linux gnu kernel nucleo

initrd e initramfs

Ahora bien, para poder cargar el sistema operativo primero debemos cargar muchos controladores de diversos dispositivos de hardware. Por ejemplo, podríamos tener el disco configurado en RAID o LVM donde tenemos la partición raíz («/»), o podríamos disponer de varios módulos del núcleo que realicen diferentes tareas. Si toda la funcionalidad estuviera presente en el mismo kernel Linux, la imagen comprimida sería enorme!

No obstante, la imagen del núcleo necesita ser más pequeña, y por eso, entre otras cosas, se encuentra comprimida. Las funcionalidades adicionales no están presentes en dicha imagen, sino que son cargadas mediante un sistema de archivos similar al sistema raíz provisto por initrd, por lo que muchas veces a initrd se lo denomina un «sistema de archivos raíz inicial«.

Initrd es utilizado por el kernel antes de que se monte el sistema raíz «/» real. En general esta imagen de un sistema de archivos de inicio suele llamarse «initramfs» dentro del directorio /boot.

cpio sysv sysvinit upstart systemd secuencia de arranque linux gnu kernel nucleo

Desempaquetando initramfs

Por si no me creen, les voy a mostrar cómo ver el contenido de este archivo. Es un archivo comprimido en formato gzip, podemos verlo si corremos el comando file sobre dicho archivo. En mi caso, como voy a modificarlo, lo he copiado dentro del directorio /tmp para poder trabajar tranquilo sin correr riesgos:

diego@cryptos:~$ mkdir /tmp/initrd
diego@cryptos:~$ cp /boot/initramfs-linux.img /tmp/initrd/
diego@cryptos:~$ cd /tmp/initrd/
diego@cryptos:initrd$ ls
initramfs-linux.img
diego@cryptos:initrd$ file initramfs-linux.img 
initramfs-linux.img: gzip compressed data, from Unix, original size modulo 2^32 32542720
diego@cryptos:initrd$ 

Sabiendo que es gzip, vamos a renombrarlo para que tenga extensión .gz y poder descomprimirlo. Ahí veremos que el archivo ahora pasa a ser de tipo ASCII cpio:

diego@cryptos:initrd$ mv initramfs-linux.img initramfs-linux.img.gz
diego@cryptos:initrd$ ls
initramfs-linux.img.gz
diego@cryptos:initrd$ gunzip initramfs-linux.img.gz 
diego@cryptos:initrd$ ls
initramfs-linux.img
diego@cryptos:initrd$ file initramfs-linux.img 
initramfs-linux.img: ASCII cpio archive (SVR4 with no CRC)
diego@cryptos:initrd$ 

Nos queda utilizar la herramienta cpio para desempaquetarlo. Este comando debemos instalarlo previamente, en general el paquete se llama «cpio» en la mayoría de las distros (yo uso Arch Linux en este momento, y lo instalé con sudo pacman -S cpio):

diego@cryptos:initrd$ cpio -id < initramfs-linux.img 
63558 blocks
diego@cryptos:initrd$ ls
bin          dev    init                 lib       proc  sys  var
buildconfig  etc    init_functions       lib64     run   tmp  VERSION
config       hooks  initramfs-linux.img  new_root  sbin  usr

Aquí la captura de mi terminal con todo el proceso:

Como se ve, este archivo initrd contiene directorios propios del sistema de archivos raíz, como /dev, /etc, /lib, /proc, /sys, etc… todo un sistema de archivos raíz… de inicio.

Seguimos con el inicio de Linux

Una vez que se carga este «mini linux» en memoria RAM (de ahí initramfs), se procede a la verificación de hardware y controladores. Se comienza con la verificación de la arquitectura del procesador.

El kernel dirige una gran cantidad de instrucciones de hardware, y luego carga el primer proceso del sistema operativo, el proceso init, cuyo PID (Process ID) es el 1:

cpio sysv sysvinit upstart systemd secuencia de arranque linux gnu kernel nucleo

Este PID 1 no es intencional, el núcleo le da a cada proceso nuevo que se lanza un identificador incremental. En el caso de init es «1» porque es el primer proceso que se ejecuta en espacio de usuario. El proceso init se mantiene corriendo durante toda la ejecución del sistema operativo hasta que se apaga la computadora.

Luego de cargar los módulos necesarios para «levantar» los dispositivos de hardware del ordenador, comienza la carga «real» del sistema operativo: el sistema de inicio y gestor de servicios y eventos.

Aquí disponemos de varias alternativas, entre las más conocidas: SysV init, systemd, o upstart. Estos gestores se encargan de terminar el proceso de inicio y de gestionar todos los procesos de usuario.

Cada uno tiene características distintivas, y aunque hoy en día systemd es el más común (no sin controversias), existen distribuciones GNU/Linux que utilizan SysV init tales como Devuan.

Por su parte, Upstart fue introducido por primera vez en Ubuntu 6.10, pero cuando Debian migró a systemd, Ubuntu también lo hizo. Algo similar pasó con Fedora, que utilizaba upstart en su v9 para reemplazar a SysV. No obstante, Fedora 15 reemplazó a upstart por systemd también.

¿Cómo sigue la secuencia de arranque?

Dependiendo del gestor de servicios que use la distro será la forma en la que cargará los siguientes procesos. SysV trabaja con una serie de runlevels predefinidos, mientras que systemd utiliza targets con algunas equivalencias con los runlevels de Systemd.

Y como el artículo está quedando muy largo, vamos a cerrar la secuencia de arranque acá y en el siguiente artículo hablaremos específicamente de los gestores de inicio.

Espero les sea de interés! Cualquier duda, como siempre, será bienvenida en la sección de comentarios.

Hasta la próxima!

Continuará… 🙂


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador