备战驱动面试笔试:资源来自于网络

来源:互联网 发布:中国黑客攻击日本网络 编辑:程序博客网 时间:2024/06/05 06:53

对于见到的每个问题,先列出来,再搜索资源学习,最后总结为答案。

1.linux中内核空间及用户空间的区别?

答:区别有很多,简言概之就是,Linux系统采取两级保护机制,对应两种不同的操作权限,内核空间权限高于用户空间权限,内核空间和用户空间都有属于自己的虚拟空间,在32位系统中,cpu最高有32位寻址范围,即对应4G空间,内核空间被划分在高1G虚拟空间,用户空间在低3G。普通应用程序运行在用户空间,执行一些贴近用户的低权限操作,系统内核程序,操作硬件的驱动程序等一些要求高级权限的程序运行在内核空间。用户空间程序不能直接访问内核空间的数据,内核空间程序也一样不能直接访问属于用户进程空间的数据,用户空间和内核空间之间的通信必须通过一些特定的方法。

2.用户空间与内核通信方式有哪些?

答:通信方式也有很多,但常用的也就这几种:

a)首先想到的是系统调用,用户空间进程通过系统调用进入内核空间,访问指定的内核空间数据;

b).其次是驱动程序,用户空间进程可以使用封装后的系统调用接口访问驱动设备节点,以和运行在内和空间的驱动程序通信;

c).还有就是,proc文件系统,proc文件系统的主要功能是在内核空间提供一套机制为用户空间方便的查询,查看,设置内核信息,多用于查询类操作。(但我觉得有很多人把它和/dev文件系统的作用混淆了,也许是我认识还不够深刻。);

d).共享内存mmap,在代码中调用接口,实现内核空间与用户空间的地址映射,在实时性要求很高的项目中为首选,省去拷贝数据的时间等资源,但缺点是不好控制;

e).最后,copy_to_user()、copy_from_user(),是在驱动程序中调用接口,实现用户空间与内核空间的数据拷贝操作,应用于实时性要求不高的项目中。

3.linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化,高端内存概念?

答:以32位机器为例,cpu最大寻址范围为4G,Linux系统将4G虚拟地址空间划分为高1G,低3G,低3G虚拟空间属于用户空间,都是经过映射的线性地址,供用户进程空间使用,高1G并非都是像用户空间一样都是映射过的线性空间,Linux系统将高1G划分为三部分,DMA区,常规区,高端内存,其中0-896都是映射过的线性空间,剩下的896-1024即高端内存,这段高端内存都是未经过映射的虚拟地址,Linux系统利用这些有限的虚拟地址,临时动态的映射到大于896M的物理空间地址,实现了利用有限的虚拟地址访问到物理内存的所有地址。malloc用于用户空间进程申请内存空间,kmallc和vmalloc在内核空间使用,kmalloc申请到的内存空间,是线性连续的,可以用于dma。vmalloc申请的内存是逻辑连续的,但是物理地址不连续,常用与申请大的内存,请注意vmalloc可能会睡眠,在中断,阻塞的环境下不能使用。至于虚拟地址到物理地址的转化,用户空间和内和空间采用不同的映射机制。用户空间的地址映射经过mmu(内存管理单元)管理。而内核空间的虚拟地址到物理地址的映射是一一对应的,例如虚拟空间地址0xc0000004,对应的物理地址空间地址为:0xc0000004 - 0xc0000000 = 0x04,以此类推。(基于个人理解)。

3. linux中中断的实现机制,tasklet与workqueue的区别及底层实现区别?为什么要区分上半部和下半部?

答:Linux中断分为硬件中断和内部中断(异常),调用过程:外部中断产生->发送中断信号到中断控制器->通知处理器产生中断的中断号,让其进一步处理。对于中断上半部和下半部的产生,为了中断处理过程中被新的中断打断,将中断处理一分为二,上半部登记新的中断,快速处理简单的任务,剩余复杂耗时的处理留给下半部处理,下半部处理过程中可以被中断,上半部处理时不可被中断。至于tasklet和工作队列,在网上看了一圈,由于不常用,看的有点迷糊,个人理解: 两者都是中断下半部的一种实现方法,区别在于,tasklet支持smp,不可睡眠。工作队列基于线程的封装,因此支持睡眠。

4.linux中断的响应执行流程?

答:处理器收到来自中断控制器的中断处理请求,保存中断上下文,跳转到中断对应的处理处,(快速完成中断中断上半部,中断上半部返回后执行中断下半部。如果做了上下半部处理的话),中断处理函数返回时恢复现场。

5.谈谈Linux的同步机制。

答:首先说说常见的同步接口,包括进程同步,信号量,自旋锁,互斥锁,条件变量,读写锁。个人理解:多进程并发一般考虑使用信号量机制,在线程并发时多采用互斥锁,条件变量,个人觉得条件变量在某些角度就是线程版的信号量实现,因为两者都是在考虑持有锁时间较长情况下使用,而互斥锁,自旋锁一般都是用在持有锁时间不会很长的情况下,在自旋锁有使用意义的前提下,如果持锁时间 会非常短则自旋锁效率高于互斥锁,否则应该使用互斥锁,因为互斥锁会持续占有cpu资源,不宜过长,而互斥锁会导致抢不到锁的线程睡眠,进入等待队列。互斥锁和自旋锁都可以用在进程上下文,而在中断上下文只能使用自旋锁,因为互斥锁会睡眠。

6./dev/下面的设备文件是怎么创建出来的?

答:普遍说法有三种方式,devfs机制,udev机制,再有一个就是手动创建设备节点。谈谈个人见解:devfs机制从来没用过,应该是2.6以前的内核使用的;udev,其实就是现在常用的device_create()、class_create()这一套接口,所谓udev是上层用户空间程序,是基于驱动中创建使用了这两个接口而起作用的,但是udev在日常开发中几乎接触不到,我们只需在驱动中调用创建节点的这两个API就ok了,剩下的工作就交给udev去做了,有想深究它具体实现原理的那就自己去研究吧,我觉得会用就行了;mknod ,新手最常用的一种创建设备节点方法,但并非入门后就再没有用途,在某些情境下,或许有人不想使用udev机制,于是把节点创建工作写在脚本里,这样也是无可厚非的。

7.原子操作该怎么理解?

答:原子操作,就是开始执行到执行结束期间不会被打断的操作单元。

8.insmod一个驱动模块,会执行模块中的哪个函数?rmmod呢?这两个函数在设计上要注意哪些?遇到过卸载驱动出现异常没?是什么问题引起的?

答:分别会执行module_init()和module_exit()指定的init函数和exit函数。要注意的就是尽量使在init函数中出现的资源申请及使用有对应的释放操作在exit中,init申请,eixt释放。卸载出现的异常?那很稀松平常了,大多数都是资源使用完,没释放,但是模块却卸载了。

9.在驱动调试过程中遇到过oops没?你是怎么处理的?

答:遇到过,这种类似的段错误什么的其实最好处理了,因为它有call trace,根据堆栈信息去代码里面查看就行了,如果代码中看不到明显低级错误,就printk联机调试呗,这对调试驱动的人来说是成就感来的最容易的地方,然而这种很少。

8.ioctl和unlock_ioctl有什么区别?

答:ioctl是老的内核版本中的驱动API,unlock_ioctl是当下常用的驱动API,区别在于ioctl调用前后,使用了大内核锁(网上这么说的,半信半疑去了解了下啥叫个大内核锁),而unlock_ioctl顾名思义就是没加大内核锁的新接口呗,改变的只是驱动调的方法,用户应用程序调用的接口不变。谈谈大内核锁吧,大内核锁是Linux hacker在应付多处理器初期提出的一种锁,目的在于当一个处理核心在运行内核时,加上大内核锁,不让其他cpu核心同时运行内核程序,显然这样是有用的,然而这样大大降低了多处理器的存在意义,于是跟随时代更迭,大内核锁被一步一步的剔除,ioctl接口的升级就是典范!我觉得这样的问题太没有意义了,对开发有多大用处?

9.驱动中操作物理绝对地址为什么要先ioremap?

答:ioremp是内核中用来将外设寄存器物理地址映射到主存上去的接口,即将io地址空间映射到虚拟地址空间上去,便于操作。为什么非要映射呢,因为保护模式下的cpu只认虚拟地址,不认物理地址,给它物理地址它并不帮你做事,所以你要操作外设上的寄存器必须先映射到虚拟内存空间,拿着虚拟地址去跟cpu对接,从而操作寄存器。

10.设备驱动模型三个重要成员是?platfoem总线的匹配规则是?在具体应用上要不要先注册驱动再注册设备?有先后顺序没?

答:总线,设备,驱动。匹配规则就是当有一个新的设备挂起时,总线被唤醒,match函数被调用,用device名字去跟本总线下的所有驱动名字去比较。相反就是用驱动的名字去device链表中和所有device的名字比较。如果匹配上,才会调用驱动中的probe函数,否则不调用。至于先后顺序,鉴于个人理解,不会有影响,不管谁先谁后,bus都会完成匹配工作。谈谈对Linux设备驱动模型的认识:设备驱动模型的出现主要有三个好处,设备与驱动分离,驱动可移植性增强;设备驱动抽象结构以总线结构表示看起来更加清晰明了,谁是属于哪一条bus的;最后,就是大家最熟悉的热插拔了,设备与驱动分离,很好的奠定了热插拔机制。

11.linux中RCU原理?

答:rcu是2.6出现的一种读写锁,可以说是老的读写锁的升级版,主要用在链表这种数据结构上,经典使用场景是多读者少写者的情况,rcu允许多个读者一个写者共同操作数据而不必加锁,这是经典用法,若出现多个写者时,写者与写者之间就得自己手动同步。当要删除一个节点时,删除后并不会马上释放节点,而是会等待在删除动作之前已经开始读该节点的读者都完成读操作之后才会释放此节点,这段时间被称为宽限期。

12.谈谈Linux软中断?

答:Linux系统中的软中断是专为一些不是不是特别要紧的耗时任务而产生的一种机制,多数用在中断处理过程中,典型应用就是用于中断下半部,tasklet机制就是基于软中断的典型下半部应用。软中断就是结合任务调度,延迟处理等让守护进程去处理一些不是特别紧急又耗时的任务。

13.linux系统实现原子操作有哪些方法?

答:这个问题网上回答五花八门,答非所问。提到原子操作我首先想到的是针对整形的原子操作,atomic_t类型,这里面有一整套针对整形的原子操作API可以调用。既然整型能原子操作,那其他也应该可以吧,结合原子操作的定义,要想对其他类型结构实现原子操作,那就加锁咯,将需要原子操作的部分放在临界区。

14.linux中系统调用过程?

答:系统调用,比如open(),它并不是真正的系统调用实现函数,其实它只是一个c库函数,内部实现就做了两件事,先把系统调用号传递给内核,最后拉起一次软中断,自此cpu进入内核态运行,内核在软中断向量表中找出对应的中断类型,根据中断类型找到对应的软中断执行函数,执行函数根据系统调用号,在系统调用号表里面找到对应的系统调用函数。

15.谈谈linux内核的启动过程(源代码级)?

答:首先内核镜像自解压,解压完之后从head.s开始运行,即引导内核,在内核引导期间将会设置内核参数。随后,跳转到第一个c函数start_kernel(),进入内核启动阶段,在内核启动过程中进行一些必要的硬件初始化工作,在内核启动的最后,挂载文件系统,然后创建第一个用户空间进程,init进程,进一步完成驱动挂载,用户服务初始化工作。

16.谈谈Linux调度原理?

答:Linux将进程按权限分为两大类,常规进程和实时进程,常规进程对应一种调度算法,实时进程有两种对应着两种不同的调度算法。进程按照状态又可以分为几种,常见的状态有,运行态,可中断睡眠态,不可中断睡眠态,停止态。处于运行态的进程根据调度算法接受调度在cpu上运行。

17.谈谈对Linux网络子系统的认识?

答:网络子系统可以概括描述为:应用程序-》系统调用接口(主要是指socket接口)-》协议无关接口(有socket实现,提供一套通用接口支持不同的协议)-》网络协议(包括tcp、udp在内的网络协议)-》设备无关接口(有net_device接口组织的一组通用接口将网络协议与各种网络设备联系起来)-》设备驱动(即各种网络设备的驱动程序,负责管理具体的网络设备)-》网络设备(具体的网络硬件设备)。

18.内核中申请内存有哪几个函数?有什么区别?

答:只谈谈常见的三个接口,kmalloc(),vmalloc()和__get_free_pages()。kmalloc()操作的空间位于直接映射区(即4G空间中的896M区域),申请到空间物理地址多为连续地址,常用于操作频繁的数据结构,连续地址利于提高访问效率。而对于一些操作不频繁的数据结构可以用vmalloc()申请内存,vmalloc()操作的空间优先选择高端内存,这里申请出的内存物理地址往往不是连续的,所以访问效率不会很高。__get_free_pages()操作的区域跟kmalloc()相同,位于直接映射区,不同的是它申请的是物理页的整倍数大小的内存。

19.谈谈内核函数mmap的实现机制?

答:

0 0