linux内核编译与内核模块

 linux内核简介、配置编译与内核模块

Linux系统架构

主要分为用户空间和内核空间。用户空间包括应用程序和C库等。内核空间包括系统调用接口,linux内核以及体系结构相关代码。关于linux要区分内核空间和用户空间的原因。首先要明白,内核空间与用户空间是程序运行的不同状态。现代的处理器往往有很多工作模式,以ARM9为例就有7中工作方式:管理模式,系统模式,用户模式,外部中断模式,快速中断模式,数据终止模式和未定义指令异常模式。X86也分有Rang0--Rang3四种模式。在不同的模式下,所使用的寄存器与访问权限不尽相同。Linux为了保护操作系统本身,系统分成了用户空间和内核空间,用户空间的访问权限要小,这样就起到了保护内核的作用。

Linux内核架构:如下表所示

                    -- 系统调用接口

                    --Linux内存管理子系统(重点掌握)

                    --Linux 进程管理子系统

Linux内核的组成 -----Linux 网络子系统(网络协议栈)

                    --虚拟文件系统

                        --驱动 

                        --体系结构相关代码(汇编)

Linux内核的配置与编译(X86平台上)

第一步:Make clean或者Make mrproper或者Make distclean

第二步:make config 或者 make menuconfig

第三步:make zImage 或者 make bzImage 

第四步:编译内核模块 make modules

第五步:安装内核模块 make modules_install (将编译好的内核模块拷贝至/lib/modules目录下面)

第六步:制作initramdisk

Linux内核模块

为何需要内核模块?如果把所有组件都编译进内核,那会使得内核模块非常庞大。另外如果想要添加或者删除某个组件就必须重新编译内核。所以提供了一种内核模块的机制。

首先要区别内核模块与一般程序的区别:

普通程序从main函数开始,从头到尾执行,然后从内存中消失。而内核模块通过初始化函数在内核中注册,然后一直存在内核中,等待将来的某个请求。模块始终存在于内核中,知道执行了卸载函数。

内核模块的写法。下面是一片hello world 的范例

#include <linux/module.h>

#include <linux/init.h>

MODULE_LICENSE("GPL");

MODULE_AUTHOR("DAVID");

MODULE_DESCRIPTION("Hello world module");

static int __init hello_init(void)

{

printk(KERN_ERR "hello world!\n");

return 0;

}

static void __exit hello_exit(void)

{

printk(KERN_EMERG "hello exit!\n");

}

module_init(hello_init);

module_exit(hello_exit);

有了内核模块的源文件,还必须有makefile。但这个makefile其实是一个假的makefile。它的作用是指定一个linux内核中的真正的makefile。下面是一篇makefile的范例(注意,这是针对X86平台的):

ifneq ($(KERNELRELEASE),)

obj-m :=hello.o

else

KDIR:= /lib/modules/2.6.18-53.el5/build

all:

make -C $(KDIR) M=$(PWD) modules 

clean:

rm -f *.ko *.o *.mod.o *.mod.c .symvers

endif

内核模块的安装与卸载

安装使用:insmod ***.ko;卸载使用 :rmmod  *** (注意不需要后缀名);查看已经安装的内核模块使用 lsmod

linux内核启动流程

uImage由zImage和uboot head相关两组成。而zImaeg又是由解压缩代码和压缩的vmlinux代码构成。总的来说内核启动流程可以分为 解压缩 、 初始化 、 启动应用程序三部分组成。初始化的最后一句代码是:run init_process("sbin/init").所以这也解释了为什么把程序放在这里面就能够开机自启动了。

linux内存管理

   首先从几个地址的概念谈起。一是物理地址,这个很容易理解,它就是CPU所使用的地址,也就是在地址总线上传输的地址。二是线性地址或者成为虚拟地址,它的大小是根据地址线的根数来确定的。但它不表示实际的内存地址。因为就算地址线能达到4G,实际的内存很可能没有4G。所以它成为虚拟地址。三是逻辑地址,这个是针对段式管理的产物。也就是段式管理中的偏移地址。

   一个程序中,代码寻址用的就是逻辑地址,一个逻辑地址经过段式管理,成了线性地址,线性地址经过页式管理,才准换成真正的物理地址。但由于很多处理器没有使用段式管理,所以linux有限制的采用了段式管理机制,将所有的段基地址都设置为0,那么偏移地址也就是逻辑地址和线性地址也就完全对应了,可以理解为相同的。也就是说,在linux中,逻辑地址,线性地址,虚拟地址都是一致的。然后线性地址经过页式转换就得到了真正的物理地址。

对于段式管理的起源,要有一定的认识。出现在intel的16位处理器上面。

你可能感兴趣的:(linux内核编译与内核模块)