linux第7章 内核编程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第7章内核编程本章内容1.Linux内核体系结构2.内核引导与设置3.内核构建4.系统调用1、Linux内核体系结构2、内核引导与设置加电BIOS/OF引导装入初始化内核/sbin/init或系统初始化系统运行切断断电BIOS/OF加电后处理器首先访问通常位于只读内存(一般是FlashROM或仅仅是Flash)中的某一地址。BIOS(基本输入输出)是x86系统加电后最先运行的代码。引导系统并与硬件相关的系统初始化代码,功能见下页。OpenFirmware是PPC(PowerPC)系统加电后最先运行的代码。BIOS功能自检及初始化程序;自检,对CPU,640K基本内存,1M以上的扩展内存,ROM,主板,CMOS存储器,串并口,显示卡,软硬盘子系统及键盘进行测试等。初始化,包括创建中断向量、设置寄存器等。引导程序,引导DOS或Linux等操作系统。硬件中断处理;系统在加电引导机器时,要读取CMOS信息,用来初始化机器各个部件的状态。它靠系统电源和后备电池来供电,系统掉电后其信息不会丢失。程序服务请求;程序服务处理程序主要是为应用程序和操作系统服务,这些服务主要与输入输出设备有关,例如读磁盘、文件输出到打印机等引导装入程序(BootLoaders)格式化磁盘时,会创建主引导记录(MBR),该记录存储在引导设备的第一个扇区(0扇区、0磁道、0磁头)。包含:一个小程序一张四入口点的分区表结束标识符(0XAA55),用来做MBR的有效性检测。GRUB(GrandUnifiedBootloader),基于x86的引导装入程序,用来加载Linux。LILO(LinuxLoader)x86中Linux的加载程序。Yaboot是基于PowerPC及其OF的引导装入程序。GRUB运行步骤第一阶段初始化;检测正在装载的驱动器;加载第二阶段的第一个扇区;跳转到第二阶段。第二阶段加载第二阶段的剩余部分;跳转到已加载的代码LILO运行步骤第一阶段开始执行并显示“L.”;检测磁盘集合信息并显示“I.”;加载第二阶段的代码。第二阶段开始执行并显示“L.”;确定引导数据和操作系统的位置,并显示“O.”;确定启动哪个操作系统,并跳转到该操作系统。GRUB与LILOLILO将配置信息存储在主引导记录中。若有任何改动,必须运行/sbin/lilo来更新主引导记录。LILO不能读取不同的文件系统。LILO没有交互式的命令接口。LILO不支持网络引导,而GRUB支持。LILO将关于可以引导的操作系统位置的信息物理上存储在MBR中。如果修改了LILO配置文件,必须将LILO第一阶段引导加载程序重写到MBR。相对于GRUB,这是一个更为危险的选择,因为错误配置的MBR可能会让系统无法引导。使用GRUB,如果配置文件配置错误,则只是默认转到GRUB命令行界面。体系结构相关的内存初始化X86和PowerPC在硬件方面都具有支持实寻址和虚寻址的内存管理特征。Linux的内存管理依赖于底层的硬件结构。现在PPC和x86的代码都集中在init/main.c的start_kernel()中,位于与体系结构无关的代码段中,调用特定体系结构的例程来完成内存初始化。开始:start_kernel()Init/main.c中start-kernel(),执行进程0(即超级用户线程rootthread),进程0又产生进程1(即init进程),然后进程0就变成CPU的空闲进程。Linux内核只提供了轻量进程的支持,限制了更高效的线程模型的实现。目前最流行的线程机制LinuxThreads所采用的就是线程-进程“一对一”模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。3、内核构建Linux集成套件包括多种内核,能够处理各种机器。通过编译内核,选择符合硬件类型的驱动等,可以调整Linux系统,使其更合理地安装到计算机中。重新编译内核以便实现一些新功能,如将Linux系统设置为一个临时路由器。使得全世界内核设计者提供的各种为改进性能而设计的内核得到充分利用。构建Linux内核Linux官方源代码发布网址:,gzip压缩的.tar.gz包,bzip2压缩的.tar.bz2。这些压缩包的源代码适用于任何体系结构。Linux源代码分为:与系统结构相关的部分与系统结构无关的部分文档和工具与体系结构相关的源代码(usr/src/linux-2.6/)arch/目录包含了所有与系统结构相关的代码,每个子目录对应一种支持的体系结构。如:Arch/i386Arch/ppc与体系结构无关的源代码Crypto:保存加密的API及各种加密解密算法;Drivers:设备驱动程序代码;Fs:VFS及Linux支持的所有文件系统代码;Include:头文件;Init:引导程序代码以及初始化代码;Ipc:支持进程间通信的代码;Kernel:内核空间特有代码;Lib:函数库的代码;Mm:用于内存管理的代码;Net:支持各种网络协议的代码;Sound:支持音频系统的代码。其他文件COPYING:Linux的GPL许可证;CREDITS:列出了对Linux作出贡献的人名;MAINTAINERS:当提交内核改动时设计的维护人员及说明;README:发布说明;REPORTING-BUGS:描述报告“bug”的过程;Documentation/:包含了Linux内核及其源代码的有关文档,当内核有所更新时,这里含有丰富的改动信息;Scripts/:编译内核时可以使用的功能及脚本。Linux内核的Makefiles文件源代码树的每个子目录下都有一个makefile文件。在源代码树的根目录下执行make,则调用顶层makefile文件,它定义了随后要输出到其他makefile的变量,以及向子目录中的每个makefile发出make调用。Script/makefile.build中定义了makefile向下级子目录递归并编译的规则。编译内核过程预处理配置内核生成内核安装内核建立模块预处理Linux内核源文件缺省位置:/usr/src/linux从Internet下载最新版本到你创建的主目录。如~Li清除以前试图建立内核过程遗留下的多余文件。Makemrproper配置内核makeconfig:手工逐项配置makemenuconfig:菜单选项配置makexconfig:XWindow配置修改配置文件/linux/.config注意,makemrproper命令要删除这个文件,可以从/linux/arch/i386/defconfig拷贝复制一个。生成内核有三步:1、makedep:生成相关性例如:如果激活“SetVersionInformationForAllSymbolsOnModules”选项,那么它为所建立的模块确定其版本信息。2、makeclean:清除一些目录中现有文件,将存储创建的新文件。3、makebzImage:编译内核本身,花费时间长。对于新内核规模小,可以使用makezImage,如果不确定,最好还是使用bzImage。建立/linux/arch/i386/boot/bzImage安装内核大多数集成套件使用LILO作为引导装入程序。/etc/lilo.conf文件中的“image=”su命令成为超级用户登录,把刚创建的bzImage拷贝到/boot中。cp~Li/linux/arch/i386/boot/bzImage/boot/vmLinuz修改lilo.conf文件中“image”行。告诉LILO更新其配置信息:/sbin/lilo建立模块配置Linux内核时,可将许多选项配置为模块而不是放进内核。每个模块可以分别装入和卸载。/linux目录下makemodules:创建在配置过程中要求的模块,但是并不安装。Makemodules_install:将已经完成的模块拷贝到对应该内核版本的/lib/modules/子目录中。管理多内核不同的情况使用不同的内核如笔记本电脑在公司和在家时因为网络接口或打印机等的不同而使用不同的内核lilo.conf文件……delay=15#15-seconddelay……image=/boot/vnlinuxlabel=Linux……image=/home/Li/bzImageLabel=TestKernel最后,执行/sbin/liloAddedLinux*(表示Linux标记为缺省内核)AddedTestKernel(表示添加新内核)4、系统调用每个系统调用都是通过一个单一的入口点多路传入内核。eax寄存器用来标识应当调用的某个系统调用,这在C库中做了指定(来自用户空间应用程序的每个调用)。当加载了系统的C库调用索引和参数时,就会调用一个软件中断(0x80中断),它将执行system_call函数(通过中断处理程序),这个函数会按照eax内容中的标识处理所有的系统调用。在经过几个简单测试之后,使用system_call_table和eax中包含的索引来执行真正的系统调用了。从系统调用中返回后,最终执行syscall_exit,并调用resume_userspace返回用户空间。然后继续在C库中执行,它将返回到用户应用程序中。使用中断方法的系统调用的简化流程系统调用表和各种链接系统调用接口的核心是系统调用多路分解表。这个表如左图所示,使用eax中提供的索引来确定要调用该表中的哪个系统调用(sys_call_table)系统调用多路分解有些系统调用会由内核进一步进行多路分解。例如,BSD(BerkeleySoftwareDistribution)socket调用(socket、bind、connect等)都与一个单独的系统调用索引(__NR_socketcall)关联在一起,不过在内核中会进行多路分解,通过另外一个参数进入适当的调用。请参看./linux/net/socket.c中的sys_socketcall函数。对用户空间进行读写Linux内核提供了几个函数,可以用来将系统调用参数移动到用户空间中,或从中移出。方法包括一些基本类型的简单函数(例如get_user或put_user)。要移动一块数据(如结构或数组),可以使用另外一组函数:copy_from_user和copy_to_user。可以使用专门的调用移动以null结尾的字符串:strncpy_from_user和strlen_from_user。通过调用access_ok来测试用户空间指针是否有效。这些函数都是在linux/include/asm/uaccess.h中定义的。对用户空间进行读写(续)要在内核和用户空间移动一些简单类型(例如int或long类型),可以使用get_user和put_user轻松地实现。这两个宏都包含一个值以及一个指向变量的指针。get_user函数将用户空间地址(ptr)指定的值移动到所指定的内核变量(var)中。put_user函数则将内核变量(var)指定的值移动到用户空间地址(ptr)。如果成功,这两个函数都返回0。在第二个系统调用中采用了put_user函数,向一块用户内存写数据。intget_user(var,ptr);intput_user(var,ptr);内核中进行输出(printk)当函数在内核中运行时,只能使用内核空间的资源,不能使用用户态的资源,例如C库。所以在输入信息的时候使用printk。printk是printf的一个简化版本,不能输出像浮点数之类的复杂数据类型。与printf不同的是,printk按照相关的记录级或优先级将消息严格分类。在第三个系统调用中采用了prink函数输出一些信息,到/var/log/messages中。Linux2.4内核添加系统添加新函数1运

1 / 50
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功