| up to assignments page ↑ |
Value: (See the Grading section of the Syllabus.)
Due Date and Time: (See the Course Calendar.)
Summary:
This is not exactly a programming exercise, since you will not be writing any new code. You will step through the mechanical steps of configuring, compiling, installing, and testing a kernel. You will then do the same for a trivial kernel module, given in the text. This will make sure you can handle the mechanics, let you see first-hand the time scales of some of the development steps you will be repeating frequently throughout the course, and expose you to some of the many possible failure modes of a kernel module.
Objectives:
Tasks:
Perform the following, on the machine in the lab that is assigned to you, or on a machine of your own that you can bring in to demonstrate. If you do not use one of the lab machines, take care to check that it has a parallel port, since you will be using the same machine for the first three assignments and for assignment #3 you will need the parallel port.
These instructions are for use with a particular version of the Linux kernel source tree (2.6.25.3) and a particular Linux system distribution (Fedora Core 6). If you are using a different Linux distribution you will need to adapt the instructions, or install a compatible distribution.
The detailed instructions explain one way of doing the job. If you have built Linux kernels before, you are free to do it your own way, so long as it works. If you catch anything that looks like a typo or omission in my description, please let me know.
You can skip this step if you have a Linux installation that you find satisfactory, on a machine of your own or in the lab. If you do decide to install a Linux distribution of your own choosing, you will need to read and follow the intallation instructions for that distribution. I will suggest a few choices you should make during the installation process. If you get into trouble ask for assistance. For this (unlike programming assignments) it is OK to get help from other students in the class.
Before you do the installation, check how much RAM is installed in your machine, by watching the BIOS messages as it boots. If it is less than 512 Mbytes, please submit a helpdesk ticket to systems group (or send e-mail to help@cs.fsu.edu), indicating the IP address of the machine (the one that is on the tag) that needs more memory.
When the installation script asks you about how you want the disk partitioned, if you are inexperienced, you may use the default partition structure. However, if you do, it will allocate most of the disk as one huge root partition. Then, when your kernel crashes and the reboot requires running fsck it will take a very long time. If you are experienced or brave enough to repartition the disk you may want to consider creating your own partitions. For example, you could set up a system for future dual-booting with the following partitions:
I would suggest you select the "ext3" filesystem for your (non-swap) partitions. This has a journaling feature that will be more robust against the inevitable crashes, and require running fsck less frequently.
When the installation asks you what components you want to install, you should select the components that are needed for a kernel software development workstation. This includes, at least the C compiler, linker, and standard libraries, your favorite text editor(s), kernel sources, and probably also kernel documentation. You probably want to install networking support, enough to use ftp and ssh. (It may also help to have some of the network diagnostic tools.) You probably also want to install enough of the X-windows environment (Gnome is much smaller than KDE) to use a browser (Firefox/Mozilla). The simplest way to do this is to choose the distribution's standard development workstation configuration.
If you are using a machine in the lab I recommend taht you take a piece of tape, PostIt note, or the like, and use it to label the monitor of the machine with your name, the hostname and the IP address. (You can remove the tags on the machines from last term.)
After the installation of the OS, power on and boot up the machine, if it is not already running, and log in as "root", using the password you set when you installed Linux. If you did not do so during the installation, create yourself at least one ordinary user account, so that you don't have to do all your work as "root". You may also want to create a "guest" account for use by other students, later, if you set your machines up in pairs for remote console message logging using the serial ports.
To create a new user account do the following, substituting for "developer" whatever user name you want:
useradd -m developer
Then execute the following to set the password of this account to some password of your choice:
passwd developer
Use this account for most of your development work. You can use any name you like, but in the examples below, we will assume you have created an account for a user named developer.
I recommend that you only do as root those things that require it, to reduce the risk of clobbering your system if you make a mistake. In general, it is wise to log in first as a normal user, and then just "su" to root temporarily when necessary, or to use one of the Linux "virtual consoles" for a separate root login that you use just for the commands that require it.
If you are working from the normal console of the machine, you can select any of six virtual consoles using the function kes F1-F6. F1 is the initial virtual console. F7 is reserved for the X-windows display. For example, if you are running X-windows, you can switch over to virtual console #2 using the F2 key to log in as root and do something, then switch back to the X-windows display using F7.
Unless your machine already has networking configured, some time during installation, or after, you need to set the hostname and an IP address for your system. Do not use DHCP. You should manually configure the network.
hostname: "devicexx", where "xx" is in the range shown for this course on the whiteboard in the lab.
IP address: 192.168.10.xx, where "xx" is the same as above
gateway: 192.168.10.1
DNS server: 128.186.120.178
netmask : 255.255.255.000
Check the information on the whiteboard against the IP addresses for gateway and DNS server, etc. above. If there is any difference, the information one whiteboard should be more trusted.
Assuming you performed the default installation, the machine will probably come up with an X-windows display manager screen. If so, edit the file /etc/inittab to change the initial run-level from 5 to 3. (You can get X-windows back later by changing the runlevel from 3 to 5, of by just executing the "startx" command from a login shell.) If the machine comes up with just a login prompt, skip this step.
Shut off all unnecessary services. One way to do this, if you have X-windows and Gnome installed, is to use the GUI service editor tool. Another way, which does not depend on having X-One way is to use the command /usr/sbin/setup. When the setup menu appears, use the downarrow and Enter keys to select system services for configuration. On the Services menu, use the arrow keys and spacebar to toggle on and off services. You will need to exercise a little bit of trial and error if you want to get the absolute minimum set of services. Since I occasionally want to use a browser to look up information and download code, I run a few more than the minimum set of services, namely:
Use the tab and Enter keys to save the updated services configuration and quit the setup program.
Test the system with the reduced services, by rebooting, and verifying that the system is working well enough for you to continue with the rest of this exercise. You can use the command "reboot" to reboot.
Do not power-cycle your system to reboot. It is will prematurely age your hardware. If halt and reboot don't work, try <CTRL><ALT><DEL>; if that does not work, use the reset switch. On the lab machines, the reset switch is a small switch beneath the power switch on the front of the machine. On some other machines it is only accessible via a small hole, using a wire pin, like a bent paper clip.
Get a copy of the latest Linux kernel sources. You can download them via ftp from ftp.kernel.org, or (maybe faster) from a copy I have posted in the directory http://www.cs.fsu.edu/~baker/devices/files/, or from a CD that I have made and will leave in the lab.
If you use a CD you will need to mount the CD. Linux distributions normally come with some kind of auto-mounting support for removable devices, but with your stripped-down development kernel they probably will have been disabled. You can still mount a CD manually, using the mount command directly, or you can add lines to the file "/etc/fstab", so that you can easily mount both cdrom's and usb storage devices. The details will depend on which device names the system has assigned to your CD-ROM and/or USB storage drive(s). For example, if the system has assigned the name "/dev/sr0" to your CD-ROM drive, you could put into /etc/fstab the following line:
/dev/sr0 /mnt/cdrom auto noauto,ro 0 0
The line in /etc/fstab are essentially summaries of the parameters that need to be passed to the mount operation. The first is the physical device name, and the second is the location where it should be mounted in the filesystem namespace. To use these, you will need to create a matching mount point. For example, this can be done as follows:
mkdir /mnt/cdrom
Then, you can mount a CD by typing:
mount /mnt/cdrom
and unmount it by:
umount /mnt/cdrom
You can mount, use, and unmount a USB storage device similarly.
So, to get data from a CD, assuming the account you set up has home directory /home/developer, is the following:
mount /mnt/cdrom cp /mnt/cdrom/* /home/developer chown -R developer:developer /home/developer/* umount /mnt/cdrom
This is the last you should need to do as root, for a while.
You may need to install additional rpms (RedHat Package manager files) to compile and build a kernel.
As the normal user to whose home directory you copied the kernel source code, extract the kernel source tree from the archive file and put in a location of your choice. For example, if you followed the steps above, you could next do the following:
cd /home/developer tar xjpf linux-2.6.25.3.tar.bz2 ln -s linux-2.6.25.3 linux
Notice that the kernel source tree version, "2.6.25.3" in the example above, should be replaced by whatever kernel version you are using, and if your file is gzipped instead of bzip2ed, you use the tar option "z" instead of "j".
Once you have the kernel source tree uncompressed and untarred, cd into the source directory ("linux" in the examples above), and configure the kernel, as follows:
cd linux make mrproperto remove junk left from the old configuration. (This is probably not necessary with the newer kernel Makefiles, but it does no harm.)
The kernel comes in a default configuration, determined by the people who put together the kernel source code distribution. It will include support for nearly everything, since it is intended for general use, and is huge. It will take a long time to compile and a long time to load. For use in this course, you want a different kernel configuration. The "make menuconfig" step allows you to choose that configuration. It will present you with a series of menus, from which you will choose the options you want to include. For most options you have three choices: (blank) leave it out; (M) compile it as a module, which will only be loaded if the feature is needed; (*) compile it into monolithically into the kernel, so it will always be there from the time the kernel first loads.
There are several things you want to accomplish with your reconfiguration:
Make sure support is compiled in for using a serial port as a console.
Reduce the size of the kernel, by leaving out unnecessary components. This is helpful for kernel development. A small kernel will take less time to compile and less time to load. It will also leave more memory for you to use, resulting in less page swapping and faster compilations.
Retain the modules necessary to use the hardware installed on your system. To do this without including just about everything conceivable, you need to know what hardware is installed on your system. You can find out about that in several ways.
To reduce the size of the kernel you will need to figure out what hardware it has and what software OS features you need, so that you include all (and only) the necessary components.
If you have a running Linux system with a working kernel, one way to find out about what hardware drivers you are using is to look at the system log file, /var/log/messages, or use the command dmesg. You can also use the command lspci to list out the hardware devices that use the PCI bus. You can also check the hardware documentation for your system, or open up the box and read the labels on the components.
Using the available information, knowledge about your own system if you are not using the lab, and common sense, select a reasonable set of options. Along the way it would be a good idea to read through the on-line help descriptions for a least all the top-level menu options, so that you become more familiar with the range of drivers and software components in the Linux kernel.
Before exiting the final menu level and saving the configuration, it is a good idea to save it to a named file, using the "Save Configuration to an Alternate File" option. By saving different configurations under different names you can reload a configuration without going through all the menu options again.
Too avoid wasting too much time on the kernel trimming process (which involves quite a bit of guesswork, trial, and error) start with a kernel that works, trim just a little at a time, and test at each stage.
make -j3 make -j3 modules_install make install
The first command will compile the kernel and create a compressed binary image of the kernel. After the first step, the kernel image can be found at arch/i386/boot/bzImage (for a x86 based processor). The second command will compile the dynamically loadable kernel modules you have selected in the configuration step and install them in a subdirectory of "/lib/modules". The resulting modules have the suffix ".ko". For example, if you chose to compile the network device driver for the Realtek 8139 card as a module, there will be a kernel module name 8139too.ko. The third command will copy the new kernel into the directory "/boot" and update the Grub boostrap loader configuration file "/boot/grub/grub.conf" to include a line for the new kernel.
If there are error messages from any of the make stages, you may be able to solve them by going back and playing with the configuration options. It seems (from my experience) that some options require other options, or cannot be used in conjunction with other options. These dependences and conflicts are not documented. I had to solve such problems by guesswork, based on the compilation or linkage error messages. For example, if the linker complains about a missing definition of some symbol in some module, you might either turn on an option that seems likely to provide a definition for the missing symbol, or turn off the option that made reference to the symbol.
When you have built a kernel without any fatal compilation or linkage errors (Sad to say, there will still be a few warning messages. The Linux kernel team is not perfect.), you can try using the kernel. Before you do this, it would be a good idea to hand-edit the file /boot/grub/grub.conf to comment out some options that hide informative messages. If it has a line with "nomenu", comment that out (by adding "#" at the beginning). Similarly, comment out lines with "splashimage" and "hiddenmenu". Also find the line that specifies the timeout for the menu and increase it to a number of seconds While you are looking at the file, verify that it has some lines that reference your new kernel image, "vmlinux-2.6.20.1" as well as the original installation's kernel image. You will need the latter to reboot when your new image fails.
Reboot the system, selecting your new kernel from the boot loader menu. Watch the messages. See if it works. If it does not, reboot with the old kernel, try to fix what went wrong, and repeat until you have a working new kernel. (If you want to learn more about Grub, you will find that you have options to temporarily modify menu lines on-line, to work around typos in the Grub configuration, but that is beyond the scope of this exercise.)
When you reach a point of frustration -- from too many cycles of pruning, recompiling, testing, crashing, and rebooting -- stop. Take whatever kernel you have that will compile and run, and go on to the next step. If you are working on a machine in the lab and have not succeeded in producing any working kernel from the 2.6.26.3 source tree, fetch the file myconfig.7, copy it into your Linux source directory under the name ".config", run "make oldconfig", and then "make -j3; make -j3 modules_install; make". It should give you a modest-sized kernel that ran on at least one of the machines in the lab.
Now, using the new kernel, compile and test the simple
"hello" kernel modules from the text. If you are not
working directly in "examples/misc-modules" you will need to copy
both the code of the module ("hello.c") and the Makefile from the
to a working directory of your own. With kernel 2.6.25.3, you may
need to add "#include
For your convenience, the code of all the examples in the text, including the module ( http://www.cs.fsu.edu/~baker/devices/lxr/http/source/ldd-examples/misc-modules/hello.c) is provided on line. A gzipped tarfile of the ldd-examples directory is provided in the directory http://www.cs.fsu.edu/~baker/devices/files/.
After you have compiled the module, to get hello.o, test it, by executing the following commands:
insmod ./hello.o lsmod rmmod hello
Now, make a copy of the module code and change it so that init_module() returns 1, recompile, and retest.
You will need to modify the Makefile to add the name of your new module to it. For example, if you call your new module source file "hello1.c", you will need to add "hello1.o" to the line
obj-m := hello.o .... kdataalign.o
What happens? Why?
Now, change the module so that either init_module() or cleanup_module() does some bad thing. Create another file to do this, with a new name. Compile it. If it compile OK, test it, but before testing it, use "sync" to synchronize the file system in-memory structures with those on disk, since it is likely that the system will crash, and you will need to reboot.
The following are some typical errors. Some of these may be caught at compilation or link time, and some may only cause problems when you call insmod with the module.
Repeat a few such experiements, and see of you can hang or crash the entire system. Keep a journal of what you try, and what effects you observed. Save copies of the "bad" modules you tested, by giving them different names.
Beware that some of the things you do may have no immediate visible effect, but may have a delayed effect that is disastrous. This is generally the case if you write garbage into random locations of kernel memory. The location you corrupt may not be referenced to a while. It will be referenced later, and then the effect will occur. Therefore, you cannot assume that the thing you did most recently is necessarily the cause of a crash.
One consequence is that you need to test any new kernel code extensively, letting the system run long enough (and with enough other activities going on) to give you confidence that your new code has no harmful side-effects.
Another consequence is that when you are debugging your own code, if you have tested some code that seems to have gone badly wrong, but not badly enough to crash the system (yet), you may want to reboot the system before testing your revised code. I have seen cases where a system crashed while executing the corrected code, but the crash was because of the delayed effect of damage that had been done by the previously executed (bad) version of the code. When this happens, the student sometimes mistakenly thinks the new code is bad, too, and becomes very confused.
Do not go overboard on this part of the assignment. The objective is to expose you to the various ways a kernel failure can manifest itself, in preparation for testing your own code. The objective is not to do the most damage possible to your system. In particular, it would better if you you do not trash your hard drive, since reinstalling the entire system takes a frustratingly long time. For example, a student once tried writing garbage into memory, walking downward through the kernel memory toward address zero. Some of that memory is mapped to hardware devices, like the disk controller, and some of it is used for buffers, like disk I/O buffers. Somehow, he managed to corrupt some of the OS files on the hard drive.
Prepare a copy of your journal, and have it ready to hand to the instructor when you demonstrate your project.
Advice:
Get started right away. You have only four days to do this.
Feel free to ask for information/help from other students with the kernel configuration and similar technical set-up details, but don't let them do the work for you. Do it on your own. If you can't do this simple exercise by yourself now, you won't be able to do the other exercises later. In particular, do not ask someone else what changes they made to the kernel module, and what happened to them (until after the due date and all assignments are turned in). Moreover, the odds of two people in the class having the same exact results are very slim, so if you just copy I am likely to notice.
References:
Delivery Method:
In class on the due date, arrange an appointment with the instructor to demonstrate what you have done.
At the appointment, come to the lab and demonstrate your work. At that time, turn in on paper your journal/notes of the "bad" modules you tested, including copies of the code, what behavior they caused (e.g., system locked up, kernel panic), and what output (if any) was generated. Be prepared to demonstrate your kernel booting up and your modules loading and executing, explain what steps you took, walk through your configuration option selections, and demonstrate the module(s) that caused crashes. Have the test modules ready to go; do not try to edit code during the demonstration. Notes will be taken of your kernel's memory footprint, how many services you have running, and how long the system takes to boot up.
Assessment:
If you do everything that is required and can explain it adequately at the demonstration you will receive a perfect score. Deductions will be made for skipped steps, steps done incorrectly, or inability to explain.
| © 2003-2008 T. P. Baker ($Id: prog1.html,v 1.1 2008/04/28 17:57:51 baker Exp baker $) |