Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Chapter 8.  Customizing a Kernel

One of the hardest parts of building your own version of the Linux kernel is determining exactly which drivers and configuration options are needed for your machine to work properly. This chapter will walk you through this process of finding and selecting the correct drivers.

Using a Distribution Kernel

One of the easiest ways to determine which modules are necessary is to start with the kernel configuration that comes with your distribution's kernel package. It is also much easier to determine which drivers are needed on a running system, where the proper drivers are already bound to the hardware.

If you do not already have a Linux distribution installed on the machine that you are building the kernel for, use a LiveCD version of a distribution. This allows you to boot Linux on the machine and determine what kernel configuration options are needed in order to get the hardware working properly.

Where Is the Kernel Configuration?

Almost all distributions provide the kernel configuration files as part of the distribution kernel package. Read the distribution-specific documentation for how to find these configurations. It is usually somewhere below the /usr/src/linux/ directory tree.

If the kernel configuration is hard to find, look in the kernel itself. Most distribution kernels are built to include the configuration within the /proc filesystem. To determine if this is true for your running kernel, enter:

$ 
ls /proc/config.gz

/proc/config.gz

If the /proc/config.gz filename is present, copy this file to your kernel source directory and uncompress it:

$ 
cp /proc/config.gz ~/linux/

$ 
cd ~/linux

$ 
gzip -dv config.gz

config.gz:       74.9% -- replaced with config

Copy this configuration file into your kernel directory and rename it to .config. Then use it as the basis of the kernel configuration to build the kernel as described in Chapter 5, Configuring and Building .

Using this configuration file should always generate a working kernel image for your machine. The disadvantage of this kernel image is that you will have built almost every kernel module and driver that is present in the kernel source tree. This is almost never needed for a single machine, so you can start to turn off different drivers and options that are not needed. It is recommended that you disable only those options that you are sure you do not need, as there might be parts of the system that rely on specific options to be enabled.

Finding Which Module Is Needed

A configuration file that comes from a distribution takes a very long time to build, because of all of the different drivers being built. You want to build only the drivers for the hardware that you have, which will save time on building the kernel, and allows you to build some or all of the drivers into the kernel itself, possibly saving a bit of memory, and on some architectures, making for a faster running system. To cut your drivers down, you need to determine which modules are needed to drive your hardware. We will walk though two examples of how to find out what driver is needed to control what piece of hardware.

Several locations on your system store useful information for determining which devices are bound to which drivers in a running kernel. The most important location is a virtual filesystem called sysfs. sysfs should always be mounted at the /sys location in your filesystem by the initialization scripts of your Linux distribution. sysfs provides a glimpse into how the different portions of the kernel are hooked together, with many different symlinks pointing all around the filesystem.

In all of the following examples, real sysfs paths and hardware types are shown. Your machine will be different, but the relative locations of information will be the same. Do not be alarmed if the file names in sysfs are different from your machine; it is to be expected.

Additional, the internal structure of the sysfs filesystem constantly changes around, due to the re-organization of devices and rethinking by the kernel developers about how to best display internal kernel structures to userspace. Because of this, over time, some of the symlinks previously mentioned in this chapter might not be present. However the information is all still there, just moved around a little bit.

Example: determining the network driver

One of the most common and important devices in the system is the network interface card. It is imperative to figure out which driver is controlling this device and enable it in your kernel configuration so that networking works properly.

First, work backward from the network connection name to find out which PCI device is controlling it. To do this, look at the different network names:

$ 
ls /sys/class/net/

eth0  eth1  eth2  lo

The lo directory represents the network loopback device, and is not attached to any real network device. The eth0, eth1, and eth2 directories are what you should pay attention to, as they represent real network devices.

To look further at these network devices in order to figure out which you care about, use the ifconfig utility:

$ 
/sbin/ifconfig -a

eth0      Link encap:Ethernet  HWaddr 00:12:3F:65:7D:C2  
          inet addr:192.168.0.13  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST NOTRAILERS RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2720792 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1815488 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100 
          RX bytes:3103826486 (2960.0 Mb)  TX bytes:371424066 (354.2 Mb)
          Base address:0xdcc0 Memory:dfee0000-dff00000 

eth1      Link encap:UNSPEC  HWaddr 80-65-00-12-7D-C2-3F-00-00-00-00-00-00-00-00-00  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

eth2      Link encap:UNSPEC  HWaddr 00-02-3C-04-11-09-D2-BA-00-00-00-00-00-00-00-00  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:60 errors:0 dropped:0 overruns:0 frame:0
          TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:13409 (13.0 Kb)  TX bytes:13409 (13.0 Kb)

From this list, you can tell that the eth0 device is the network device that is active and working, as can be seen by the lines:

eth0      Link encap:Ethernet  HWaddr 00:12:3F:65:7D:C2  
          inet addr:192.168.0.13  Bcast:192.168.0.255  Mask:255.255.255.0

These show this is an Ethernet device with valid IP (inet) address assigned to it.

Now that we have determined that we want to make sure the eth0 device will be working in our new kernel, we need to find which driver is controlling it. This is simply a matter of walking the different links in the sysfs filesystem, which can be done in a one-line command:

$ 
basename `readlink /sys/class/net/eth0/device/driver/module`

e1000

This shows that the module named e1000 is controlling the eth0 network device. The basename... command shown compresses the following steps into a single command line:

  1. Follow the /sys/class/net/eth0/device symlink into the directory within the /sys/device/ tree that contains the information for the device that controls eth0. Note that the /sys/class/net/eth0 directory might also be a symlink on the newer versions of the kernel.

  2. Within the directory that describes the device in sysfs, there is a symlink to the driver bound to this device. That symlink is called driver, so we follow that link.

  3. Within the directory that describes the driver in sysfs, there is a symlink to the module that this driver is contained within. That symlink is called module. We want the target of that symlink. To get the target, we use the readlink command, which produces output such as:

    $ 
    readlink /sys/class/net/eth0/device/driver/module
    
    ../../../../module/e1000
    

  4. As we care only about the name of the module, we want to strip the rest of the path off the output of the readlink command, and only save the rightmost portion. That is what the basename command does. Executed directly on a pathname, it would produce:

    $ 
    basename ../../../../module/e1000
    
    e1000
    

So we put the output of the long symlink traversal to the readlink location into the basename program, enabling the whole process to be done in one line.

Now that we have the module name, we need to find the kernel configuration option that controls it. You can look through the different network device configuration menus or search the kernel source code itself to make sure you have the right option:

$ 
cd ~/linux/linux-2.6.17.8

$ 
find -type f -name Makefile | xargs grep e1000

./drivers/net/Makefile:obj-$(CONFIG_E1000) += e1000/
./drivers/net/e1000/Makefile:obj-$(CONFIG_E1000) += e1000.o
./drivers/net/e1000/Makefile:e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o

Remember to replace the e1000 used for this example with the name of the module that you are looking to find.

The important thing to look for in the output of the previous find command is any line that has the term CONFIG_ in it. That is the configuration option that the kernel needs to have enabled in order to build the module. In the above example, the option CONFIG_E1000 is the configuration option that you are looking for.

Now you have the information you need to configure the kernel. Run the menu configuration tool:

$ 
make menuconfig

Then press the / key (which initiates a search) and type in the configuration option, minus the CONFIG_ portion of the string. This process is shown in Figure 8.1, “Searching in menuconfig”.

Figure 8.1. Searching in menuconfig

Searching in menuconfig

The kernel configuration system will then tell you exactly where to select the option to enable this module. See Figure 8.2, “Result of searching in menuconfig”.

Figure 8.2. Result of searching in menuconfig

Result of searching in menuconfig

The first item in the display exactly matches what you searched for. The location information in the display tells you that to build the module e1000 into the, kernel the following configuration option must be enabled:

Device Drivers
    Network device support
        [*] Network device support
            Ethernet (1000 Mbit)
	    [*] Intel(R) PRO/1000 Gigabit Ethernet support

These steps will work for any type of device active in the kernel.

Example: a USB device

As another example, let us look at a USB-to-serial converter that is present in our example system. It is currently connected to the /dev/ttyUSB0 port, so you need to look in the sysfs tty section:

$ 
ls /sys/class/tty/ | grep USB

ttyUSB0

You can trace through sysfs for this device to find the controlling module, as shown in the previous section:

$ 
basename `readlink /sys/class/tty/ttyUSB0/device/driver/module`

pl2303

Then search the kernel source tree to find the configuration option that you need to enable:

$ 
cd ~/linux/linux-2.6.17.8

$ 
find -type f -name Makefile | xargs grep pl2303

./drivers/usb/serial/Makefile:obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o

Use the kernel configuration tool, as shown in Figure 8.3, “Searching for USB_SERIAL_PL2303”, to find the proper option to enable in order to set the CONFIG_USB_SERIAL_PL2303 option.

Figure 8.3. Searching for USB_SERIAL_PL2303

Searching for USB_SERIAL_PL2303

In our case, this displays the screen shown in Figure 8.4, “Result of searching for USB_SERIAL_PL2303”.

Figure 8.4. Result of searching for USB_SERIAL_PL2303

Result of searching for USB_SERIAL_PL2303

This shows exactly where to find the USB Prolific 2303 Single Port Serial Driver option that is needed to control this device properly.

Summary of device discovery

In summary, here are the steps needed to find the driver for a device that has a working driver already bound to it:

  1. Find the proper sysfs class device that the device is bound to. Network devices are listed in /sys/class/net and tty devices in /sys/class/tty. Other types of devices are listed in other directories in /sys/class, depending on the type of device.

  2. Trace through the sysfs tree to find the module name that controls this device. It will be found in the /sys/class/ class_name/device_name /device/driver/module, and can be displayed using the readlink and basename applications:

    $ 
    basename `readlink /sys/class/
    class_name/device_name
    /device/driver/module`
    
    

  3. Search the kernel Makefiles for the CONFIG_ rule that builds this module name by using find and grep :

    $ 
    find -type f -name Makefile | xargs grep 
    module_name
    
    
    
    

  4. Search in the kernel configuration system for that configuration value and go to the location in the menu that it specifies to enable that driver to be built.

Let the kernel tell us what we need

Now that we have gone through all of the steps of poking around in sysfs and following symlinks to module names, here is a very simple script that will do all of that work, in a different way:

#!/bin/bash
#
# find_all_modules.sh
#
for i in `find /sys/ -name modalias -exec cat {} \;`; do
    /sbin/modprobe --config /dev/null --show-depends $i ;
done | rev | cut -f 1 -d '/' | rev | sort -u

This script goes through sysfs and finds all files called modalias. The modalias file contains the module alias that tells the modprobe command which module should be loaded to control this device. The module alias is made up of a combination of device manufacturer, ID, class type, and other unique identifiers for that specific type of device. All kernel driver modules have an internal list of devices that they support that is generated automatically by the list of devices the driver tells the kernel it supports. The modprobe looks through this list of devices by all drivers and tries to match it up with the alias it has. If it finds a match, it will then load the module (this procedure is how the automatic driver loading functionalty in Linux works.)

The script has the modprobe program stop before actually loading the module, and just print out what actions it would take. This gives us a list of all of the modules that are needed to control all devices in the system. A little cleaning up of the list, by sorting it and finding the proper field to display, results in this output:

$ 
find_all_modules.sh

8139cp.ko
8139too.ko
ehci-hcd.ko
firmware_class.ko
i2c-i801.ko
ieee80211.ko
ieee80211_crypt.ko
ipw2200.ko
mii.ko
mmc_core.ko
pcmcia_core.ko
rsrc_nonstatic.ko
sdhci.ko
snd-hda-codec.ko
snd-hda-intel.ko
snd-page-alloc.ko
snd-pcm.ko
snd-timer.ko
snd.ko
soundcore.ko
uhci-hcd.ko
usbcore.ko
yenta_socket.ko

This is a list of all of the modules that are needed to control the hardware in the machine.

The script will also probably print out some error messages that look like:

FATAL: Module pci:v00008086d00002592sv000010CFsd000012E2bc03sc00i00 not found.
FATAL: Module serio:ty01pr00id00ex00 not found.

Which means that it could not find a module that can control that device. Do not be concerned about this, as some devices do not have kernel drivers that will work for them.


 
 
  Published under the terms of the Creative Commons License Design by Interspire