Linux作为最受程序员欢迎的开源操作系统,从上世纪90年代到现在,一直在成长,一直在进步,吸纳了不计其数的程序员的代码,来自世界各地的程序员都活跃在Linux社区,很多公司也贡献自己的代码,同时也发布各个的版本,大家都从中获益颇丰。要参与Linux的开发,或者使用Linux,就要不同程度的阅读、修改Linux代码,运行自己编译的Linux镜像。然而,我们必须要做一些准备工作。
入门概念
内核划分
一般内核可将内核划分为如下几个部分:
进程管理
内核负责创建和销毁进程,并处理它们与外部世界的联系,处理进程间通讯(IPC,通过信号,管道,IPC原语等);调度器控制进程如何共享CPU;内核的进程管理活动,实现了多个进程在一个或者几个CPU之上的抽象。
内存管理
内存是PC的主要资源,处理内存的策略对系统性能至关重要,内核为每一个进程分配了一个虚拟地址空间,内核提供一套函数调用来供内核其他部分与内存管理交互。
文件系统
Linux中的任何东西都可以看做一个文件,内核在非结构化的硬件设备之上建立了一个结构化的文件系统,Linux支持多个文件系统类型(物理介质上不同的数据组织方式),例如ext3,FAT等。
设备控制
几乎所有系统操作最终都映射到一个物理设备上,任何外设的控制操作都由要访问的外设相关的代码(设备驱动)来完成,要想使用外设,内核必须嵌入响应的设备驱动。
网络
因为大部分的网络操作不是特定于某一个进程,进入系统的报文又是异步的,报文在某一个进程接手前必须被收集,识别,分发。内核负责在应用程序和网络接口卡之间递送报文,内核根据程序的网络活动来控制程序的执行,并且所有的路由,地址解析都由内核完成。
设备和模块的分类
Linux的设备分为,字符设备,块设备,网络设备,因此Linux的模块可分为,字符模块,块模块,网络模块。
字符设备
字符设备是一种可以当做一个字节流来访问的设备,字符设备驱动至少实现open,close,read,和write系统调用。大部分字符设备仅仅是数据通道,只能顺序访问,不能像普通文件一样可以移来移去。
块设备
块设备应该可以驻有一个文件系统,Linux允许应用程序像字符设备一样访问块设备,每次传送任意字节的数据。字符设备、块设备的区别仅仅在于内核内部管理数据的方式,因此内核/驱动的软件接口就不同。
网络设备
网络设备可以是硬件设备,也可以是软件设备(环回loop),网络设备在网络子系统的驱动下,负责发送和接收数据报文,网络设备驱动对单个连接一无所知,它只处理报文。网络设备不是面向流的,因此不容易简单的映射到文件系统节点上,但是Linux也给网络设备分配了名字,虽然没有对应的文件系统入口,因此内核和网络设备的通讯也不同于字符设备、块设备,调用函数也不同,不能使用read/write。
除了以上的分类方式,还有一些其他的分类方式,例如,我们可以说,USB模块,串口模块,SCSI模块;每一个USB设备由一个USB模块驱动,与USB子系统一起工作,但是它可能表现为一个字符设备(USB串口),块设备(USB内存卡),网络设备(USB网卡)。
文件系统类型是一种软件驱动,它将低级数据结构映射为高级数据结构,文件系统决定一个文件名多长,在一个目录入口中存储每个文件的什么信息,文件系统模块必须实现最低级的系统调用,来存取目录和文件,通过映射文件名和路径到保存在数据块中的数据结构。内核声明了不同操作,可以在一个文件系统节点,目录,文件和超级块上进行操作。
安全相关
内核调用init_module来检查进程是否有权加载模块到内核。
安全是一个策略问题,所以一般,驱动程序员应该避免编写与安全相关的代码到设备驱动中,安全应该由系统管理员在内核高层来处理。
驱动必须检查,会影响全局资源的设备操作(例如设置中断线),可能会损坏硬件(例如加载固件),或者可能影响其他用户。
驱动要避免引入安全bug,例如缓冲区覆盖,除非能核实用户输入,否则不能信任,小心未初始化的内存。
如果不能以root运行预编译的二进制文件,最好不要运行一个预编译的内核。
版本编号
运行于Linux之上的软件存在依赖性,一般我们需要一个包的特殊版本来运行另一个包的特殊版本。
对于Linux内核,偶数版本的内核是发布版本,奇数版本的内核是开发快照。建议使用偶数版本的发布内核。
版权条款
Linux遵从GPL V2(GNU通用公共版权版本2),只要接收方能够获取到源码并对其行使同样的权利,GPL允许任何人重新发布,销售,GPL涵盖的任何产品。如果要完全重新发行源自使用GPL产品的软件产品,必须置于GPL下发行。
如果想把自己的代码放进主流内核,或者对内核打补丁,那么发行代码时,必须使用一个GPL兼容的许可。
GPL的主要目的是让知识增长、传播。任何人都可以修改代码。
一些提供商,基于已公布的内核接口,发布二进制的模块,目前也是允许的。
准备Linux kernel tree
使用发布的内核
一般都需要安装内核源码树,例如在ubuntu下,使用uname -r获取到内核版本字符串(例如2.6.32-38-generic),然后检查/usr/src/下是否存在目录-linux-headers-2.6.32-38-generic,如果没有可以运行sudo apt-get install linux-headers-2.6.32-38-generic安装。
自己编译的内核
一般自己编译完内核,运行自己的内核;然后,编译模块时,指定编译内核目录为内核源码树目录。
配置Linux
有很多选择可以用来配置Linux,可根据自己的选择来使用:
make config - 文字界面
make menuconfig - 基于文字的彩色菜单,有单选列表,对话框
make xconfig - 基于Qt的X windows配置工具
make gconfig - 基于Gtk的X windows配置工具
make oldconfig - 使用./.config里已有的,没有的就询问
make defconfig - 基于体系架构,从arch/$ARCH/defconfig或者arch/$ARCH/configs/${PLATFORM}_defconfig,生成./.config
make allyesconfig - 所有询问Yes/No的选Yes,从而生成./.config
make allmodconfig - 所有询问module的选m,从而生成./.config
make allnoconfig - 所有询问Yes/No的选No,从而生成./.config