1. 准备工作
此处重点介绍基础概念,为后面介绍数据包收发打下基础。本次代码层面基于Linux 4.4 Kernel。
1.1 系统调用
Linux的系统运行分为用户态和内核态,内核态控制着系统资源。通过定时器进行调度,把cpu分配给用户进程使用;通过中断来响应外设请求;并有一定的框架来管理内存、文件、网络等。
系统调用流程如下:
1.2 中断
内核和网络设备驱动是通过中断的方式来处理的。当设备上有数据到达的时候,会给CPU的相关引脚上触发一个电压变化,以通知CPU来处理数据。对于网络模块来说,由于处理过程比较复杂和耗时,如果在中断函数中完成所有的处理,将会导致中断处理函数(优先级过高)将过度占据CPU,将导致CPU无法响应其它设备,例如鼠标和键盘的消息。因此Linux中断处理函数是分上半部和下半部的。上半部是只进行最简单的工作,快速处理然后释放CPU,接着CPU就可以允许其它中断进来。剩下将绝大部分的工作都放到下半部中,可以慢慢从容处理。2.4以后的内核版本采用的下半部实现方式是软中断,由ksoftirqd内核线程全权处理。和硬中断不同的是,硬中断是通过给CPU物理引脚施加电压变化,而软中断是通过给内存中的一个变量的二进制值以通知软中断处理程序。
操作系统对于中断处理流程一般为:
关中断:CPU关闭中段响应,即不再接受其它外部中断请求
保存断点:将发生中断处的指令地址压入堆栈,以使中断处理完后能正确地返回。
识别中断源:CPU识别中断的来源,确定中断类型号,从而找到相应的中断服务程序的入口地址。
保护现场所:将发生中断处理有关寄存器(中断服务程序中要使用的寄存器)以及标志寄存器的内存压入堆栈。
执行中断服务程序:转到中断服务程序入口开始执行,可在适当时刻重新开放中断,以便允许响应较高优先级的外部中断。
恢复现场并返回:把“保护现场”时压入堆栈的信息弹回原寄存器,然后执行中断返回指令(IRET),从而返回主程序继续运行。