Homework 1
Due October 18th via handin
The amount of coding for this assignment is minimal. The bulk of your time will likely be spent setting up an environment for kernel development, and waiting for the kernel to compile.
You will need some way to develop your kernel code under Linux -- by using a separate machine, a dual-boot system, or most likely a virtual machine (VM). I'll cover the VM option here.
A virtual machine allows you to install "guest" operating systems, allowing them to run just as any other program inside a window on your "host" operating system. For example, Linux or FreeBSD can be run inside Windows Vista, or Vista inside Mac OS X.
There are several virtual machine products. You can choose any product you are comfortable with, as long as it runs on your host operating system and supports Linux as a guest. VirtualBox is a multi-platform open source project by Sun that should work fine. Virtual PC for Windows is a free offering from Microsoft. Popular commercial products include VMware for most OSs and Parallels for OS X.
Linux technically is just a kernel, and is packaged by many different "distributions" which include various user software usually tailored for a specific audience. You can pick any distribution, but you must use Linux kernel 2.6.20. This version of the kernel is several years old and will not be included in recent distributions, so make sure you are comfortable retrofitting your distribution with an older kernel. I will cover how to retrofit Ubuntu 9.04 with kernel 2.6.20 for those wanting a safe option.
Getting started:Installation instructions will vary by VM, but the general procedure will be the same: specify the guest OS type (sometimes auto-detected), specify the location and size of the virtual hard disk, specify the resources for the guest (amount of RAM, number of processors), and specify how to install your guest OS. In our case, we'll tell the VM to treat our downloaded ISO as a virtual CD and boot from it to install Ubuntu. Here's how it looks in Parallels:


Once you boot from the ISO, Ubuntu will guide you through the install process. You'll eventually need to specify your name, a login id, and password, and Ubuntu will reboot into the Gnome desktop.
For ECS150 we will use an older version of the kernel, as later assignments are based on code that has since been replaced. You will need to download kernel 2.6.20, install an older version of gcc, and edit a few files before you can compile and boot the kernel.
sudo apt-get install wget wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.20.21.tar.bz2 tar xvjf linux-2.6.20.21.tar.bz2 sudo mv linux-2.6.20.21 /usr/src cd /usr/src sudo ln -s linux-2.6.20.21 linux
This runs the apt-get utility to install the wget utility, which will download the kernel source code from the kernel.org website. Sudo will prompt you for your password so that apt-get will have permission to install wget. You can alternatively download the source using Firefox, though becoming familiar with apt-get will be helpful later.
Next we want to configure the kernel.
cd linux cp /boot/config-2.6.28-11-generic .config make oldconfig (hold enter until back at bash prompt)
The kernel can be configured with many different options. A good place to start is the default Ubuntu kernel config stored in the /boot directory. The kernel build process reads its configuration from a file named .config, so we make a copy of the default configuration. Finally, we let the kernel scan this file and prompt the user for any new options not set in the .config file. Hold the enter key to accept the default values until you are returned to the shell prompt, as we aren't interested in customization at the moment. You can easily browse all available options by installing the ncurses-dev package using apt-get, and running make menuconfig.
Unfortunately, recent versions of gcc including 4.3 and 4.4 have trouble compiling the older 2.6.20 kernel. We'll need to use apt-get to install gcc 4.2, and edit a few files to fix a missing header and use version 4.2 of gcc.
sudo apt-get install gcc-4.2 add #include <limits.h> to scripts/mod/sumversion.c edit Makefile, change the line CC=$(CROSS_COMPILE)gcc to CC=$(CROSS_COMPILE)gcc-4.2
You can now compile the kernel. Here's one way to do it:
make make modules sudo make install sudo make modules_install sudo update-initramfs -c -k 2.6.20.21
Recall from class we talked about code that can be loaded into the kernel at run time -- you are compiling and installing such code here, along with the kernel itself. Your .config file determines what code will be statically linked into the kernel, what code will be dynamically linked, and what code will not be built at all. The compilation step may take several hours due to the number of drivers and options built by default.
The boot loader is a tiny piece of code which allows selecting various operating systems when your system starts. The default bootloader for Ubuntu is named grub. Grub's configuration files are stored in /boot/grub. In particular, you may want to examine /boot/grub/menu.lst. It contains a list of kernels, normally stored in /boot, which the loader will allow you to select from if you hit the escape key during startup. You will use this often during kernel development -- a change is made, you reboot into your new kernel, there is an bug causing the kernel to crash, and you reboot and select the default Ubuntu kernel to get your system back into a useable state and fix the bug.
The kernel you just compiled must be added to /boot/grub/menu.lst. You can do this manually, following the pattern of existing entries, or run:
sudo update-grub
This will add all kernels stored in /boot to your menu.lst file. You can now reboot.
sudo reboot
Make sure to watch for Grub's message about pressing the Escape key to see the boot menu. The default window of time is very brief.
Your book outlines the basic steps for this assignment on pages 93-97, though a few details have changed. First create a new file linux/kernel/newsys.c:
#include <linux/linkage.h>
#include <linux/kernel.h>
asmlinkage int sys_helloworld()
{
printk("<0>Hello World\n");
return 0;
}
This is the actual syscall code. Notice we use a function named printk instead of the familiar printf. We'll talk about that later.
Next, edit linux/kernel/Makefile and add:
obj-y += newsys.o
This adds your file newsys.c to the list of files to be compiled into .o files and linked into the kernel.
Next, edit linux/include/asm-i386/unistd.h. This file maps system call numbers to function names. Use the other entries in this file as a guide, and make sure to increment NR_syscalls. If you added your call in the right place, you should have assigned it syscall number 320.
Finally, edit linux/arch/i386/kernel/syscall_table.S, the list of syscall handlers. Use the other entries as a guide, adding your syscall to the end of the file.
You can now recompile and boot your new kernel, but you'll need some way to test it worked. Compile and execute the following user-space program:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("returned %d\n", syscall(320));
return 0;
}
You should see your system call returned 0.
You should also see Hello World printed to your screen. This is because we called printk in your syscall. Your syscall is running in kernel space and has no access to the printf function used by user space programs. The printk function provides similar functionality, with 2 main differences. The first is that messages sent via printk are fetched by the kernel logging service klogd, which forwards them to the system logging service syslogd. On Ubuntu, you can see syslogd decided to write your message to the end of /var/log/syslog:
tail /var/log/syslog
The second difference is the use of message priorities called loglevels. By starting our message with the text <0> we specified a loglevel of KERN_EMERG. There are 7 loglevels constants defined in linux/kernel.h ranging from debugging to emergency, and we can use these constants for more readable code instead of their explicit values:
printk(KERN_EMERG "Hello World\n"); printk(KERN_INFO "Hello World, Part Deux\n");That's all you need for this assignment.