一、Linux系统驱动的调度过程
大致流程:
1、加载一个驱动模块,产生一个设备文件,有唯一对应的inode结构体
2、应用层调用open函数打开设备文件,对于上层open调用到内核时会发生一次软中断,从用户空间进入到内核空间。
3、open会调用到sys_open(内核函数),sys_open根据文件的地址,找到设备文件对应的struct inode结构体描述的信息,可以知道接下来要操作的设备类型(字符设备还是块设备),还会分配一个struct file结构体。
4、根据struct inode结构体里面记录的主设备号和次设备号,在驱动链表(管理所有设备的驱动)里面,根据找到字符设备驱动
5、每个字符设备都有一个struct cdev结构体。此结构体描述了字符设备所有信息,其中最重要的一项就是字符设备的操作函数接口
6、找到struct cdev结构体后,linux内核就会将struct cdev结构体所在的内存空间首地址记录在struct inode结构体i_cdev成员中,将struct cdev结构体中的记录的函数操作接口地址记录在struct file结构体的f_ops成员中。
7、执行xxx_open驱动函数。
二、基本概念
1、内核态和用户态
根据计算机系统—rk3399软硬件资源分配情况(CPU资源、内存资源、I/O资源)访问权限是不同的,Linux操作系统运行状态分为两个等级:内核态和用户态。内核态的访问权限是最高,对资源访问几乎没有限制;用户态的访问权限是最低的。
Linux内核运行于内核态,应用程序只能运行于用户态。
应用程序(app)如果需要访问内核提供的服务或硬件设备的交互,需要通过系统调用--接口函数API,让内核实现的功能。此时系统从用户态转入到内核态(调用对应的驱动程序的),这个内核工作处理完毕,返回到用户态,继续执行应用程序的代码app。
关键点:应用层决定产品的功能 --> 内核辅助完成 。
2、内核空间和用户空间
Linux操作系统的内存管理采用虚拟内存的方式,以32位操作系统为例,总共4GB的虚拟空间,被划分为2个独立空间:内核空间和用户空间。 内核运行于内核空间,应用程序运行于用户空间。
默认情况下,用户空间位于(1G~4G)的虚拟内存段,内核空间位于(0G~1G)的虚拟内存地址段。但是可以通过内核编译之前配置菜单调整两个空间的分配。
从宏观上看,应用程序访问内核资源或硬件设备有3种方式:
(1)通过系统调用API: open 、 read 、 write 、 close ...(系统调用接口函数)
(2)通过shell脚本---命令
(3)通过公用函数(例如glib C库) :fopen fread fwrite...(标准IO)
最终还是通过系统调用转由内核代为操作。
Linux系统调用大约250个左右,它集成了UNIX系统调用中最基础和最有用的部分。这些系统调用按照功能逻辑大致可以分为:进程控制、进程间通信、文件系统控制、网络管理、套接字控制、用户管理等。
3、进程上下文和中断上下文
进程上下文:
应用程序(app)向内核同步发起系统调用后,系统会转入内核态,也可以切换到用户态,此后内核代应用程序运行于进程上下文。
中断上下文:
设备向内核异步发起中断后,会打断linux内核当前运行的工作,执行中断相关的事情(进入到中断服务函数),此时内核运行于中断上下文。中断执行完毕之后,内核会返回进程上下文中。
注意:进程上下文(系统调用的接口API)和中断上下文(系统异常)界限是非常明确,在同一个CPU处理器同一时刻不能并存。
进程上下文与中断上下文的区别?
①产生原因:进程上下文是由于进程切换而产生的,而中断上下文是由于硬件中断而产生的。
②内容差异:进程上下文包含了进程的所有执行环境和状态信息,而中断上下文则主要包含了与中断处理相关的硬件信息和内核需要保存的环境信息。
③执行特点:运行在进程上下文的内核是可以被抢占的,但中断上下文则会一直运行至结束,不会被抢占。
4、同步和异步
在计算机领域,同步和异步经常被提到(同步是有约束的,异步没有约束的),不同的环境有不同的含义。
(1)用于物理设备之间的通信时,同步表示使用同一个时钟源,异步表示使用各自的时钟源。例子:CLK
(2)用于程序发起的设备的I/O请求时,同步表示程序等待I/O操作完成后继续往下执行,否则一直等待(阻塞);异步表示程序发起I/O请求后继续往下执行,不管I/O是否操作完成(非阻塞)。
(3)用于多线程对共享数据的处理方式时,同步表示多个线程按照指定顺序依次访问共享资源,异步表示不可预料,突发的,在CPU看来时由外部设备随机发起的中断。
(4)用于中断时,同步表示计划之中,意料之中。异步表示不可预料,突发的,并且在CPU看来是由外部设备发起的中断。
5、阻塞和非阻塞
一个进程或者线程在请求某个资源的时候—例如:scanf(),如果资源不能立即被使用或操作对应的结果不能立即返回,则进程有两种处理方法:
第一种:阻塞 --在结构返回之前,一直等待
第二种:非阻塞 --就是不等待
而等待也有有两种方式:
第一种:放弃CPU,等待资源可用被唤醒—例如:进程要sleep(2),等待的时候,需要放弃CPU使用权。
第二种:自旋:忙等,时钟占用CPU—不放弃CPU使用权