From: Michael Lucas <michael.lucas@linuxworld.com>
Subject: Customizing the FreeBSD Kernel (eng)
Customizing the FreeBSD Kernel
FreeBSD for the Linux administrator
Summary
As Linux and FreeBSD often run side by side, Linux administrators
would do well to learn how to configure FreeBSD to meet their
needs. Michael Lucas presents a guide to customizing the FreeBSD
kernel, written for the Linux oriented. (3,400 words)
By Michael Lucas
C ustomizing a Unix kernel is a rite of passage for the system
administrator. Linux and many System V Unixes have a friendly,
menu-driven kernel configuration system. A system administrator needs
to have a good grounding in a variety of Unixes, however. You would
configure FreeBSD's kernel in a manner completely different than the
one in which you would System V or Linux.
Linux and FreeBSD are frequently found side by side. They're both free
Unix-like systems. Each has particular strengths; FreeBSD is known for
its network services, and Linux has strong desktop facilities. A
multiple-boot system can have both FreeBSD and Linux partitions. With
FreeBSD's Linux compatibility and the right kernel options, you can
even use both simultaneously.
This step-by-step guide includes a discussion of some of the core
differences between the FreeBSD kernel and the Linux kernel;
descriptions of the kernel configuration, build processes, and common
kernel options; ways you can gather more information; and steps to
take if you have trouble.
The FreeBSD kernel building system is very powerful, and it only
requires a bit of familiarity to use it quickly and efficiently.
We'll only discuss the i386 kernel here. The Alpha kernel is handled
in a very similar manner, but most of us aren't lucky enough to have
an Alpha lying around to test new operating systems. Alphas also have
slightly different kernel requirements, and not all functions are
fully implemented. Check LINT (more on this later) for details.
You can also apply most of the information discussed here to NetBSD
and OpenBSD, with some minor changes.
Your hardware
Before building your kernel, you need to know what hardware you have.
If you're not sure, a good place to start is the file
/var/run/dmesg.boot. This records the results of the dmesg command
immediately after boot. The dmesg command displays the contents of the
system message buffer; if your system has been up for a while, the
buffer probably contains system information other than boot probes.
/var/run/dmesg.boot remains, however.
If a device shows up as not found, you may in fact not have the
device; your hardware or kernel could also be misconfigured. The
kernel probe routines are fairly intelligent, but some hardware
doesn't lend itself to easy detection. For example, if you have an
old-fashioned, dumb-as-a-brick NE2000 network card sitting on IRQ 11
and port 0x320, the default kernel setting of IRQ 10 and port 0x280
isn't going to find it. You will need to change one or the other.
Basic kernel information
The Linux kernel appears in frequent, incremental releases. Every so
often Linus Torvalds double-checks what he has, tars it up, assigns it
a version number, and posts it. The FreeBSD kernel, on the other hand,
is in a state of continuous release. The kernel and user programs are
available via CVS (Cyclic Software's Concurrent Version System version
control software). Users are expected to be able to compile the
current kernel at any time.
Similarly, Linux kernels are expected to have certain minimal levels
of glibc and other system utilities. The FreeBSD kernel is expected to
be in sync with the user programs. This makes sense, given the
different development methods: the FreeBSD project is responsible for
both the kernel and user programs, while Linux is strictly speaking
just the kernel, with distribution designers being responsible for
user programs.
We'll assume that you have a FreeBSD system on which the kernel and
user programs are already in sync, because it installs and stays that
way unless you make a CVS error.
The kernel code is stored under /sys. Don't bother backing up this
directory; if there's an error, you could use CVS to back it out. To
configure your kernel, look under /sys/i386/conf. You will find a
variety of files. The important ones for our purposes are:
* GENERIC: A default kernel configuration
* LINT: A kernel configuration that contains all possible options
Kernel configurations are simple text files stating which options,
device drivers, and functions the kernel will support. The FreeBSD
kernel has thousands and thousands of possible combinations of
options; a menu system would run several screens deep and take far too
long to use.
Building your own kernel config file
In Linux, to build a kernel config file you would unpack your new
kernel source or apply the patch from the previous version. You'd then
either make config, make menuconfig, or make xconfig. Each of these
tools brings up a configuration interface, which would take the form
of a simple string of questions, a cursor-based menu, or an X Window
point-and-click configuration tool. All of these options are simple
enough that almost any computer-literate person can use them.
FreeBSD, on the other hand, has no menu configuration tool. The
configuration is stored in a simple text file. Functions are enabled
and disabled via flags on each device. A graphic interface to this
system would run several levels deep, and each menu would be
different.
The best place to start building your custom kernel is the GENERIC
file. Do not edit this file directly; the next system upgrade will
overwrite your changes. Copy GENERIC to another file, which we'll call
NEWSERVER. It's fairly traditional to name your kernel configuration
after the machine itself, and to use all capital letters.
The apparent problem with the GENERIC file is that it isn't self
documenting. GENERIC isn't supposed to include extensive
documentation. That's what the LINT file is for.
First, you will want to go through your config file and change any
occurrence of the word GENERIC to NEWSERVER.
Then you might want to comment out unnecessary entries. Removing
drivers for unnecessary devices will shrink your kernel. This also
means that you have to rebuild your kernel to add hardware. If your
hardware changes a lot, leave more drivers in; if it's constant, trim
them.
The equipment that makes up your system is also important in deciding
whether to leave a feature-rich or stripped-down kernel. My desktop
machine is an AMD K6 350 with 192 MB of RAM, a 19-inch monitor, and a
2 GB hard drive; the kernel is lugging around drivers for hardware I
hope to be able to afford one day. Meanwhile, the office firewall is a
486/25 with 8 MB of RAM. Its kernel is so stripped it could be
arrested for indecent exposure.
GENERIC is divided into sections for various types of cards,
controllers, and functions. Some are easy to find; if you have an
ATAPI-only system, you can delete all the SCSI devices. Some are less
obvious, and you need to check the LINT file for the entry's
description.
A few of the obvious ones to check are:
* I386_CPU, I486_CPU, I586_CPU, and I686_CPU: These are for CPU
types. The I586 is a Pentium; Pentium II and above are I686. If
you're not sure what your CPU probes as, check
/var/run/dmesg.boot.
Some chips don't probe as you might expect; for example, some
older AMD chips probe as a lower-level CPU than their clock speed
seems to indicate. If you don't include the proper CPU in your
finished kernel, the machine will no longer boot. You might as
well remove the drivers for all the CPUs you don't have; changing
CPU class will probably mean so many other hardware changes that
you'll need a new kernel anyway.
* MFS, MFS_ROOT, NFS, NFS_ROOT, MSDOSFS: If you're not using Memory
File System, Network File System, or FAT filesystem, you can
remove these. The filesystem features are all available as KLMs
(kernel loadable modules) if you later discover that you do need
them.
* wdc*, wd*, acd*, wfd*: These are standard ATAPI controllers,
disks, CD-ROMs, and LS-120 floppies. You probably want to leave
the wdc controllers; most motherboards have them, even if there
are no ATAPI devices attached.
* SCSI: If you don't have any SCSI systems, you can remove all the
SCSI controllers and peripherals. If you do this, be certain you
have eliminated all the SCSI devices. They're all arranged in a
nice little block. If you pull all the controllers, but leave a
peripheral or two, the kernel will not compile.
* Network card: Check /var/run/dmesg.boot to see if your NIC was
detected. Any modern NIC probably will be. If not, check the NIC
list in LINT to see what driver your card should use, and how to
set its port and IRQ, if necessary. You can remove drivers for all
the network devices you don't have.
* Pseudodevices: The ppp device is used for kernel PPP, sl is used
for slip, and tun is used for user programs' PPP. You can remove
whichever devices you don't need.
The BPF pseudodevice allows you to sniff network traffic. If you
use DHCP, you need it. If you don't want the machine to have
Ethernet packet sniffing capabilities, you want to lose it.
Now that you've trimmed the kernel to the reasonable minimum needed to
support your system, see what you want to add. Scroll through LINT
looking for features you might like. Adding extra features won't hurt;
the kernel will grow, but on most modern systems that's not a serious
problem. If you're not running an original first-edition Pentium, for
example, you should use the NO_F00F_HACK option. (Foof was a bug in
the original Pentium design that allowed users to lock up the system.
If your CPU doesn't have the bug, you don't need kernel protection
against it.)
For Linux compatibility, you need the POSIX options and the USER_LDT
option. If you have a Linux partition, you probably want the EXT2FS
option as well.
Don't be surprised if you run into a fundamental design difference
between the Linux and FreeBSD kernels. Linux tends to install
everything that might be needed; FreeBSD has a more spartan core.
Everything you need is there, but you must add the appropriate
options. This philosophy holds true both in the kernel and across the
user programs.
Kernel tweaking
Once you have all the functions you want in your kernel, you might
find that it doesn't work exactly as you'd like. Check LINT for more
information on each feature. Also, every device driver has a man page;
check there for details on how to tweak the configuration. Many Linux
command-line options are kernel options in FreeBSD; similarly, some
Linux kernel options are controlled on the FreeBSD command line.
For example, the wd (aka IDE) driver in GENERIC isn't configured to do
DMA (direct memory access) by default. Check the wd man page for the
proper flags to use. In this particular case, you probably want to add
flags 0xa0ffa0ff to the IDE controller.
Do you want your console to default out a particular serial port? Go
to the man page for sio. Do you want to force an Intel EtherExpress
network card to run at 10BaseT instead of 100BaseTX? Check the man
page for fxp. You might find that some functions should be configured
in /etc/rc.conf instead of in your kernel, or that you need to drop a
two-line shell script into /usr/local/etc/rc.d instead of building it
into the kernel.
Kernel building
Now that you have your kernel configuration file in shape, do the
following as root:
%config NEWSERVER
Don't forget to do a make depend
Kernel build directory is ../../compile/NEWSERVER %
The config program parses your config file and makes sure that you
have no egregious errors. It also makes a compile directory if one
doesn't exist already, and installs all the header and source files
needed to start the build process therein.
If config returns a compile directory, your config file parsed
properly. This doesn't guarantee that it will compile; it just means
that the file passed config's simple checks.
You might get errors and a compile directory. Fix the errors before
trying to build a kernel. In the best case, the kernel won't compile.
Alternately, it might compile but not boot -- and at worst, it could
boot and break something. If the latter occurs, go to the compile
directory and type:
make depend all install
This is fairly similar to the Linux kernel build procedure. You don't
need to make clean.
The kernel will build and install as /kernel. Your old kernel will be
moved to /kernel.old. On your next reboot, you will be running your
customized kernel. There is no need to muck about with the loader
(FreeBSD's LILO equivalent) to install a kernel, as you would in
Linux.
Updating your kernel
When you update your system source code, either through CVSup and make
world, or off a CD-ROM, you will want to rebuild your kernel to take
advantage of the new code.
Glance through /usr/src/UPDATING to see if any of your preferred
kernel options have changed. If you're feeling paranoid, check GENERIC
and LINT as well. Then simply do the following:
* %cd /sys/i386/conf
* %config NEWSERVER
* %cd ../../compile/NEWSERVER
* %make depend && make all install
This will rebuild only the parts of the kernel that have changed and
assemble them into the new kernel. If a kernel subsystem hasn't
changed, it won't be recompiled. Building new kernels can be extremely
rapid if the configuration or source code hasn't changed much.
If you don't want to keep your prior kernel around as /kernel.old, you
can use make depend && make all reinstall. This will simply overwrite
your old kernel.
Again, you shouldn't have to make clean as you would in Linux. The old
object files are used to build the new kernel more quickly; only
changed objects are built. If the build fails, however, you might try
make clean before make depend.
If you are doing a large upgrade (for example, FreeBSD 3-STABLE to
4-STABLE), you are probably better off starting with the new GENERIC
config file and rebuilding your configuration from scratch.
If you want to use your own config, I highly recommend diff -uw
GENERIC MYSERVER to generate a unified diff. Go through the diff
carefully and be sure you understand every option you need to add or
remove.
For those of us who upgrade our entire systems from source every week,
however, the quick configure and compile is a major timesaver.
Troubleshooting
If your kernel build fails, look at the last lines of the compile
output. At times the problem is obvious; perhaps a particular kernel
component cannot coexist with another, or an option requires another
option. Many of these errors are fairly self-explanatory.
Others aren't. Consider the example below:
===> sys/modules/xl cc -O -pipe -D_KERNEL -Wall -Wredundant-decls
-Wnested-externs -Wstrict-prototypes -Wmissing-prototypes
-Wpointer-arith -Winline -Wcast-qual -fformat-extensions -ansi
-DKLD_MODULE -nostdinc -I- -I. -I@ -I@/../include
-mpreferred-stack-boundary=2 -c
/usr/src/sys/modules/xl/../../pci/if_xl.c
/usr/src/sys/modules/xl/../../pci/if_xl.c:155: syntax error before `<'
cpp: output pipe has been closed *** Error code 1
Stop in /usr/src/sys/modules/xl. *** Error code 1
Stop in /usr/src/sys/modules. *** Error code 1
Stop in /usr/src/sys. *** Error code 1
Stop in /usr/src. *** Error code 1
Stop in /usr/src. *** Error code 1
Everything after the first *** is noise.The error is probably
immediately before this.
If you get an error you don't understand, or aren't up to reading
kernel code to debug it at the moment, take the last bit of the
compile failure (ignoring the error code 1 lines and other associated
crud) and go to the FreeBSD Webpage. (See Resources for a link.)
Search the freebsd-questions mailing list archive for your particular
error. Unless you've discovered a new error, someone will have already
had the problem, and someone else will have provided a solution.
If your answer isn't there, email the list yourself at
freebsd-questions@freebsd.org. Include the following information:
* Your FreeBSD version number
* The contents of /var/run/dmesg/boot
* The output of uname -a
* The kernel config file
* The end of the output of the failed compile
Yes, it's going to be a long message; but if you don't include all
this information, someone will probably write back and ask for the
missing piece.
Disaster recovery
You might install a kernel only to discover that you've blown away
some vital function. If you're one of the brave souls running
FreeBSD-current, you might find that your new kernel is phoning the
police every hour and telling them you're smuggling gerbils. Avoid
this. Keep a good kernel around.
The kernel install procedure copies the old kernel to /kernel.old. You
can boot this kernel instead of /kernel, the default. When the machine
first boots, you will see a countdown: booting kernel in ... seconds.
Hit the space bar to interrupt the autoboot, and type:
(Your prompt may differ, depending on exactly when you interrupt the
autoboot.)
I keep a known good kernel, /kernel.good, on all my systems. This way,
if I have two goofball kernels in a row I can still boot the machine.
The system installs a /kernel.GENERIC for this purpose, but GENERIC
might lack functions you need or have some incorrect settings. You can
also use RCS (Revision Control System) on your kernel config file to
allow you to back up to a prior version; this is a good idea when
you're just learning about all the options.
If you find that you goofed in building your new kernel and assigned a
dumb device the wrong memory address or IRQ, you don't have to crack
your case or rebuild your kernel. Interrupt the boot process as above
and type the following:
disk1s1a>boot -c
This will bring you up into the kernel configuration tool. You can
alter IRQs, memory ports, and other system information here. The next
time you have to rebuild your kernel, you can fix it properly.
Summary
FreeBSD's kernel build process is configured just like Samba, named,
Apache, or any other common network utility: it is done with a text
configuration file. The average Linux administrator is generally
comfortable with this sort of configuration, and shouldn't be put off
just because it's the kernel.