Personalización, reducción y compilación de un kérnel Linux a medida

La compilación de un kérnel GNU/Linux es una práctica poco habitual respecto a hace una década. Hoy en día, apenas se realiza una recompilación del kernel y, cuando se hace, es para soportar un nuevo hardware no incluido en el kérnel de la distribución o bien por puro interés en aprender a realizar esta técnica. También se realiza para el uso en sistemas embebidos o dispositivos empotrados como puede ser Raspberry Pi o smartphones.
Esta entrada busca como fin la optimización y reducción de tamaño del kérnel utilizado por Debian Jessie, desintegrando los módulos no necesarios en dicho núcleo y rechazando el uso de otro tipo de funcionalidades como conexiones inalámbricas o puertos USB.
Partiendo de cero
Para hacer una compilación del kérnel necesitamos los ficheros fuente del núcleo. Uno de los primeros pasos conocer qué kérnel estamos utilizando en nuestro sistema para poder descargarnos los ficheros fuente. La orden
uname -r
nos indica que el núcleo utilizado por nuestro Debian Jessie en nuestro caso es el 3.16.0-4-amd64.
Este se puede instalar con apt-get install linux-source-X.X
, siendo el resultado un fichero comprimido ubicado en /usr/src/linux-source-X.X.tar.xz o bien a través del sitio web kernel.org, donde aparece como última versión estable la 4.8 en estos momentos.
Continuamos creando un directorio donde ubicar los archivos del núcleo y realizar la compilación. Para ello ejecutamos mkdir ~/Kernel
y dentro de él ejecutamos tar xf /usr/src/linux-source-3.16.tar.xz
.
Copiando la configuración del kérnel actual
Para agilizar y afinar el proceso de configuración de la nueva compilación, tomamos como punto de partida la configuración del núcleo actual. Esta configuración la copiamos con cp /boot/config-
Si tenemos únicamente un núcleo instalado en nuestro sistema, no es necesario hacer uso de uname -r
/home/nano/Kernel/linux-source-3.16/.config
.uname -r
Es necesario etiquetar el nuevo núcleo desde la constante EXTRAVERSION del fichero Makefile, ubicado dentro del directorio descomprimido. Un ejemplo sería comenzar con -01 e ir incrementando conforme vayamos realizando nuevas compilaciones, pues nuestro objetivo final es obtener un núcleo muy básico a la vez que funcional.
Por defecto, el núcleo de Linux incluye soporte para todos los dispositivos de hardware. El comando make localmodconfig
permite configurar la nueva compilación con los dispositivos hardware de nuestra máquina.
Compilando un nuevo kérnel de Linux
Compilar un núcleo es un proceso que requiere de la capacidad de cómputo de nuestro procesador. Por ello, mientras mayor sea la capacidad del procesador y menor sea el tamaño de la compilación, menor será el tiempo de espera. En mi caso pasó de compilar en seis minutos a no llegar a los dos minutos.
En 1990, compilar el primer kérnel le llevó a Linus Torvalds unos 12 minutos. Aunque el tamaño de este núcleo era muchísimo menor que el actual. En 2010 confirmaba que su sistema podía llegar a hacerlo en apenas un minuto.
En Debian, podemos conocer el número de cores de nuestro procesador con la instrucción grep processor /proc/cpuinfo | wc -l
para aprovechar al máximo su capacidad y reducir el tiempo de compilación.
El resultado de la nueva compilación de nuestro kérnel lo guardaremos en un un paquete .deb. En mi caso, ejecutaré el comando make -j8 INSTALL_MOD_STRIP=1 deb-pkg
. Establecer el parámetro INSTALL_MOD_STRIP a 1 eliminará los símbolos propios de debug, reduciendo el tamaño del paquete generado.
Podemos conocer el tiempo que tarda en finalizar esta tarea anteponiéndole time
En un principio, la compilación original y con los símbolos debug ocupaba 33MB y había tomado un total de 23 minutos. Mientras que la compilación ejecutada con la configuración de nuestro hardware y el parámetro INSTALL_MOD_STRIP activado pasa a ser un paquete de 6,6MB y 6 minutos de compilación.
Configuración a través de una herramienta gráfica
Desde el archivo .config copiado anteriormente es posible establecer la configuración de la compilación. Aún así, es un proceso enfarragoso que puede llevar a muchos errores, pues hay módulos que depende de otros módulos. Para agilizar esta tarea, existen herramientas gráficas que ayudan a modificar las opciones y módulos a compilar. Por un lado está menuconfig, que lo hace a través de una consola gráfica y por otro GConf y xconfig que utilizan el entorno de escritorio.
Antes de compilar nuevamente (en caso de que lo hayamos hecho) es recomendable eliminar los paquetes antiguos ejecutando rm ../*
dentro del directorio que en el trabajamos (linux-source-3.16 en mi caso). Igualmente, ejecutamos make clean
que mantiene el fichero de configuración previo y cambiamos el EXTRAVERSION del fichero Makefile.
A continuación, utilizaremos xconfig para la configuración de los módulos a compilar. xconfig utiliza las librerías de desarrollo Qt3 (qt3-dev-tools) y se ejecuta con make xconfig
Instalando el kérnel compilado
El núcleo compilado se instala como cualquier paquete .deb dpkg -i ../linux-image-3.16.36-01_3.16.36-01-1_amd64.deb
Esto desempaquetará, instalará, actualizará el initramfs y generará una nueva configuración de GRUB, añadiendo una nueva entrada.
Tras reiniciar, accedemos a la opción «Opciones avanzadas para Debian GNU/Linux» donde podremos elegir el sistema operativo Debian Jessie con el núcleo 3.16.36-01. Si el arranque se produce correctamente podemos comprobar nuestro núcleo con la ejecución de uname -r
en una terminal de comandos.
En caso de que la compilación sea fallida y no cargue, debemos iniciar con el núcleo de siempre, eliminando igualmente los paquetes .deb generados y ejecutando en esta ocasión make mrproper
para partir de una base aún más limpia (sin el .config utilizado). También deberemos desinstalar este kérnel de nuestro sistema.
Eliminando y desinstalando una versión del kérnel Linux
Si hemos realizado una compilación que hace que no arranca en nuestro sistema o que simplemente no usamos, podemos desinstalarla para liberar espacio y que no aparezca en el gestor arranque GRUB.
Con superusuario, ejecutamos dpkg -l | grep linux-image
para ver los kérnels instalados en nuestro sistema. Mientras que con apt-get remove --purge linux-image-X.X.X-X
desinstalamos el kérnel que no funciona correctamente, como en este caso ha sido el linux-image-3.16.36-04. Nuevamente se actualizará el initramfs y las entradas del GRUB.
Recuerda eliminar el paquete .deb generado y ejecutar make clean
para volver a activar aquellos módulos que crees que fallan o make mrproper
para poder partir desde cero, eliminando también el archivo .config.
Versionado del kérnel
Como resultado final, os dejo una tabla con las modificaciones progresivas que he ido realizando. Pasé de un paquete de 33MB a un paquete de 2,8MB, mientras que vmlinuz pasó de 3,1MB a 1,8MB. En esta tabla encontráis todos los módulos restados al kérnel de Linux tras la ejecución del comando make localmodconfig
y su correspondiente reducción de tamaño.
# | Módulos | .deb | vmlinuz |
---|---|---|---|
01 | Optimize for size (CC_OPTIMIZE_FOR_SIZE), High Resolution Timer Support (HIGH_RES_TIMERS), Linux guest support (HYPERVISOR_GUEST), Network packet filtering framework (Netfilter) (NETFILTER), QoS and/or fair queueing (NET_SCHED), Bluetooth subsystem support (BT), BF switch subsystem support (RFKILL), Parallel port support (PARPORT), Macintosh device drivers (MACINTOSH_DRIVERS), Wireless LAN (WLAN), Wan interfaces support (WAN), Hardware Monitoring support (HWMON), Multimedia support (MEDIA_SUPPORT), Sound card support (SOUND), Hardware crypto devices (CRYPTO_HW), Virtualization (VIRTUALIZATION) | 5MB | 2,6MB |
02 | Resource counters (RESOURCE_COUNTERS), DMA memory allocation support (ZONE_DMA), Symmetric multi-processing support (SMP), Memtest (MEMTEST), Enable DMI scanning (DMI), IBM Calgary IOMMU support (CALGARY_IOMMU), Enable support for 16-bit segments (X86_16BIT), Allow for memory hot-add (MEMORY_HOTPLUG), Track memory changes (MEM_SOFT_DIRTY), x86 architectural random number generator (ARCH_RANDOM), AC Adapter (ACPI_AC), Battery (ACPI_BATTERY), The IPv6 protocol (IPV6), Amateur Radio support (HAMRADIO), Wireless (WIRELESS) | 4,3MB | 2,3MB |
03 | AMD MCE features (X86_MCE_AMD), Supervisor Mode Access Prevention (X86_SMAP), IP: multicast routing (IP_MROUTE), USB Gadget Support (USB_GADGET), LED Trigger support (LEDS_TRIGGERS), Accessibility support (ACCESSIBILITY), Virtualization drivers (VIRT_DRIVERS), Staging drivers (STAGING), Platform support for Chrome hardware (CHROME_PLATFORMS), Network File Systems (NETWORK_FILESYSTEMS) | 4MB | 2,2MB |
04 | Support for paging of anonymous memory (swap) (SWAP), Enable the block layer (BLOCK), Enable VM86 support (VM86), Namespaces support (NAMESPACES), Processor (ACPI_PROCESSOR), Extended Error Log support (ACPI_EXTLOG), Support for PCI Hotplug (HOTPLUG_PCI), ACPI Platform Error Interface (APEI) (ACPI_APEI), /dev/agpgart (AGP Support) (AGP), 09ACPI (Advanced Configuration and Power Interface) Support (ACPI), SCSI low-level drivers (SCSI_LOWLEVEL) | 3,6MB | 2,0MB |
05 | Fusion MPT device support (FUSION), Fibre Channel driver support (NET_FC), BSD Process Accounting (BSD_PROCESS_ACCT), Export task/process statistics through netlink (TASKSTATS) | 3,6MB | 1,9MB |
06 | SFI (Simple Firmware Interface) Support (SFI), CPU Frequency scaling (CPU_FREQ), CPU idle PM support (CPU_IDLE), ISDN support (ISDN), Watchdog Timer Support (WATCHDOG), Intel 8xx/9xx/G3x/G4x/HD Graphics (DRM_I915), GPIO Support (GPIOLIB), Power supply class support (POWER_SUPPLY) | 3,2MB | 1,9MB |
07 | Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) (DRM), Support for frame buffer devices (FB), Backlight & LCD device support (BACKLIGHT_LCD_SUPPORT), USB support (USB_SUPPORT), Machine Check / overheating reporting (X86_MCE), System V IPC (SYSVIPC), POSIX Message Queues (POSIX_MQUEUE), Enable process_vm_readv/writev syscalls (CROSS_MEMORY_ATTACH), Enable system-call auditing support (AUDITSYSCALL), Enable VM event counters for /proc/vmstat (VM_EVENT_COUNTERS), Profiling support (PROFILING) | 2,9MB | 1,9MB |
08 | Checkpoint/restore support (CHECKPOINT_RESTORE), IP: multicast routing (IP_MROUTE), FDDI driver support (FDDI), HIPPI driver support (HIPPI), Joystick interface (INPUT_JOYDEV), Joysticks/Gamepads (INPUT_JOYSTICK), Tablets (INPUT_TABLET), Touchscreens (INPUT_TOUCHSCREEN), Miscellaneous devices (INPUT_MISC), Mice (INPUT_MOUSE), Mouse interface (INPUT_MOUSEDEV), DM uevents (DM_UEVENT), Debug memory initialisation (DEBUG_MEMORY_INIT), Compile the kérnel with debug info (DEBUG_INFO), Native language support (NLS), Miscellaneous filesystems (MISC_FILESYSTEMS), RISCiX partition support (ACORN_PARTITION_RISCIX), NSA SELinux AVC Statistics (SECURITY_SELINUX_AVC_STATS), NSA SELinux Development Support (SECURITY_SELINUX_DEVELOP), Extended 8250/16550 serial driver options (SERIAL_8250_EXTENDED), LED Support (NEW_LEDS), EDAC (Error Detection And Correction) reporting (EDAC), Real Time Clock (RTC_CLASS) | 2,8MB | 1,8MB |
09 | VGA Arbitration (VGA_ARB), Generic Thermal sysfs driver (THERMAL), VGA text console (VGA_CONSOLE), Enable full-sized data structures for core (BASE_FULL), CCM support (CRYPTO_CCM), CTR support (CRYPTO_CTR), ECB support (CRYPTO_ECB), NSA SELinux Support (SECURITY_SELINUX), AppArmor support (SECURITY_APPARMOR), TOMOYO Linux Support (SECURITY_TOMOYO), SHA1 digest algorithm (CRYPTO_SHA1), SHA224 and SHA256 digest algorithm (CRYPTO_SHA256), AES cipher algorithms (AES-NI) (CRYPTO_AES_NI_INTEL), ARC4 cipher algorithm (CRYPTO_ARC4), Enable dynamic printk() support (DYNAMIC_DEBUG), Enable suppor for printk (PRINTK), Print quota warnings to console (OBSOLETE) (PRINT_QUOTA_WARNING), Quota support (QUOTA), Report quota messages through netlink interface (QUOTA_NETLINK_INTERFACE) | 2,4MB | 2,0MB |
10 | Enable loadable module support (MODULES) | 2,3MB | 2,0MB |
Referencias
- How-To: Compilar un kérnel de Linux
- Eliminar versiones anteriores del kernel que no usemos
- Customizing & Installing Linux Kernel on Debian Wheezy
Muy bien explicado, pero ¿que beneficio hay en acortarle el tamaño al kernel?
¡Hola Luis!
Como explico brevemente en la intro, realmente es una práctica poco habitual y que no aporta ningún beneficio al usuario común. Mucho menos en relación esfuerzo -> resultado.
El kernel incluye soporte para que funcione (al menos lo básico) en cualquier equipo y con pequeñas excepciones en equipos muy nuevos (como el caso de portátiles) en el que puede ser que algún hardware no incluya soporte. Éste se carga en memoria con módulos que ni siquiera utilizará tu equipo, ocupando espacio en memoria. Así que esto suponía un problema en algunos equipos de hace años, pues las limitaciones en memoria RAM eran evidentes.
A día de hoy la carga que supone a equipos modernos es ridícula. Aún así, como comento, hay quien reduce el tamaño del kernel para optimizar su uso en dispositivos ARM como las Raspberry Pi o smartphones.
También existen personas que, aunque no reducen el tamaño del kernel, lo recompilan incluyendo los módulos que utiliza su hardware nuevo. Esto daría como resultado un kernel híbrido.
Espero que te haya servido 🙂