Linux操作系统分析与实践.ppt_第1页
Linux操作系统分析与实践.ppt_第2页
Linux操作系统分析与实践.ppt_第3页
Linux操作系统分析与实践.ppt_第4页
Linux操作系统分析与实践.ppt_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux操作系统分析与实践第七讲 Linux驱动程序编写基础 Linux操作系统分析与实践 课程建设小组北京大学二零零八年春季 致谢 感谢Intel对本课程项目的资助 本讲主要内容 Linux内核模块中断和中断处理下半部 Linux内核模块 Linux操作系统的内核是单一体系结构 monolithickernel 有了模块机制后 提高Linux操作系统的可扩充性 内核编程不再是一个恶梦什么是模块呢 模块的全称是 动态可加载内核模块 LoadableKernelModule LKM 模块在内核空间运行模块实际上是一种目标对象文件没有链接 不能独立运行 但是其代码可以在运行时链接到系统中作为内核的一部分运行或从内核中取下 从而可以动态扩充内核的功能这种目标代码通常由一组函数和数据结构组成 Linux内核模块的优点与缺点 优点使得内核更加紧凑和灵活修改内核时 不必全部重新编译整个内核 系统如果需要使用新模块 只要编译相应的模块 然后使用insmod将模块装载即可模块的目标代码一旦被链接到内核 它的作用域和静态链接的内核目标代码完全等价缺点由于内核所占用的内存是不会被换出的 所以链接进内核的模块会给整个系统带来一定的性能和内存利用方面的损失 装入内核的模块就成为内核的一部分 可以修改内核中的其他部分 因此 模块的使用不当会导致系统崩溃 为了让内核模块能访问所有内核资源 内核必须维护符号表 并在装入和卸载模块时修改符号表 模块会要求利用其它模块的功能 所以 内核要维护模块之间的依赖性 Linux内核模块与应用程序的区别 C语言程序Linux内核模块运行用户空间内核空间入口main module init 指定 出口无module exit 指定 编译gcc cMakefile连接ldinsmod运行直接运行insmod调试gdbkdbug kdb kgdb等 模块相关命令 insmod moduleparameters Loadthemodule注意 只有超级用户才能使用这个命令RmmodUnloadthemodulelsmodListallmodulesloadedintothekernel这个命令和cat proc modules等价modprobe r Loadthemodulespecifiedandmodulesitdepends 模块依赖 一个模块A引用另一个模块B所导出的符号 我们就说模块B被模块A引用 如果要装载模块A 必须先要装载模块B 否则 模块B所导出的那些符号的引用就不可能被链接到模块A中 这种模块间的相互关系就叫做模块依赖 最简单的内核模块例子 include include includestaticint inithello init void printk KERN INFO Helloworld n return0 staticvoid exithello exit void printk KERN INFO Goodbyeworld n module init hello init module exit hello exit staticint inithello init void staticvoid exithello exit void Static声明 因为这种函数在特定文件之外没有其它意义 init标记 该函数只在初始化期间使用 模块装载后 将该函数占用的内存空间释放 exit标记该代码仅用于模块卸载 Init exit宏 module init module exit声明模块初始化及清除函数所在的位置装载和卸载模块时 内核可以自动找到相应的函数module init hello init module exit hello exit 编译内核模块 Makefile文件obj m hello oall make C lib modules shelluname r buildM shellpwd modulesclean make C lib modules shelluname r buildM shellpwd cleanModuleincludesmorefilesobj m hello ohello objs a ob o 装载和卸载模块 相关命令lsmodinsmodhello kormmodhello ko 模块参数传递 有些模块需要传递一些参数参数在模块加载时传递 insmodhello kotest 2参数需要使用module param宏来声明module param的参数 变量名称 类型以及访问许可掩码支持的参数类型Byte short ushort int uint long ulong bool charpArray module param array name type nump perm include include include includestaticinttest module param test int 0644 staticint inithello init void printk KERN INFO Helloworldtest d n test return0 staticvoid exithello exit void printk KERN INFO Goodbyeworld n MODULE LICENSE GPL MODULE DESCRIPTION Test MODULE AUTHOR xxx module init hello init module exit hello exit 导出符号表 如果一个模块需要向其他模块导出符号 方法或全局变量 需要使用 EXPORT SYMBOL name EXPORT SYMBOL GPL name 注意 符号必须在模块文件的全局部分导出 不能在函数部分导出 更多信息可参考文件Modules仅可以使用由Kernel或者其他Modules导出的符号不能使用Libc proc kallsyms可以显示所有导出的符号 内核模块操作 proc文件 proc文件系统 这是内核模块和系统交互的两种主要方式之一 proc文件系统也是Linux操作系统的特色之一 proc文件系统不是普通意义上的文件系统 它是一个伪文件系统 通过 proc 可以用标准Unix系统调用 比如open read write ioctl 等等 访问进程地址空间可以用cat more等命令查看 proc文件中的信息 用户和应用程序可以通过 proc得到系统的信息 并可以改变内核的某些参数 当调试程序或者试图获取指定进程状态的时候 proc文件系统将是你强有力的支持者 通过它可以创建更强大的工具 获取更多信息 proc相关函数 create proc entry 创建一个文件proc symlink 创建符号链接proc mknod 创建设备文件proc mkdir 创建目录remove proc entry 删除文件或目录 Linux2 6内核中有关模块部分的改变 模块引用计数器Linux2 4中在linux module h中定义了三个宏来维护实用计数 MOD INC USE COUNT当前模块计数加一 MOD DEC USE COUNT当前模块计数减一 MOD IN USE计数非0时返回真在Linux2 6中 模块引用计数器由系统自动维护 所以程序中有关这些宏都可以注释掉 关于符号导出列表 listofexportedsymbols Linux2 4中会用EXPORT NO SYMBOLS宏 来表示不想导出任何变量或函数 在Linux2 6中这个宏也已经消失 系统默认为不导出任何变量或函数 模块程序编译方法的改变Linux2 4中命令为 gcc Wall DMODULE D KERNEL DLINUX c源文件名 c其中 KERNEL 即告诉头文件这些代码将在内核模式下运行MODULE 即告诉头文件要给出适当的内核模块的定义LINUX 并非必要 Wall 显示所有warning信息 Linux2 6中必须写makefile 通过make命令编译程序 Linux2 6中makefile的写法 以helloworld为例 Makefileobj m hello oall make C lib modules shelluname r buildM PWD modulesclean make C lib modules shelluname r buildM PWD clean 注意 all下一行需要有一个 Tab 键 不要写成空格或略去 不然系统无法识别 报错 nothingtobedonefor all 用以加载的目标文件类型已经改变Linux2 4中用以加载为模块的目标文件扩展名为 oLinux2 6中中用以加载为模块的目标文件扩展名为 ko在Linux2 4中 函数init module 和函数cleanup module 是必不可少的 而在Linux2 6中 同样功能的函数并非一定要起这两个函数名 Lab模块编程 WriteTwoModule Module1 HelloWorldModule Load unloadthemodulecanoutputsomeinfo Module2 Moduleacceptsaparameter Loadthemodule outputtheparameter svalue ModifyModule1andModule2 letModule1exportssymbols Module2usethesymbols 注 详见实验指导 二 中断和中断处理程序 中断处理的基本过程Whenreceivinganinterrupt CPUprogramcounterjumpstoapredefinedaddress interruptvectors ThestateofinterruptedprogramissavedThecorrespondingserviceroutineisexecutedTheinterruptingcomponentisserved andinterruptsignalisremovedThestateofinterruptedprogramisrestoredResumetheinterruptedprogramattheinterruptedaddress 中断描述符表IDT 中断描述符表是一个系统表 它与每一个中断或者异常向量相联系每个向量在表中有相应的中断或者异常处理程序的入口地址 每个描述符8个字节 共256项 占用空间2KB内核在允许中断发生前 必须适当的初始化IDTCPU的idtr寄存器指向IDT表的物理基地址 Interruptvectorsonx86 初始化IDT Linux内核在系统的初始化阶段要初始化可编程控制器8259A 将中断描述符表的起始地址装入IDTR寄存器 并初始化表中的每一项当计算机运行在实模式时IDT被初始化 并由BIOS使用 真正进入了Linux内核IDT就被移到内存的另一个区域 并为进入保护模式进行预初始化 中断处理程序 注册中断处理程序intrequest irq unsignedintirq irq handler t handler longirqflags constchar devname void dev id 释放中断处理程序intfree irq unsignedintirq void dev id 编写中断处理程序intirqreturn thandler intirq void dev id structpt regs regs 共享的中断处理程序register irq withSA SHIRQflagTheregistrationfailsifotherhandleralreadyregisterthesameIRQwithoutSA SHIRQflagThedev idargumentmustbeuniquetoeachhandlerTheinterrupthandlermustbeabletofindoutwhetheritsdeviceactuallygenerateaninterruptHardwaremustprovideastatusregisterforinquiry 中断上下文 当执行中断处理程序或下半部时 内核处于中断上下文中断上下文不同于进程上下文中断或异常处理程序执行的代码不是一个进程它是一个内核控制路径 代表了中断发生时正在运行的进程执行 作为一个进程的内核控制路径 中断处理程序比一个进程要 轻 中断上下文只包含了很有限的几个寄存器 建立和终止这个上下文所需要的时间很少 中断上下文不可以睡眠 也不能调用某些函数 具有较为严格的时间限制 解决办法 中断处理划分为上半部分和下半部分上半部 中断处理程序 内核立即执行Simpleandfast dealingwithtime criticalhardwaretasksE g packetstransmissionandreceiving下半部 留着稍后处理DeferringworktoalaterpointwhereinterruptscanbeenabledProcessingtime consumingandmaybesoftware onlytasksEworkprotocolsprocessing 下半部及推后执行的工作 中断处理程序的局限中断处理程序必须非常快速结束来避免打断其他重要代码的执行中断实时任务或其他中断处理程序当前IRQ被屏蔽或者CPU上所有的IRQ被屏蔽 如果设置了SA INTERRUPT 运行在中断上下文 不是运行在进程上下文 不能被阻塞 BH2 6中去除taskqueue 任务队列 2 6中去除软中断 softirq 2 4引入Tasklet2 4引入工作队列 workqueue 2 4引入 下半部的环境 下半部可以通过多种机制实现 分别由不同的接口和子系统组成BH接口静态创建由32个Bottomhalf组成的链表Taskqueue任务队列机制软中断Tasklet工作队列 SoftIRQ 软中断 在编译期间静态分配的Only32softIRQscanexistonly6currentlyused 由softirq action结构表示 structsoftirq action void action structsoftirq action 待执行的函数void data 传给函数的参数 中定义了一个包含32个该结构体的数组staticstructsoftirq actionsoftirq vec 32 6个当前使用的SoftIRQs include linux interrupt h109enum110 111HI SOFTIRQ 0 112TIMER SOFTIRQ 113NET TX SOFTIRQ 114NET RX SOFTIRQ 115BLOCK SOFTIRQ 116TASKLET SOFTIRQ117 软中断处理程序 注册软中断处理程序 kernel softirq c 205voidopen softirq intnr void action structsoftirq action void data 206 207softirq vec nr data data 208softirq vec nr action action 209 当软中断处理程序运行时 当前处理器上的软中断被禁止 其它处理器仍可以执行别的软中断 引入软中断的原因就是其可扩展性 如果不需要扩展到多个处理器 那么就使用tasklet 软中断不能睡眠 raise softirq 调用open softirq 进行注册后 新的软中断就可以运行了 调用raise softirq 可以将一个软中断设置为挂起状态 使它在下一次调用do softirq 函数投入运行 do softirq 在下列地方 待处理的软中断会被检查和执行从一个硬件中断代码处返回时在ksoftirqd内核线程中在那些显式检查和执行待处理的软中断的代码中 无论什么方式 软中断都要在do softirq 中执行 遍历每一个软中断 调用他们的处理程序 Tasklets Tasklets是利用软中断实现的一种下半部机制 Tasklet结构体structtasklet struct structtasklet struct next 队列指针 unsignedlongstate tasklet的状态 atomic tcount 引用计数 通常用1表示disabled void func unsignedlong 函数指针 unsignedlongdata func data 在软中断中相关的向量 softirq vec HI SOFTIRQ softirq vec TASKLET SOFTIRQ 触发 激活 调度 tasklet HI tasklet hi schedule TASKLET tasklet schedule 通过do softirq 调度tasklet的运行HIaction tasklet hi action TASKLETaction tasklet action Tasklet实现的软中断向量表 使用tasklet 大多数情况下 tasklet机制是实现下半部的最佳选择编写tasklet处理程序声明tasklet调度tasklet编写tasklet处理程序定义一个小任务的处理函数并把用户的代码写到其中 voidmy tasklet fun unsignedlong 用户代码 声明takslet使用DECLARE TASKLET 宏DECLARE TASKLET my tasklet my tasklet func data 调用tasklet schedule 函数系统会在适当的时候调度并运行这个tasklet tasklet schedule 工作队列 workqueue 工作队列使用内核线程来执行驱动中需延迟执行的工作 BottomHalf 这些内核线程被称为工作线程 在Linux2 6内核中 系统除了提供默工作认线程来帮助驱动方便的执行延迟操作 还允许驱动自己产生自定义的工作线程来执行某些特殊的延迟工作 默认工作线程被称作events n 其中n为CPU个数 也就是说 每个CPU都有一个默认工作线程 一般情况下 大多数驱动都使用默认工作线程来执行自己的Bottom Half工作 某些情况下 驱动产生自己的自定义工作线程可以满足更高的性能要求 并可以减轻默认工作线程的负担 工作线程 每种类型的工作线程都有一个这样的结构与其关联 它有一个重要的成员CPU wq 即元素类型为CPUworkqueue struct的数组 表示系统中的每个CPU都有自己的工作线程假设需要在有2个CPU的计算机上创建类型为myworker的工作线程 则系统除了有2个类型为events的默认工作线程外 还有2个类型为myworker的工作线程 每一个events或myworker都有一个CPU workqueue struct结构与之关联 structworkqueue struct structCPU workqueue structCPU wq NR CPUS constchar name structlist headlist structCPU workqueue struct spinlock tlock lockprotectingthisstructure longremove sequence least recentlyadded nexttorun longinsert sequence nexttoadd structlist headworklist 该CPU上的所需处理的工作队列 wait queue head tmore work wait queue head twork done structworkqueue struct wq 所属的workqueue struct task t thread 所关联的工作线程 intrun depth run workqueue recursiondepth 工作单元 每个CPU的同一类型工作单元被连接成一个工作队列work struct用来表示每一个需要被延迟处理的工作单元 structwork struct unsignedlongpending isthisworkpending structlist headentry linklistofallwork void func void handlerfunction void data argumenttohandler void wq data usedinternally structtimer listtimer timerusedbydelayedworkqueues worker thread 线程函数 所有的工作线程都是普通内核线程 使用worker thread 作为线程函数该线程函数在进行一段初始化操作后便进入无限循环 并睡眠等待 当有需处理的延迟工作被加入到工作队列中时 该线程函数被唤醒并循环处理对应工作队列中的每一个工作单元 当工作队列中没有工作单元需要被处理时 它又重新进入睡眠状态 等待下一次的唤醒 主要任务就

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论