"A crash reduces
your expensive computer
to a simple stone."
—Anonymous, GNU error message haiku page
Welcome to the second meeting of the Operating Systems course! Today we're going to configure and compile a Linux kernel from source code. Even if you've done this kind of thing before, this studio will introduce the source code and resources that this class depends on, along with giving you additional experience working with the Raspberry Pi platform.
In this studio, and throughout the semester, you will use a two-stage cross-compilation approach:
Having the code and the build process on other machines has some key advantages besides
probably building faster than on your Pi. First,
if you get locked out of your Pi, or at some point a (modified) kernel crashes (see the
error message haiku above :-) most of the work you have done is safe in another
location which allows you to start over efficiently by re-imaging your Pi to
the default setup, fixing whatever bugs may have caused the crash, recompiling the kernel,
installing it, and proceeding from there. Second, the CEC servers (such as
shell.cec.wustl.edu) give you a place to create backup copies of any code
before you modify it - or even to run version control software such as
git so that if a change you make goes awry you can quickly recover to
a previous (working) version of your code.
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.
As you work through these exercises, please record your answers, and when finished email your results to firstname.lastname@example.org with the phrase Welcome To Linux Studio in the subject line.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
Boot up and log into your Raspberry Pi, open up a terminal window, and use the
uname command to get a variety of information about the currently
running system, such as the current kernel version or the date on which
the currently running kernel was compiled. As the answer to this exercise,
give the output from running the command
To save time, and to avoid potential freezing of your Raspberry Pi during
long-running local compiles, we will
be cross-compiling the kernel using a university-managed server
shell.cec.wustl.edu) and dedicated Linux machines.
First, ssh into
shell.cec.wustl.edu using your WUSTL Key id and password.
The following directions will let you do that from one of the Windows lab machines - on a Mac or Linux laptop, you can just run ssh directly from within a terminal window.
Once you are logged into
shell.cec.wustl.edu, create a folder called
linux_source in which to keep all of your source code and build files organized.
cd command to move into your new folder and issue the following
commands, each of which may take a while to finish:
tar -xzf raspberrypi-kernel_1.20160506-1.tar.gz
This has the effect of downloading a specific version of the
Raspberry Pi 3 Linux distribution, which is the version that
this course was developed with. Newer versions exist, which we won't
use for this class but you can pursue on your own time if you'd like. Once
the files finish unpacking you'll have a new directory, which we
suggest renaming as something simpler with the
command. We renamed ours linux, which is what the
rest of these instructions will assume you've done as well.
To save space, please delete the
.tar.gz file once it is unpacked.
Move into your new linux directory, and issue the
make kernelversion, which will tell you which Linux
kernel version you've just checked out. As the answer to this exercise, give the output
from that command.
module add raspberry (this adds the cross-compiler to your PATH variable)
KERNEL=kernel7 (this is used by some build scripts)
Note that in some terminal environments (depending on how your account is set up and what shell is running in it on
shell.cec.wustl.edu) you may need to do this using the set command instead:
echo $KERNEL (this outputs the current value stored in the
KERNEL environment variable, which should be
kernel7 if the previous command was successful)
make -j8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
To reiterate, if you were building a general purpose kernel, you wouldn't use the previous commands, which set up a default configuration for the Raspberry Pi .
Next, we want to set custom configuration options. Issue the command:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
After a moment, you'll get a kernel configuration menu. As you can see, there are a _lot_ of options. For now, we're just going to do two things. First, we will choose the kernel's preemption model. Go into "Kernel Features", select "Preemption Model", and then select the "Preemptible Kernel (Low-Latency Desktop)" option.
Next you'll add your own unique identifier to the kernel you build.
Exit "Kernel Features" and navigate to "Local version" under "General
setup". The local version
string you specify here will be appended to the output of the
uname command. If you applied the default Raspberry Pi
configuration correctly, this currently should be set to "
-v7". Go ahead
and append your own unique identifier to that string, though recall that
already gives you the kernel version number, the day and time the kernel was
compiled, as well as other info.Warning: do not include any spaces in the
local version string - this will break the build script when you run
sudo make modules_install in the future.
Choose an interesting sounding option and use the "H" key to bring up a short description. As the answer to this exercise, give the option's name, a short summary, and the option's symbol. Once you're done, exit the configurator and be sure to answer "Yes" when asked to save your changes.
Because kernel compiles are
computationally intensive, you should not run them on the
shell.cec.wustl.edu server, and instead you should run the
qlogin command, which will let you log into a dedicated Linux host using your WUSTL Key id and password.
Once you are logged into one of the dedicated Linux machines, confirm that you are still in
linux_source/linux directory (or if not
cd into it).
To track how long this step takes, which you will need for the answer to this exercise, make note of (and write down) the current time. Then, issue the following commands to cross-compile the kernel:
module add raspberry
KERNEL=kernel7 (or if your shell requires it
echo $KERNEL (confirm the
KERNEL variable was set to
make -j8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
The compile may take a while (possibly an hour or more, depending on the machine you're compiling on). Once it's done, issue the following command:
This will create a directory that the cross-compiler will use to store the kernel modules that it creates. You will later transfer these files to your Raspberry Pi. Then issue the command:
make -j8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Note the time again, and as the answer to this exercise please indicate approximately how long it took to complete it.
linux_sourcethat will serve as a place to organize your code. Move inside your
linux_sourcedirectory and create a directory called
liband another directory called
boot. The naming is important, because the Pi's version of sftp will only transfer entire directories if the source and destination folders have the same name. From your
linux_sourcedirectory run the following commands:
sftp [your wustl key]@shell.cec.wustl.edu
get -r modules/lib/
get -r linux/arch/arm/boot/
quit (to get back to your Pi)
Back up your directories
/boot, because you will
be modifiying their contents. To do this, we used
sudo cp -r /lib ~/Desktop/lib_backup and a similar
/boot. You should be in
linux_source directory (if not, navigate there).
Run the following commands:
sudo cp -rd * /lib/
sudo cp boot/dts/*.dtb /boot/
sudo cp boot/dts/overlays/*.dtb* /boot/overlays
sudo cp boot/dts/overlays/README /boot/overlays
sudo ./mkknlimg boot/zImage /boot/$KERNEL.img
At this point, your new kernel is installed. When you reboot, you'll be running your very own, custom kernel.
Go ahead and reboot now. If everything went OK,
the new system should look and feel the same as before. You can verify
that your new kernel is running with the command
In particular, the build date should be today, the version string should
include the local version string you specifed during configuration, and
your Linux source code version (as well as the characters "PREEMPT")
As the answer to this exercise, give the output that was just produced by
uname -a for the new kernel.
Congratulations! You've just compiled an operating system from source!
make -jN where N is the number of cores you want to use to compile
sudo make modules_install install
That's all there is to it! The
install targets will
automatically and correctly install the new kernel for common
Linux distributions. In the base source code directory there's a file called
README which contains compilation and installation instructions for a wide
range of scenarios.
For a sufficently powerful machine, building a new kernel is pretty painless. Our lab's 16 core, 3.2Ghz Intel machines take about 15 minutes to compile and install.