




已阅读5页,还剩67页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux驱动学习总结汇报,2016年11月12日,内核模块Bootloder并发控制中断处理设备驱动的结构,Linux内核重要子系统,系统调用接口进程管理内存管理虚拟文件系统网络堆栈设备驱动,最简单的嵌入式系统,MTK的Bootloader,在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。MTK的bootloader有两部分组成:(1)第1部分bootloader,也就是MTK内部(in-house)的pre-loader,这部分依赖平台。(2)第2部分bootloader,也就是LittleKernel,这部分依赖操作系统,负责引导linux操作系统和Android框架。源码位置:vendormediatekproprietarybootablebootloader,MTK的Bootloader,正常启动的主要工作如下:(1)设备上电后,BootROM开始运行。(2)BootROM初始化软件堆栈(softwarestack)、通信端口和可引导存储设备(比如NAND/EMMC)。(3)BootROM从存储器中加载pre-loader到内部SRAM(ISRAM)中,因为这时候还没有初始化外部的DRAM。(4)BootROM跳转到pre-loader的入口处并执行。(5)Pre-loader初始化DRAM和加载LK到RAM中。(6)Pre-loader跳转到LK中并执行,然后LK做一些初始化,比如显示的初始化等。(7)LK从存储器中加载引导镜像(bootimage),包括linux内核和ramdisk(Android呢?)(8)LK跳转到linux内核并执行。,MTK的Bootloader,pre-loaders中涉及的硬件部分,(1)PLL模块1)PLL模块用于调整处理器和外部内存的频率。2)在PLL模块初始化后,处理器和外部内存的频率可由26MHZ/26MHZ增加到1GHZ/192MHZ。(2)UART模块1)UART模块用于调试或是META(MobileEngineeringTestingArchitecture)模式下的握手。2)默认情况下,UART4初始化波特率为9216000bps和用于调试信息的输出,UART1初始化为115200bps和作为UARTMETA端口。但也可以使用UART1作为调试或是UARTMETA端口。(3)计时器(timer)模块这是个基本的模块,用来计算硬件模块所需要的延时或是超时时间。,(4)内存模块1)Pre-loader由bootROM加载和在芯片组内部的SRAM中执行,因为外部的DRAM还没有初始化。2)为了准备软件整个可执行环境,pre-loader采用内置的内存设置来初始化DRAM(DRAMisinitializeduponpre-loaderbuilt-inmemorysettigns)。这样,LK就能够被加载到DRAM中并执行。(5)GPIO模块(6)PMIC模块为了提供一些基本的硬件功能,比如控制外设电源,pre-loader初始化上层模块(uppermodules)。(7)RTC模块1)当通过power按键开机后,pre-loader拉高RTC的PWBB来保持设备一直有电(keepthedevicealive)和继续引导LK。2)RTC闹钟(alarm)有可能是设备开机的启动源,对于这种情况,设备部需要按power按键就可自动启动。,(8)USB模块当USB线插入时,它初始化来和外部工具通信,比如用于升级系统的下载工具或是META模式触发器的META工具。(9)NAND模块(10)MSDC模块Pre-loader可以从NANDflash或是EMMC中加载LK,这两者只能选择其中一种来启动。,LK中涉及的硬件部分,LK是第2个loader,它由pre-loader引导并执行。从根本上来说(basically),pre-loader已经初始化了相关的硬件模块,而不需要在LK中重新配置这些模块了。但一些模块在LK中被重新复位来配置硬件寄存器,这样可创造一个干净的环境。比如计时器模块,在LK中,计时器重新复位清零硬件计数来对计时进行复位。所有在LK中需要初始化的列在下面:(1)计时器模块通过复位硬件寄存器来复位计时。(2)串口模块LK采用串口模块来配置它的输入/输出系统,在这个模块初始化后,我们可以使用LK提供的“printf()”等函数来使用串口功能。,(3)I2C模块(4)PWM模块(5)PMIC模块(6)RTC模块和计时器模块一样,在U-Boot中,I2C/PMIC/RTC重新复位寄存器来复位这些模块。(7)LED模块通过这poweroffcharging个模块,设备能够通知用户当前的充电状态。(8)充电模块这个模块负责关机充电(poweroffcharging)、低电压充电(lowercharginginthesystem)。,(9)LCD模块使用这个模块,设备能够显示logo或是任何通知的消息。(10)NAND模块因为U-Boot也需要从flash读取镜像(比如内核或是ramdisk),所以有必要在U-Boot中初始化NAND相关的功能。(11)MSDC模块支持MSDC启动,一些重要的数据结构,大部分驱动程序涉及三个重要的内核数据结构:文件操作file_operations结构体文件对象file结构体索引节点inode结构体,Linux设备驱动,Linux下设备的属性设备的类型:字符设备、块设备、网络设备主设备号:标识设备对应的驱动程序。一般“一个主设备号对应一个驱动程序”次设备号:每个驱动程序负责管理它所驱动的几个硬件实例,这些硬件实例则由次设备号来表示。同一驱动下的实例编号,用于确定设备文件所指的设备。可通过lsl“设备文件名”命令查看设备的主次设备号,以及设备的类型。,18,分配和释放字符设备号,编写驱动程序要做的第一件事,为字符设备获取一个设备号。事先知道所需要的设备编号(主设备号)的情况:intregister_chrdev_region(dev_tfirst,unsignedcount,constchar*name)first是要分配的起始设备编号值。first的次设备号通常设置为0。Count所请求的连续设备编号的个数。Name设备名称,指和该编号范围建立关系的设备。分配成功返回0。,19,分配和释放字符设备号,动态分配设备编号(主要是主设备号)intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name)dev是一个仅用于输出的参数,它在函数成功完成时保存已分配范围的第一个编号。baseminor应当是请求的第一个要用的次设备号,它常常是0.count和name参数跟request_chrdev_region的一样.,20,分配和释放字符设备号,不再使用时,释放这些设备编号。使用以下函数:voidunregister_chrdev_region(dev_tfrom,unsignedcount)在模块的卸载函数中调用该函数。,21,字符设备的注册,内核内部使用structcdev结构表示字符设备。编写设备驱动的第二步就是注册该设备。包含头文件。获取一个独立的cdev结构:structcdev*my_cdev=cdev_alloc();调用cdev_init初始化cdev结构体voidcdev_init(structcdev*cdev,structfile_operations*fops);初始化该设备的所有者字段:dev-cdev.owner=THIS_MODULE;初始化该设备的可用操作集:dev-cdev.ops=,22,字符设备的注册,编写设备驱动的第二步就是注册该设备。cdev结构已建立和初始化,最后通过cdev_add函数把它告诉内核:intcdev_add(structcdev*dev,dev_tnum,unsignedintcount);dev是要添加的设备的cdev结构,num是这个设备对应的第一个设备编号,count是应当关联到设备的设备号的数目.卸载字符设备时,调用相反的动作函数:voidcdev_del(structcdev*dev);,23,Linux设备驱动的并发控制,24,设备驱动的并发控制,在驱动程序中,当多个线程同时访问相同的资源时,可能会引发“竞态”,必须对共享资源进行并发控制。并发和竞态广泛存在。并发控制的目的:使得线程访问共享资源的操作是原子操作。原子操作:在执行过程中不会被别的代码路径所中断的操作。驱动程序中的全局变量是一种典型的共享资源。,25,考虑一个非常简单的共享资源的例子:一个全局整型变量和一个简单的临界区,其中的操作仅仅是将整型变量的值增加1:i+该操作可以转化成下面三条机器指令序列:得到当前变量i的值并拷贝到一个寄存器中将寄存器中的值加1把i的新值写回到内存中,原子操作,26,Linux内核的并发控制,在内核空间的内核任务需要考虑同步内核空间中的共享数据对内核中的所有任务可见,所以当在内核中访问数据时,就必须考虑是否会有其他内核任务并发访问的可能、是否会产生竞争条件、是否需要对数据同步。,27,确定保护对象找出哪些数据需要保护是关键所在内核任务的局部数据仅仅被它本身访问,显然不需要保护。如果数据只会被特定的进程访问,也不需加锁大多数内核数据结构都需要加锁:若有其它内核任务可以访问这些数据,那么就给这些数据加上某种形式的锁;若任何其它东西能看到它,那么就要锁住它。,Linux内核的并发控制,28,Linux内核的并发控制,并发控制的机制中断屏蔽,原子数操作,自旋锁和信号量都是解决并发问题的机制。中断屏蔽很少被单独使用,原子操作只能针对整数来进行。因此自旋锁和信号量应用最为广泛。,29,锁机制可以避免竞争状态正如门锁和门一样,门后的房间可想象成一个临界区。在一段时间内,房间里只能有一个内核任务存在,当一个任务进入房间后,它会锁住身后的房门;当它结束对共享数据的操作后,就会走出房间,打开门锁。如果另一个任务在房门上锁时来了,那么它就必须等待房间内的任务出来并打开门锁后,才能进入房间。,加锁机制,30,任何要访问临界资源的代码首先都需要占住相应的锁,这样该锁就能阻止来自其它内核任务的并发访问:,加锁机制,31,原子数操作,整型原子数操作原子变量初始化atomic_ttest=ATOMIC_INIT(i);设置原子变量的值voidatomic_set(atomic_t*v,inti)获得原子变量的值atomic_read(v)原子变量加voidatomic_add(inti,atomic_t*v)原子变量减voidatomic_sub(inti,atomic_t*v),32,原子数操作,整型原子数操作原子变量的自增操作voidatomic_inc(atomic_t*v)原子变量的自减操作voidatomic_dec(atomic_t*v)操作并测试(测试其是否为0,0为true,否为false)atomic_inc_and_test(atomic_t*v)atomic_dec_and_test(atomic_t*v)intatomic_sub_and_test(inti,atomic_t*v)操作并返回(返回新值)intatomic_add_return(inti,atomic_t*v)intatomic_sub_return(inti,atomic_t*v),33,原子数操作,原子位操作设置位voidset_bit(intnr,volatileunsignedlong*addr)清除位voidclear_bit(intnr,volatileunsignedlong*addr)改变位change_bit(nr,p)测试位test_bit(intnr,constvolatileunsignedlong*p)测试并操作位test_and_set_bit(nr,p),34,自旋锁,自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分。而对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,不需要自旋锁。自旋锁最多只能被一个内核任务持有,若一个内核任务试图请求一个已被持有的自旋锁,那么这个任务就会一直进行忙循环,也就是旋转,等待锁重新可用。自旋锁可以在任何时刻防止多于一个的内核任务同时进入临界区,因此这种锁可有效地避免多处理器上并发运行的内核任务竞争共享资源。,35,自旋锁,自旋锁的初衷就是:在短期间内进行轻量级的锁定。一个被争用的自旋锁使得请求它的线程在等待锁重新可用的期间进行自旋(特别浪费处理器时间),所以自旋锁不应该被持有时间过长。如果需要长时间锁定的话,最好使用信号量。,36,自旋锁,自旋锁防止在不同CPU上的执行单元对共享资源的同时访问,以及不同进程上下文互相抢占导致的对共享资源的非同步访问。在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。自旋锁不允许任务睡眠。,37,自旋锁,自旋锁的基本形式如下:spin_lock(,38,自旋锁,自旋锁原语要求包含文件是.锁的类型是spinlock_t.锁的两种初始化方法:spinlock_tmy_lock=SPIN_LOCK_UNLOCKED;voidspin_lock_init(spinlock_t*lock);进入一个临界区前,必须获得需要的lock。voidspin_lock(spinlock_t*lock);自旋锁等待是不可中断的。一旦你调用spin_lock,将自旋直到锁变为可用。释放一个锁:voidspin_unlock(spinlock_t*lock);,39,自旋锁,关中断的自旋锁Spin_lock_irq()Spin_unlock_irq()Spin_lock_irqsave()Spin_unlock_irqrestore(),40,信号量,Linux中的信号量是一种睡眠锁。如果有一个任务试图获得一个已被持有的信号量时,信号量会将其推入等待队列,然后让其睡眠。当持有信号量的进程将信号量释放后,在等待队列中的一个任务将被唤醒,从而便可以获得这个信号量。信号量的睡眠特性,使得信号量适用于锁会被长时间持有的情况;信号量的操作信号量支持两个原子操作P()和V(),前者做测试操作,后者叫做增加操作。Linux中分别叫做down()和up()。,41,信号量,42,信号量,43,Linux信号量的实现,内核代码必须包含,才能使用信号量。相关的类型是structsemaphore,信号量的定义,structsemaphoreatomic_tcount;intsleepers;wait_queue_head_twait;,44,Linux信号量的实现,信号量的声明和初始化直接创建一个信号量structsemaphore*sem;接着使用sema_init来初始化这个信号量:voidsema_init(structsemaphore*sem,intval);互斥模式的信号量声明,内核提供宏定义.DECLARE_MUTEX(name);信号量初始化为1DECLARE_MUTEX_LOCKED(name);信号量初始化为0,45,自旋锁忙等待,无调度开销;进程抢占被禁止;锁定期间不能休眠;信号量拿不到就切换进程,有调度开销;锁定期间可以休眠;,46,Linux的中断处理,47,为什么会有中断,中断最初是为克服对I/O接口控制采用程序查询所带来的处理器低效率而产生的。处理器速度一般比外设快很多用轮询的方式来查询设备的状态,CPU效率不高,CPU和外设不能并行工作。中断机制让CPU启动设备后,就去处理其他任务,只有当外设真正完成数据传输的准备,请求CPU服务的时候,CPU才转过来处理外设的请求。,48,中断和异常,外部中断:外部设备所发出的I/O请求。随着计算机系统结构的不断改进以及应用技术的日益提高,中断的适用范围也随之扩大,出现了所谓的内部中断(或叫异常)。异常:为解决机器运行时所出现的某些随机事件及编程方便而出现的。,49,I/O中断处理,为了保证系统对外部的响应,一个中断处理程序必须被尽快的完成。因此,把所有的操作都放在中断处理程序中并不合适Linux中把紧随中断要执行的操作分为三类紧急的(critical)一般关中断运行。诸如对PIC应答中断,对PIC或是硬件控制器重新编程,或者修改由设备和处理器同时访问的数据非紧急的(noncritical)如修改那些只有处理器才会访问的数据结构(例如按下一个键后读扫描码),这些也要很快完成,因此由中断处理程序立即执行,不过一般在开中断的情况下,50,I/O中断处理,Linux中把紧随中断要执行的操作分为三类非紧急可延迟的(noncriticaldeferrable)这些操作可以被延迟较长的时间间隔而不影响内核操作,有兴趣的进程将会等待数据。内核用下半部分这样一个机制来在一个更为合适的时机用独立的函数来执行这些操作。如把缓冲区内容拷贝到某个进程的地址空间(例如把键盘缓冲区内容发送到终端处理程序进程)。,51,注册中断服务例程,中断号是一个宝贵且常常有限的资源。内核维护一个中断号的注册表。要使用中断,就要进行中断号的申请,也就是IRQ(InterruptReQuirement)。只有当设备需要中断的时候才申请占用一个IRQ,或者是在申请IRQ时采用共享中断的方式,让更多的设备使用中断。,52,注册中断服务例程,在实现中断注册接口:intrequest_irq(unsignedintirq,irqreturn_t(*handler)(int,void*,structpt_regs*),unsignedlongflags,constchar*dev_name,void*dev_id);voidfree_irq(unsignedintirq,void*dev_id);request_irq的返回值是0指示申请成功,为负值时表示错误码。函数返回-EBUSY表示已经有另一个驱动占用了所要申请的中断线。,53,注册中断服务例程,request_irq的参数说明:unsignedintirq,要申请的中断号。irqreturn_t(*handler)(int,void*,structpt_regs*),要安装的中断处理函数指针。constchar*dev_name,用在/proc/interrupts中显示中断的拥有者。,54,注册中断服务例程,request_irq的参数说明:unsignedlongflags,与中断管理相关的位掩码选项。Flags的每个位有不同含义SA_INTERRUPT当该位被设置时,表示这是一个“快速”中断。快速中断处理例程运行时,屏蔽中断。SA_SHIRQ这个位表示中断可以在设备间共享。void*dev_id这个指针用于共享的中断号。做为驱动程序的私有数据区(可用来识别那个设备产生的中断)。不使用共享中断线方式时,可设置为NULL。,55,实现中断处理例程,中断处理例程特别之处:在中断时间内运行,不能向用户空间发送或者接收数据。不能做任何导致休眠的操作。不能调用schedule函数。无论快速还是慢速中断处理例程,都应该设计成执行时间尽可能短。,56,实现中断处理例程,中断处理函数的参数和返回值irqreturn_t(*handler)(intirq,void*dev_id,structpt_regs*regs)Irq中断号Dev_id驱动程序可用的数据区,通常可传递指向描述设备的数据结构指针。structpt_regs*regs,保存了处理器进入中断代码之前的cpu寄存器的值。一般驱动可不要。,57,实现中断处理例程,启动和禁用中断驱动禁止特定中断线的中断:#include.voiddisable_irq(intirq);voidenable_irq(intirq);禁止所有中断voidlocal_irq_save(unsignedlongflags);local_irq_save在当前处理器上禁止中断递交,在保存当前中断状态到flags。voidlocal_irq_disable(void);local_irq_disable关闭本地中断递交而不保存状态;,58,实现中断处理例程,打开中断:voidlocal_irq_restore(unsignedlongflags);恢复由local_irq_save存储于flags的状态,而local_irq_enable无条件打开中断.voidlocal_irq_enable(void);,59,顶半部和底半部,中断处理的一个主要问题是如何在处理中进行长时间的任务。响应一次设备中断需要完成一定数量的工作,但是中断处理需要很快完成并且不使中断阻塞太长。Linux把中断处理例程分两部分:顶部分:实际响应中断的例程。底部分:被顶部分调用,通过开中断的方式进行。两种机制实现:Tasklet工作队列workqueue,60,顶半部和底半部,顶半部顶半部的功能是“登记中断”,当一个中断发生时,它进行相应地硬件读写后就把中断例程的下半部挂到该设备的底半部执行队列中去。顶半部执行的速度就会很快,可以服务更多的中断请求。底半部仅有“登记中断”是远远不够的,因为中断的事件可能很复杂。Linux引入了一个底半部,来完成中断事件的绝大多数使命。底半部和顶半部最大的不同是底半部是可中断的,而顶半部是不可中断的,底半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断!底半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上下文中执行。,61,软中断和tasklet的关系如下图:,小任务机制tasklet,62,小任务机制tasklet,ksoftirqd是一个后台运行的内核线程,它会周期的遍历软中断的向量列表,如果发现哪个软中断向量被挂起了(pend),就执行对应的处理函数。tasklet所对应的处理函数就是tasklet_action,这个处理函数在系统启动时初始化软中断时,就在软中断向量表中注册。,63,小任务以数据结构的形式存在:structtasklet_structstructtasklet_struct*next;unsignedlongstate;atomic_tcount;void(*func)(unsignedlong);unsignedlongdata;每个结构一个函数指针func,指向自定义的函数。这就是我们要执行的小任务函数。,小任务机制tasklet,64,tasklet的接口DECLARE_TASKLET(name,function,data)此接口初始化一个tasklet;name是tasklet的名字,function是执行tasklet的函数;data是unsignedlong类型的function参数。staticinlinevoidtasklet_schedule(structtasklet_struct*t)调度执行指定的tasklet。将定义后的tasklet挂接到cpu的tasklet_vec链表。而且会引起一个软tasklet的软中断,既把tasklet对应的中断向量挂起(pend)。,小任务机制tasklet,65,工作队列,工作队列类似taskets,允许内核代码请求在将来某个时间调用一个函数,不同在于:ta
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 畜牧设备牧场养殖场环境保护法律法规考核试卷
- 职场健康促进考核试卷
- 婴幼儿睡眠规律培养考核试卷
- 煤化工实验室技术与分析考核试卷
- 灯具基础知识入门考核试卷
- 纸板容器跨国经营风险管理考核试卷
- 环境保护宣传教育教材开发考核试卷
- 硅冶炼厂的生态环境保护考核试卷
- 矿用设备声学监测技术考核试卷
- 社会服务项目策划与执行考核试卷
- 加装电梯项目安全、文明施工措施
- 《健康体检介绍》课件
- 项目验收意见书
- 交通运输的节能与环保措施
- 游艇会服务流程
- 高压带电显示器说明书全解
- 数据中心基础设施管理系统DCIM技术方案
- 企业网络安全与数据保护策略
- 2024届高考英语语法填空专项课件
- 第五课滴答滴答下雨了课件
- 新教师岗前培训讲座中小学教学常规PPT
评论
0/150
提交评论