本笔记是我看过此书后,自己整理的提纲简要,初学linux,有不足之处,希望大家多多指教
linux处在尚未完善的阶段
本书的主要目的是为linux2.0写一个内核模块。模块是对象代码,可以在运行的内核中动态加载新功能
(1)内核模块的正确安装开始
(2)描述一些块设备驱动程序和网络接口
第一章 linux内核简介
大多数设备驱动程序原则和基本技巧是一致的
作为一个程序员,可以选择自己的驱动程序,在编程所需的时间和结果的灵活性之间做到可以接受的权衡
机制(需要做什么)和策略(这个程序怎么用)之间的差别是Unix设计背后最好的点子之一
软盘驱动程序和设备无关
设备驱动程序应该仅仅处理硬件,而把如何使用硬件的问题留给应用程序
驱动程序位于应用层和实际设备之间
不同的程序提供不同的驱动能力,甚至相同设备提供相同能力
实际驱动程序设计应该在众多需求中找到平衡点,比如,如尽可能给用户多的选项,平衡需要时间,错误尽量少,代码还要简单
策略无关其实是众多软件设计的要求
内核是一整块可被执行代码,负责所有的请求。以下作用:
(1)进程管理
(2)内存管理
(3)文件系统
(4)设备控制
(5)网络
Linux一个很好的特性:运行时刻扩展内核代码
每个增加到内核的代码被称为模块,每个模块由目标代码组成,insmod连接它们去内核,rmmod可以删除它们
每个模块通常只实现一个驱动程序,因此可以分门别类
驱动程序类型
(1)字符设备
(2)块设备
(3)网络接口
由于文件系统将原始数据类型组织为高层信息,所以它是软件驱动程序
安全问题
安全性有两方面
(1)用户的误操作
(2)程序员的错误
模块的特权是CPU确认的
所有安全性检查都是由内核代码完成的,如果内核有安全性漏洞,系统就有漏洞
注意避免编译来源不靠谱的内核,如果不能以root身份运行编译好的二进制代码,最好不要运行编译好的代码
linux每个软件包都有它自己的发行号。偶数版本是标准版,奇数版本是快照
几乎所有的linux都有GUN
如果你的代码深入内核,而你又想发布代码,就要使用GPL
大部分源代码都可以重新发布,或者以源代码形式,或者以二进制代码形式
第二章 编写和运行模块
printk:由内核拟定,功能与printf相似;模块可以调用printk,insmod加载模块后,模块就被连到内核里了,也可以调用内核符号
只要超级用户才能加载和卸载模块
一个应用从头到尾完成一个任务,模块是为以后处理某些请求而注册自己,完成任务后主函数就停止了
init_module:模块入口点 cleanup_module:第二个入口点,当模块被下载前才可以
模块化可以被下载
一个应用程序可以调用应用本身没有意义的函数:前后的连接编译过程中可以用相应的函数库解析那些外部引用
内核要是仅能连接编译到内核,只能调用由内核开发出的那些函数
源码文件不可以模块化任何常规头文件
名字空间污染是当存在很多函数和全局变量时,他们的名字已经不可以有足够的意义来区分彼此的问题
解决的方法:static
应用程序失效可以用调试器解决,内核失调却致命
模块在内核空间运行,应用程序在用户空间运行
操作的系统:给程序提供计算机硬件的视图,且操作系统处理程序的独立操作,并防止对资源的未经授权的访问
不同级有不同作用,有些操作不允许最低级使用
内核在最高级执行,应用程序在最低级执行
执行态为:内核空间和用户空间,分别引用不同的内存映射,程序代码使用不同的地址空间
处理中断的代码相对进程是异步的,与任何一个进程都无关
模块的功能就是拓展内核的功能,模块化的代码在内核中运行
内核异步工作,代表进程执行系统调用
内核负责输入输出以及系统内对每一个进程的资源管理
内核函数在同一个线程中执行
由于代码需要区分不同的数据流,内核必须维护内部数据结构以区分不同的操作
内核运行时,上下文切换不会无意中发生。
使用-Wall系统,全面报警编译选项
ld-r:将模块连在一起
-r:可重定位,输出文件时可以重定位的
insmod:不修改磁盘文件,而是修改内存映像
可以在模块连接到内核前修改模块中的整数值和字符串值
系统调用的名字前面一般都有sys-
相连接每一版内核,模块都要相应的编译一次
如果版本不匹配,想强行加载模块,在insmod里使用-f
为特定的内核编译模块,必须在上面的makefile编译头文件
模块被加载时,声明的任意全局变量都成为内核符号表的一部分,可以从文件/proc/ksyms或命令ksyms看见
register-symtab:在内核主符号表中注册符号表
如果在模块初始化过程中调用它,全局变量就不是开放的了
模块从内核中卸载时它所声明的公共符号自动注销
通过调用内核函数完成新设施的注册
模块可以注册如下项目:
(1)其他设备
(2)串行端口
(3)行规
(4)终端设备驱动程序
(5)/proc文件
(6)二进制文件格式
(7)Exec域
(8)符号表
如果注册过程中出现了错误,必须取消失败前完成的所有注册
建议用goto处理错误恢复
返回值err是个错误编码。在linux内核里,err是一个负值
为了确定模块是否可以安全卸载,系统为每个模块保留了一个使用计数
如果忘了更新使用计数,就不能再卸载模块了
rmmod:卸载模块,由于无需连接,任务比加载简单
cleanup_module:负责注销所有由模块注册了的项目
模块不使用资源是无法完成任务的,资源包括:内存 IO端口 中断 DMA通道
kmalloc:分配内存
kfree:释放内存
设备驱动程序必须以独占的方式访问端口
端口有请求/释放机制
文件的每一项都有驱动程序锁定的范围,释放前,其他驱动程序不允许访问这些端口
区别设备:通过写目标端口然后再读的方法
系统也使用了一系列类似的请求释放策略维护中断
ISA槽上的目标设备可能会提供片上内存,范围在640KB到1MB之间
自动和手动配置
根据系统的不同,驱动程序需要了解的若干参数也发生变化
除了IO地址,还有很多参数会影像系统的驱动程序,如设备的品牌和发行号(用户显示或驱动程序自己检测)
insmod:可以给参数赋值
在用户空间编写驱动程序
取代内核完成“负责硬件控制的唯一代理”的任务
有时用户空间驱动程序只授权一个程序访问设备