RSS
热门关键字:  几款非主流QQ头像  数字的颜色  峡谷攻防战  依然非主流QQ头像  QQ卡通可爱头像

方法:解读Linux操作系统内核源码

来源: 作者: 时间:2008-03-29 点击:

关键字:解读Linux操作系统内核源码的方法 Linux系统中使用命令行修改时区 Linux系统下调整屏幕刷新率的方法 Linux操作系统摄像头驱动的安装 在Linux系统下如何利用SSH进行远程控制 通过网络安装Linux CentOS 系统的方法 Linux和Windows系统线程间的区别 Linux操作系统下修改IP、DNS等网络配置

 

针对好多Linux 爱好者对内核很有兴趣却无从下口本文旨在介绍一种解读linux内核源码入门方法而不解说linux复杂内核机制;

一.核心源程序文件组织:

1.Linux核心源程序通常都安装在/usr/src/linux下而且它有一个非常简单编号约定:任何偶数核心(例如2.0.30)都一个稳定地发行核心而任何奇数核心(例如2.1.42)都一个开发中核心

本文基于稳定2.2.5源代码第二部分实现平台为 Redhat Linux 6.0

2.核心源程序文件按树形结构进行组织在源程序树最上层你会看到这样一些目录:

●Arch :arch子目录包括所有和体系结构相关核心代码每一个子目录都代表一种支持体系结构例如i386就关于intel

cpu及与之相兼容体系结构子目录PC机一般都基于此目录;

●Include: include子目录包括编译核心所需要大部分头文件与平台无关头文件在 include/linux子目录下与 intel

cpu相关头文件在include/asm-i386子目录下,而include/scsi目录则有关scsi设备头文件目录;

●Init: 这个目录包含核心初始化代码(注:不系统引导代码)包含两个文件main.c和Version.c研究核心如何工作一个非常好起点

●Mm :这个目录包括所有独立于 cpu

体系结构内存管理代码如页式存储管理内存分配和释放等;而和体系结构相关内存管理代码则位于arch/*/mm/例如arch/i386/mm/Fault.c

●Kernel:主要核心代码此目录下文件实现大多数linux系统内核函数其中最重要文件当属sched.c;同样和体系结构相关代码在arch/*/kernel中;

●Drivers: 放置系统所有设备驱动程序;每种驱动程序又各占用一个子目录:如/block

下为块设备驱动程序比如ide(ide.c)如果你希望查看所有可能包含文件系统设备如何初始化你可以看drivers/block/genhd.c中device_setup()它不仅初始化硬盘也初始化网络因为安装nfs文件系统时候需要网络其他:

如, Lib放置核心库代码; Net,核心与网络相关代码; Ipc,这个目录包含核心进程间通讯代码; Fs

,所有文件系统代码和各种类型文件操作代码每一个子目录支持一个文件系统例如fat和ext2;

Scripts, 此目录包含用于配置核心脚本文件等

一般在每个目录下都有一个 .depend 文件和一个 Makefile

文件这两个文件都编译时使用辅助文件仔细阅读这两个文件对弄清各个文件这间联系和依托关系很有帮助;而且在有目录下还有Readme

文件对该目录下文件一些说明同样有利于我们对内核源码理解;

二.解读实战:为你内核增加一个系统调用

虽然Linux 内核源码用树形结构组织得非常合理、科学把功能相关联文件都放在同一个子目录下这样使得程序更具可读性然而Linux

内核源码实在太大而且非常复杂即便采用很合理文件组织方法在不同目录下文件之间还有很多关联分析核心一部分代码通常会要查看其它几个相关文件而且可能这些文件还不在同一个子目录下

体系庞大复杂和文件之间关联错综复杂可能就很多人对其望而生畏主要原因当然这种令人生畏劳动所带来回报也非常令人着迷:你不仅可以从中学到很多计算机底层知识(如下面将讲到系统引导)体会到整个操作系统体系结构精妙和在解决某个具体细节问题时算法巧妙;而且更重要:在源码分析过程中你就会被一点一点地、潜移默化地专业化;甚至只要分析十分之一代码后你就会深刻地体会到什么样代码才一个专业程序员写什么样代码一个业余爱好者写

使读者能更好体会到这一特点下面举一个具体内核分析实例希望能通过这个实例使读者对Linux内核组织有些具体认识从中读者也可以学到一些对内核分析方法

以下即为分析实例:

A、操作平台:

硬件:cpu intel Pentium II ;

软件:Redhat Linux 6.0; 内核版本2.2.5

B、相关内核源代码分析:

1.系统引导和初始化:Linux 系统引导有好几种方式:常见有 Lilo,

Loadin引导和Linux自举引导(bootsect-loader),而后者所对应源程序为arch/i386/boot/bootsect.S它为实模式汇编程序限于篇幅在此不做分析;无论哪种引导方式最后都要跳转到

arch/i386/Kernel/setup.S setup.S主要进行时模式下初始化为系统进入保护模式做准备;此后系统执行

arch/i386/kernel/head.S (对经压缩后存放内核要先执行 arch/i386/boot/compressed/head.S);

head.S 中定义一段汇编程序setup_idt 它负责建立一张256项 idt 表(Interrupt Descriptor

Table),此表保存着所有自陷和中断入口地址;其中包括系统调用总控程序 system_call

入口地址;当然除此之外head.S还要做一些其他初始化工作;

2.系统初始化后运行第一个内核程序asmlinkage void __init start_kernel(void) 定义在

/usr/src/linux/init/main.c中,它通过调用usr/src/linux/arch/i386/kernel/traps.c 中一个函数

void __init trap_init(void) 把各自陷和中断服务程序入口地址设置到 idt

表中,其中系统调用总控程序system_cal就中断服务程序之一;void __init trap_init(void) 函数则通过调用一个宏

set_system_gate(SYSCALL_VECTOR,&system_call); 把系统调用总控程序入口挂在中断0x80上;

其中SYSCALL_VECTOR定义在 /usr/src/linux/arch/i386/kernel/irq.h中一个常量0x80; 而

system_call

即为中断总控程序入口地址;中断总控程序用汇编语言定义在/usr/src/linux/arch/i386/kernel/entry.S中;

3.中断总控程序主要负责保存处理机执行系统调用前状态,检验当前调用否合法, 并根据系统调用向量使处理机跳转到保存在 sys_call_table

表中相应系统服务例程入口; 从系统服务例程返回后恢复处理机状态退回用户程序;

而系统调用向量则定义在/usr/src/linux/include/asm-386/unistd.h 中;sys_call_table

表定义在/usr/src/linux/arch/i386/kernel/entry.S 中; 同时在

/usr/src/linux/include/asm-386/unistd.h 中也定义系统调用用户编程接口;

4.由此可见 , linux 系统调用也象 dos 系统 int 21h 中断服务, 它把0x80 中断作为总入口, 然后转到保存在

sys_call_table 表中各种中断服务例程入口地址 , 形成各种不同中断服务;

由以上源代码分析可知, 要增加一个系统调用就必须在 sys_call_table 表中增加一项 ,

并在其中保存好自己系统服务例程入口地址,然后重新编译内核当然系统服务例程必不可少

由此可知在此版linux内核源程序中,与系统调用相关源程序文件就包括以下这些:

arch/i386/boot/bootsect.S

arch/i386/Kernel/setup.S

arch/i386/boot/compressed/head.S

arch/i386/kernel/head.S

init/main.c

arch/i386/kernel/traps.c

arch/i386/kernel/entry.S

arch/i386/kernel/irq.h

include/asm-386/unistd.h

当然这只涉及到几个主要文件而事实上增加系统调用真正要修改文件只有include/asm-386/unistd.h和arch/i386/kernel/entry.S两个

一流导航网16dh.com

最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册
栏目列表