本文主要用于记录操作,包括linux内核的编译过程,入门驱动的程序编写,相关命令或术语简介,参考价值有限...

0. 最好不要在虚拟机编译,内存容易出问题;注意权限的使用;遇到的若干Error不再赘述,网上有成堆的解决方案。

1. 查看系统和内核版本,下载内核并解压。这里我下载了相近的3.14.63版本。

Linux1

2. 配置内核,得到.config文件。

Linux2

为方便,将/boot/目录下的配置文件,这里我的是config-3.13.0-79-generic,复制到内核根目录下。然后在编译界面选择<Load>,填写刚刚的文件名,<OK>返回上层,<Save>,将文件名命名为.config,<OK>返回上层,<Exit>。回到内核根目录使用ls -a 查看配置文件,如果存在.config文件则说明配置成功。

Linux3

3. 编译内核,得到内核映像zImage和内核模块映像initrd-$version。

Linux4

前面得到了bzImage内核镜像,bzImage和vmlinuz是完全一样的东西,只是习惯将bzImage放到/boot目录下时重名名为vmlinuz;接下来需要制作initrd文件,initrd全称是boot loader initialized RAM disk,就是由boot loader初始化的内存盘。在linux内核启动前, boot loader会将存储介质中的 initrd文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的initrd文件系统。在boot loader 配置了initrd的情况下,内核启动被分成了两个阶段,第一阶段先执行initrd文件系统,完成加载驱动模块等任务,第二阶段才会执行真正的根文件系统中的/sbin/init 进程。

Linux5

4. 安装内核,经过前面的编译阶段,我们得到了bzImage 和initrd-3.14.63 ,将这两个文件copy 到/boot/目录下,修改启动项/etc/grub.conf里面的加载内核文件和内核模块的部分,并更新。

Linux6

5. 清除文件,安装完成以后还得把内核代码里留下的痕迹清理。

6. hello world驱动编写。编写my_module.c和Makefile文件。注:做这部分的时候到实验室换了台机器...其实没啥区别。

Linux7

看上述代码,假设driver对应模块的初始化函数为int test_init(void),那么module_init(test_init)实际上等于: static initcall_t  __initcall_test_init_6 __used __attribute__((__section__(".initcall6.init"))) = test_init; 即,声明了一个类型为initcall_t (typedef int (*initcall_t)(void))函数指针类型的变量__initcall_test_init_6并将test_init赋值给它。这里的函数指针变量声明比较特殊的地方在于,将这个变量放在了一个叫做".initcall6.init"的地方,结合vmlinux.lds:

以及do_initcalls:

此时可见module_init中初始化函数的调用过程,在系统启动过程中:start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()。module_exit分析同理。

7. 编译驱动,并加、卸载,tty1查看运行输出。由于printk的优先级问题,选择了tty打印。

Linux8

8. 在/sys/目录下查看编译的驱动文件。

Linux9