Una introducción a los procesos de arranque e inicio de Linux

Entender los procesos de arranque e inicio de Linux es importante tanto para poder configurar Linux como para resolver problemas de inicio. Este artículo presenta una visión general de la secuencia de arranque utilizando el gestor de arranque GRUB2 y la secuencia de arranque tal y como la realiza el sistema de inicialización systemd.

En realidad, hay dos secuencias de eventos que se requieren para arrancar un ordenador Linux y hacerlo utilizable: el arranque y el inicio. La secuencia de arranque comienza cuando se enciende el ordenador, y se completa cuando se inicializa el kernel y se lanza systemd. El proceso de arranque toma entonces el relevo y finaliza la tarea de poner el ordenador Linux en estado operativo.

En general, el proceso de arranque e inicio de Linux es bastante sencillo de entender. Se compone de los siguientes pasos que se describirán con más detalle en las siguientes secciones.

  • POSICIÓN DE LA BIOS
  • Cargador de arranque (GRUB2)
  • Inicialización del núcleo
  • Iniciar systemd, el padre de todos los procesos.
  • Note que este artículo cubre GRUB2 y systemd porque son el cargador de arranque y el software de inicialización actuales para la mayoría de las distribuciones principales. Otras opciones de software se han utilizado históricamente y todavía se encuentran en algunas distribuciones.

    El proceso de arranque

    El proceso de arranque puede iniciarse en una de un par de maneras. En primer lugar, si la alimentación está apagada, al encenderla se iniciará el proceso de arranque. Si el ordenador ya está ejecutando un usuario local, incluyendo root o un usuario sin privilegios, el usuario puede iniciar la secuencia de arranque de forma programada utilizando la GUI o la línea de comandos para iniciar un reinicio. Un reinicio hará primero un apagado y luego reiniciará el ordenador.

    POSICIÓN DE LA BIOS

    El primer paso del proceso de arranque de Linux realmente no tiene nada que ver con Linux. Es la parte de hardware del proceso de arranque y es el mismo para cualquier sistema operativo. Cuando el ordenador se enciende por primera vez, se ejecuta el POST (Power On Self Test) que es parte de la BIOS (Basic I/O System).

    Cuando IBM diseñó el primer PC en 1981, la BIOS fue diseñada para inicializar los componentes de hardware. La POST es la parte de la BIOS cuya tarea es garantizar que el hardware del ordenador funcione correctamente. Si la POST falla, el ordenador puede no ser utilizable y, por tanto, el proceso de arranque no continúa.

    La POST de la BIOS comprueba la operatividad básica del hardware y luego emite una interrupción de la BIOS, INT 13H, que localiza los sectores de arranque en cualquier dispositivo de arranque conectado. El primer sector de arranque que encuentra que contiene un registro de arranque válido se carga en la RAM y el control se transfiere al código que se cargó desde el sector de arranque.

    El sector de arranque es realmente la primera etapa del cargador de arranque. Hay tres cargadores de arranque utilizados por la mayoría de las distribuciones de Linux, GRUB, GRUB2 y LILO. GRUB2 es el más nuevo y se utiliza con mucha más frecuencia en estos días que las otras opciones más antiguas.

    GRUB2

    GRUB2 significa «GRand Unified Bootloader, version 2» y es ahora el cargador de arranque principal para la mayoría de las distribuciones de Linux actuales. GRUB2 es el programa que hace que el ordenador sea lo suficientemente inteligente como para encontrar el núcleo del sistema operativo y cargarlo en la memoria. Debido a que es más fácil escribir y decir GRUB que GRUB2, puedo utilizar el término GRUB en este documento pero me referiré a GRUB2 a menos que se especifique lo contrario.

    GRUB ha sido diseñado para ser compatible con la especificación multiboot que permite a GRUB arrancar muchas versiones de Linux y otros sistemas operativos libres; también puede cargar en cadena el registro de arranque de sistemas operativos propietarios.

    GRUB también puede permitir al usuario elegir arrancar entre varios núcleos diferentes para cualquier distribución de Linux. Esto permite la capacidad de arrancar a una versión anterior del kernel si uno actualizado falla de alguna manera o es incompatible con una pieza importante de software. GRUB puede ser configurado usando el archivo /boot/grub/grub.conf.

    GRUB1 se considera ahora un legado y ha sido reemplazado en la mayoría de las distribuciones modernas con GRUB2, que es una reescritura de GRUB1. Las distros basadas en Red Hat se actualizaron a GRUB2 alrededor de Fedora 15 y CentOS/RHEL 7. GRUB2 proporciona la misma funcionalidad de arranque que GRUB1, pero GRUB2 es también un entorno de pre-arranque basado en comandos como el de mainframe y permite más flexibilidad durante la fase de pre-arranque. GRUB2 se configura con /boot/grub2/grub.cfg.

    La función principal de cualquiera de los dos GRUB es conseguir que el kernel de Linux se cargue en memoria y se ejecute. Ambas versiones de GRUB funcionan esencialmente de la misma manera y tienen las mismas tres etapas, pero usaré GRUB2 para esta discusión de cómo GRUB hace su trabajo. La configuración de GRUB o GRUB2 y el uso de los comandos de GRUB2 está fuera del alcance de este artículo.

    Aunque GRUB2 no utiliza oficialmente la notación de etapas para las tres etapas de GRUB2, es conveniente referirse a ellas de esa manera, así que lo haré en este artículo.

    Etapa 1

    Como se mencionó en la sección de POST de la BIOS, al final de la POST, la BIOS busca en los discos conectados un registro de arranque, normalmente localizado en el Master Boot Record (MBR), carga el primero que encuentra en la memoria y entonces comienza la ejecución del registro de arranque. El código de arranque, es decir, la etapa 1 de GRUB2, es muy pequeño porque debe caber en el primer sector de 512 bytes del disco duro junto con la tabla de particiones. La cantidad total de espacio asignado para el código de arranque real en un MBR genérico clásico es de 446 bytes. El archivo de 446 bytes para la etapa 1 se llama boot.img y no contiene la tabla de particiones, que se añade al registro de arranque por separado.

    Debido a que el registro de arranque debe ser tan pequeño, tampoco es muy inteligente y no entiende las estructuras del sistema de archivos. Por lo tanto, el único propósito de la etapa 1 es localizar y cargar la etapa 1.5. Para lograr esto, la etapa 1.5 de GRUB debe estar localizada en el espacio entre el propio registro de arranque y la primera partición de la unidad. Después de cargar la etapa 1.5 de GRUB en la RAM, la etapa 1 pasa el control a la etapa 1.5.

    Etapa 1.5

    Como se mencionó anteriormente, la etapa 1.5 de GRUB debe estar ubicada en el espacio entre el propio registro de arranque y la primera partición de la unidad de disco. Este espacio se dejó sin usar históricamente por razones técnicas. La primera partición del disco duro comienza en el sector 63 y con el MBR en el sector 0, eso deja 62 sectores de 512 bytes -31.744 bytes- en los que almacenar el archivo core.img que es la etapa 1.5 de GRUB. El archivo core.img es de 25.389 Bytes por lo que hay mucho espacio disponible entre el MBR y la primera partición del disco en la que almacenarlo.

    Debido a la mayor cantidad de código que se puede acomodar para la etapa 1.5, puede tener suficiente código para contener algunos controladores de sistemas de archivos comunes, como el estándar EXT y otros sistemas de archivos de Linux, FAT y NTFS. El core.img de GRUB2 es mucho más complejo y capaz que la antigua etapa 1.5 de GRUB1. Esto significa que la etapa 2 de GRUB2 puede ubicarse en un sistema de archivos EXT estándar pero no puede ubicarse en un volumen lógico. Así que la ubicación estándar para los archivos de la etapa 2 es en el sistema de archivos /boot, específicamente /boot/grub2.

    Note que el directorio /boot debe estar ubicado en un sistema de archivos que sea soportado por GRUB. No todos los sistemas de archivos lo son. La función de la etapa 1.5 es comenzar la ejecución con los controladores del sistema de archivos necesarios para localizar los archivos de la etapa 2 en el sistema de archivos /boot y cargar los controladores necesarios.

    Etapa 2

    Todos los archivos de la etapa 2 de GRUB se encuentran en el directorio /boot/grub2 y varios subdirectorios. GRUB2 no tiene un archivo de imagen como las etapas 1 y 2. En su lugar, consiste principalmente en módulos del kernel en tiempo de ejecución que se cargan según sea necesario desde el directorio /boot/grub2/i386-pc.

    La función de la etapa 2 de GRUB2 es localizar y cargar un kernel de Linux en la memoria RAM y entregar el control del ordenador al kernel. El kernel y sus archivos asociados se encuentran en el directorio /boot. Los archivos del kernel son identificables ya que todos tienen un nombre que comienza con vmlinuz. Puede listar el contenido del directorio /boot para ver los kernels actualmente instalados en su sistema.

    GRUB2, como GRUB1, soporta el arranque desde una selección de kernels de Linux. El gestor de paquetes de Red Hat, DNF, soporta mantener múltiples versiones del kernel de forma que si ocurre un problema con el más reciente, se puede arrancar una versión más antigua del kernel. Por defecto, GRUB proporciona un menú de prearranque de los kernels instalados, incluyendo una opción de rescate y, si se configura, una opción de recuperación.

    La etapa 2 de GRUB2 carga el kernel seleccionado en la memoria y entrega el control del ordenador al kernel.

    Kernel

    Todos los kernels están en un formato autoextraíble y comprimido para ahorrar espacio. Los kernels se encuentran en el directorio /boot, junto con una imagen de disco RAM inicial, y mapas de dispositivos de los discos duros.

    Después de que el kernel seleccionado se cargue en la memoria y comience a ejecutarse, primero debe extraerse a sí mismo de la versión comprimida del archivo antes de que pueda realizar cualquier trabajo útil. Una vez que el kernel se ha extraído a sí mismo, carga systemd, que es el sustituto del antiguo programa de inicio SysV, y le entrega el control.

    Este es el final del proceso de arranque. En este punto, el kernel de Linux y systemd se están ejecutando pero no pueden realizar ninguna tarea productiva para el usuario final porque no se está ejecutando nada más.

    El proceso de arranque

    El proceso de arranque sigue al proceso de arranque y lleva al ordenador Linux a un estado operativo en el que es utilizable para el trabajo productivo.

    systemd

    systemd es la madre de todos los procesos y es responsable de llevar el host de Linux a un estado en el que se puede realizar el trabajo productivo. Algunas de sus funciones, que son mucho más extensas que las del antiguo programa init, consisten en gestionar muchos aspectos de un host Linux en funcionamiento, incluyendo el montaje de sistemas de archivos, y el inicio y gestión de los servicios del sistema necesarios para tener un host Linux productivo. Cualquier tarea de systemd que no esté relacionada con la secuencia de arranque está fuera del alcance de este artículo.

    En primer lugar, systemd monta los sistemas de archivos como se definen en /etc/fstab, incluyendo cualquier archivo o partición de intercambio. En este punto, puede acceder a los archivos de configuración ubicados en /etc, incluyendo el suyo propio. Utiliza su archivo de configuración, /etc/systemd/system/default.target, para determinar el estado u objetivo en el que debe arrancar el host. El archivo default.target es sólo un enlace simbólico al verdadero archivo target. Para una estación de trabajo de escritorio, normalmente será el graphical.target, que es equivalente al nivel de ejecución 5 en el antiguo SystemV init. Para un servidor, es más probable que sea el multiuser.target, que es como el nivel de ejecución 3 en SystemV. El target.emergency es similar al modo de usuario único.

    Note que los targets y los servicios son unidades de systemd.

    La tabla 1, a continuación, es una comparación de los targets de systemd con los antiguos niveles de ejecución de arranque de SystemV. Los alias de objetivos de systemd son proporcionados por systemd para la compatibilidad con versiones anteriores. Los alias de destino permiten a los scripts -y a muchos administradores de sistemas como yo- utilizar comandos de SystemV como init 3 para cambiar los niveles de ejecución. Of course, the SystemV commands are forwarded to systemd for interpretation and execution.

    SystemV Runlevel systemd target systemd target aliases Description
    halt.target Halts the system without powering it down.
    0 poweroff.target runlevel0.target Halts the system and turns the power off.
    S emergency.target Single user mode. No services are running; filesystems are not mounted. This is the most basic level of operation with only an emergency shell running on the main console for the user to interact with the system.
    1 rescue.target runlevel1.target A base system including mounting the filesystems with only the most basic services running and a rescue shell on the main console.
    2 runlevel2.target Multiuser, without NFS but all other non-GUI services running.
    3 multi-user.target runlevel3.target All services running but command line interface (CLI) only.
    4 runlevel4.target Unused.
    5 graphical.target runlevel5.target multi-user with a GUI.
    6 reboot.target runlevel6.target Reboot
    default.target This target is always aliased with a symbolic link to either multi-user.target or graphical.target. systemd always uses the default.target to start the system. El default.target nunca debe tener el alias de halt.target, poweroff.target o reboot.target.

    Tabla 1: Comparación de los niveles de ejecución de SystemV con los objetivos de systemd y algunos alias de objetivos.

    Cada objetivo tiene un conjunto de dependencias descritas en su archivo de configuración. systemd inicia las dependencias necesarias. Estas dependencias son los servicios necesarios para ejecutar el host Linux en un nivel específico de funcionalidad. Cuando todas las dependencias enumeradas en los archivos de configuración del objetivo se cargan y ejecutan, el sistema se ejecuta en ese nivel de objetivo.

    systemd también busca en los directorios de init de SystemV heredados para ver si existe algún archivo de inicio allí. Si es así, systemd utiliza esos como archivos de configuración para iniciar los servicios descritos por los archivos. El servicio de red obsoleto es un buen ejemplo de uno de los que todavía utilizan los archivos de inicio de SystemV en Fedora.

    La Figura 1, a continuación, está copiada directamente de la página man de bootup. Muestra la secuencia general de eventos durante el arranque de systemd y los requisitos básicos de ordenación para asegurar un arranque exitoso.

    Los objetivos sysinit.target y basic.target pueden considerarse como puntos de control en el proceso de arranque. Aunque systemd tiene como uno de sus objetivos de diseño iniciar los servicios del sistema en paralelo, todavía hay ciertos servicios y objetivos funcionales que deben iniciarse antes de que otros servicios y objetivos puedan iniciarse. Estos puntos de control no pueden pasarse hasta que se cumplan todos los servicios y objetivos requeridos por ese punto de control.

    Así que el objetivo sysinit.target se alcanza cuando se completan todas las unidades de las que depende. Todas esas unidades, el montaje de sistemas de archivos, la configuración de los archivos de intercambio, el inicio de udev, la configuración de la semilla del generador aleatorio, el inicio de los servicios de bajo nivel y la configuración de los servicios criptográficos si uno o más sistemas de archivos están encriptados, deben completarse, pero dentro del sysinit.target esas tareas pueden realizarse en paralelo.

    El sysinit.inicia todos los servicios de bajo nivel y las unidades necesarias para que el sistema sea marginalmente funcional y que se requieren para permitir pasar al basic.target.

local-fs-pre.target
|
v
(various mounts and (various swap (various cryptsetup
fsck services...) devices...) devices...) (various low-level (various low-level
| | | services: udevd, API VFS mounts:
v v v tmpfiles, random mqueue, configfs,
local-fs.target swap.target cryptsetup.target seed, sysctl, ...) debugfs, ...)
| | | | |
\__________________|_________________ | ___________________|____________________/
\|/
v
sysinit.target
|
____________________________________/|\________________________________________
/ | | | \
| | | | |
v v | v v
(various (various | (various rescue.service
timers...) paths...) | sockets...) |
| | | | v
v v | v rescue.target
timers.target paths.target | sockets.target
| | | |
v \_________________ | ___________________/
\|/
v
basic.target
|
____________________________________/| emergency.service
/ | | |
| | | v
v v v emergency.target
display- (various system (various system
manager.service services services)
| required for |
| graphical UIs) v
| | multi-user.target
| | |
\_________________ | _________________/
\|/
v
graphical.target

Figura 1: El mapa de inicio de systemd.

Después de que se cumpla el sysinit.target, systemd inicia el basic.target, iniciando todas las unidades necesarias para cumplirlo. El objetivo básico proporciona alguna funcionalidad adicional al iniciar unidades que son necesarias para el siguiente objetivo. Esto incluye la configuración de cosas como rutas a varios directorios ejecutables, sockets de comunicación y temporizadores.

Por último, los objetivos a nivel de usuario, multiuser.target o graphical.target pueden ser inicializados. Observe que el objetivo multiusuario debe ser alcanzado antes de que las dependencias del objetivo gráfico puedan ser satisfechas.

Los objetivos subrayados en la Figura 1, son los objetivos de inicio habituales. Cuando se alcanza uno de estos objetivos, entonces el arranque se ha completado. Si el objetivo multiusuario es el predeterminado, entonces debería ver un inicio de sesión en modo texto en la consola. Si graphical.target es el predeterminado, entonces debería ver un inicio de sesión gráfico; la pantalla de inicio de sesión GUI específica que vea dependerá del gestor de pantalla predeterminado que utilice.

Cuestiones

Recientemente tuve la necesidad de cambiar el kernel de arranque predeterminado en un equipo Linux que utilizaba GRUB2. Me encontré con que algunos de los comandos no parecían funcionar correctamente para mí, o que no los estaba utilizando correctamente. Todavía no estoy seguro de cuál era el caso, y necesito investigar un poco más.

El comando grub2-set-default no estableció correctamente el índice del kernel por defecto para mí en el archivo /etc/default/grub por lo que el kernel alternativo deseado no arrancó. Así que cambié manualmente /etc/default/grub GRUB_DEFAULT=saved a GRUB_DEFAULT=2 donde 2 es el índice del kernel instalado que quería arrancar. Luego ejecuté el comando grub2-mkconfig > /boot/grub2/grub.cfg para crear el nuevo archivo de configuración de grub. Esta elusión funcionó como se esperaba y arrancó con el kernel alternativo.

Conclusiones

GRUB2 y el sistema de init systemd son los componentes clave en las fases de arranque e inicio de la mayoría de las distribuciones modernas de Linux. A pesar de que ha habido controversia en torno a systemd especialmente, estos dos componentes trabajan juntos sin problemas para cargar primero el kernel y luego para iniciar todos los servicios del sistema necesarios para producir un sistema Linux funcional.

Aunque encuentro tanto GRUB2 como systemd más complejos que sus predecesores, también son igual de fáciles de aprender y manejar. Las páginas man tienen una gran cantidad de información sobre systemd, y freedesktop.org tiene el conjunto completo de páginas man de systemd en línea. Consulte los recursos, a continuación, para obtener más enlaces.