编译内核
$ tar xvf linux-3.0.tar.bz2
$ cd linux-3.0
$ cp -vi /boot/config-`uname -r` .config
$ make localmodconfig (参见: Easy local kernel configuration)
$ make -j4 (增加编译速度)
$ sudo make modules_install$ sudo make install
$ sudo update-initramfs -u -k 3.0.0 (如果在/boot下没有生成initrd.img-3.0.0文件)
编译内核的外部模块(自己写的模块)
在$HOME的module目录下创建Makefile和test.c
# Makefile for single source file
obj-m := test.o
# Makefile for two source files
obj-m := test.o
test-objs := file1.o file2.o
# Makefile from the Linux Device Drivers
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := simple.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif
/* test.c */
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int test_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void test_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(test_init);
module_exit(test_exit);
编译模块
$ make -C /lib/modules/`uname -r`/build M=`pwd` modules
内核编程时的注意点
- Applications are laid out in virtual memory with a very large stack area. The stack, of course, is used to hold the function call history and all automatic variables created by currently active functions. The kernel, instead, has a very small stack; it can be as small as a single, 4096-byte page. Your functions must share that stack with the entire kernel-space call chain. Thus, it is never a good idea to declare large auto-matic variables; if you need larger structures, you should allocate them dynamically at call time.
- <linux/config.h>已经过时了,可以删除源代码中的相关引用。
- container_of的作用: cast a member of a structure out to the containing structure。我的理解是,根据结构体中的一个成员(的地址),获取这个结构体(的地址)。参考信息
- 通过/proc和ioctl获取(调试)信息的优缺点对比
a. /proc相对简单
b. ioctl更高效。In addition, ioctl doesn’t require splitting data into fragments smaller than a page.
c. ioctl命令常駐于驱动中,如果没有文档说明,用户几乎不会知道它们的存在。相对地,通过/proc来获取调试信息的话,通常是在DEBUG版本下进行的,而且所有的用户都可以访问这些调式信息。 - 避免Race Condition的经验法则
a. 如果可能,尽量避免共享的资源,比如避免使用全局变量。
b. 全局变量远不是共享资源的唯一形式。比如,任何时候你的代码向内核的其它部分传递了一个指针,就创建了一个潜在的共享资源。共享是不可争辩的事实。
c. Here is the hard rule of resource sharing: any time that a hardware or software resource is shared beyond a single thread of execution, and the possibility exists that one thread could encounter an inconsistent view of that resource, you must explicitly manage access to that resource. - Note the check on the return value of down_interruptible
If it returns nonzero, the operation was interrupted. The usual thing to do in this situation is to return -ERESTARTSYS. Upon seeing this return code, the higher layers of the kernel will either restart the call from the beginning or return the error to the user. If you return -ERESTARTSYS, you must first undo any user-visible changes that might have been made, so that the right thing happens when the system call is retried. If you cannot undo things in this manner, you should return -EINTR instead.
- Sleeping
Never sleep when you are running in an atomic context.
- Exclusive waits
Employing exclusive waits within a driver is worth considering if two conditions are met: you expect significant contention for a resource, and waking a single process is sufficient to completely consume the resource when it becomes available.
内核代码理解
braced-group within expression
/* so, i = 100 */
int i = ({ int k = 1; k += 99; });