Arrencar Linux

De WikiMar
Dreceres ràpides: navegació, cerca

There is nice summary and a nice table at http://lpi.aluzina.org/wiki/LPIC-2/201_2 Here copy of some part of it:


Arrancar Grub (grub-0.97-r2)

  • Repaso del arranque de la BIOS.
  • Hacer un arranque manual con el GRUB. ¿Cómo funciona todo esto?
  • emerge grub y parar justo después del configure. [ http://www.gnu.org/software/grub/manual/grub.html#Bootstrap-tricks Cómo funciona el arranque].
    • Analizar stage1/stage1.S. Después del make debería ocupar 512 bytes. Esto es lo que se copia en el MBR del disco. En stage1/stage1.S +100 se ve cómo se copia un sector (512 bytes) del stage1.5 en memoria en la dirección 0x8000, esto está en la parte de boot de la partición reiserfs (después del MBR de la partición). En stage1/stage1.S +373 hace el salto al stage1.5.
    • Ir al directorio stage2/ y hacer un make reiserfs_stage1_5. Ver como se meten en orden el start.S, asm.S, ... El start.S es lo que se carga por el stage1 que son sólo 512 bytes. Él se auto carga lo que le queda (ya que está a continuación) y con el driver de reiserfs accede ya al fichero disperso de más de 100K directamente a /boot/grub/stage2.
    • Hacer un make completo del directorio stage2/. Ver cómo se crea el fichero stage2 que es una suma de start + pre_stage2. Esto contiene el programa que lee directamente del sistema de ficheros. Básicamente está todo en stage2/stage2.c.
    • En el fichero stage2/asm.S +101 se ve claro que el stage2 carga el fichero /boot/grub/menu.lst. Además debe llamarse así.
  • A continuación para cargar un núcleo de linux hay que ejecutar dos comandos en el grub:
    • kernel (hd0,6)/usr/src/linux/arch/i386/boot/bzImage root=/dev/hdb5. Esto ejecuta la función stage2/boot.c +40 (load_image). Identificando la dirección de la parte de setup, te la imprime por pantalla.
    • boot. Este comando ejecuta stage2/builtins.c +273 (boot_func) y se escapa por la línea 301 en la llamada a big_linux_boot(), en stage2/asm.S +1748. Como se ve, esto llama a la dirección del setup mediante un call de 32 bits.

Arrancar Linux (linux-2.6.18-gentoo-r2)

  • Repaso arranque del núcleo:
  • arch/i386/boot/setup.S por el grub directo
  • arch/i386/boot/compressed/head.S -> salta al start_kernel()
  • init/main.c start_kernel()
    • rest_init() -> cpu_idle.
    • init/main.c:685 init(). Esta función llama en la línea 729 a prepare_namespace(). Y finalmente llama a run_process_init() que carga el ejecutable /sbin/init.

Nota sobre el montaje del sistema raíz, dónde se monta el initrd:

  • init/do_mounts.c
    • prepare_namespace():396
      • mount_root() -> mount_block_root() -> do_mount_root()

Parámetros que se pasan al init

En la fución gigante start_kernel():456, se llama a la función parse_args donde se analizan todos los argumentos que se pasan al núcleo (incluido el root=). La función toma como último argumento la función unknown_bootoption():226, que se ejecuta cada vez que no reconoce un argumento. Ese argumento se añade al array argv_init en la línea :278.

Los parámetros más típicos son:

  • root=. Dispositivo raíz.
  • init=. Primer programa. Al llamar al run_init_program se le pasa éste.

El argv_init es el que se le pasa a la función execve() de /sbin/init para pasarle los parámetros en init/main.c:682 run_init_process()

Por lo tanto, el programa /sbin/init recibe todos los parámetros no reconocidos del núcleo que son pasados por el cargador de arranque (grub). Más adelante se verá la utilidad de esto para arrancar en modo super-usuario.

Initrd

  • Intro initrd. Motivación. Distribuciones grandes.
  • stage2/boot.c +799 (load_initrd). Se ejecuta esta función cuando se le ordena al grub cargar el initrd. Copia al final de la memoria y actualiza los campos ramdisk_image y ramdisk_size de la cabecera del setup. La cabecera del setup está en stage2/shared.h +388 (struct linux_kernel_header).
  • Una vez en Linux, recordemos que el sistema de ficheros / se monta en init/do_mounts +396 prepare_namespace().
  • Antes de montar el sistema de ficheros, se ejecuta init/do_mounts.c +421 initrd_load() que carga la imagen del initrd en el ramdisk, la descomprime y la monta en /, a continuación ejecuta el kernel thread /linuxrc, se puede ver cómo lo hace en init/do_mounts_initrd +59 handle_initrd().
  • Cómo generar esa imágen?? El manual de EVMS describe cómo hacerlo paso por paso. Básicamente se trata de:
    • Generar un fichero vacío.
    • Formatearlo en ext2
    • Montarlo en algún lugar
    • Copiar todo lo necesario: librerías, shell, módulos, etc...
    • Crear un script llamado /linuxrc con insmod de módulos necesarios y demás.
    • Desmontarlo y comprimir el archivo en gzip. Ya está listo.
  • Para ello, hay una utilidad llamada mkinitrd que te simplifica la vida.

Programa init (sysvinit-2.86-r5)

  • Hacer un equery b /sbin/init
  • emerge sysvinit y pararlo después del configure
  • ver el src/init.c
  •  :2636 main(). Interesante el análisis de opciones en las líneas 2686 a 2701.
  •  :2708 llama a init_main():2352. El cual, al final tiene un bucle infinito de programa . Init es el proceso madre de todos, el cual va esperando a que procesos que tienen hijos mueran y puedan ser heredados por init.
  •  :2484 init_main() llama a read_inittab():1117, el cual lee el fichero de configuración /etc/inittab en la línea 1150, se ve claro el fopen.

inittab

El formato del fichero es: id:niveles_ejecucion:accion:proceso. Es importante notar que el órden no importa!! ¡¡No es un autoexec.bat!!

Las posibles acciones son:

  • sysinit. Se ejecuta antes de nada (de cualquier boot o bootwait).
  • Luego boot o bootwait. Se ejecutan antes de entrar en cualquier nivel de ejecución. La diferencia entre los dos es que en la versión wait, init se espera a que acabe de ejecutarse el comando antes de ejecutar otra cosa.
  • Se escoje el nivel de ejecución en el que se entrará. Explicar los diferentes niveles de ejecución. Para ello, se le pasa como parámetro a init. Si no hay ningún parámetro, está la directiva initdefault que arranca en uno por defecto.
  • once o wait. El wait se debería llamar oncewait, se ejecuta la acción cuando se entra en el nivel de ejecución, la diferencia entre los dos es como antes: si se espera o no.
  • respawn. Es como wait, pero al acabar el programa lo vuelve a ejecutar.

Hay otras cositas como:

  • ctrlaltdel. Qué hacer cuando se presionan las teclas malditas.
  • powerwait, powerfail, powerokwait... Cosas de SAIs, opera bajo la señal SIGPWR.

/sbin/rc (baselayout-1.12.6)

  • Se le llama al principio con el parámetro boot y luego default. Estos son los SOFTLEVELS de Gentoo. Diferencia con las demás distribuciones:
    • Arranque de servicios en paralelo.
    • No hay orden numérico en la instalación, el orden viene dado por la dependencia implícita. Estilo Windows NT/2000/XP.
    • Cuando se para un servicio del cual otros dependen de él, éstos tambien se paran. Lo mismo al arrancar, se arrancan también los que dependen de él.
  • Servicios en /etc/init.d/ como siempre. Mirar las dependencias de cada servicio con el vi. Salen al principio del servicio con la función depend().
  • Softlevels en /etc/runlevels/. Allí hay enlaces a los respectivos servicios. Para añadir el servicio para que se arranque en el correspondiente SOFTLEVEL sólo hay que añadir un enlace simbólico. Aunque hay una utilidad para esto:
Ubuntu/Debian OpenSuse/Fedora/Mandriva Slackware Gentoo
Instalar update-rc.d servicio defaults chkconfig add servicio - rc-update add servicio default/boot
Desinstalar update-rc.d -f servicio defaults chkconfig del servicio - rc-update del servicio default/boot
  • El orden final viene dado por la variable RC_PARALLEL_STARTUP de /etc/conf.d/rc. Si está a yes el órden simplemente viene dado por la dependencia, si no orden aleatorio secuencial para satisfacer dependencias.
  • Cuando se modifica el contenido del directorio /etc/init.d/, se ejecuta automáticamente el comando /sbin/depscan.sh, que recalcula la caché de dependencias en /var/lib/init.d/dep*.
  • Una vez que el servicio se arranca queda enlazado en /var/lib/init.d/started/ servicio.