学习半年多的linux驱动了,也从互联网上获取了很多信息资料,今天突然觉得要开始回馈给互联网了,废话不多说开始吧:
__init定义的函数放到了.init.text段中去
__exit定义的函数放到了.exit.text段中去
被module__init修饰的函数在加载时会调用
同理module__exit
内核导出符号:导出别处定义完的函数在别处使用
定义方:
EXPORT_SYMBOL +(函数名)
EXPORT_SYMBOL holle
引用方用:
extern +(函数定义)
如:extern int holle (void)
当然也可以用include “。。。”
定义变量一定要在可执行代码之前,(习惯:可移植高)
不管是变量还是指针都应该定义初值
变量不定初值默认值随机,结果就不一定了
指针不定初值调用的时候就变野指针,很可能导致内核中文件的破坏。
为内存空间赋值即模块参数,用户空间给模块的
module_param(name,type,perm)
perm可以用代码搜索查到他们的权限的宏这就 他说到底就是0XXX的数值,如0700,且可 “|”,type中注意字符指针为charp,无符号短整型ushort,无符号用u代表布尔反值invbool
module_param_array(name,type,nump,perm)
nump元素个数
通过调用该函数时赋值即可,如insmod holle.ko xx=1 xx2=4....
模块加载完 在、sys/module/modparam/parameters/下有你使用的参数,这里也可以改当时定的权限,也可以改元素的值(全局变量)可以通过这种机制来调试驱动程序的途径。。。可以测试驱动
物理地址:出现在地址上的值
虚拟地址(线性地址):每个进程都有)到3G独立地址(3~4内核使用了)针对32位而言,UC编程使用的地址。
逻辑地址:汇编文件使用的偏移地址
逻辑地址->段式管理单元->虚拟地址->页式管理单元->物理地址。
段式管理单元:
段基址寄存器:cs,ds,ss,es。
段内偏移寄存器:ip,sp,bx
虚拟地址=(段基址<<4)+段内偏移 32为CPU
内部总线32b 内部寄存器32b
实模式:类似于以上16cpu的段式管理单元(寻址较弱)
保护模式:绝大多数时间在保护模式,用偏移地址把32分成两部分 base等于前面加上后面等于逻辑地址,这个偏移地址有保护的。页式管理机制完成虚拟地址到物理地址的转换,当物理不足的时候他会通过某机制把不常用的进程或资源放进交换分区中等待要用时再把它放回内存使用,这用使得进程感觉都是独占cpu,当然可能虚拟地址有4G,但内核物理地址就2G,用这个机制虚拟出4G内存来的。
linux中使用的是页式管理机制。linux始终认为基地址寄存器指为0,linux使用了四级页表,linux内存管理的最小单元为页(32位CPU通常一页为4k struct page)
内核中内存的分配:
用于空间有:malloc/free c
new/delete c++
valloc
内核空间有:
kmalloc /kfree
vmalloc/vfree (申请空间不连续)
__get_fre_page/fre_pages 申请空闲页
kmalloc(size_t size,gfp_t flags) 申请失败会返回错误值否则返回地址 flags:GFP_KERNEL(分配内存分配过程可能导致睡眠即阻塞) GFP_ATOMIC(分配中不睡眠直接返回,会返回错误值) GFP_DMA(S申请到的内存通常在0~16M之间,处理的事不用CPU参与) __GFP_HIGHMEM(申请高端内存,896以上的物理地址)
中断上下文即中断函数(在{}中的函数)
IS_ERR PTR_ERR获取错误编号
__get__free_pages(gfp_t gfp_mask,unsigned int order) 返回值是unsigned char *)分配指定页数的低地址内存,只能从高端内存分配 order:请求或释放的页数的2的幂。记得释放内存不管当前错误还是对,都要对以前的申请负责(使用goto),不然会发生内存泄漏。 free_pages(unsigned long addr,unsgned int order)