Kernel Hacking Lesson #5: Your First printk
Here's where you prove that kernel hacking is NOT magic. Remember, at
this point you have compiled and booted your new Linux kernel. Now
we're going to "hack the kernel." We're going to add a printk, a
function that prints out a message, during bootup.
First, bring up the file init/main.c in your favorite editor. If
you are using source control, be sure to check out the file first. In
BitKeeper, use the command bk edit init/main.c. In CVS, use cvs co
init/main.c. Find the calibrate_delay(void) function in the file.
The first lines are declarations of a few variables, and will look
something like this:
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
Now, type in the following line just below them:
printk("*** I am a kernel hacker! ***\n");
And now, recompile using make bzImage or make zImage, run LILO
or ybin or whatever you need, and boot your new kernel. You don't need to
run make clean. Watch the screen when you boot up -
you should see your new message. If it scrolls off the screen too
quickly for you to read it, login and type:
$ dmesg | less
You should see your message near the beginning of the output.
Congratulations! You have just hacked the kernel. printk's are one
of the main tools of the kernel hacker. You will need to use them
constantly.
More printk Tricks
printk is in many ways the kernel equivalent of the C standard
function printf. The formats are mostly the same. You will use
certain formats far more often in kernel code than you do in user
code. The "%x" or "%p" formats are especially useful. "%x" says to
print out the value in hexadecimal, which is base 16, and is usually
far more useful information than the value in decimal, which is base
10. This is because the logical unit of information in a computer is
a byte (8 bits), and a byte fits into two digits in a hexadecimal
representation. So the hexadecimal value:
0x12345678
Represents these 4 bytes (ignoring endian-ness):
0x12
0x34
0x56
0x78
As you can see, it's easy to separate out a hexadecimal value into
individual byte values - just read it two digits at a time. The "0x"
part just says that the following numbers are in base 16, not base
10. (Note: only obsolete and irrelevant machines have bytes which are
not 8 bits. We don't care about bytes which are not 8 bits long.)
The "%p" format says to print out the value as a pointer, or an
address in memory. This format will depend on the machine, but is
always in hexadecimal. It prints leading 0's, too.
Your next assignment is to print out the address of a variable. Below
your first printk, add this printk:
printk("The address of loops_per_jiffy is %p\n", &loops_per_jiffy);
Recompile and boot. Now you know what virtual address in memory the
variable loops_per_jiffy is stored at. You can also find this out
from the file System.map in your top-level Linux source directory:
$ grep loops_per_jiffy System.map
Next, we're going to learn about loglevels. You can specify each
printk to have a certain level of importance. Depending on the
current loglevel, some messages will be printed to the console (your
video monitor, usually) and some won't. Add this below your other
printk's:
printk(KERN_DEBUG "*** This is a debug message only. ***\n");
If your loglevel is configured normally, you won't see this message
printed out during bootup. Once you've finished booting, login and
look at the kernel messages again:
$ dmesg | less
Below your other messages, you should see:
*** This is a debug message only. ***
This is convenient since you only have to look at the output when you
want to, instead of having it printed on the screen (possibly while
you're typing). The definition of all the different KERN_* loglevels
in include/linux/kernel.h. Usually, you will only need KERN_INFO
and KERN_DEBUG.
Whenever you want to find out what's going on inside the kernel, a
good way to start is by putting printk's in strategic places. Be
careful that you don't print out too much information - it can slow
down your kernel to the point of unusability. In certain places,
adding a printk can cause a crash, or cause a bug, or fix a bug. To
find out exactly what printk does, start reading in the file
kernel/printk.c.
Have fun with your printk's!
|