当用户态的进程调用一个系统调用时,CPU从用户态切换到内核态并开始执行一个内核函数。Linux通过由向量为128(0x80)的编程异常实现CPU由用户态到内核态的转换。
因为内核实现了许多不同的系统调用,为了区别他们,进程必须传递一个系统调用号的参数来识别所需的系统调用。EAX寄存器是负责传递系统调用号的。
系统调用处理程序执行下列操作:
(1)在内核栈保存大多数寄存器的内容(这个操作对所有的系统调用都是通用的,并用汇编语言编写)。
(2)调用系统调用服务例程的相应的C函数处理系统调用。
(3)通过syscall_exit_work()函数从系统调用返回(这个函数用汇编语言编写)。
1.初始化系统调用
内核初始化期间调用trap_init()函数建立IDT表(中断描述符表)中128号向量对应的表项,语句如下:
set_system_gate(SYSCALL_VECTOR, &system_call);
其中SYSCALL_VECTOR是一个宏定义,其值为0x80,该调用把下列值装入这个门描述符的相应域。
(1)段选择子:因为系统调用处理程序属于内核代码,填写内核代码段__KERNEL_CS的段选择子。
(2)偏移量:指向system_call()系统调用处理程序。
(3)类型:置为15.表示这个异常是一个陷阱门,相应的处理程序不禁止可屏蔽中断。
(4)DPL(描述符权级):置为3。这就允许用户态