Tarde o temprano te va a tocar. Vamos a hacer un repaso práctico y humano sobre cómo trabajar con los módulos de Linux.
Lsmod – Lista de módulos del sistema
El primer paso es tener un vistazo de todos los módulos que tenemos en nuestro sistema con lsmod:
[root@jota-pc ~]# lsmod Module Size Used by nls_ascii 16384 1 nls_cp437 20480 1 vfat 20480 1 fat 69632 1 vfat vhost_net 20480 3 vhost 45056 1 vhost_net macvtap 24576 1 vhost_net macvlan 24576 1 macvtap tun 28672 7 vhost_net ses 20480 0 enclosure 16384 1 ses scsi_transport_sas 45056 1 ses uas 24576 1 usb_storage 73728 4 uas fuse 98304 9 ebtable_filter 16384 0 ebtables 36864 1 ebtable_filter pci_stub 16384 1 vboxpci 24576 0 vboxnetadp 28672 0 vboxnetflt 28672 0 vboxdrv 458752 3 vboxnetadp,vboxnetflt,vboxpci bridge 135168 0 stp 16384 1 bridge llc 16384 2 bridge,stp ip6table_filter 16384 0 ip6_tables 28672 1 ip6table_filter nf_log_ipv4 16384 1 nf_log_common 16384 1 nf_log_ipv4 ...
De esta manera podemos ver las dependencias que existen entre módulos observando la columna Used by. Dichas dependencias también podemos observarlas con depmod -v
:
[root@jota-pc ~]# depmod -v | grep -i nvidia /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia-modeset.ko needs "nvidia_register_module": /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia.ko /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia-drm.ko needs "drm_framebuffer_cleanup": /lib/modules/4.9.0-4-amd64/kernel/drivers/gpu/drm/drm.ko /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia-drm.ko needs "drm_atomic_helper_plane_destroy_state": /lib/modules/4.9.0-4-amd64/kernel/drivers/gpu/drm/drm_kms_helper.ko /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia-drm.ko needs "nvKmsKapiGetFunctionsTable": /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia-modeset.ko /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia-uvm.ko needs "nvUvmInterfaceDisableAccessCntr": /lib/modules/4.9.0-4-amd64/updates/dkms/nvidia.ko
También podemos listar los módulos de nuestro sistema haciendo cat /proc/modules
[root@jota-pc ~]# cat /proc/modules nls_ascii 16384 1 - Live 0xffffffffc1cb8000 nls_cp437 20480 1 - Live 0xffffffffc0f93000 vfat 20480 1 - Live 0xffffffffc0f8d000 fat 69632 1 vfat, Live 0xffffffffc1ca6000 vhost_net 20480 3 - Live 0xffffffffc0f87000 vhost 45056 1 vhost_net, Live 0xffffffffc0f74000 macvtap 24576 1 vhost_net, Live 0xffffffffc0ad2000 macvlan 24576 1 macvtap, Live 0xffffffffc0f6d000 tun 28672 7 vhost_net, Live 0xffffffffc0ac1000 ses 20480 0 - Live 0xffffffffc0acc000 enclosure 16384 1 ses, Live 0xffffffffc0a2b000 scsi_transport_sas 45056 1 ses, Live 0xffffffffc09fa000 uas 24576 1 - Live 0xffffffffc0a24000 usb_storage 73728 4 uas, Live 0xffffffffc0aae000 fuse 98304 9 - Live 0xffffffffc0a95000 ebtable_filter 16384 0 - Live 0xffffffffc09e0000 ebtables 36864 1 ebtable_filter, Live 0xffffffffc09f0000 pci_stub 16384 1 - Live 0xffffffffc09eb000 vboxpci 24576 0 - Live 0xffffffffc09d9000 (O) vboxnetadp 28672 0 - Live 0xffffffffc09d1000 (O) vboxnetflt 28672 0 - Live 0xffffffffc09c5000 (O) vboxdrv 458752 3 vboxpci,vboxnetadp,vboxnetflt, Live 0xffffffffc1c35000 (O) bridge 135168 0 - Live 0xffffffffc0a73000 stp 16384 1 bridge, Live 0xffffffffc0931000 ...
Modinfo – Información concreta de un módulo
Una vez tenemos una lista de todos los módulos, podemos indagar en cada uno de ellos en busca de información más detallada. Con modinfo obtenemos información de un módulo en concreto: autor, licencia, nombre del fichero de módulo, dependencias… Como pista, los ficheros de módulos tienen sufijo .ko (ej.: nvidia.ko) que significa Kernel Object y son compilados para cada versión del kernel Linux que tengamos.
Así, por ejemplo en mi caso para el módulo vboxpci:
[root@jota-pc ~]# modinfo vboxpci filename: /lib/modules/4.9.0-4-amd64/misc/vboxpci.ko version: 5.1.30 r118389 license: GPL description: Oracle VM VirtualBox PCI access Driver author: Oracle Corporation srcversion: 599E658DBEB70A080F1FE14 depends: vboxdrv vermagic: 4.9.0-4-amd64 SMP mod_unload modversions
Información del módulo de la gráfica Nvidia:
[root@jota-pc lib]# modinfo nvidia filename: /lib/modules/4.9.0-3-amd64/updates/dkms/nvidia.ko alias: char-major-195-* version: 384.90 supported: external license: NVIDIA srcversion: 9D546A76FA9D9523F03995D alias: pci:v000010DEd00000E00sv*sd*bc04sc80i00* alias: pci:v000010DEd*sv*sd*bc03sc02i00* alias: pci:v000010DEd*sv*sd*bc03sc00i00* depends: vermagic: 4.9.0-3-amd64 SMP mod_unload modversions parm: NVreg_Mobile:int parm: NVreg_ResmanDebugLevel:int parm: NVreg_RmLogonRC:int parm: NVreg_ModifyDeviceFiles:int parm: NVreg_DeviceFileUID:int parm: NVreg_DeviceFileGID:int parm: NVreg_DeviceFileMode:int parm: NVreg_UpdateMemoryTypes:int parm: NVreg_InitializeSystemMemoryAllocations:int parm: NVreg_UsePageAttributeTable:int parm: NVreg_MapRegistersEarly:int parm: NVreg_RegisterForACPIEvents:int parm: NVreg_CheckPCIConfigSpace:int parm: NVreg_EnablePCIeGen3:int parm: NVreg_EnableMSI:int parm: NVreg_TCEBypassMode:int parm: NVreg_UseThreadedInterrupts:int parm: NVreg_EnableStreamMemOPs:int parm: NVreg_MemoryPoolSize:int parm: NVreg_RegistryDwords:charp parm: NVreg_RegistryDwordsPerDevice:charp parm: NVreg_RmMsg:charp parm: NVreg_AssignGpus:charp
¿Qué módulo está utilizando mi dispositivo (PCI)?
Podemos obtener esta información con la opción -k
de lspci siempre que tengamos un Kernel Linux 2.6 o superior:
[root@jota-pc ~]# lspci -k ... 00:1f.2 SATA controller: Intel Corporation 6 Series/C200 Series Chipset Family SATA AHCI Controller (rev 05) Subsystem: ASUSTeK Computer Inc. P8 series motherboard Kernel driver in use: ahci Kernel modules: ahci 00:1f.3 SMBus: Intel Corporation 6 Series/C200 Series Chipset Family SMBus Controller (rev 05) Subsystem: ASUSTeK Computer Inc. P8 series motherboard Kernel driver in use: i801_smbus Kernel modules: i2c_i801 01:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1) Subsystem: ASUSTeK Computer Inc. GM206 [GeForce GTX 960] Kernel driver in use: nvidia Kernel modules: nouveau, nvidia_drm, nvidia 01:00.1 Audio device: NVIDIA Corporation Device 0fba (rev a1) Subsystem: ASUSTeK Computer Inc. Device 8520 Kernel driver in use: snd_hda_intel Kernel modules: snd_hda_intel 02:00.0 Network controller: Ralink corp. RT3090 Wireless 802.11n 1T/1R PCIe Subsystem: Lite-On Communications Inc RT3090 Wireless 802.11n 1T/1R PCIe Kernel driver in use: rt2800pci Kernel modules: rt2800pci 03:00.0 USB controller: ASMedia Technology Inc. ASM1042 SuperSpeed USB Host Controller Subsystem: ASUSTeK Computer Inc. P8B WS Motherboard Kernel driver in use: xhci_hcd Kernel modules: xhci_pci ...
Todos estos dispositivos PCI estarán mapeados en /proc/bus/pci/devices. Podemos hacer un cat aunque el resultado no es demasiado legible, por lo que es mejor filtrar con awk por la columna nº 18 en la que podemos encontrar todos los drivers utilizados:
[root@jota-pc pci]# cat devices | awk '{print $18}' snb_uncore pcieport mei_me e1000e ehci-pci snd_hda_intel pcieport pcieport pcieport pcieport ehci-pci lpc_ich ahci i801_smbus nvidia snd_hda_intel rt2800pci xhci_hcd xhci_hcd ahci
Cargar y descargar un módulos
Para cargar un módulo podemos utilizar insmod o modprobe. Es recomendable utilizar el segundo ya que tiene en cuenta las dependencias que tiene un módulo para cargarlas de forma automática:
# Insmod insmod /lib/modules/4.9.0-3-amd64/updates/dkms/nvidia.ko # Modprobe modprobe nvidia
Si queremos descargar un módulo podemos utilizar modprobe -r o rmmod:
# Modprobe modprobe -r nvidia # Rmmod rmmod nvidia
¿Kernel con soporte para carga de módulos?
Existen varias formas de comprobar si nuestro kernel tiene soporte para carga de módulos. En primer lugar si hacemos un cat /proc/modules
obtendremos un resultado con la lista de módulos cargados en el kernel:
nvidia_uvm 659456 0 - Live 0xffffffffc1e1f000 (PO) vhost_net 20480 3 - Live 0xffffffffc0f76000 vhost 45056 1 vhost_net, Live 0xffffffffc0f6a000 macvtap 24576 1 vhost_net, Live 0xffffffffc0de0000 macvlan 24576 1 macvtap, Live 0xffffffffc0c8d000 tun 28672 7 vhost_net, Live 0xffffffffc0bbe000 fuse 98304 9 - Live 0xffffffffc0dc3000 ebtable_filter 16384 0 - Live 0xffffffffc0bb9000 ebtables 36864 1 ebtable_filter, Live 0xffffffffc0bab000 pci_stub 16384 1 - Live 0xffffffffc0ba6000 vboxpci 24576 0 - Live 0xffffffffc0b9b000 (O) vboxnetadp 28672 0 - Live 0xffffffffc0b93000 (O) vboxnetflt 28672 0 - Live 0xffffffffc0aa9000 (O) vboxdrv 458752 3 vboxpci,vboxnetadp,vboxnetflt, Live 0xffffffffc1dae000 (O) bridge 135168 0 - Live 0xffffffffc0b6d000 stp 16384 1 bridge, Live 0xffffffffc0aa4000 llc 16384 2 bridge,stp, Live 0xffffffffc0a52000 ip6table_filter 16384 0 - Live 0xffffffffc0a37000 ip6_tables 28672 1 ip6table_filter, Live 0xffffffffc0b65000 nf_log_ipv4 16384 1 - Live 0xffffffffc0a28000 nf_log_common 16384 1 nf_log_ipv4, Live 0xffffffffc0a0c000 xt_LOG 16384 1 - Live 0xffffffffc0850000 xt_limit 16384 1 - Live 0xffffffffc09bf000
Dicho resultado también podríamos verificarlo también lanzando lsmod.
Además, por ejemplo suponiendo que tengamos un kernel 4.9.0-4 para arquitectura 64 bits, tendremos un subdirectorio dentro de /lib/modules/ correspondiente a esa versión del kernel con configuración relativa a carga de módulos, dependencias, etc…:
[jota@jota-pc ~]$ ls -l /lib/modules/4.9.0-4-amd64/ total 4152 lrwxrwxrwx 1 root root 36 Sep 28 19:27 build -> /usr/src/linux-headers-4.9.0-4-amd64 drwxr-xr-x 12 root root 4096 Oct 7 18:24 kernel drwxr-xr-x 2 root root 4096 Oct 16 22:00 misc -rw-r--r-- 1 root root 1012238 Oct 19 07:01 modules.alias -rw-r--r-- 1 root root 971143 Oct 19 07:01 modules.alias.bin -rw-r--r-- 1 root root 4018 Sep 28 19:27 modules.builtin -rw-r--r-- 1 root root 5327 Oct 19 07:01 modules.builtin.bin -rw-r--r-- 1 root root 399424 Oct 19 07:01 modules.dep -rw-r--r-- 1 root root 550668 Oct 19 07:01 modules.dep.bin -rw-r--r-- 1 root root 402 Oct 19 07:01 modules.devname -rw-r--r-- 1 root root 133512 Sep 28 19:27 modules.order -rw-r--r-- 1 root root 523 Oct 19 07:01 modules.softdep -rw-r--r-- 1 root root 510617 Oct 19 07:01 modules.symbols -rw-r--r-- 1 root root 625163 Oct 19 07:01 modules.symbols.bin lrwxrwxrwx 1 root root 37 Sep 28 19:27 source -> /usr/src/linux-headers-4.9.0-4-common drwxr-xr-x 3 root root 4096 Oct 7 18:25 updates
Dadas estas pistas, si nuestro kernel no tuviera soporte para carga de módulos no debería existir ni el directorio de módulos correspondiente anterior ni /proc/modules. Además, lsmod no deberia tampoco arrojar ningún resultado si lo lanzamos.
¿Cómo habilitamos el soporte para la carga de módulos? O bien compilamos un nuevo kernel o recompilamos el existente activando la opción «Enable loadable module support» cuando estemos generando el fichero .config en el proceso de compilación.
Para estos menesteres os puede resultar útil el artículo sobre cómo compilar un kernel Linux de forma genérica y también para el caso particular de Debian.