小白学驱动--资源来自网络(有整合和个人理解)

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

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

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

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

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

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

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

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

f).信号:从内核空间向进程发送信号。在用户程序出现重大错误时,内核发送信号杀死相应进程。

  • 用户态切换到内核态的3种方式

a. 系统调用

这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。

b. 异常

当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

c. 外围设备的中断

当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

这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,以此类推。(别人的个人理解,没怎么看懂)。
驱动中操作物理绝对地址为什么要先ioremap?

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

因为内核没有办法直接访问物理内存地址,必须先通过ioremap获得对应的虚拟地址。


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

谈谈Linux的同步机制。

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

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

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

原子操作该怎么理解?

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

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

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

谈谈Linux软中断?

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

linux中系统调用过程?

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

谈谈Linux调度原理?
答:Linux将进程按权限分为两大类,常规进程和实时进程,常规进程对应一种调度算法,实时进程有两种对应着两种不同的调度算法(先进先出SCHED_FIFO和轮转调度SCHED_RR)。进程按照状态又可以分为几种,常见的状态有,运行态,可中断睡眠态,不可中断睡眠态,停止态。处于运行态的进程根据调度算法接受调度在cpu上运行。
https://blog.csdn.net/tennysonsky/article/details/44964597

void *mmap(void *addr,size_t length ,int prot, int flags, int fd, off_t offset);     mmap系统调用的实现过程:
1.先通过文件系统定位要映射的文件; 

2.权限检查, 映射的权限不会超过文件打开的方式, 也就是说如果文件是以只读方式打开, 那么则不允许建立一个可写映射; 
3.创建一个vma对象, 并对之进行初始化; 
4.调用映射文件的mmap函数, 其主要工作是给vm_ops向量表赋值; 
5.把该vma链入该进程的vma链表中, 如果可以和前后的vma合并则合并; 
6.如果是要求VM_LOCKED(映射区不被换出)方式映射, 则发出缺页请求, 把映射页面读入内存中.
; ;; ; ; ;;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值