Creating a Custom Linux Kernel in Debian GNU/Linux

The most current version of this document can be found at http://users.wowway.com/~zlinuxman/Kernel.htm.

Contents

Disclaimer
Maintenance Log
Introduction
Step 1: Update Your sources.list File
Step 2: Update the List of Available Packages
Step 3: Apply Pending Updates
Step 4: Install the Kernel Source Package
Step 5: Unpack the Kernel Sources
Step 6: Install kernel-package
Step 7: Patch the Kernel
Step 8: Configure the Kernel
Step 9: Create the Kernel Image Package
Step 10: Customize the Kernel Installation Environment
     Changing Boot Loaders
     Customizing the squeeze (6.0) Environment
     Customizing the wheezy (7.x) Environment
     Customizing the jessie Environment
Step 11: Install the Kernel Image Package
Step 12: Shutdown and Reboot
Step 13: Clean Up
Step 13a: Clean Up (Part Two)
Step 14: Maintenance
Alternatives
A Specific Example
Another Specific Example
Conclusion

Disclaimer

This is not an official Debian site.  The author is not a member of the Debian kernel team.  This is not an official Linux kernel site.  This document details the author's experiences and recommendations in building a custom Linux kernel under Debian GNU/Linux.  All opinions expressed are those of the author and do not necessarily represent the opinions or the official positions of Debian, the Linux kernel organization, or any other organization or individual.  This information is presented in the hope that it will be useful, but without any warranty or guarantee of any kind.  This information is presented free of charge, free of support, free of service, and free of liability.  Take this information with as many grains of salt as you think it's worth; and use it, if you choose to do so, entirely at your own risk.  The author hereby explicitly places this material in the public domain.  All trademarks, registered trademarks, service marks, etc. are the property of their respective owners.

Maintenance Log

Introduction

Most of the time, the stock kernel images obtained from Debian are adequate.  But occasionally one may need to create a custom kernel image in order to take advantage of some special feature or solve a particular problem.  Or you may want to create a custom kernel in order to create a "lean and mean" kernel: one which is as small as possible and contains only the code necessary to do the function assigned to this machine.  (This is often done in embedded systems.)  I assume that you already know why you need or want to build a custom kernel.  The purpose of this document is to show you how.  Most of my examples are from the i386 architecture, but the techniques are applicable to all architectures.

I had a roommate in college who had spent four years in the Navy.  He told me that in the Navy there are three ways to do everything: the right way, the wrong way, and the Navy way!  Well, kernel building in Debian is like that too.  Although there are similarities to other distributions, Debian definitely has its own way of building kernels.  Information that you may find on distribution-independent Linux sites or sites from non-Debian-based distributions that talk about building a custom kernel are not likely to be very useful in Debian.  Debian wants everything, including the kernel itself, to go through its package management system.  As a result, kernel building in Debian is quite different from other non-Debian-based distributions.

I have found that the documentation for kernel building in Debian is spread out over several different sources.  Some of these documents are out of date.  Furthermore, there are a number of small but important steps that are often left out.  This write-up is an attempt to document the procedure in detail.  In addition, this document shows how a custom kernel fits in with the overall lifecycle of upgrading and maintaining a Debian system.  If you're going to be running a custom kernel on an on-going basis, you need to know how to integrate the custom kernel with Debian maintenance procedures.

I am assuming that you have never downloaded or configured a kernel source package on your system before and that you want to create a custom kernel image package of the same kernel release as the stock kernel that you are currently running.  I'll be using kernel 3.2.60 from the wheezy (7.x) release and the i386 architecture in most of my examples, but as I said earlier the techniques are applicable to all releases and architectures.

If you're going to follow the procedures recommended in this document, your non-root user account must be enrolled in the "src" group.  For example,
 

     # adduser steve src

Make sure you do that before you start, and verify (by means of the "groups" command) that your non-root user account actually has the "src" group listed in the output of the "groups" command before you attempt to perform any of these steps using that account.  It used to be that once root enrolled a user in a new group, all instances of that user had to logout before a new login of that user would actually have the privileges of that group.  This included the graphical desktop environment, if that user logged into the graphical desktop.  In rare cases, such as hung processes, etc., one had to reboot after enrolling the non-root user in a new group before the output of the groups command issued by that user would show the new group as one of its groups.

However, with newer systems, this no longer appears to be the case.  It now appears that any session which existed prior to the new group being added will not have the privileges of the new group, but any new login session created after the privilege has been granted appears to have the privileges of the new group.  I'm not sure exactly when that change was made; so you'll have to follow one procedure or the other, depending on the age of your system.  The bottom line: do whatever it takes to get the output of the "groups" command issued by the non-root user to show the new group in its list of groups.

Also, make sure that the directory /usr/src is owned by user root and by group src, and that the group has read and write privileges on the directory.  Execute privileges on the directory should be granted to all users (user, group, and other).  Also, make sure that the "set-group-ID" file mode bit is set for the directory.  This can be checked by issuing "ls -ld /usr/src".  The "s" flag will show in the output.  For example:
 

     $ ls -ld /usr/src
     drwxrwsr-x 3 root src 4096 Aug 24 13:52 /usr/src

The lower-case letter "s" in the seventh position of the file attributes indicates that the "set-group-ID" file mode bit is set for the directory and that the group also has the execute privilege on the directory.  (An upper-case "S" in this position would indicate that the "set-group-ID" file mode bit is set for the directory, but that the execute privilege for the group is missing.)  This used to be the default, but this changed sometime during the squeeze (6.0) release.  If it is not set, set it using the following command:
 

     # chmod g+s /usr/src

(Any changes to the privileges on the /usr/src directory must be done by root.)  Once you select a non-root user account for kernel-building purposes, you must use that same userid for all non-root steps.

Step 1: Update Your sources.list File

Do this step as root.  The retrieval of packages in Debian is controlled by a file called /etc/apt/sources.list.  If you installed Debian from a CD-ROM, chances are that only the first CD is listed in the sources.list file.  If you have a complete set of CDs, but only the first one is listed, you need to update this file.  However, adding CDs to sources.list cannot be accomplished via a text editor.  Other files in other places must be updated too in order for a CD entry in sources.list to work.  To add new CDs to the sources.list file, use the following command:
 

     apt-cdrom add

You will need to issue this command once for every CD in your set that is not already listed in sources.list.  If you have several "disk 1" CDs in your set, don't scan the alternate ones.  For example, wheezy (7.x) ships with 4 "disk 1" CDs: one for a GNOME-based desktop environment, one for a KDE-based desktop environment, one for an LXDE-based desktop environment, and one for an XFCE-based desktop environment.  The GNOME-based one is considered the "standard" disk 1 CD.  If you installed from the GNOME version of disk 1, it is the one listed in your sources.list file.  Don't scan any of the other three "disk 1" CDs with apt-cdrom.  Each time you run apt-cdrom, it will prompt you to insert a CD and press Enter.  After you do this, it will mount the CD, scan the CD looking for package information, then umount the CD.  It will then update /etc/apt/sources.list.  When the command completes, remove the CD from the CD drive.  apt-cdrom is also used if you have installed from DVDs or Blu-ray disks.  (Of course, there will be far fewer DVDs or Blu-ray disks in a complete set than there are for a complete set of CDs, since a DVD or Blu-ray disk holds much more data per disk.)

When running a graphical desktop environment, such as GNOME, the udisks daemon may give you trouble.  The udisks daemon tries to auto-mount any data CD inserted in the CD drive while it is running and interferes with CD mounting and unmounting by apt-cdrom.  (Later, it will also interfere with CD mounting and unmounting by apt-get.)  If you are having this problem, you need to disable auto-mounting in some way.  One way to do this is to shutdown and reboot, do not login to the graphical desktop at all, and do your system administration from a text console.  (udisks-daemon is not normally running in this environment.)  Another possibility is to temporarily disable polling while you're doing your work.  In one terminal session, issue
 

     udisks --inhibit-polling /dev/sr0

(I am assuming here that /dev/sr0 is the block special file name of your CD drive, or a symbolic link to the block special file name of your CD drive.  If not, substitute the appropriate device name.)  Don't wait for the command to complete.  It will never complete.  Then, while the command is running, switch to another terminal session and do your work.  When finished, including removal of the last CD from the CD drive, switch back to the terminal session running udisks and type ^C (Ctrl+C) to cancel the udisks command.  If you don't have any mountable media sources listed in /etc/apt/sources.list, and you don't plan to add any with apt-cdrom, you don't need to worry about this problem.

If you have access to the internet, you should also include an internet server in sources.list.  This is true even if you installed Debian from CDs.  You should also make sure that the updates and security sites are present as well.  Updates takes the place of the old volatile site.  (The updates and security sites should only be used if you are running the stable release.)  If you didn't have access to the internet during installation, the installer may have included such entries, but commented them out.  If you have access to the internet now, but you didn't during installation, uncomment these entries.  This will allow you to install the most recent version of a package, if there is a newer version than the one on the CD.

Packages in the stable release are not normally updated during the life of the release except to fix bugs involving security vulnerabilities or to replace data that is highly volatile in nature.  Examples are a security vulnerability in openssl or updated virus signature data for an anti-virus software package.  Occasionally some "safe" fixes are also introduced.  These are important fixes which have been well tested and are extremely unlikely to cause any forward compatibility issues.  (Well, that's the theory anyway.)  An example is support for newer hardware.  These fixes are introduced from time to time as "stable point releases."  You might also want to add entries for the "non-free" and "contrib" sections of the archive, in addition to the "main" section.  Official CDs contain only the "main" section.

With the exception of the security site, which must use HTTP, you have a choice, for most of the Debian mirrors, whether to use HTTP or FTP as the file transfer protocol.  Be careful though — some of the mirrors use a different path name for HTTP and FTP.  For a full list of Debian mirrors, see http://www.debian.org/mirror/list.  Choose the mirror nearest to you or which gives you the shortest latency or the highest data transfer rate.  Make sure you choose a mirror which supports the file transfer method you want to use and specify the correct path for that type of file transfer.  Also, make sure that you choose a mirror that mirrors your machine architecture.  (Not all mirrors mirror all architectures!)  For more information, see the man page for sources.list(5) and the above-mentioned web page which lists all the mirrors.  For all sources except CDs, DVDs, and Blu-ray disks, the sources.list file can and should be edited by a text editor.  Make sure that the internet sources are listed after the CD/DVD/Blu-ray sources, and make sure that the security source is listed last.  Here is a sample sources.list file for a system running the current stable release, wheezy (7.x):
 

     .
     . (possible CD/DVD/Blu-ray entries added by apt-cdrom)
     .
     deb ftp://carroll.aset.psu.edu/pub/linux/distributions/debian wheezy main non-free contrib
     deb-src ftp://carroll.aset.psu.edu/pub/linux/distributions/debian wheezy main non-free contrib
     deb ftp://carroll.aset.psu.edu/pub/linux/distributions/debian wheezy-updates main non-free contrib
     deb-src ftp://carroll.aset.psu.edu/pub/linux/distributions/debian wheezy-updates main non-free contrib
     deb http://security.debian.org wheezy/updates main non-free contrib
     deb-src http://security.debian.org wheezy/updates main non-free contrib

The "deb" entries specify a server for binary packages and the "deb-src" entries specify a server for source packages.  Penn State's Debian mirror site has been selected for both package types, using the FTP protocol.  Only packages from the wheezy (7.x) distribution will be selected, but the "non-free" and "contrib" sections have been added to the standard "main" section.  wheezy-updates has been added also.  This takes the place of what used to be called the "volatile" site.  The standard Debian security server has been added at the end, using the HTTP protocol.

Note: always use a release code name, such as wheezy, jessie, etc., rather than a status, such as stable, testing, etc., in /etc/apt/sources.list.  The reason for this is that nasty things will happen when a new release comes out if you code a status.  For example, suppose you used "stable" in your /etc/apt/sources.list file back when squeeze (6.0) was the stable release.  The result will be an attempted release upgrade from squeeze (6.0) to wheezy (7.x) at the next "apt-get update" / "apt-get upgrade" / "apt-get dist-upgrade" sequence following wheezy (7.x) becoming the stable release.  That is not the proper way to do a release upgrade.  See the Debian "release notes" for the release to which you wish to migrate for the proper way to do a release upgrade.

Sometimes you may need to define multiple releases in your sources.list file.  For example, you are running the testing release; but you need at least one package from unstable (or maybe even experimental).  In particular, if you need or want to fetch kernel source code that is newer than the newest source code available in your current release, you will need to define multiple releases in sources.list.  Here is a sample sources.list file for a system which is running the current testing release (jessie) but that also needs one or more packages from the unstable release (sid) or experimental:
 

     .
     . (possible CD/DVD/Blu-ray entries added by apt-cdrom)
     .
     deb ftp://carroll.aset.psu.edu/pub/linux/distributions/debian jessie main non-free contrib
     deb-src ftp://carroll.aset.psu.edu/pub/linux/distributions/debian jessie main non-free contrib
     deb ftp://carroll.aset.psu.edu/pub/linux/distributions/debian sid main non-free contrib
     deb-src ftp://carroll.aset.psu.edu/pub/linux/distributions/debian sid main non-free contrib
     deb ftp://carroll.aset.psu.edu/pub/linux/distributions/debian experimental main non-free contrib
     deb-src ftp://carroll.aset.psu.edu/pub/linux/distributions/debian experimental main non-free contrib

Once again note that status names (testing, unstable, etc.) are not used: release code names (jessie, sid, etc.) are used instead.  Also note that the updates site (jessie-updates) is not used, since jessie is not yet the stable release.  The security site is absent also, for the same reason.  Also note that the "non-free" and "contrib" sections of the archive have been added to the standard "main" section for all defined repositories.

When mixing releases in the same system, it is important to define the default release.  You do this in /etc/apt/apt.conf.  Put a line such as the following in the above-named file:
 

     APT::Default-Release "jessie";

This will cause apt-get to give priority to the jessie release.  A package which exists in jessie and also in another defined release, such as sid or experimental, will be fetched from jessie, even if a newer version of the package exists in another release, unless (1) a specific target release or package version is specified in the command; or (2) a newer version of the package than is available in the default release is needed to satisfy a package dependency relationship; or (3) the currently installed version of a package is already newer than the version of the package in the default release.  (apt-get will not downgrade a package.)

Note: synaptic does not understand or honor this definition of a default release.  In synaptic you set the default release with Settings -> Preferences, click on the Distribution tab, select the radio button next to "Prefer versions from:", then select your default release from the drop-down menu.  I'd avoid using synaptic if I were you.  My advice, for what it's worth, is to stick with apt-get to do all your installs and upgrades.

Once jessie becomes the stable release, the sid and experimental entries should be deleted, the updates and security entries should be added, and the definition of the default release should be deleted.

Step 2: Update the List of Available Packages

Do this step as root.  Once the sources.list file has been updated, you need to update the package management system's list of available packages.  I recommend "apt-get update" for this purpose.

Step 3: Apply Pending Updates

Do this step as root.  After updating the list of available packages, as outlined above, you should apply all the pending updates that have accumulated since you last applied updates (or since installation, if you have never applied updates).  To do this, enter the following commands:
 

     apt-get upgrade
     apt-get clean
     apt-get --purge dist-upgrade
     apt-get clean
     apt-get --purge autoremove
     aptitude forget-new
     aptitude keep-all

The first command will apply all upgrades that are possible without installing any new packages or removing old ones.  The second command deletes package files downloaded from the internet from the package cache (/var/cache/apt/archives).  The third command does not have the restrictions of the first command.  It will allow new packages to be installed or old packages to be removed, if necessary, in order to upgrade existing packages.  The --purge option specifies that any packages which are removed will also be purged.  In theory, the first and second commands are redundant, if they are going to be followed by the third and fourth commands.  In practice, there are fewer upgrade problems if you do it this way.  The fourth command cleans up the package cache again.  The fifth command removes (and purges, due to the --purge option) any packages which are marked as automatically installed but which are no longer required by any currently installed package.  The last two commands keep aptitude's database in sync with changes made by apt-get.  I used to recommend aptitude to upgrade the system, but I don't anymore.  The main reason for this is that apt-get maintains the "recommends" dependency relationships during an upgrade, but aptitude does not.

aptitude does have its uses though.  In particular, the interactive mode of aptitude (full-screen terminal required), which is entered when aptitude is invoked with no arguments, is useful for identifying obsolete packages.  An obsolete package is a package which is currently installed, but which is no longer present in the Debian archive.  You should consider removing (and purging) obsolete packages, even if they were not automatically installed.  If you install, remove, or purge a package with apt-get or dpkg, you should do an "aptitude keep-all" afterwards to resync the database.

Note: whenever you apply updates, as per above, and you have more than one kernel image package installed, watch the console output carefully to see if an initial RAM file system image file gets rebuilt; and if it does, check to see if the initial RAM file system image file that got rebuilt is the one that corresponds to your running kernel.  This is especially important if you are using MODULES=dep in /etc/initramfs-tools/initramfs.conf or /etc/initramfs-tools/conf.d/driver-policy.  Normally, the initial RAM file system image file that gets rebuilt under these circumstances is the one which sorts highest in the ASCII collating sequence for all the currently-installed kernels that have an initial RAM file system image file.  In any case, the one it picks to rebuild is not necessarily the one which corresponds to your running kernel; and that can cause problems.

As an example, suppose that you have two kernels installed: 2.6.32-3-686 and 2.6.32-5-686.  You have a traditional IDE hard disk.  You have "MODULES=dep" specified in /etc/initramfs-tools/conf.d/driver-policy.  You are currently running the 2.6.32-3-686 kernel.  You run "apt-get upgrade", which causes "update-initramfs -u" (without the "-k" option) to be run.  The initial RAM file system image file for the 2.6.32-5 kernel will likely be re-built while you are running the 2.6.32-3 kernel.  This is known as "cross-building" an initial RAM file system image file, and it should be avoided if you are using MODULES=dep.  Since these two kernels use different drivers for your IDE hard disk, chances are that the 2.6.32-5 kernel will no longer boot!

If you apply maintenance and it causes the initial RAM file system image file for your running kernel to be re-built, shutdown and boot the other installed kernel images in turn and rebuild their initial RAM file system image files with
 

     update-initramfs -u -k $(uname -r)

Continue the process until all the initial RAM file system image files have been rebuilt while running the corresponding kernel.

If the maintenance causes a cross-build of an initial RAM file system image file, and you are using MODULES=dep; first rebuild the correct initial RAM file system image file (i.e. the initial RAM file system image file for your running kernel) by issuing
 

     update-initramfs -u -k $(uname -r)

Then change MODULES=dep to MODULES=most, cross-build the same initial RAM file system image file again that was cross-built the first time, then shutdown and boot that kernel.  After the reboot, change MODULES=most back to MODULES=dep and rebuild the initial RAM file system image file for that kernel again.  If there are any other installed kernels besides these two, shutdown and boot each of the remaining kernels in turn, rebuilding their initial RAM file system image files while the corresponding kernel is running.

In any case, whenever an initial RAM file system image file is rebuilt as the result of applying updates, and you have more than one kernel image package installed, you must take care to rebuild all of the remaining initial RAM file system image files manually.  The exact procedure to use will depend on the circumstances.  If you are installing a new kernel and you are using MODULES=dep, it is safest to use MODULES=most initially, then re-build with MODULES=dep after you are running that kernel.

The Debian maintenance system is supposed to be smart enough to know when an initial RAM file system image needs to be rebuilt and to do so automatically.  However, there have been times, when running "apt-get upgrade" or "apt-get dist-upgrade", that I have seen packages serviced that I was fairly sure were in the initial RAM file system; but the initial RAM file system image did not get automatically rebuilt.  This is especially true if you have user-defined initramfs-tools hook scripts.  Lately I have gotten into the habit of manually rebuilding the initial RAM file system image file after applying maintenance — just in case.  (Unless, of course, it was rebuilt automatically during the application of maintenance.)  I think this is a good idea.  It never hurts to rebuild the initial RAM file system image file, and it might help.

I recommend that you subscribe to three mailing lists if you are running the current stable release.  They will tell you when updates are made.  The first is the debian-security-announce mailing list.  This informs you of security-related updates.  The second is the debian-stable-announce mailing list.  This informs you of updates to volatile packages, such as a new virus signature file for an anti-virus software package or new time zone data due to changes to time zones or Daylight Saving Time observance practices.  The third is the debian-announce mailing list, which will inform you of new stable point releases.  When you get one of these announcements, wait a day or two for the updates to propagate to all mirrors, including the one you use, then update the list of packages again with "apt-get update".  Then use the procedure above to apply the updates.  If you are running the testing release or the unstable release, you should do this regularly, since updates are not generally announced.  Once the updates have been installed, it is a good idea to shutdown and reboot.  This is especially true if the kernel has been serviced or an initial RAM file system image has been rebuilt.

Note: only package files downloaded from the internet end up in the package cache.  Package files read from CD-ROM, DVD, or Blu-ray disks are not staged to the package cache but are processed directly from the mountable media.

Note: if you are running the testing or unstable releases, "apt-get upgrade" or "apt-get dist-upgrade" can sometimes cause problems.  Different components that have dependencies on each other are often worked on by different developers and are not necessarily updated at the same time.  Or, two packages which must coordinate with each other are uploaded to sid at the same time, but one migrates to testing and the other doesn't, due to a bug.  There are various techniques available to work around these problems, such as postponing updates, manually installing or removing certain packages, etc.  A full discussion of these maintenance techniques is beyond the scope of this document.

Step 4: Install the Kernel Source Package

Do this step as root.  Once you have updated the list of available packages with "apt-get update", you will be able to install any package which is available in any release defined in the /etc/apt/sources.list file.  Normally, you will want to install the kernel source code for the stock kernel that you are currently running.  If you don't know what kernel you're currently running, you can find out by issuing the command:
 

     uname -r

Use apt-cache to list the available kernel source packages that you can install.  For example,
 

     apt-cache -n search linux-source-

To install the package, use apt-get.  For example,
 

     apt-get install linux-source-3.2

This will install the kernel source code.  (Although it is kernel source, it is classified as a "binary" package in the Debian packaging system; therefore, you must be root to install it.)

You can obtain kernel source code packages from other places, such as pristine kernel source tarballs from kernel.org or one of its mirrors; but I recommend using official Debian kernel source packages whenever possible because they contain all of the Debian-specific modifications.  Another advantage to using a Debian package is that you will automatically get the package dependencies.  However, under certain circumstances, you may need to download the very latest pristine kernel source code, such as when testing a fix written by the kernel people for a problem you reported.  When manually downloading a pristine kernel source tarball, do so as the non-root user and download to directory /usr/src.

If you have out-of-kernel-source-tree kernel module source packages to install, do that at this time also.  (If you don't know what an out-of-kernel-source-tree kernel module source package is, you probably don't need one; so don't worry about it at this point.)  Once these commands have completed, enter
 

     apt-get clean

to delete the package files (.deb files) from the package cache.  A kernel source package file is huge; so this is important to save disk space.  (Obviously, you don't need to issue "apt-get clean" if you only downloaded a pristine kernel source tarball from kernel.org or one of its mirrors.  You also don't need to to issue "apt-get clean" if all the installed packages came from CD-ROM, DVD, or Blu-ray disks.)

Step 5: Unpack the Kernel Sources

Do this step as a non-root user.  Use the same userid for all non-root steps.  The non-root user must be a member of group "src".  So what did "apt-get install linux-source-3.2" just do?  If everything worked correctly, you should now have a file in the /usr/src directory that starts out as "linux-source" and ends in ".tar.bz2".  (Newer kernels end in ".tar.xz".  That will be covered later.)  It is at this point that some people make a mistake.  They create a directory in /usr/src called linux-source-3.2, move the kernel source tar file to that directory, then unpack the tar file from there.  Don't do that.  If you do, you will end up with two levels of directory called linux-source-3.2.  Instead, change directories to /usr/src and unpack the kernel sources right where they are.  For example:
 

     cd /usr/src
     tar -xj -f linux-source-3.2.tar.bz2

The "x" switch of tar indicates that the "extract" function will be used.  The "j" switch tells tar to filter the archive through bunzip2 to decompress the archive first, before tar itself processes the file.  And finally, the "f" switch specifies that input is to be read from a file specified on the command line, instead of standard input.

The above "tar" command will create a directory under the current directory (/usr/src) called linux-source-3.2.  All the kernel source code and associated files will be unpacked to this directory and its subdirectories.  Strictly speaking, one is not supposed to erase a file belonging to an installed package.  But once the archive has been unpacked, there's really no use in keeping it around.  I recommend getting rid of it.  This saves some more disk space.  I suppose the "right" way to do it would be to purge the package; but then you won't get updates for it, which you want.  So my approach is to simply delete the tar file once it has been unpacked.  Another advantage to deleting the tar file once it has been unpacked is that it is easier to tell when an "apt-get upgrade" or "apt-get dist-upgrade" command has resulted in an updated source package being installed.  If you make a habit of deleting the tar file after unpacking it, then if you discover a tar file in the /usr/src directory, you will know that an updated source package has been installed.  (And therefore, you need to rebuild your custom kernel.)
 

     rm -f linux-source-3.2.tar.bz2

Note: The -f option in the above command is necessary because the file is considered "write-protected".  It is considered write-protected because you are neither the file owner (root), nor a member of the group which owns the file (root).  You can still delete it because you are a member of the group which owns the directory (src), and the group has write privileges on the directory.  However, the -f option is required under these circumstances.  If you forget to use the -f option, you will be prompted with, "Are you sure you want to delete a write-protected file?", or words to that effect.  Reply with a "y", and it will let you delete it.

Recent official Debian Linux kernel source packages for wheezy (7.x) now also install another file in /usr/src besides the source tarball.  For example, package linux-source-3.2 now installs files linux-source-3.2.tar.bz2 and linux-patch-3.2-rt.patch.bz2.  The first file is the standard source tarball; the second is a compressed patch file which you can apply to the kernel source if you want your custom kernel to be capable of real-time preemption.  (It should be noted, however, that these patches have historically been released only for even-numbered minor release numbers, such as 3.0.x, 3.2.x, 3.4.x, etc.  Also, real-time preemption is supported only for the i386 (686-pae) and amd64 architectures.)  If you want to incorporate the patch file into your kernel source, then issue the following sequence of commands after unpacking your kernel source code:
 

     cd /usr/src
     bunzip2 linux-patch-3.2-rt.patch.bz2
     cd linux-source-3.2
     patch -p1 <../linux-patch-3.2-rt.patch
     cd ..
     rm linux-patch-3.2-rt.patch

The bunzip2 command will create the file linux-patch-3.2-rt.patch and will also erase the source file, linux-patch-3.2-rt.patch.bz2.  (If you do not wish to apply the patch, simply erase the compressed patch file instead.  The "-f" option of the "rm" command will once again be required.)

Starting with Debian package linux-source-3.10, available in jessie and sid, a different compression format is used: the xz format.  The source tarball will have a file name ending in .tar.xz instead of ending in .tar.bz2.  Make sure you have the xz-utils package installed to deal with this compression format.  The real time preemption patch file, if present, may be decompressed by using the unxz command.  If you receive an error message from unxz about not being able to set the group, ignore it.  Newer versions of tar support decompressing the xz format by using an upper-case "J" switch instead of the lower-case "j" switch, which is used to decompress bz2 format.  For example,
 

     tar -xJ -f linux-source-3.10.tar.xz

If your version of tar does not support the -J switch, you can do the decompression and extraction as two separate steps.  For example,
 

     unxz linux-source-3.10.tar.xz
     tar -x -f linux-source-3.10.tar

Alternatively, you can use a pipeline to avoid creating an intermediate file.  For example,
 

     xz -dc linux-source-3.10.tar.xz|tar -x -f -

If you have installed out-of-kernel-source-tree kernel module source packages, their tar files will also be present in /usr/src.  Unpack them also in a similar manner and then delete the tar files once they have been successfully unpacked.  These tar files will be extracted to a directory under /usr/src/modules.

Step 6: Install kernel-package

Do this step as root.  If you have not already done so, install the "kernel-package" package.  You can check to see if it is already installed by using
 

     dpkg-query -l kernel-package|grep ii

If it is not already installed, install it. 
 

     apt-get install kernel-package

Under jessie, you might want to consider using the --no-install-recommends option of apt-get when installing kernel-package, since the jessie version of kernel-package now brings in a boat load of extra packages that you don't need to compile a kernel.  And some of them take up a lot of disk space.  For example, do you really need complete documentation for latex in order to compile a kernel?  I don't think so.  I hope that some further consideration is given to the recommendations.

Read the README file for kernel-package.
 

     zless /usr/share/doc/kernel-package/README.gz

Determine what additional packages you may need, assuming that you are going to use "make menuconfig".  Since there are a number of different kernel configuration methods (config, menuconfig, xconfig, etc.), and since kernel-package doesn't know which one you plan to use, it does not mark anything as a prerequisite unless it is a prerequisite for all configuration methods.  Also, depending on how the kernel is configured, additional packages may be needed to compile the kernel and build a kernel image package.  kernel-package does not make these packages a dependency either, since they aren't always required.  Finally, some packages are required only for some architectures, and these are not dependencies of kernel-package either.  At the time of this writing, the following packages will be required for the menuconfig method under Debian squeeze (6.0) and later releases:
 

     gcc (This is actually a dependency package which brings in the real one)
     libc6-dev
     libncurses5-dev
     binutils
     make
     module-init-tools (or kmod in wheezy (7.x) and newer releases)
     mawk | gawk (one or the other, you don't need both)
     gzip
     coreutils
     grep
     zlib1g-dev (if CONFIG_LGUEST is set)
     fakeroot (if building the kernel as a non-root user)

(Note: bin86 used to be required to compile the kernel for the i386 architecture, but as of kernel releases 2.4.x and later, bin86 is no longer required.)  Many of these packages will already be installed.  To check to see if these packages are installed, use dpkg-query.  For example:
 

     dpkg-query -l gcc|grep ii

Install those packages which you need with "apt-get install".  For example:
 

     apt-get install libncurses5-dev zlib1g-dev
     apt-get clean

There may also be some packages needed to install the kernel image package once it has been built.  For example, you may need initramfs-tools to build the initial RAM file system image file during kernel image package installation.  (But it should be installed already.)

At this point I recommend that you edit the kernel-package config file (/etc/kernel-pkg.conf) and change the "maintainer" and "email" tags to your own name and e-mail address.

A new official Debian port was added between squeeze and wheezy: s390x.  s390x is a full 64-bit IBM mainframe port, both kernel space and user space.  The earlier s390 port provided a 64-bit kernel space, but user space was still 32-bit.  (It's called 32-bit because of the size of the registers, even though it only uses 31-bit addressing.)  The s390 port is provided in wheezy for the last time: it has been discontinued in jessie.  The s390x port is available in wheezy for the first time and is also available in jessie. 

kernel-package in wheezy does not provide official support for the s390x port.  The jessie version attempted to add s390x support, but it didn't quite work.  (See Debian bug report 751928 for details.)  To add s390x support in the wheezy version of kernel-package, use this patch;  to fix the s390x support in the jessie version of kernel-package, use this patch.  As root, copy the applicable patch to the /usr/share/kernel-package directory, then apply the patch.  For example,
 

     cd /usr/share/kernel-package
     [download the patch with your browser]
     patch -p1 <add-s390x-support.patch

Step 7: Patch the Kernel

Do this step as a non-root user.  Use the same userid for all non-root steps.  The non-root user must be a member of group "src".  At this point, apply any patches to the kernel source code that are needed or desired for your custom kernel.  If you have any patches to apply to out-of-kernel-source-tree kernel module source packages, apply them at this time as well.

As an example, here is a patch that I used to run on my custom kernel: edid_strict.diff.  This patch allows monitors with invalid EDID check sums or EDID version numbers, but which otherwise have usable EDID data in them, to be used with Linux, despite the failure to strictly comply with the EDID standard.  (It only works with KMS-based drivers.)  In particular, it allows a Future Power 17DB77 CRT monitor to be used at 1024x768 resolution with an 85 Hz vertical refresh rate (non-interlaced).  Without this patch, a 60Hz vertical refresh rate (non-interlaced) was the best I could get out of it.  Even then, I got errors written to /var/log/syslog about every 10 seconds, which will fill up the hard drive eventually, if the system stays up long enough.  With the patch, I get error messages written to /var/log/syslog during boot; but ongoing error messages every ten seconds disappears.

Here's how to use the patch.  Download the patch to a file in the /usr/src directory.  Give it a meaningful name.  I called it edid_strict.diff on my system. 

Now apply the patch:
 

     cd /usr/src/linux-source-3.2
     patch -p1 <../edid_strict.diff

Now create a file in /etc/modprobe.d called local.conf.  (You'll have to create this file as root.)  Put the following line in it:
 

     options drm edid_strict=0

Save the file and exit the editor.  I hope that someday this patch, or something similar to it, will be incorporated into the official kernel; but in the mean time, you can add this support yourself by patching the kernel source code and building a custom kernel.

Step 8: Configure the Kernel

Do this step as a non-root user.  Use the same userid for all non-root steps.  The non-root user must be a member of group "src".  First, change directories to the home directory for the source code.
 

     cd /usr/src/linux-source-3.2

Now, initialize the .config file based on the configuration file used by the stock Debian kernel.
 

     cp /boot/config-3.2.0-4-686-pae .config

This means that if you make no changes, your custom kernel will be configured exactly like the stock Debian kernel.  Obviously, adjust the name of the config file to copy based on your architecture and kernel release.  The file you need will start with "config" and will have your kernel version name in it.

Note: this assumes that you have installed the kernel source code for one of the stock kernels that is currently installed.  I don't recommend that you migrate to a new kernel release this way.  Don't use a config file from one kernel release as the basis for customization of a different kernel release (unless the kernel source is newer than the config file and you follow-up with "make oldconfig").  If you can't get a copy of a stock kernel config file for the same release as your source code, and you can't, or don't want to, run "make oldconfig", then don't initialize the .config file at all.  Also, if you're using a recent wheezy (7.x) kernel source code package (or newer releases) and you have applied the patches for real-time preemption, make sure that the config file you copy is from a stock kernel that has "-rt" in its package name, such as config-3.2.0-4-rt-686-pae.  If it's not, then you will need to run "make oldconfig" afterwards to add the options for preemtable kernels.

Similarly, if you're using a recent wheezy (7.x) kernel source code package (or newer releases) and you have not applied the patches for real-time preemption, make sure that the config file you copy is from a stock kernel that does not have "-rt" in its package name.  If it does, I'm not sure if "make oldconfig" can fix the problem in this case.  "make oldconfig" was designed to upgrade an older config file to a newer kernel, not downgrade a newer config file to an older kernel.

Starting with Debian package linux-source-3.10, installing the kernel source package now creates a new directory in /usr/src called linux-config-3.10, which contains xz-compressed config files for each architecture supported by the Linux kernel.  This means that you don't have to install the stock kernel which corresponds to the source package in order to get a copy of its config file.  Instead, you just have to copy the right file from the linux-config-3.10 directory.  For example,
 

     cd /usr/src
     cp linux-config-3.10/config.i386_rt_686-pae.xz .
     unxz config.i386_rt_686-pae.xz
     cp config.i386_rt_686-pae linux-source-3.10/.config
     rm config.i386_rt_686-pae
     cd linux-source-3.10

Now it's time to configure the kernel:
 

     make menuconfig

After some preliminaries, an ncurses-based full-screen application will be launched that allows you to configure the kernel.  I assume that you know what to do here.  (Obviously this is going to require that you are using a full-screen terminal.  Don't try this on a pure line-mode device, such as a teletype machine or something analogous to it.  On systems which do not have a full-screen console, such as s390/s390x, login via a remote ssh client to perform this step.)

Note: In the process of configuring your kernel, make sure that you leave CONFIG_BLK_DEV_INITRD set to Y, which is the default.  This is listed under "General Setup" as "Initial RAM file system and RAM disk (initramfs/initrd) support".  You're probably going to need that.  I'll have more to say about that later.

Note: Newer kernel config files contain some settings that you should not use.  These include CONFIG_LOCALVERSION (Local version - append to kernel release) and CONFIG_LOCALVERSION_AUTO (Automatically append version information to the version string).  These are found under "General Setup".  make-kpkg has its own way of specifying this information.  I'll have more to say about that later.

Note: even if you do not plan to change the kernel configuration file copied from the /boot directory at all, you must still run "make menuconfig".  make-kpkg relies on certain files that are created when you run "make menuconfig".  If you don't wish to change anything, immediately select "Exit" when the initial screen is displayed.

It used to be a real pain to create a "lean and mean" custom kernel: one which only contains the function necessary to execute on your specific machine.  It can easily take all day to customize the kernel configuration to get everything you need but nothing that you don't need, and it is easy to leave something out that you need but don't realize that you need.  However, starting with kernel version 2.6.32, a new kernel configuration option is available called "make localmodconfig".  Initialize the .config file, either by copying it from the stock kernel config file in /boot or by running "make menuconfig" with no previous .config file, then run the preceding command. It runs "lsmod" to find all the modules loaded on the currently running system.  It will then read all the Makefiles to map which CONFIG enables which module.  It will then read the Kconfig files to find the dependencies and selects that may be needed to support a CONFIG.  Finally, it reads the .config file and removes any module ("=m") that is not needed to enable the currently loaded modules.  With this tool, you can strip the .config file of all drivers which are not useful in your machine, and it will take much less time to build the kernel.  80% compile time reduction seems to be typical, depending on the architecture.  Architectures with more drivers available obviously yield more compile time savings.

Of course, before you run this, you should plug in and turn on all peripheral equipment that you ever plan to use with this machine but which is not always connected.  For example, if you have an external USB CD-ROM drive that is not always attached, be sure it is connected and active at the time you run "make localmodconfig".  Otherwise, you may not have support in your kernel for this device.  You can then run "make menuconfig" afterwards to fine tune the configuration file created by "make localmodconfig".  There is also a "make localyesconfig" command which will try to build the needed support directly into the kernel, if it can, instead of having the support in a module.

Of course there is a down side to building a "lean and mean" kernel: if you subsequently reconfigure your system, such as changing video cards, network adapters, sound cards, etc., there will likely be no support in your previously-built kernel for the new hardware.  This is a trade-off you will have to weigh and decide what's most important to you.

Unless you specifically intend to debug the kernel, I recommend that you set CONFIG_DEBUG_INFO to N (i.e. leave it unset).  (This option is under "Kernel Hacking" and is listed as "Compile the kernel with debug info".  Starting with 3.11 kernel releases, this option is in a submenu under "Kernel Hacking" called "Compile-time checks and compiler options".)  Setting this option makes the kernel and modules much larger and provides no benefit under ordinary operating conditions.  Setting it to N (i.e. leaving it unset) greatly reduces the size of the kernel and its modules.

If you build your kernel with make-kpkg, make-kpkg somewhat mitigates the damage of having CONFIG_DEBUG_INFO set by setting make variable INSTALL_MOD_STRIP to 1 before invoking the modules_install step.  If you really need the debugging symbols for the modules, add the kernel_debug target to the end of the make-kpkg command.  This will produce a separate package which contains the debugging symbols.  If you are using "make deb-pkg", you can manually pass the INSTALL_MOD_STRIP=1 make variable to "make deb-pkg" if you want; but "make deb-pkg" has no ability to create a separate package with the debugging symbols in it.

Step 9: Create the Kernel Image Package

Do this step as a non-root user.  Use the same userid for all non-root steps.  The non-root user must be a member of group "src".  This step will compile the kernel source code and create a Debian binary package file for the custom kernel.  But before I get to the specific commands, I need to discuss naming conventions.  This is critically important.  I need to talk about the difference between the kernel version name and the kernel revision name.  Both the kernel version name and the kernel revision name become part of the package file name (.deb file) that gets created.  However, when the package file gets installed, the kernel revision name does not become part of the package name.  It also does not become part of the kernel image file name or the initial RAM file system image file name that gets created in the /boot directory.  Similarly, the directory in which the kernel modules get installed (/lib/modules/...) does not contain the kernel revision name either.  Since you want to retain your existing kernel image file, initial RAM file system image file, and kernel modules unaltered as a backout, you must make the kernel version name different from the stock kernel version name in some way.

This is accomplished by means of the "--append-to-version" flag of make-kpkg.  I usually include the word "custom" in the name to distinguish it from the stock kernel of the same version.  In this example, the stock kernel has an "--append-to-version" value of "-4-686-pae".  (In other words, "uname -r" reports "3.2.0-4-686-pae".  The version proper is "3.2.0" and the "--append-to-version" value is "-4-686-pae".)  My first cut at a custom kernel would probably have an "--append-to-version" value of "-4custom01-686-pae".  For subsequent custom versions of the same kernel I would probably use "-4custom02-686-pae", "-4custom03-686-pae", etc.

On the other hand, I would keep the kernel revision exactly the same as the stock kernel.  That way, I know exactly which stock kernel revision it corresponds to.  For example, at the time of this writing, the current "--revision" value is "3.2.60-1+deb7u3", which corresponds to Debian stable point release 7.6 plus some security updates.  I obtain this value from the version reported by "dpkg-query -W linux-source-3.2" or "dpkg-query -W linux-image-3.2.0-4-686-pae".  If the kernel source package and the stock kernel image package are in sync, their versions will match.  In case of a discrepancy, use the version from the source package, since that is what you are actually compiling.  It's confusing that the package "version" matches the kernel "revision", but that is the gist of it.

Of course, if you're using a pristine kernel source tarball from kernel.org or one of its mirrors instead of a Debian source package, there won't be a Debian package version to use.  You'll have to make something up in this case.  However, make sure that whatever you choose is compliant with Debian policy guidelines for kernel image package version names.  Otherwise, either make-kpkg will reject it, or if it gets past make-kpkg, dpkg won't let you install it.  The most important rule to remember is that it must start with a numeric digit.  If you use a pattern similar to that used by a Debian stock kernel, you should be fine.

One other complication has arisen starting with wheezy (7.x).  The kernel's "internal version" is no longer consistent with the version implied by the package name for stock kernel image packages.  The three parts of the kernel version are known as "VERSION", "PATCHLEVEL", and "SUBLEVEL", from left to right, and the "SUBLEVEL" for a stock kernel image package in wheezy is always set to 0, regardless of the actual SUBLEVEL value of the kernel source code.  For example, at the time of this writing, the stock kernel image package name in wheezy (7.x) for modern machines of the i386 architecture is "linux-image-3.2.0-4-686-pae".  (This is the version without real-time preemption support.)  This package name implies that the kernel version proper is "3.2.0" and the "--append-to-version" value is "-4-686-pae".  However, the internal version proper, at the time of this writing, is actually "3.2.60".  This is reflected in the package version, which is, at the time of this writing, "3.2.60-1+deb7u3".  (This corresponds to the "--revision" option of make-kpkg.)  The corresponding kernel source package name is "linux-source-3.2".  It also has a package version of "3.2.60-1+deb7u3" at the time of this writing.  In jessie, SUBLEVEL has been eliminated altogether for stock kernel image package names, although there is currently a proposal to put it back as zero, as they did in wheezy.

When you build a kernel image package with make-kpkg, it always uses the internal version name, which in this example is 3.2.60, when constructing a package name.  So if you download "linux-source-3.2" and build a custom kernel from it using make-kpkg, the package name will start out with "linux-image-3.2.60" (at the time of this writing) and will be followed by whatever you specify with the "--append-to-version" option, even though the stock kernel image package built from the same source starts out as "linux-image-3.2.0".  I don't know why the change in naming convention was made, but you need to be aware of it and remember how make-kpkg names the packages that it creates.  "make deb-pkg" also uses the internal version name.  (By the way, the internal version name is prominently displayed on the initial screen of "make menuconfig"; so you'll know what it is before you run make-kpkg.)

Note: if you are using a kernel source with the real-time preemption patches applied, the patches will automatically include the "-rt" string in the final kernel version name; so there is no need to include "-rt" in the --append-to-version option of make-kpkg.  If you do, you will end up with "-rt" in the kernel version name twice.  As an example, using the latest version of linux-source-3.2 available at the time of this writing, with the real-time preemption patches applied, I specified an --append-to-version value of -4custom01-686-pae and got a final kernel version name of 3.2.60-4custom01-686-pae-rt87.  The number after the "rt", 87 in this case, appears to be a serialization number which gets incremented each time a new version of the real-time preemption patches is produced.  Unfortunately, the location of the "rt" string is not in the same place as it is in the naming convention for stock Debian kernels.  (The corresponding stock kernel has a kernel version name of 3.2.0-4-rt-686-pae.)  Also, the serialization number is missing in the stock kernel version name.  However, since make-kpkg uses the internal version name (3.2.60 in this case) instead of a contrived version name (3.2.0 for stock kernels), the package name for a custom kernel will sort higher in the ASCII collating sequence than the package name for the corresponding stock kernel will; and that is the most important thing.

Also, I need to talk about initial RAM file system images.  A standard stock Debian kernel is configured with almost everything built as a module, if it can be a module, rather than built in to the kernel.  This allows for installation on as wide a variety of hardware configurations as possible while holding the size of the kernel down as much as possible.  But modules reside on disk.  And any kernel function that is required for the kernel to be able to mount the partitions or do I/O to the disks must be loaded into storage before any kernel modules can be read from disk.  This means that either this support must be compiled into the kernel or else it must be loaded from the initial RAM file system.  This is the primary purpose for an initial RAM file system: it allows the kernel to load modules that it needs before it can read them from disk.  (Recently, the initial RAM file system has acquired a second purpose: it allows user-space processes, such as udev, to be launched that assist the kernel in finding its permanent root file system and suspend/resume images.)  Once the permanent root file system is mounted read-only, the initial RAM file system is freed from memory.

As an example from the i386 architecture, suppose your permanent root file system, which contains /lib/modules/..., is mapped to a partition on a SCSI disk.  But the kernel support for the SCSI adapter is not compiled into the kernel: it is a loadable module.  As an example from the s390x architecture, how can you load the dasd driver modules from disk when those modules must be loaded in order to do I/O to the disk?  In such cases, you need an initial RAM file system.

Stock Debian kernel image packages are set up via the boot loader (grub, lilo, zipl, etc.) to use initial RAM file system image files.  I am assuming in these instructions that you are going to do the same.  If not, then you must do five things: (1) You must make sure that all kernel function needed to get the permanent root file system mounted is built-in to the kernel.  (2) You must disable initial RAM file system support in the kernel.  This is handled by the CONFIG_BLK_DEV_INITRD variable, which you should set to N (i.e. make unset).  In the menuconfig menus, this is labeled "Initial RAM file system and RAM disk (initramfs/initrd) support".  For recent kernels, this is in "General Setup".  (3) You must not supply the "--initrd" option to make-kpkg when you invoke it.  (4) You must change your boot loader configuration file so that it does not expect an initial RAM file system image file.  And (5) you must make sure that your boot loader configuration file does not specify the permanent root file system by means of a UUID=xxx or LABEL=xxx specification, nor does it make use of udev-created symbolic links.  (Without an initial RAM file system, the udev user space process cannot be started until after the permanent root file system has been mounted read-only.)  Taking the path of least resistance, I am assuming that you are going to use an initial RAM file system image the way the stock kernels do.

OK, with all that said, we are ready to start issuing commands.  Issue the following command to build the package(s):
 

     make-kpkg --append-to-version -4custom01-686-pae \
      --revision 3.2.60-1+deb7u3 --initrd --rootcmd fakeroot \
      kernel_image modules_image

If you don't have any out-of-kernel-source-tree kernel module source packages installed, you can omit the modules_image target.  The "--initrd" flag indicates that a kernel which uses an initial RAM file system image is to be built.  The actual initial RAM file system image file, however, is not built at this time.  That is deferred until the package is installed.  If you are intentionally building a kernel image package which contains no initial RAM file system image support, omit this option.  The "--rootcmd fakeroot" option tells make-kpkg what command to issue in order to become root.  (In this case, it only simulates becoming root; but that is good enough for package-building purposes.)

If your computer has more than one processor, and your currently-running kernel is SMP (Symmetric Multi-Processing) enabled, you may be able to get the compilation done faster by using the CONCURRENCY_LEVEL environment variable.  Set the CONCURRENCY_LEVEL environment variable to the number of simultaneous compile tasks that you want to use.  The maximum practical value for CONCURRENCY_LEVEL is the number of processors which are online in your configuration.  The minimum value is one.  The default value, if CONCURRENCY_LEVEL is not set, is also one.  For example,
 

     CONCURRENCY_LEVEL=2 make-kpkg ...

will allow two simultaneous compile tasks.  However, if your system is memory (RAM) constrained, this can actually slow things down.  Running too many simultaneous compiles may cause excessive paging, which will cause the overall process to take even longer than if fewer compile tasks were running simultaneously.  If you use this option, make sure you have enough memory to support it.

By the way, a system with a single "core" that is "hyper threaded" will appear to the kernel as a system with two processors.  Using both of them simultaneously can increase throughput, but not to the same extent as a system with two cores which are not hyper threaded.  The two "threads" compete for access to the same "core", and if one thread is using the core, it can block the other thread.

By using the "getconf" command, you can set CONCURRENCY_LEVEL to the number of processors currently online, which, assuming that you have sufficient memory (RAM), will be the optimum value for compiling the kernel in the shortest possible time.  For example,
 

     CONCURRENCY_LEVEL=$(getconf _NPROCESSORS_ONLN) make-kpkg ...

Of course, making all processors available for simultaneous compilation will slow down the rest of the system.  There's always trade-offs!

A well-packaged out-of-kernel-source-tree kernel module source package will have a Debian package designed for use with kernel-package.  An example is nvidia-kernel-source.  (This package is designed for use with kernel-package or module-assistant.  Another package, nvidia-kernel-dkms, is provided for use with dkms.)  For these, the modules_image target, as above, is all you need.  Unfortunately, some out-of-kernel-source-tree kernel module source packages do not provide a Debian package designed for use with kernel-package.  An example is sl-modem-dkms.  This package is designed for use only with dkms (or by hand with "make" / "make install") and no alternate source package is available for use with kernel-package.

You can still use these uncooperative packages with your custom kernel created by make-kpkg, but in order to do so you will first need to build a linux-headers-* package for your custom kernel.  (This is really stupid, since the entire kernel source tree is already installed; but faced with these uncooperative packages, what else can one do?)  If this is your situation, you will need to do two things: (1) add the kernel_headers target to the make-kpkg command line, and (2) run the entire make-kpkg command under fakeroot, eliminating the "--rootcmd fakeroot" option.  For example, if sl-modem-dkms is the only out-of-kernel-source-tree kernel module source package that you have to deal with, your command would look like this:
 

     fakeroot make-kpkg --append-to-version -4custom01-686-pae \
       --revision 3.2.60-1+deb7u3 --initrd kernel_image kernel_headers

This will cause make-kpkg to build a linux-headers-* package for your custom kernel, as well as a linux-image-* package.  If you have a mixture of out-of-kernel-source-tree kernel module source packages to deal with, some of which are designed for use with kernel-package and some of which are not, you will need to use all three targets: kernel_image, kernel_headers, and modules_image, and the entire command must be run under fakeroot, as above.  Whenever you run the entire make-kpkg command under fakeroot, you must always eliminate the "--rootcmd fakeroot" option.  It is best to use the "--rootcmd fakeroot" option, when possible, rather than running the entire make-kpkg command under fakeroot, since this keeps the use of (fake) root privileges to a minimum; but when building kernel headers packages you don't have a choice: you must run the entire make-kpkg command under fakeroot.  (Of course, if you run make-kpkg as root, then you don't use either one: don't pre-pend fakeroot onto the command and don't use the "--rootcmd fakeroot" option either.)

Note: the latest version of kernel-package that comes with jessie doesn't have this restriction.  With this version of kernel-package you may use the "--rootcmd fakeroot" option with the kernel_headers target, and you don't have to run the entire make-kpkg command under fakeroot.

Compiling the entire kernel takes a while.  We're talking hours, probably, depending on the speed of your processor, and assuming that your kernel configuration is not too different from a stock kernel configuration file.  If you have configured a "lean and mean" kernel, it will compile much faster.  For example, it may only take an hour instead of five hours.

When make-kpkg is finished, there will be a Debian kernel image package in the parent directory (.. or /usr/src) of the current directory (. or /usr/src/linux-source-3.2).  If you included the modules_image or kernel_headers target(s), there may be other Debian package files (.deb files) present as well.

I should probably say something here about fakeroot.  Compiling the kernel does not require root privileges, but building a Debian package file (.deb file) normally does.  Root privileges are normally needed by make-kpkg (or by lower-level commands called by make-kpkg) to use Linux file system functions such as chmod(2), stat(2), etc., that normally will not work as expected unless the user has root authority.  Without going into a lot of detail, suffice it to say that fakeroot was specifically created for the purpose of allowing non-root users to create Debian package files (.deb files).  It makes the software think that it has root authority when it really doesn't, but the ruse is good enough for package building purposes.  For more information, see the documentation for fakeroot.

Step 10: Customize the Kernel Installation Environment

Do this step as root.  This step has proven to be the most difficult one for me to document clearly (and concisely) because there are so many variations.  Before we get lost in the nitty gritty details, I think it would be good to step back and review a little history.  This will explain why this step is so messy.

The Debian kernel team used to use kernel-package (make-kpkg) to create official Debian stock kernel image packages.  The maintainer scripts that come with a kernel image package created by make-kpkg examine a configuration file, if it is present, called /etc/kernel-img.conf, which can be used to "tune" the kernel installation environment.  /etc/kernel-img.conf is not specific to any particular kernel image package: it is a system-wide configuration file that affects the installation of all kernel image packages created by make-kpkg.  The file is typically generated by the Debian installer and is maintained by hand thereafter.

The advantage of making /etc/kernel-img.conf a system-wide configuration file is that the installation of all kernel image packages created by make-kpkg can be controlled by a single file.  And since official Debian stock kernel image packages and user-created custom kernel image packages were both created by make-kpkg in those days, so much the better!

On the down side, however, is that /etc/kernel-img.conf does not belong to any package in particular.  Therefore, which package is responsible for documenting its contents?  (In other words, which package is responsible for providing and maintaining the "man page" for kernel-img.conf(5)?)  Well, since the common point of origin is kernel-package, that task fell to kernel-package.  I guess that's OK for people who create their own custom kernel image packages, but it's a poor choice for people who only use official Debian stock kernel image packages, which is the vast majority of Debian users.  For users who only use official Debian stock kernel image packages, they must install kernel-package (and all of its dependencies) in order to get the man page for kernel-img.conf(5).  That's like buying Maxwell House to get a cup of coffee, but that's the way it works.

With the exception of the documentation issue for /etc/kernel-img.conf, this arrangement worked quite well for a long time; but during the transition from etch (4.0) to lenny (5.0), the Debian kernel team made the decision to stop using make-kpkg from kernel-package to create their official stock kernel image packages.  I do not know why that decision was made, but it was.  Thus began the current confusing situation.  Of course, their initial maintainer scripts were based on the maintainer scripts provided by kernel-package, with some slight modifications to suit their purposes.  In particular, the maintainer scripts provided with official Debian stock kernel image packages continued to use /etc/kernel-img.conf as their configuration file for tuning the kernel installation environment; but now there was no official documentation at all for /etc/kernel-img.conf as used by official Debian stock kernel image packages.  Initially, the options were the same as those supported by the maintainer scripts for kernel image packages created by make-kpkg; but over time, the supported options began to differ.

One could argue that if the Debian kernel team felt compelled to use their own tools for creating official Debian stock kernel image packages, they should have used a different configuration file than /etc/kernel-img.conf, since that was already in use by kernel-package; but they didn't.  So now we have the confusing situation that the same configuration file is used for the same purpose by two separately-maintained sets of maintainer scripts which support different options.  Furthermore, there is no official documentation for the options supported by official Debian stock kernel image packages.

Things weren't too bad until squeeze (6.0).  But the version of kernel-package that comes with squeeze (6.0) and later releases has undergone a major philosophical change.  The new philosophy is that most post-installation activities, such as creating an initial RAM file system image file, maintaining symbolic links, and running the boot loader installer, will no longer be done by the maintainer scripts.  If you want these functions done, you must provide "hook scripts" to do this.  The maintainer scripts provided with stock kernel image packages still perform some of these functions via options in /etc/kernel-img.conf, but they are all undocumented, of course!  And hook scripts provided for use with kernel image packages created by make-kpkg will also be executed when a stock kernel image package is installed or removed, whether you want them to be or not!

To further muddy the waters, the upstream Linux kernel developers now support a "make deb-pkg" option that allows a Debian kernel image package to be produced directly from kernel sources (for 2.6.31 and later kernels) without using any Debian-specific tools, such as make-kpkg.  These kernel image packages use maintainer scripts which are different from those included with kernel image packages created by make-kpkg and those included with official Debian stock kernel image packages.  As far as I know, these maintainer scripts do not use a configuration file during installation or removal.  Finally, there are many different boot loaders available, each with slightly different requirements.  Customizing the kernel installation environment to allow for all of these variations can be quite challenging.  The future direction seems to be to do everything in hook scripts, and /etc/kernel-img.conf will eventually fade away.  But the future is not here yet, and we have to come up with something that works today.

Changing Boot Loaders

This web page really isn't about how to change boot loaders; but this seems like a good time and place to mention it, since we are up to our ears in kernel image package installation issues here.  If you are interested in switching to the LILO boot loader (my personal favorite), see my LILO Web Page.  Even if you do not plan to change boot loaders, you may find it useful to read this page because it provides useful insights into how the kernel maintainer scripts, /etc/kernel-img.conf, update-initramfs, hook scripts, and the boot loader interact.  It also provides some useful information about the boot process in general.

Customizing the squeeze (6.0) Environment

If you are running wheezy (7.x), you should still read this section because this section is the foundation for both.  squeeze (6.0) changes things.  The maintainer scripts that are packaged with a kernel image package created by make-kpkg under squeeze (6.0) and later releases no longer perform most post-installation tasks, such as building an initial RAM file system image file, updating symbolic links, or running the boot loader installer, even if such tasks are requested in /etc/kernel-img.conf.  The maintainer scripts that are packaged with kernel image packages created by make-kpkg in squeeze (6.0) and later releases rely on "hook scripts" to provide these functions, if needed.  The same holds true for the maintainer scripts that are packaged with kernel image packages created by "make deb-pkg".  Furthermore, it appears to be the goal of the Debian kernel team to make examination of /etc/kernel-img.conf unnecessary eventually, even for stock kernel image packages.

Here is a simplified overview of how hook scripts work under squeeze (6.0).  After a kernel image package is installed, any executable files found in /etc/kernel/postinst.d will be invoked.  These executable files are normally script files placed there by various packages that need or want to know about a kernel image package installation or upgrade.  The kernel image package maintainer script invokes these scripts via the run-parts utility, and run-parts executes them in alphabetical order.  They are called hook scripts because they are invoked by a kernel image package maintainer script, but they do not belong to the kernel image package itself: they are "hooks" placed there by other packages.

One of the post-installation scripts in this directory is initramfs-tools.  Its purpose is to create an initial RAM file system image file for a kernel image package which needs one when that kernel image package is installed.  It exits without doing anything if a stock kernel image package is being installed, since stock kernel image package maintainer scripts take care of creating the initial RAM file system image file for a stock kernel image file.  It also exits without doing anything if the kernel image package was created by make-kpkg and the --initrd option was not specified on the make-kpkg command line when the kernel image package was created.  It also exits without doing anything for kernel image packages created by "make deb-pkg" if CONFIG_BLK_DEV_INITRD=y was not specified in the kernel configuration file when "make deb-pkg" was invoked.  But for all other cases the initramfs-tools hook script creates the initial RAM file system image file which is needed by these kernel image files.

Similarly, when a kernel image package is removed or purged, any executable files found in /etc/kernel/postrm.d will be invoked.  Again, the run-parts utility is used to execute these scripts, and they are run in alphabetical order.  One of the post-removal scripts in this directory is initramfs-tools.  Its purpose is to delete the initial RAM file system image file for a kernel image package that uses one when that kernel image package is removed.  It currently exits without doing anything if a stock kernel image package is being removed, since the maintainer scripts for a stock kernel image package take care of deleting the initial RAM file system image file for a stock kernel image file.  Otherwise, it attempts to delete the initial RAM file system image file.  But if one is not found, it still exits cleanly.

For completeness' sake, I should also mention that there are two other directories where hook scripts can be installed: /etc/kernel/preinst.d and /etc/kernel/prerm.d.  You can probably guess by their names when their contents are invoked.  But you normally won't need to be concerned about them.

As soon as multiple hook scripts are placed into the same directory, the issue of execution order arises.  As previously stated, the run-parts utility is used to execute these hook scripts; and they are run in alphabetical order.  Thus, the naming convention directly determines in what order the scripts will execute.  The theory is that a boot loader hook script, if present, should execute last.  Therefore, current policy is that boot loader hook scripts must start with "zz-"; and no other hook scripts are allowed to start with "zz-" or any other string which sorts later than "zz-" in the collating sequence used by run-parts.

If your boot loader does not use symbolic links, you probably don't need any more hook scripts.  But if you are using a boot loader that makes use of symbolic links, such as lilo or zipl, you will probably need some additional hook scripts.  The current hook script policy can be found here.  At the time of this writing, boot loaders which need them provide hook scripts; but they are usually not optimal.  For example, they may not handle symbolic link maintenance for custom kernel image packages or may not prevent unnecessary invocations of the boot loader installer.

At the time of this writing, no boot loader packages that I have looked at provide hook scripts that maintain symbolic links.  The maintainers apparently assumed that symbolic links would be taken care of by "do_symlinks = yes" in /etc/kernel-img.conf, but that only works for official Debian stock kernel image packages.  For kernel image packages created by the squeeze (6.0) or later versions of make-kpkg or for kernel image packages created by "make deb-pkg", this setting has no effect; and symbolic links, if used, must be maintained by hook scripts.

At the time of this writing, there are no hook scripts available as part of the official Debian system which will maintain symbolic links; but I have written some which are available on my web site for download.  You can install the zy-symlinks hook script in the /etc/kernel/postinst.d directory and the zy-symlinks hook script in the /etc/kernel/postrm.d directory.  Because of the naming convention, they will be invoked after the initramfs-tools hook script but before the boot loader hook script, which is what needs to happen.  (Note that these two hook scripts, though they are not identical, do have identical names; so don't download both of them to the same download directory or the second one downloaded will replace the first one downloaded!)

Once you have downloaded these files and copied them to their proper destination directories, be sure to use chown, chgrp, and chmod commands, as needed, to set their attributes properly.  The group should be root, the owner should be root, and the permissions should be -rwxr-xr-x (0755).

The boot loader hook scripts provided with lilo and zipl do not distinguish between pre-configure, configure, remove, and purge calls, and thus invoke the boot loader installer more times than necessary.  (See Debian bug number 599931 and Debian bug number 599934 for more information.)  What I do on my systems is enhance the hook scripts provided with the boot loaders based on the suggestions in the above bug reports plus install the zy-symlinks hook scripts.  I still have to remember to re-customize the hook scripts when the boot loader package is updated, but this seems to be the best solution for right now.

These hook scripts may run underneath a higher-level process, debconf to be specific, which has redirected both standard input (STDIN) and standard output (STDOUT).  When the interface is fully active, debconf expects the program to write debconf protocol commands to STDOUT and read result codes on STDIN.  Thus, output to STDOUT does not display on the terminal and can potentially wreak havoc.  Thus, any console output produced by hook scripts must be redirected to standard error (STDERR).  This is accomplished by means of the >&2 redirection operator.  You can see this on all commands in the scripts that would normally write to STDOUT.  Similarly, if a command normally reads from STDIN, its input must be redirected to another source, such as a file.  If you don't anticipate STDIN being used, but you want to protect yourself against STDIN being accidentally used, you can redirect STDIN to /dev/null.  This is done by the </dev/null redirection operator.  If you see these redirection operators on commands in the hook scripts, you now know why they are there.

When run under debconf, for example during an "apt-get upgrade" or an "apt-get dist-upgrade", the postinst hook scripts are called during pre-configuration and again during configuration.  No action need be taken during pre-configuration; therefore, the zy-symlinks hook script tests for this condition and returns without doing anything if called for pre-configuration.  The initramfs-tools hook script does the same thing.  However, in squeeze (6.0), the zz-zipl and zz-runlilo hook scripts provided with the s390-tools and lilo packages, respectively, do not provide such logic.  I have local modifications to them on my systems to add this logic, as detailed in the above-mentioned Debian bug reports.

The postrm hook scripts are called for both a remove and a purge.  For a purge, they don't need to do anything, since all the work was done at remove time.  Therefore, the zy-symlinks hook script tests for this condition.  If it is being invoked for a purge it returns to its caller without doing anything.  The initramfs-tools hook script does the same thing.  However, in squeeze (6.0), the zz-zipl and zz-runlilo hook scripts provided with the s390-tools and lilo packages, respectively, do not provide such logic.  I have local modifications to them on my systems to add this logic, as detailed in the above-mentioned Debian bug reports.

Note: Debian bug number 599934 is now fixed in wheezy (7.x) for the lilo package, and Debian bug number 599931 is now fixed in wheezy (7.x) for the s390-tools package.  But these fixes have yet to make it into an update for squeeze (6.0), and probably never will.  Therefore, if you're running squeeze (6.0), you will either have to live with them or else fix them by hand.

OK, so we've installed these hook scripts for the benefit of kernel image packages created by make-kpkg or "make deb-pkg"; but how do they affect stock kernel image packages?  The maintainer scripts for a stock kernel image package know that the kernel needs an initial RAM file system image file; so they always create one during installation.  The initramfs-tools hook script knows this also, and it does not create an initial RAM file system image file for a stock kernel image package.  If you have do_symlinks = yes specified in /etc/kernel-img.conf, the maintainer scripts for a stock kernel image package currently honor this and will maintain the symbolic links during installation.  If you have the zy-symlinks hook scripts installed, you should change this to do_symlinks = no to avoid duplication of effort.

do_bootloader = yes in /etc/kernel-img.conf is no longer honored in squeeze (6.0).  Set this variable to "no" or eliminate it altogether.  The boot loader hook scripts will take care of running the boot loader installer during kernel image package installation, update, and removal, if needed; and "update-initramfs -u" will run the boot loader installer as well, if needed.

The postinst_hook = update-grub and the postrm_hook = update-grub lines from the /etc/kernel-img.conf file, if they exist, should be deleted.  Even if you are still running grub, this will be taken care of by the boot loader hook scripts.  And if you're not running grub, that's all the more reason to eliminate them!

The maintainer scripts for a stock kernel image package delete the initial RAM file system image file during a remove.  The initramfs-tools hook script knows this and does not attempt to delete the initial RAM file system image file for a stock kernel image package.  If you have do_symlinks = yes specified in /etc/kernel-img.conf, the maintainer scripts for a stock Debian kernel image package will currently attempt to remove broken links caused by the removal of the kernel image file and its initial RAM file system image file.  If you have the zy-symlinks hook scripts installed, this is not necessary, since the zy-symlinks hook script will take care of this for you.  You should set do_symlinks = no in this case to avoid duplication of effort.  Finally, the maintainer scripts for a stock kernel image package do not run the boot loader installer during a remove.  However, the boot loader hook script will take care of that for you, if needed.

In summary, this is what I recommend for /etc/kernel-img.conf for squeeze (6.0) and later releases when the proper hook scripts are used:
 

     do_symlinks = no

do_symlinks = no is there because the default value for this variable is still "yes" for stock kernels, and we need to override the default.  For custom kernels, the option is vestigial.  The zy-symlinks hook scripts, if installed, will take care of symbolic link maintenance for you, both for stock and custom kernels.  relative_links is now vestigial in squeeze (6.0), both for stock and custom kernels; so it should be omitted.  link_in_boot is now vestigial for custom kernels, but still has meaning for stock kernels.  However, its value doesn't matter when do_symlinks = no is used; so it is also omitted.

The zy-symlinks hook scripts maintain the symbolic links wherever they are found.  If they exist in both / and /boot, the ones in / take precedence.  You should not allow them to exist in both places.  If you are changing the location where the symbolic links are maintained from where they were previously, you will have to manually delete the old symbolic links and manually create the new symbolic links the first time.  Thereafter, they will be maintained automatically.  (Of course, your boot loader configuration file will need to be changed too.)

do_bootloader is omitted because its default value is "no" for stock kernel 2.6.32.  For later stock kernels, it is a vestigial option.  The option is vestigial for all custom kernels in squeeze (6.0) and later releases.  The boot loader hook scripts will take care of running the boot loader installer during a kernel image package install, update, or remove; and "update-initramfs -u" will take care of running the boot loader installer, when necessary, for updates of the initial RAM file system image file.  do_initrd is also omitted because it is now a vestigial option, both for stock and custom kernels.  As you can see, /etc/kernel-img.conf is no longer as important as it once was.

There is one final hook script directory of which you should be aware.  To allow the removal of special boot loader processing logic from initramfs creators (initramfs-tools, yaird, etc.), the new policy requires hook scripts in the /etc/initramfs/post-update.d directory for any boot loader that uses initial RAM file system image files and that reads the initial RAM file system image files by means of a list of blocks saved at boot loader installer run time, such as lilo and zipl.

Since "update-initramfs -u" invokes the boot loader installer anyway, when needed, you may wonder why the initramfs hook script is needed.  Due to migration considerations, it takes two releases to get rid of boot-loader-specific logic from initramfs-tools (or any other initramfs creator package).  The goal is to remove the boot-loader-specific logic from initramfs-tools in wheezy (7.x).  In order to do that, they must be able to assume that the squeeze (6.0) release always uses an initramfs hook script when needed.  The boot-loader-specific code is there only to facilitate migrations from lenny (5.0) and must not be relied upon in squeeze (6.0) itself.

Customizing the wheezy (7.x) Environment

The wheezy (7.x) Environment is nearly identical to the squeeze (6.0) environment.  The main differences are as follows:
 

Customizing the jessie Environment

The jessie environment is currently customized the same way as the wheezy (7.x) environment.

Regardless of whether you are running squeeze (6.0), wheezy (7.x), or jessie, the customization of the kernel installation environment only needs to be done the first time you prepare to install a kernel image package created by make-kpkg or "make deb-pkg".  Once you've done it, you can create as many kernel image packages with make-kpkg or "make deb-pkg" as needed and install them, skipping this step.

Step 11: Install the Kernel Image Package

Do this step as root.  OK, now it's time to actually install the kernel image package.  You won't use apt-get to install the kernel image package.  That is due to the fact that it doesn't have to be fetched from anywhere.  Instead, use the low-level package tool dpkg.
 

     cd /usr/src
     dpkg -i linux-image-3.2.60-4custom01-686-pae_3.2.60-1+deb7u3_i386.deb

Obviously, use the actual name of the package file, which can be determined by using the ls command.  If you have both a kernel image package and one or more modules image packages, install the kernel image package first, then the modules image packages.  The latter will probably have a dependency on the former.  If you had to build a linux-headers-* package to accommodate an uncooperative kernel module source package, install the linux-headers-* package first, then the linux-image-* package.  (dkms may get activated to build a new binary kernel module when you install the linux-image-* package, and the build will fail if you don't have the linux-headers-* package installed already.  You can ignore dkms-related error messages which occur during installation of the headers package.)

If the kernel installation environment has been properly customized, the maintainer scripts or the hook scripts will automatically create the initial RAM file system image file, update the symbolic links (if requested), and re-run your boot loader installer, if necessary.  But before you shut down and reboot, it is a good idea to check everything out in /boot and in your boot loader configuration to make sure that the new kernel was installed properly.

Step 12: Shutdown and Reboot

Do this step as root.  Shutdown and reboot to run your new custom kernel!
 

     shutdown -r now;exit

Step 13: Clean Up

Do this step as a non-root user.  Use the same userid for all non-root steps.  The non-root user must be a member of group "src".  Once the new kernel image package has been installed, you can delete the package file (.deb file). 
 

     cd /usr/src
     rm linux-image-3.2.60-4custom01-686-pae_3.2.60-1+deb7u3_i386.deb

If you have also installed one or more modules image packages, you can delete their package files too.  The same goes for a linux-headers-* package.

Step 13a: Clean Up (Part Two)

Do this step as root.  Once you are satisfied with the new kernel, you may wish to de-install the old kernel image package.  I like to keep at least one back version unless I know that the old kernel will no longer work due to changes made since migrating to the new kernel.  For example, if my system now depends on a kernel module that did not exist in the old kernel, there's not much point in keeping the old kernel around.
 

     apt-get purge linux-image-3.2.0-4-686-pae

This will de-install the old kernel image package and save some more disk space.  If you have out-of-kernel-source-tree kernel module image packages installed that are tied to the old kernel image package, purge the kernel module image packages first, then purge the old kernel.  If you have a linux-headers-* package that is tied to the old kernel, purge it last.

Note: make sure you have shut down and re-booted using the new kernel before attempting to purge the old kernel!  You don't want to try to purge a kernel while it is running!  Besides, you don't yet know if your new kernel works!

May you have much enjoyment running your new custom kernel!

Step 14: Maintenance

This is a mixed-mode step: some commands are issued as root and some commands are issued as a non-root user.  OK, now what if you get the new custom kernel installed and running, but you want to make changes to the kernel configuration?  Maybe you forgot something the first time.  Use a sequence of commands something like this.  (Note: the commands which must be run as root are prefaced with a pound sign.  The commands which should be run as a non-root user are prefaced with a dollar sign.  Use the same userid for all non-root steps.  The non-root user must be a member of the "src" group.)
 

     $ cd /usr/src/linux-source-3.2
     $ make-kpkg --rootcmd fakeroot modules_clean
     $ make-kpkg clean
     $ make menuconfig
     $ make-kpkg --append-to-version -4custom02-686-pae \
     > --revision 3.2.60-1+deb7u3 --initrd --rootcmd fakeroot \
     > kernel_image modules_image
     $ cd ..
     $ su
     # dpkg -i linux-image-3.2.60-4custom02-686-pae_3.2.60-1+deb7u3_i386.deb
     .
     . ("dpkg -i" commands to install the modules image package files)
     .
     # exit
     .
     . ("rm" commands to remove the modules image package files)
     .
     $ rm linux-image-3.2.60-4custom02-686-pae_3.2.60-1+deb7u3_i386.deb
     $ su
     # shutdown -r now;exit

Something like the above will do nicely.  (The ">" is the shell's continuation prompt.  Do not type it literally, just as you don't type the "$" or "#" literally.)  Note the extra commands to do cleanup (make-kpkg with the modules_clean and clean targets).  Since you've done a previous build and have not wiped out the source directories and started over, these targets are recommended at this point.  Note that "--rootcmd fakeroot" is not needed for the "clean" target, but it is usually needed (depending on how the modules are packaged) for the "modules_clean" target.  Notice that the "--append-to-version" flag needs to be changed slightly each time.  If you do not have out-of-kernel-source-tree kernel module source packages to build, don't issue the "make-kpkg --rootcmd fakeroot modules_clean" command, remove the modules_image target from the last make-kpkg command, and of course there will be no extra ".deb" files to install or remove.

As before, if you need a headers package, add the kernel_headers target to the main make-kpkg command, remove the "--rootcmd fakeroot" option, and run the entire make-kpkg command under fakeroot.  (Once again, the jessie version of make-kpkg does not have this restriction.  You can use the --rootcmd fakeroot option of make-kpkg with the kernel_headers target with this version of kernel-package.)  Add a command to install the headers package immediately prior to the command to install the main image package and a command to erase the headers package file after installation.

For boot loaders which use symbolic links, such as lilo and zipl, your boot loader is typically configured to boot two kernels: the primary kernel, which is the most recently installed one, and one alternate one, which is the next most recently installed one.  If you didn't de-install the stock kernel last time, you should probably do so now.  You've got three kernel image packages installed on your machine now: the original stock kernel, your first custom kernel, and your second custom kernel.  And only the two custom ones are bootable at this point, unless you've been customizing your boot loader configuration as well.
 

     # apt-get purge linux-image-3.2.0-4-686-pae

If you have out-of-kernel-source-tree kernel module image packages installed that are tied to the old kernel image package, purge the kernel module image packages first, then purge the old kernel.  If you have a headers package installed which is tied to the old kernel, purge it last.  Once your first custom kernel rolls off the boot loader menu, de-install it in a similar manner.  For boot loaders such as grub which do not use symbolic links, it's up to you how many back-level kernels you want to keep around.  For most people, two bootable kernels (the current one and the previous one) are adequate.

OK, you've been happily running your custom kernel for several months now; and you get a security update notice from Debian.  After waiting a couple of days for the upload to propagate to all mirrors, including the one you use, you update the list of available packages via "apt-get update", then you upgrade your system.  And when you do, you notice that an updated kernel source package (in this example, linux-source-3.2) has been downloaded and installed.  What do you do now?

Well, it's time to clean house.  Of course you've already run "apt-get clean", right?  (You should always run "apt-get clean" after upgrading your system.)
 

     $ cd /usr/src
     $ rm -r linux-source-3.2
     $ tar -xj -f linux-source-3.2.tar.bz2
     $ rm -f linux-source-3.2.tar.bz2

For wheezy (7.x) and later kernels, you will also have the real-time preemption patches to deal with, as discussed earlier.  Either install them or erase them, per your choice.

For jessie kernels (3.10.x and later), use the -J switch of tar instead of the -j switch of tar, since the source tarball name will end in .xz instead of .bz2.  The config file directory (for 3.10 kernels and later) will have been updated already by virtue of the new package being installed.  However, if a new kernel minor release has been installed (for example, an update from 3.10.x to 3.11.x), the new config file directory will have a different name; so you can safely erase the old config file directory.  However, the right way to do this is to purge the old source code package.  This will take the old config file directory with it.  For example,
 

     apt-get purge linux-source-3.10

This must be done as root, of course.  The old source directory, since it does not get created automatically during package installation, must be erased manually.

A similar procedure is followed if an out-of-kernel-source-tree kernel module source package has been downloaded and installed.  For example, if nvidia-kernel-legacy-96xx-source is downloaded and installed, you would do the following:
 

     $ cd /usr/src
     $ rm -r modules/nvidia-kernel-legacy-96xx
     $ tar -xj -f nvidia-kernel-legacy-96xx-source.tar.bz2
     $ rm -f nvidia-kernel-legacy-96xx-source.tar.bz2

If your kernel source is replaced, you don't need to use the "clean" target of make-kpkg.  Similarly, if your module source is replaced, you don't need to use the "modules_clean" target of make-kpkg for that module.  But for those sources which are not replaced, it is a good idea to run make-kpkg with the appropriate "clean" target.  If some but not all of your module sources have been replaced, you can use the --added-modules option to specify which module sources to clean (the ones that weren't replaced).  The "clean" target cannot be specified in conjunction with any other target; so the "clean" and "modules_clean" targets must be specified in separate commands, and "clean", if needed, should be last.  Remember, your current directory must be the kernel source directory (i.e. /usr/src/linux-source-3.2) whenever you run make-kpkg, including the "clean" targets.

Now proceed to step 7, with some minor variations.  If the kernel source was replaced, you will need to reapply the patches, if any.  (The patch files themselves will still be there in /usr/src.)  If a kernel module source package was replaced, do the same for any patch files you have against the module source.  If the kernel source was replaced, the name of the config file that gets copied from the /boot directory to .config in the current directory must change to match the current kernel config file.  Since the old config file may no longer be exactly in sync with the new source code, you will need to run "make oldconfig" after you copy the old config file from /boot to ".config".  (Alternatively, you can obtain a config file from a stock kernel built from the exact same source; or for 3.10.x kernels and later, copy the appropriate config file from the config file directory.)

You must re-run "make menuconfig", even if you don't change a thing in the kernel configuration, because some files get created by "make menuconfig" that make-kpkg needs, and replacing the kernel source or running "make-kpkg clean" erases them.

The "--append-to-version" flag must change slightly to not conflict with any of the kernel versions you currently have installed.  If the kernel source was replaced, the "--revision" flag must change too, since kernel source package updates always change the package version.  (If you're using pristine kernel sources, change your "made up" revision name for consistency.)  The name of the kernel image package file, the kernel headers package file, and the module image package files will change too; so the "dpkg -i" command(s) will also change, as will the commands to remove (rm) the package files.  And of course the "apt-get purge" commands must change to de-install the correct old version of the kernel image package, the kernel headers package, and their associated module image packages.  By now you get the idea.

Note: sometimes the stock kernel configuration file will change with a security update or a new stable point release.  The powers that be may have decided to change a kernel configuration option for security or other reasons.  The announcement e-mail should tell you what was changed and why.  In that case, if you want to keep your custom kernel configuration file in sync with the latest stock kernel, you will need to make a corresponding change to your custom kernel config file when you run "make menuconfig".  Alternatively, you can obtain a config file from the updated stock kernel and copy it to .config before running "make menuconfig".  For 3.10.x kernels and later, you also have the option of copying an appropriate updated kernel config file from the config file directory.

If you're using an official Debian kernel source package, such as linux-source-3.2, you will automatically get updates to it when you upgrade your system.  However, if Debian moves on to a different kernel version, you don't get the updated kernel source automatically.  For example, when wheezy (7.x) was first made the testing release, it was running a 2.6.32 kernel, just as squeeze (6.0) does.  However, as time went on, wheezy (7.x) changed from a 2.6.32 kernel to a 2.6.39 kernel, and later to a 3.0.0 kernel.  By the time it became the stable release, it was running a 3.2.41 kernel.  With linux-source-2.6.32 installed, one got automatic source updates as long as 2.6.32 was the current kernel version; but once wheezy (7.x) moved on to 2.6.39 as the current kernel, source updates ceased.

You can get around this problem by installing the linux-source package.  linux-source is a meta-package which depends on the latest kernel source package.  If you have linux-source installed, you will automatically get kernel source package updates even when the kernel version changes.  Obviously, if you are using pristine kernel source tarballs from kernel.org or one of its mirrors, moving on to a new kernel version is an entirely manual process.

Alternatives

For Linux kernels 2.6.31 and later, "make deb-pkg" is an alternative to make-kpkg.  ("make deb-pkg" is supported upstream, whereas make-kpkg is a Debian-specific tool.)  But the author of kernel-package has pointed out that "make deb-pkg" is not as feature rich as make-kpkg.  For example, one can't produce doc or debug packages from one's custom sources with "make deb-pkg".

If you have a kernel source package new enough to support "make deb-pkg", you are running squeeze (6.0) or later, support for headers packages, if needed, is present, and you want to try out "make deb-pkg", go ahead.

If you decide to use "make deb-pkg", you will need to know the analogies to the options of make-kpkg.  To start out, the CONCURRENCY_LEVEL environment variable is not supported; but you can use the -j option of make to obtain equivalent function.  The maintainer's name and e-mail address, which for make-kpkg are specified in the /etc/kernel-pkg.conf file, are specified by the DEBFULLNAME and DEBEMAIL make variables, respectively, for "make deb-pkg".  The equivalent of make-kpkg's --append-to-version option is the EXTRAVERSION make variable.  The equivalent of make-kpkg's --revision option is the KDEB_PKGVERSION make variable.

make-kpkg's --initrd option, or lack thereof, is automated in "make deb-pkg".  If CONFIG_BLK_DEV_INITRD=y is specified in the kernel configuration file at the time that "make deb-pkg" is invoked, then the resulting kernel image package will request that an initial RAM file system image file be created at installation time by /etc/kernel/postinst.d/initramfs-tools.  If CONFIG_BLK_DEV_INITRD is not set in the kernel configuration file at the time that "make deb-pkg" is invoked, then the resulting kernel image package will not request that an initial RAM file system image file be created at installation time by /etc/kernel/postinst.d/initramfs-tools.  The equivalent of make-kpkg's --rootcmd option is the make variable KBUILD_PKG_ROOTCMD.  If "make deb-pkg" is not run as root (or under fakeroot), and KBUILD_PKG_ROOTCMD is not set, "fakeroot" is assumed as its default value.  If fakeroot is not installed, you will get an error message.  Here is an example of building a kernel image package using "make deb-pkg".
 

     make -j$(getconf _NPROCESSORS_ONLN) DEBFULLNAME="Stephen Powell" \
     DEBEMAIL=zlinuxman@wowway.com EXTRAVERSION=-4custom01-686-pae \
     KDEB_PKGVERSION=3.2.60-1+deb7u3 KBUILD_PKG_ROOTCMD=fakeroot \
     INSTALL_MOD_STRIP=1 deb-pkg

Note the use of INSTALL_MOD_STRIP=1, which was previously discussed.  Anything pertaining to modules, such as the MODULE_LOC environment variable, the --added-modules option, the modules_* targets, etc., has no equivalent, since "make deb-pkg" does not create kernel module image packages.  If your kernel source is new enough, "make deb-pkg" will create a linux-headers-* package; otherwise it won't.  If it does create a linux-headers-* package, you can handle out-of-kernel-source-tree kernel module source packages designed for use with module-assistant or dkms.  Finally, "make clean" takes the place of "make-kpkg clean".

"make deb-pkg" currently has a problem with the s390x port.  (See Debian bug report 750925 for details.)  But fortunately, there is a circumvention available for this bug: specify the KBUILD_DEBARCH make variable manually. 

The following is an example of how I built a custom kernel for s390x in jessie recently.
 

     make -j$(getconf _NPROCESSORS_ONLN) DEBFULLNAME="Stephen Powell" \
     DEBEMAIL=zlinuxman@wowway.com EXTRAVERSION=-2custom01-s390x \
     KDEB_PKGVERSION=3.14.13-2 KBUILD_PKG_ROOTCMD=fakeroot \
     INSTALL_MOD_STRIP=1 KBUILD_DEBARCH=s390x deb-pkg

The main reason I have been building custom kernels for s390x recently is to apply a patch to fix a 3215 hang problem.  (See Debian bug report 747922 for details.)  A patch is referenced in the bug report.  The patch referenced in the preceding bug report works for jessie kernels, but not for wheezy kernels.  For wheezy kernels, use this patch instead.  Another patch I apply fixes a problem with tabs on 3215 ttys.  (See Debian bug report 758264 for details.)  Again, the patch is referenced in the bug report.  This patch works for both wheezy and jessie kernels.

Now that patches are available for kernel-package to support the s390x port, for both wheezy and jessie, I've gone back to using kernel-package instead of "make deb-pkg" to build my custom kernels.

/usr/src is the historic (and default) location for package source code under Debian GNU/Linux, but some people don't like to put it there because it violates the FHS (Filesystem Hierarchy Standard).  They prefer to put it somewhere else, such as ~/src.  (~ represents the home directory of the non-root user who will own the source code.)  If this is what you want to do, there are a few changes you will need to make.  After installing the source package (as root) with "apt-get install linux-source-3.2", switch to your non-root user and unpack the file like this:
 

     $ cd /usr/src
     $ tar -xj -f linux-source-3.2.tar.bz2 -C ~/src

The "-C" option of tar specifies the directory where the files will be extracted.  The default value, if the "-C" option is not specified, is the current directory.  If you are building out-of-kernel-source-tree kernel module source packages as well, use the same "-C" option on the tar commands to unpack their source tar files.  They will be unpacked to a directory under ~/src/modules.  In addition, when you build out-of-kernel-source-tree kernel module image packages, you must supply an environment variable called MODULE_LOC to make-kpkg which specifies the location of the module source code.  For example,
 

     $ cd ~/src/linux-source-3.2
     $ MODULE_LOC=~/src/modules make-kpkg ... modules_image

If MODULE_LOC is not specified, the default value is /usr/src/modules.  Make other adjustments to path specifications as appropriate.  Note that if you do your processing under your home directory, as in this example, your non-root user account does not need to be a member of the src group.  If you do your processing under some other directory, make sure that your non-root user account is a member of the group that owns the directory, make sure that the group has read, write, and execute privileges on the directory, and make sure that the "set-group-ID" attribute is set for the directory.  Also make sure that the group which owns the directory is listed in the output of the groups command issued by the non-root userid that you are going to use before proceeding.

A couple of environment variables used by make-kpkg have already been discussed (CONCURRENCY_LEVEL and MODULE_LOC), and there are a few more environment variables which affect the operation of make-kpkg that may occasionally be useful in special circumstances.  (For more information, see the man page for make-kpkg(1).)  There are two ways to specify environment variables: as a prefix to the command itself and implicitly via the "export" command.  Here is an example of the prefix method:
 

     $ cd ~/src/linux-source-3.2
     $ CONCURRENCY_LEVEL=$(getconf _NPROCESSORS_ONLN) \
     > MODULE_LOC=~/src/modules make-kpkg ...

In the prefix method, the environment variables are specified as prefixes to the make-kpkg command itself.  The values of these variables only apply to the environment of the make-kpkg command (and to all commands which are invoked by the make-kpkg command).  These environment variable values do not affect the values of any variables by the same name in the current shell.  Their previous values, if any, remain unchanged in the current shell, and if they had no previous values in the current shell, they remain unset.  Also, subsequent invocations of make-kpkg (or any other command) do not inherit these environment variable values: they apply only to that specific command.

In the export method, the environment variables are set as ordinary variables in the current shell, then they are marked for export using the shell's "export" command.  For example:
 

     $ cd ~/src/linux-source-3.2
     $ CONCURRENCY_LEVEL=$(getconf _NPROCESSORS_ONLN)
     $ MODULE_LOC=~/src/modules
     $ export CONCURRENCY_LEVEL MODULE_LOC
     $ make-kpkg ...

Optionally, the assignment of a value can take place on the export command itself.  For example,
 

     $ cd ~/src/linux-source-3.2
     $ export CONCURRENCY_LEVEL=$(getconf _NPROCESSORS_ONLN) \
     > MODULE_LOC=~/src/modules
     $ make-kpkg ...

Either way, the shell variables listed on the export command are passed to every subsequent command, whether you want them to be or not, including make-kpkg.  However, they only apply to commands invoked from the shell that issued the export command (and lower-level shells or sub-shells invoked from that shell).  One may also use a combination of the two methods.  For example, one of the above two environment variables may be set in the current shell and marked for export, while the other one is passed using the prefix method.  Use whatever method works best for you.

Note: it is important to distinguish between an environment variable and a make variable.  A make variable is only used with the make command, must be assigned a value on the make command line, and comes after the command name, not before it.  KDEB_PKGVERSION is an example of a make variable.

A Specific Example

Since I initially announced this page on the debian-user mailing list, I have been met with mostly positive reviews.  However, I have had a number of requests for a specific example.  In particular, I have had requests for a specific example that involves using out-of-kernel-source-tree kernel module source packages.  And the most popular example requested involves building a custom kernel the traditional Debian way that uses the proprietary Nvidia® graphics driver.  (I am no fan of proprietary drivers; but given the world as it is, they are sometimes necessary.)

Given: a computer of the i386 architecture with an Nvidia graphics card, chipset GeForce2 MX/MX 400, running Debian wheezy (7.x).
To accomplish: build a custom kernel from Debian kernel sources (3.2.60) that uses the proprietary "nvidia" X driver.

Note: it is not necessary to build a custom kernel in order to use the nvidia driver.  There are other installation methods available that will allow the nvidia driver to be used with an official stock Debian kernel image package.  But if you need or want to build a custom kernel for other reasons, and you also want to use the nvidia driver, this is the traditional Debian way to do it.

Assumptions:
 

The first step is to determine which kernel module source package you need.  At the time of this writing there are four nvidia kernel module source packages: nvidia-kernel-legacy-71xx-source, nvidia-kernel-legacy-96xx-source, nvidia-kernel-legacy-173xx-source, and nvidia-kernel-source.  These packages are listed from oldest to newest.  Immediately you might be thinking, "Why not always use the newest package?"  That's a good thought.  The problem is that Nvidia periodically drops support for older chipsets from their drivers; so the newest driver may not support your chipset.  That's why the legacy driver packages exist.  You want to use the newest driver package that supports your chipset.  Follow the links above for web pages which describe each package and the chipsets they support.

Note: if you don't know which chipset your Nvidia graphics card uses, the easiest way to find out is to use the lspci command.  For example:
 

     lspci|grep VGA

My first attempt at this was on a computer which has an Nvidia graphics card with a RIVA TNT2 chipset, which requires the nvidia-kernel-legacy-71xx-source kernel module source package.  I got the kernel module source package installed and the binary package built, but when it came time to install the corresponding user-space package, nvidia-glx-legacy-71xx, I got a nasty surprise: this user-space driver has not been updated to support the version of the X server which runs under wheezy (7.x)!  Attempting to install it under wheezy (7.x) caused apt-get to ask me if I wanted to de-install all of my xorg-* packages!  It doesn't work under squeeze (6.0) either.  This is not Debian's fault.  At the time of this writing, Nvidia itself has not updated this legacy driver to support the newer release of the X server; and the last I heard, they had no plans to do so.  So if your chipset requires the 71xx legacy driver, and if you want to use it on squeeze (6.0) or later releases, you're presently out of luck.  You might be able to get it to work with lenny (5.0), but not with squeeze (6.0) or later releases.

My second attempt, which is documented here, was on a computer which has an Nvidia graphics card with a GeForce2 MX/MX 400 chipset, which requires the nvidia-kernel-legacy-96xx-source kernel module source package.  The corresponding user-space package, nvidia-glx-legacy-96xx, has been updated to support the release of the X server which runs under squeeze (6.0) and later releases.

OK, now let's get started.  We assume that the login shell belongs to steve.
 

     $ su
     # apt-get install linux-source-3.2
     # apt-get install kernel-package
     # apt-get install libncurses5-dev zlib1g-dev
     # apt-get --no-install-recommends install nvidia-kernel-legacy-96xx-source
     # vi /etc/kernel-pkg.conf
     .
     . (change maintainer's name and e-mail address)
     .
     ZZ
     # exit
     $ cd /usr/src
     $ tar -xj -f linux-source-3.2.tar.bz2
     $ rm -f linux-source-3.2.tar.bz2
     $ rm -f linux-patch-3.2-rt.patch.bz2
     $ tar -xj -f nvidia-kernel-legacy-96xx-source.tar.bz2
     $ rm -f nvidia-kernel-legacy-96xx-source.tar.bz2
     $ cd linux-source-3.2
     $ cp /boot/config-3.2.0-4-686-pae .config
     $ make menuconfig
     $ make-kpkg --append-to-version -4custom01-686-pae \
     > --revision 3.2.60-1+deb7u3 --initrd --rootcmd fakeroot \
     > kernel_image modules_image

(The "--no-install-recommends" option of apt-get is used when installing nvidia-kernel-legacy-96xx-source to avoid the installation of nvidia-kernel-common.  It seems best to me to avoid installing this package until the kernel module image package has been successfully built.)  As issued above, make-kpkg will compile the kernel source package and all the installed out-of-kernel-source-tree kernel module source packages and build binary Debian package files for them.

If you wish to specify which of the installed kernel module source packages to build, use the --added-modules option of make-kpkg.  The --added-modules option value is a comma-separated list of directory names under /usr/src/modules which make-kpkg will examine.  (If your source code is not under /usr/src/modules, as it is in this example, use the environment variable MODULE_LOC to tell make-kpkg where to look for it.)  By default, all directories under /usr/src/modules (or the value of the environment variable MODULE_LOC, if specified) are examined if the --added-modules option is omitted and a modules_* target is present.

Note that the directory name does not necessarily match the package name; so be sure to use the directory name(s).  In the specific case of the nvidia-kernel-legacy-96xx-source package, the corresponding directory name is nvidia-kernel-legacy-96xx; thus the option to build only this kernel module package would be
 

     --added-modules nvidia-kernel-legacy-96xx

It is possible to build the module packages separately, but the kernel package must be built first.  Otherwise, you will get errors involving "genksyms not found", or something like that.  If you build the module package(s) separately, make sure to use the same --append-to-version and --revision options each time.  Note that the --initrd option only has meaning when building a kernel image package; so you can omit it when building only module image packages.  Similarly, the --added-modules option and the MODULE_LOC environment variable only have meaning when building module image packages; so you can omit them when building only a kernel image package.

Note that you do not need to build or install kernel headers packages when using this installation method.  They are not needed because you have the kernel source package installed, and the kernel headers are included as part of the kernel source.  Also, avoid installing packages such as module-assistant, dkms, or nvidia-kernel-legacy-96xx-dkms.  Deinstall them if you can; and if they aren't installed, don't install them.  Continuing on ...
 

     $ cd ..
     $ su
     # dpkg -i linux-image-3.2.60-4custom01-686-pae_3.2.60-1+deb7u3_i386.deb
     # apt-get install nvidia-kernel-common
     # dpkg -i nvidia-kernel-legacy-96xx-3.2.60-4custom01-686-pae_96.43.23-3+3.2.60-1+deb7u3_i386.deb

It is important to install both the custom kernel image package and nvidia-kernel-common before installing the module image package, since the module image package recommends the former and depends on the latter.  Now we are ready to install the user-space package:
 

     # apt-get install nvidia-glx-legacy-96xx
     # apt-get clean

This package (nvidia-glx-legacy-96xx) has a dependency on nvidia-kernel-96.43.23, which is a virtual package provided by the module image package, nvidia-kernel-legacy-96xx-3.2.60-4custom01-686-pae, which you just installed.  That's why we couldn't install it earlier.  Make sure that the glx package you install corresponds to the kernel module source package that you used.  (For example, if you built a module image package from the legacy-96xx kernel module source package, you also need to install the legacy-96xx glx package.)  The "apt-get clean" command cleans up the package cache after installing all these new packages.  Now make a backup copy of your existing /etc/X11/xorg.conf file, if you have one, and create a new one that looks like this:
 

     Section "Device"
             Identifier      "Configured Video Device"
             Driver          "nvidia"
     EndSection

You can tweak it later if you like, but right now we just want to make sure that the nvidia driver gets loaded.  Now enroll in the "video" group all non-root users on the system that might possibly start or use the X server, if they aren't already enrolled.  For example:
 

     # adduser steve video
     # adduser candy video

Now shutdown and reboot.  It should work.  For help with troubleshooting, see this link.  After rebooting, you might want to consider purging the stock kernel, since your system now depends on the nvidia kernel module, which doesn't exist in the stock kernel.  You may also delete the package files (.deb files) that you created in /usr/src, now that they have been installed.

Another Specific Example

This example illustrates how to use out-of-kernel-source-tree kernel module source packages which are not designed for use with kernel-package and make them work anyway.  In this example, we desire to use the proprietary kernel module for the Smart Link Audio Modem Riser card (slamr).  The corresponding out-of-kernel-source-tree kernel module source package is sl-modem-dkms.  This package is designed for use only with dkms, and there is no alternate package designed to work with kernel-package.  That's not nice!

All the assumptions for the previous specific example (except those involving Nvidia hardware and software) are repeated here.  We add the additional assumption that you have already verified that you have an internal modem physically installed and recognized by lspci or lsusb that is supported by this driver.  (This package also supports certain USB modems as well.)  We also add the assumption that no previous attempts have been made to install this driver, either through Debian packages or using native upstream installation methods.  We also make the assumption that you are using a real-time preemption kernel (3.2.0-4-rt-686-pae).  This is not a requirement for the modem driver, but I wanted an example that uses real-time preemption.

The first thing we need to do is to disable the ALSA drivers that want to take control of this modem.  Login as root, switch to directory /etc/modprobe.d, and create a file called local.conf.  The contents should look like this:
 

     blacklist snd_intel8x0m

Now, rebuild the initial RAM file system image file for the running kernel, then shutdown and reboot.
 

     # update-initramfs -uk $(uname -r)
     # shutdown -r now;exit

(The "$(uname -r)" substitutes the version name of the currently-running kernel.  In this case, it would be 3.2.0-4-rt-686-pae.)  After the reboot, login as a normal user and verify that snd_intel8x0m is no longer loaded.
 

     $ lsmod|grep snd_intel8x0m

OK, now it's time to install some stuff
 

     $ su
     # apt-get install linux-source-3.2
     # apt-get install kernel-package
     # apt-get install libncurses5-dev zlib1g-dev
     # vi /etc/kernel-pkg.conf
     .
     . (change maintainer's name and e-mail address)
     .
     ZZ
     # exit
     $ cd /usr/src
     $ tar -xj -f linux-source-3.2.tar.bz2
     $ rm -f linux-source-3.2.tar.bz2
     $ bunzip2 linux-patch-3.2-rt.patch.bz2
     $ cd linux-source-3.2
     $ patch -p1 <../linux-patch-3.2-rt.patch
     $ rm ../linux-patch-3.2-rt.patch
     $ cp /boot/config-3.2.0-4-rt-686-pae .config
     $ make menuconfig
     $ fakeroot make-kpkg --append-to-version -4custom01-686-pae \
     > --revision 3.2.60-1+deb7u3 --initrd kernel_image kernel_headers

Note that since the kernel_headers target is specified the entire make-kpkg command must be run under fakeroot and the "--rootcmd fakeroot" option must be omitted.  This is not a restriction in jessie, but in wheezy it still is.
 

     $ cd ..
     $ su
     # dpkg -i linux-headers-3.2.60-4custom01-686-pae-rt87_3.2.60-1+deb7u3_i386.deb
     # dpkg -i linux-image-3.2.60-4custom01-686-pae-rt87_3.2.60-1+deb7u3_i386.deb
     # shutdown -r now;exit

You should now be running your new kernel.  Login again as a normal user.
 

     $ su
     # apt-get install dkms
     # apt-get install sl-modem-dkms sl-modem-daemon
     # apt-get clean

dkms should automatically build the slamr and slusb kernel modules for the running kernel during installation of the sl-modem-dkms package.  The "apt-get clean" command cleans up the package cache after installing all these new packages.  Now edit /etc/modprobe.d/local.conf again.  Add two more lines to blacklist slamr and slusb.  It should now look like this.
 

     blacklist snd_intel8x0m
     blacklist slamr
     blacklist slusb

Why blacklist the new modules?  Because the init script will unload any driver modules it finds for this modem, including slamr and slusb, then it will load slamr or slusb.  So why load the appropriate module twice?  Blacklist it and it will only be loaded once.  (Remember, blacklisting a module only prevents udev from loading it.  That is due to the fact that when udev attempts to load a module, it uses the "-b" option of the modprobe command.  But the module can still be loaded by issuing the modprobe command without the "-b" option, as the init script does.)  Save the file and exit the editor.  Now update the initial RAM file system, shutdown, and reboot, as illustrated below.
 

     # update-initramfs -uk $(uname -r)
     # shutdown -r now;exit

(This time, "$(uname -r)" substitutes as "3.2.60-4custom01-686-pae-rt87", since you are now running your new custom kernel.)  Upon reboot, the modem drivers should be fully functional.  Of course, to actually use the modem, you must install some type of user space package to access it, such as minicom, ppp, etc.  Use device name /dev/ttySL0 to access the modem using these programs, rather than a traditional serial port device name (/dev/ttyS0, /dev/ttyS1, etc.).  You might want to consider purging the original stock kernel at this point, since your system now depends on the slamr or slusb kernel module, which doesn't exist in the stock kernel.  You may also delete the package files (.deb files) that you created in /usr/src, now that they have been installed.

Conclusion

Happy Kerneling!  If anyone has any comments, suggestions, complaints, corrections, or any other form of feedback, please drop me a line at zlinuxman@wowway.com.

Return to my home page