logo Kernel module loading


PRELIMINARY: This page is for Puppy 4.1alpah4+ only, updated July 17, 2008
Puppy Linux has sophisticated mechanisms for loading the correct modules at bootup, and also when hotplugging removable hardware. The overall name given to these mechanisms is pup_event_backend.
Pup_event_backend uses the 'udevd' daemon utility from the 'udev' package, together with original scripts and configuration files and GUI, that make this a very simple and easy-to-use system.
A very special feature of pup_event_backend is the automatic loading of firmware and associated setup when a module is first loaded.
Also, with our BootManager GUI we hope to avoid any need to open a text editor and edit Udev rules.
Please read this page first, then see the link on the bottom of this page to the "Event Management" page, which introduces pup_event_frontend.

Module loading at bootup

The following picture gives an idea of the bootup sequence, though this can vary as Puppy is very much a chameleon:
boot modules

Unless there is a full-install to hard drive, Puppy boots first in a "initial ramdisk" (now more correctly called an "initramfs") and the 'init' script executes. Puppy can be built in various ways, one of which is that all modules are present in the initramfs and then moved over to the main filesystem just before the 'switch_root' -- that is really a side issue as far as this page is concerned, as I want to focus on what happens after the 'switch_root', from the modules perspective.

There is a fundamental difference in how Puppy loads modules compared with any other distro. After the swich_root, the first script that executes is /etc/rc.d/rc.sysinit, and this is the key script to understand what is going on. Essentially, rc.sysinit starts the 'udevd' daemon program and then proceeds to manage loading of modules. The modules load, but before they execute 'modprobe' to actually load a module, that is where something different happens:

The first time a module is loaded, a check is made whether it has an associated "firmware tarball". If so, it is installed prior to the module actually loading.

There are no files to edit to enter arcane udev rules. Also, anything that a module might need to work properly is kept "out of the way" in a tarball until actually needed. So, you don't have scripts cluttering up /etc/init.d for example. It's very simple, you just put everything a module might need into the tarball, you edit one small file, /etc/modules/modules.firmware.<kernel version> that associates a module name with a tarball name.

However, before continuing with describing module loading from the user's perspective, a bit of in-depth on what is inside pup_event_backend:

pup_event_backend

Module loading at bootup (and when hotplugging) is managed in Puppy by a collection of executables and configuration files called the pup_event_backend. This picture outlines the files involved:
backend
That big blob outlines the files associated with pup_event_backend. /etc/rc.d/rc.sysinit is the first and main script that executes at bootup, and this starts /sbin/udevd which is a "daemon", that is, a program that once started will run continuously in the background. This daemon receives information about the computer hardware. At bootup this information is generated by the rc.sysinit script, and later on by "hotplug" events.

The udevd daemon receives information, called uevents, from the kernel, about hardware as it is discovered. The daemon processes these uevents and that may result in modules getting loaded. The actual "guts" of this processing is not udevd itself but scripts written especially for Puppy, named pup_event_backend_modprobe, pup_event_backend_firmware, etc.

The sequence of events is that when udevd receives a uevent from the kernel, it looks at its rules in /etc/udev/rules.d directory to find out if there are any special handling instructions for that uevent. If the uevent is of the type that is going to require a modue to be loaded, then the rules tell udevd to execute the Puppy script pup_event_backend_modprobe.

Now getting back to the installing of the firmware tarball. It is pup_event_backend_modprobe that takes care of this, installing the firmware. Now, what are these "firmware tarballs"?...

Firmware tarballs

A "firmware tarball" is not just firmware, it is anything that a module needs to work. This may also include an install script.

Example 1

When I compiled the 2.6.25.4 kernel, we hunted around and located any firmware that is needed by some modules, particularly the wireless neworking modules. Puppy Forum member 'tempestuous' found that the Libertas modules 'libertas_cs.ko', 'libertas_sdio.ko' and 'usb8xxx.ko' need some firmware files, which he located. So, I put them into Puppy like this:
/lib
/modules
/all-firmware/
libertas_firmware
/lib
/firmware/
libertas_cs.fw
libertas_cs_helper.fw
usb8388.bin

Well, this is done in Puppy Unleashed, the environment that we use to choose packages and build Puppy live-CDs. When the live-CD ISO file is built, the above is made into a tarball to make it small, that is:
/lib/modules/all-firmware/libertas_firmware.tar.gz
But, you can see, if that tarball is expanded at '/' then those firmware files will be installed into /lib/firmware. The file that makes the association between a module and its firmware tarball is /etc/modules/firmware.dep.<kernel version>, which in the case of the 2.6.25.4 kernel will be named 'firmware.dep.2.6.25.4'. I just added this line in the file:
libertas_firmware:libertas_cs.ko,libertas_sdio.ko,usb8xxx.ko
The boot script checks 'firmware.dep.2.625.4' to see if a module has an associated firmware tarball, if so it installs it and then "comments out" that line in  'firmware.dep.2.6.25.4' to ensure that installation only happens once. Then 'modprobe' is executed to load the module.

Example 2

Some modules need a script that has to run every time at bootup, some need a script to run just once to configure something, perhaps /etc/modprobe.conf. Some modules even have associated binary executables. Well, you just put them all into the tarball as required. The one special case is the one-time installation script. I'll use the Lucent analog modem module as example 2.
/lib
/modules
/all-firmware/
ltmodem
/etc
pinstall.ltmodem.sh
/init.d/
ltmodem

When I compiled the source code for the Lucent modem, I did of course follow the instructions. The docs explained that /etc/modprobe.conf needs this in it:
alias char-major-62 ltserial
alias /dev/ttyLT0 ltserial
One of the great beauties of this system is that we don't have to clutter up /etc/modprobe.conf with this in advance for all modules, as that can cause conflicts -- instead, these lines are only added to modprobe.conf if the Lucent module is loaded. The one-time install script is 'pinstall.ltmodem.sh' and I put this into it:
#!/bin/sh
grep "ltserial" /etc/modprobe.conf > /dev/null 2>&1
if [ $? -ne 0 ];then #=0 found.
echo "alias char-major-62 ltserial" >> /etc/modprobe.conf
echo "alias /dev/ttyLT0 ltserial" >> /etc/modprobe.conf
fi
Simple -- if you can understand basic Bash scripting, you can easily do this. Of course this is all done by us Puppy developers, so as a user you should never have to dip down into editing text files -- for the user, the Lucent modem will "just work" -- you boot Puppy, start PupDial the dialup program, and the modem is already setup ready to go! This page is outlining how that magic is achieved.

When Puppy boots, pup_event_backend take care of probing the hardware and loading the appropriate modules. This includes the Lucent module, if the matching modem hardware is detected. It's still not quite ready to be used though. What we wanted was a little script that would run at every bootup, and do this:
#!/bin/sh
[ -h /dev/modem ] && exit #if a modem found, quit...
[ ! $1 ] && exit
[ "$1" != "start" ] && exit
[ "`lsmod | grep '^ltserial'`" != "" ] && ln -snf ttyLT0 /dev/modem
What we wanted was if the boot scripts had not yet found a modem and linked /dev/modem to it, then if 'ltserial.ko' was loaded we wanted to link /dev/modem to /dev/ttyLT0. That was the reasoning, and above is the script, and I put it at /etc/init.d/lmodem so it will execute at every bootup.

It was a matter of thinking through what this Lucent module needed to make it work, then stick it all into a tarball in /lib/modules/all-firmware. In most cases it is pretty straightforward, just a matter of reading the docs that come with a source package and maybe finding the firmware.

To wrap up example 2, I also created an entry in /etc/modules/modules.dep.2.6.25.4:
ltmodem:ltserial.ko

Blacklist, overrides

You may need to have some control over what modules get loaded at bootup. Puppy has a very nice GUI application called the BootManager, that is found in the "System" menu.

The BootManager is a GUI for the configuration file /etc/rc.d/MODULESCONFIG, and you can see in the diagram above how this fits into pup_event_backend.

The BootManager can do many things. One of those is choose which modules to blacklist. There are various reasons why you would want to do this, such as two different modules loading for the same hardware but you only need one of them. Here is a picture:
blacklist manager

It is extremely simple to use. Note the reference to PupScan -- this is another application I wrote that displays useful information about modules. It is also a nice GUI. Run PupScan (also in the System menu) to find out what a module is for, in case you are in doubt whether it should be blacklisted or not.

On the otherhand, Puppy may have failed to detect a module that is required (hopefully unlikely!). Then you can use the BootManager to explicitly tell Puppy to load the module:
add list

Another very handy feature of the BootManager is to give preference to a particular module over another. For example, recently I tested a wireless networking interface that at first did not work -- the rt2500usb module was loaded and some research showed that it should have been the r73usb module.

Now, you might think, well, why not blacklist the rt2500usb module as described above? Yes, you could do, after having gone through all the hassles of having a non-functioning wireless and then searching the Internet for the solution. There is a better way, that causes the wireless interface to work first-go.

The problem with the rt2500usb and rt73usb modules is that they are both eligible for certain hardware. That is, when the pup_event_backend examines the wireless interface hardware it sees that both rt2500usb and rt73usb qualify to being used. This is a very specific situation -- most other wireless interfaces that use the rt2500usb or rt73usb modules do not have this overlap of both thinking they are eligible.

To cater for this specific situation, the BootManager has a "preferences list". Here it is:
preflist

The decision made here is that in case of conflicting eligibility, the rt73usb module is considered to be more mature and likely to work. Puppy comes preconfigured with this entry.

Hotplugging

Puppy is also able to load modules as-needed when new hardware is detected, and all of the above still applies.

Hotplugging, and event management in general, especially the complementary pup_event_frontend, is described in another page:

Puppy event management


(c) Copyright 2008 Barry Kauler, all rights reserved. puppylinux.com