El proceso de arranque de Linux implica varias etapas y es en muchos sentidos similar al BSD y otros procesos de arranque de estilo Unix , de los que deriva. Aunque el proceso de arranque de Linux depende mucho de la arquitectura de la computadora, esas arquitecturas comparten etapas y componentes de software similares, [1] incluyendo el inicio del sistema, la ejecución del gestor de arranque , la carga y el inicio de una imagen del núcleo de Linux y la ejecución de varios scripts y daemons de inicio . [2] Estos se agrupan en 4 pasos: inicio del sistema, etapa del gestor de arranque, etapa del núcleo y proceso init. [3] Cuando un sistema Linux se enciende o se reinicia, su procesador ejecutará un firmware/programa específico para la inicialización del sistema, como la autoprueba de encendido , invocando el vector de reinicio para iniciar un programa en una dirección conocida en flash/ROM (en dispositivos Linux integrados), luego carga el gestor de arranque en la RAM para su posterior ejecución. [2] En las computadoras personales (PC) compatibles con IBM PC , este firmware/programa es un monitor BIOS o UEFI , y se almacena en la placa base. [2] En los sistemas Linux integrados, este firmware/programa se llama ROM de arranque . [4] [5] Después de cargarse en la RAM, el cargador de arranque (también llamado cargador de arranque de primera etapa o cargador de arranque primario) se ejecutará para cargar el cargador de arranque de segunda etapa [2] (también llamado cargador de arranque secundario). [6] El cargador de arranque de segunda etapa cargará la imagen del núcleo en la memoria, la descomprimirá e inicializará, y luego pasará el control a esta imagen del núcleo. [2] El cargador de arranque de segunda etapa también realiza varias operaciones en el sistema, como la verificación del hardware del sistema, el montaje del dispositivo raíz, la carga de los módulos del núcleo necesarios, etc. [2] Finalmente, se inicia el primer proceso de espacio de usuario ( proceso) y se realizan otras inicializaciones del sistema de alto nivel (que involucran scripts de inicio). [2]init
Para cada una de estas etapas y componentes, existen diferentes variaciones y enfoques; por ejemplo, se pueden utilizar GRUB , coreboot o Das U-Boot como cargadores de arranque (ejemplos históricos son LILO , SYSLINUX o Loadlin ), mientras que los scripts de inicio pueden ser del estilo init tradicional , o la configuración del sistema puede realizarse a través de alternativas modernas como systemd o Upstart .
El inicio del sistema tiene diferentes pasos según el hardware en el que se inicia Linux. [7]
El hardware compatible con IBM PC es una arquitectura en la que Linux se utiliza comúnmente; en estos sistemas, el firmware BIOS o UEFI juega un papel importante.
En los sistemas BIOS, el BIOS realizará respectivamente una prueba automática de encendido (POST), que consiste en verificar el hardware del sistema, luego enumerar los dispositivos locales y finalmente inicializar el sistema. [7] Para la inicialización del sistema, el BIOS comenzará buscando el dispositivo de arranque en el sistema que almacena el sistema operativo. Un dispositivo de arranque puede ser un dispositivo de almacenamiento como un disquete, un CD-ROM, una unidad flash USB, una partición en un disco duro (donde un disco duro almacena varios sistemas operativos, por ejemplo, Windows y Fedora), un dispositivo de almacenamiento en la red local, etc. [7] Un disco duro para arrancar Linux almacena el Registro de arranque maestro (MBR), que contiene el cargador de arranque primario/de primera etapa para cargarse en la RAM. [7]
En los sistemas UEFI , el kernel de Linux puede ser ejecutado directamente por el firmware UEFI a través del stub de arranque EFI, [8] pero normalmente utiliza GRUB 2 o systemd-boot como cargador de arranque. [9] [10]
La etapa de inicio del sistema en un sistema Linux integrado comienza ejecutando el firmware/programa en la ROM de arranque en chip , que luego carga el gestor de arranque/sistema operativo desde el dispositivo de almacenamiento como eMMC, eUFS, NAND flash, etc. [5] Las secuencias de inicio del sistema varían según los procesadores [5] pero todas incluyen pasos de inicialización de hardware y prueba de hardware del sistema. [7] Por ejemplo, en un sistema con un procesador i.MX7D y un dispositivo de arranque que almacena el SO (incluido U-Boot), la ROM de arranque en chip configura primero el controlador de memoria DDR , lo que permite que el programa de la ROM de arranque obtenga los datos de configuración del SoC del gestor de arranque externo en el dispositivo de arranque. [5] La ROM de arranque en chip luego carga el U-Boot en la DRAM para la etapa del gestor de arranque. [11]
El gestor de arranque de primera etapa, que forma parte del MBR, es una imagen de 512 bytes que contiene el código de programa específico del proveedor y una tabla de particiones. [6] Como se mencionó anteriormente en la parte de introducción, el gestor de arranque de primera etapa encontrará y cargará el gestor de arranque de segunda etapa. [6] Para ello, busca en la tabla de particiones una partición activa. [6] Después de encontrar una partición activa, el gestor de arranque de primera etapa seguirá escaneando las particiones restantes de la tabla para asegurarse de que todas estén inactivas. [6] Después de este paso, el registro de arranque de la partición activa se lee en la RAM y se ejecuta como gestor de arranque de segunda etapa. [6] El trabajo del gestor de arranque de segunda etapa es cargar la imagen del núcleo de Linux en la memoria y, opcionalmente, en el disco RAM inicial. [12] La imagen del núcleo no es un núcleo ejecutable, sino un "archivo comprimido" del núcleo , comprimido en formatos zImage o bzImage con zlib . [13]
En PC x86, los cargadores de arranque de primera y segunda etapa se combinan en GRand Unified Bootloader (GRUB), y anteriormente Linux Loader ( LILO ). [12] GRUB 2 , que se utiliza ahora, se diferencia de GRUB 1 por ser capaz de detectar automáticamente varios sistemas operativos y configurarse automáticamente. La etapa 1 se carga y ejecuta mediante el BIOS desde el registro de arranque maestro (MBR). El cargador de la etapa intermedia (stage1.5, normalmente core.img) se carga y ejecuta mediante el cargador de la etapa 1. El cargador de la segunda etapa (stage2, los archivos /boot/grub/) se carga mediante el stage1.5 y muestra el menú de inicio de GRUB que permite al usuario elegir un sistema operativo o examinar y editar parámetros de inicio. Después de elegir una entrada del menú y proporcionar parámetros opcionales, GRUB carga el núcleo de Linux en la memoria y le pasa el control. GRUB 2 también es capaz de cargar en cadena otro cargador de arranque. En los sistemas UEFI , stage1 y stage1.5 generalmente son el mismo archivo de aplicación UEFI (como grubx64.efi para sistemas UEFI x64 ).
Además de GRUB, existen otros cargadores de arranque más populares:
Los cargadores de arranque históricos que ya no se usan comúnmente incluyen:
/etc/lilo.conf
se crea un archivo de configuración ( ) en un sistema en vivo que asigna información de desplazamiento sin procesar (herramienta de asignación) sobre la ubicación de los discos de kernel y ram (initrd o initramfs). El archivo de configuración, que incluye datos como la partición de arranque y la ruta del kernel para cada uno, así como opciones personalizadas si es necesario, se escribe junto con el código del cargador de arranque en el sector de arranque MBR. Cuando se lee este sector de arranque y la BIOS le otorga el control, LILO carga el código del menú y lo dibuja, luego usa los valores almacenados junto con la entrada del usuario para calcular y cargar el kernel de Linux o cargar en cadena cualquier otro cargador de arranque .La etapa del núcleo ocurre después de la etapa del cargador de arranque. El núcleo de Linux maneja todos los procesos del sistema operativo, como la administración de memoria , la programación de tareas , la E/S , la comunicación entre procesos y el control general del sistema. Esto se carga en dos etapas: en la primera etapa, el núcleo (como un archivo de imagen comprimido) se carga en la memoria y se descomprime, y se configuran algunas funciones fundamentales, como la administración básica de la memoria y la cantidad mínima de configuración del hardware. [13] Vale la pena señalar que la imagen del núcleo se descomprime automáticamente, lo que es parte de la rutina de la imagen del núcleo. [13] Para algunas plataformas (como ARM de 64 bits), la descompresión del núcleo debe ser realizada por el cargador de arranque, como U-Boot. [16]
Para conocer los detalles de estos pasos, tomemos un ejemplo con el microprocesador i386 . Cuando se invoca su bzImage, se llama a la función start()
(de ) para realizar una configuración básica del hardware y luego llama a (ubicado en ). [13] realizará la configuración básica del entorno (pila, etc.), borrará el Bloque iniciado por símbolo (BSS) y luego invocará a (ubicado en ) para descomprimir el núcleo. [13] Luego, el inicio del núcleo se ejecuta a través de una función diferente ubicada en . [13] La función de inicio para el núcleo (también llamada intercambiador o proceso 0) establece la gestión de la memoria (tablas de paginación y paginación de memoria), detecta el tipo de CPU y cualquier funcionalidad adicional como capacidades de punto flotante , y luego cambia a la funcionalidad del núcleo de Linux no específica de la arquitectura a través de una llamada a ubicado en . [13]./arch/i386/boot/head.S
startup_32()
./arch/i386/boot/compressed/head.S
startup_32()
decompress_kernel()
./arch/i386/boot/compressed/misc.c
startup_32()
./arch/i386/kernel/head.S
startup_32()
start_kernel()
./init/main.c
start_kernel()
ejecuta una amplia gama de funciones de inicialización. Configura el manejo de interrupciones ( IRQs ), configura aún más la memoria, monta el disco RAM inicial ("initrd") que se cargó previamente como el sistema de archivos raíz temporal durante la etapa del cargador de arranque. [13] El initrd, que actúa como un sistema de archivos raíz temporal en RAM, permite que el núcleo se inicie completamente y que los módulos del controlador se carguen directamente desde la memoria, sin depender de otros dispositivos (por ejemplo, un disco duro). [13] initrd contiene los módulos necesarios para interactuar con los periféricos, [13] por ejemplo, el controlador SATA, y admite una gran cantidad de posibles configuraciones de hardware. [13] Esta división de algunos controladores compilados estáticamente en el núcleo y otros controladores cargados desde initrd permite un núcleo más pequeño. [13] initramfs , también conocido como espacio de usuario temprano, ha estado disponible desde la versión 2.5.46 del núcleo Linux, [17] con la intención de reemplazar tantas funciones como sea posible que anteriormente el núcleo habría realizado durante el proceso de inicio. Los usos típicos del espacio de usuario inicial son detectar qué controladores de dispositivos se necesitan para cargar el sistema de archivos del espacio de usuario principal y cargarlos desde un sistema de archivos temporal . Muchas distribuciones utilizan dracut para generar y mantener la imagen initramfs.
El sistema de archivos raíz se cambia posteriormente a través de una llamada a pivot_root()
que desmonta el sistema de archivos raíz temporal y lo reemplaza con el uso del real, una vez que este último es accesible. [13] Luego se recupera la memoria utilizada por el sistema de archivos raíz temporal. [ aclaración necesaria ]
Finalmente, se llama a kernel_thread
(in arch/i386/kernel/process.c
) para iniciar el proceso Init (el primer proceso del espacio de usuario) y luego inicia la tarea inactiva a través de cpu_idle()
. [13]
De esta manera, la etapa del núcleo inicializa los dispositivos, monta el sistema de archivos raíz especificado por el gestor de arranque como de sólo lectura y ejecuta Init ( /sbin/init
), que está designado como el primer proceso ejecutado por el sistema ( PID = 1). [18] El núcleo imprime un mensaje al montar el sistema de archivos y Init al iniciar el proceso Init. [18]
Según Red Hat , el proceso detallado del kernel en esta etapa se resume de la siguiente manera: [14]
En este punto, con las interrupciones habilitadas, el programador puede tomar el control de la gestión general del sistema, para proporcionar multitarea preventiva, y el proceso de inicio queda a cargo de continuar iniciando el entorno del usuario en el espacio del usuario.
Una vez que el núcleo se ha iniciado, inicia el proceso init , [19] un demonio que luego arranca el espacio de usuario , por ejemplo, comprobando y montando sistemas de archivos e iniciando otros procesos . El sistema init es el primer demonio que se inicia (durante el arranque) y el último en terminar (durante el apagado ).
Históricamente, este era el "SysV init", que se llamaba simplemente "init". Es probable que las distribuciones de Linux más recientes utilicen una de las alternativas más modernas, como systemd . A continuación, se incluye un resumen de los principales procesos de inicio:
"/etc/rc..."
. El archivo de configuración de nivel superior para init está en /etc/inittab
. [20] Durante el arranque del sistema, comprueba si se especifica un nivel de ejecución predeterminado en /etc/inittab, y solicita al nivel de ejecución que ingrese a través de la consola del sistema si no es así. Luego procede a ejecutar todos los scripts de arranque relevantes para el nivel de ejecución dado, incluyendo la carga de módulos , la comprobación de la integridad del sistema de archivos raíz (que se montó como de solo lectura) y luego volver a montarlo para obtener acceso completo de lectura y escritura, y configura la red . [18] Después de haber generado todos los procesos especificados, init queda inactivo y espera que ocurra uno de tres eventos: los procesos que comenzaron a finalizar o morir, una señal de falla de energía, [ aclaración necesaria ] o una solicitud a través de /sbin/telinit
para cambiar aún más el nivel de ejecución. [21]