我们先看中断描述符的定义:
其中:
1. offset_high,offset_middle和offset_low合起来就是中断处理函数地址的偏移量;
2. segment就是相应的段选择子,根据它在GDT中查找可以最终获取到段基地址;
3. bits是该中断描述符的一些属性值:
ist表示此中断处理函数是使用pre-cpu的中断栈,还是使用IST的中断栈;
type表示所中断是何种类型,目前有以下四种:
门的概念这里主要用作权限控制,我们从一个区域进到另一个区域需要通过一扇门,有门禁权限才可以通过,因此 dpl就是这个权限,实际中我们一般称为RPL;
我们后面会通过一个例子来讲一下CPL,RPL和DPL三者之间的关系。
IDT中断描述符本身的存储
IDT 中断描述符表的物理地址存储在IDTR寄存器中,这个寄存器存储了IDT的基地址和长度。查询时,从 IDTR 拿到 base address ,加上向量 * IDT entry size,即可以定位到对应的表项(gate)。
上面的函数主要是填充好idt_data,然后调用idt_setup_from_table;
首先使用 idt_data结构来填充中断描述符变量idt_init_desc, 然后将这个中断描述符变量copy进idt_table。
看,就是这么简单~~~
-
gate_desc的多种初始化方法:
因为gate_desc是通过ida_dat填充的,所以这里关键是idt_data的初始化,我们详细看一下:
我们再来看下G这个宏的实现:
实际上就是填充idt_data的各个字段。
2
传统系统调用的实现
这里所说的传统系统调用主要指旧的32位系统使用 int 0x80软件中断来进入内核态,实现的系统调用。因为这种传统系统调用方式需要进入内核后作权限验证,还要切换内核栈后作大量压栈方式,调用结束后清理栈作恢复,两个字太慢,后来CPU从硬件上支持快速系统调用sysenter/sysexit, 再后来又发展到syscall/sysret, 这两种都不需要通过中断方式进入内核态,而是直接转换到内核态,速度快了很
传统系统调用相关IDT的设置
Linux系统启动过程中内核压解后最终都调用到start_kernel, 在这里会调用trap_init, 然后又会调用idt_setup_traps:
我们来看这里的def_idts的定义:
上面的SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32)就是设置系统调用的异常中断处理程序,其中 #define IA32_SYSCALL_VECTOR 0x80
再看一下SYSG的定义:
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!