Linux 内核系统调用与中断(学习笔记)

时间:2024-06-01 10:34:36

Linux 系统调用

1. Linux 系统为每一个系统调用准备了一个号码,为系统调用号,对于32bit系统而言:exit 为 1, write 为4等。

2. 每当应用程序调用系统调用函数时,如write,首先到 C 库中,(glibc中),调用对应的函数 write。

3. C库中的writehansh ,将对应的调用号保存到对应的寄存器中,一般是R7寄存器。然后调用 SWI(old)或者SVC(new),触发一个异常(软中断),CPU需处理该异常(软中断),需跳转到异常向量表的对应位置去处理。

4. Linux 系统的异常向量表是在内核启动初始化时,会建立异常向量表(向量表初始地址是0XFFFF0000),软中断入口为 vector_swi,应用程序触发了软中断,然后CPU会到该入口去处理这个软中断。

5,进入到软中断 vector_swi入口之后,从R7寄存器中取出之前保存的系统调用号,然后在内核已经准备好的以系统调用号为索引下标的系统调用表中,找到对应的系统调用函数,(如果是4号 write,则对应的系统调用是sys_write),然后执行,(此时已经进入了内核空间)。

6. 返回用户空间。

总结:用户空间到内核空间,是通过软中断实现的,其中的桥梁就是C库实现的对应的“系统调用”中产生的对应的系统调用号,已经使用该系统调用号作为索引的异常向量表。

32bit的机器,0~3G 是用户空间,3G~4G是内核空间,该1G内核空间的入口,就是异常向量表的入口 0XFFFF0000。这个地址往上仅仅只有0XFFFF大小的空间了。所以异常向量表中的单个函数指针占用4个字节,网上 0XFFFF/4 最多可容纳的系统调用个数就是0X3FFF,即16383个。(这一段是我猜的。。。。)

Linux 内核系统调用与中断(学习笔记)

直接从内核源码找那些所谓的类似write,socket系统调用,直接找是找不到的,因为中间有一个GLIBC的一层,从源码看的话,先要从GLIBC的代码中找到对应的接口定义,然后再跳转到内核的代码中,才能了解其全貌。

中断

1. 为什么需要中断(硬件中断)

外设/硬件处理速度远远低于CPU的处理速度,

如果采用轮询方式,(CPU一直忙等),处理外设,会大大降低CPU的利用率;

如果采用中断方式,将会大大提高CPU的利用率。

2. 中断的硬件触发或连接

外设的中断信号并不是直接输送给CPU的,而是先给中断控制器(一般集成在CPU内部),每当外设产生一个中断信号,次中单信号首先输送给中断控制器,经过中断控制器的判断之后,再决定是否给CPU发送。

中断控制器的作用:

能够屏蔽或者是某个外设中断

能够设置外设中断的优先级

能够设置CPU外部的外设的中断信号的有效触发方式

能够设置CPU外部的外设的中断信号给到哪个CPU进行发送

一旦CPU接收到外设的中断信号,CPU开始处理中断。

3. 中断的处理流程

带优先级的中断处理流程图

Linux 内核系统调用与中断(学习笔记)

其中,从正常运行的用户任务,task任务中,接收到了1号中断信号,便跳转到异常向量表中,查询对应的系统调用,并且进行相应的中断服务程序的处理。

4. 中断的软件编程

4.1 准备异常向量表

4.2 编写保护现场的代码

4.3 编写中断服务程序或者中断处理函数

4.4 编写恢复现场的代码

一般上述4个过程,不可缺少,但是,实际编程中,一般的只需要完成第三步即可。

5 Linux 内核的中断编程

除了要试下对应的中断处理服务程序,或者说中断处理函数之外,我们还需要将该中断处理函数,注册到内核中。一旦对应的中断被触发,内核会自动调用我们提供的中断服务程序。

request_irq / free_irq

在Linux内核源码 interrupt.h中

Linux 内核系统调用与中断(学习笔记)

 功能:

1. 向硬件申请中断资源

2. 注册硬件中断的中断处理函数到内核

参数:

irq: 硬件中断对应的软件编号,中断号,一般32开始,0到31号保留。该中断号实际是由芯片厂家在内核源码中定义 。

handler: 中断处理函数。

flags: 中断标志

针对外部中断,flags要指定有效的中断触发方式。

IRQF_TRIGER_FALLING: 下降沿触发

IRQF_TRIGER_RISING: 上升沿触发

IRQF_TRIGER_HIGH: 高电平触发

IRQF_TRIGER_LOW: 低电平触发

可以进行位或运算

针对内部中断,flags 给0即可。

name: 中断名称。

dev: 中断处理函数的参数。无需参数时,传入NULL。