『阿男的Linux内核世界』*15 从User Space到Kernel Space(三)*

『阿男的Linux内核世界』*15 从User Space到Kernel Space(三)*

我们目前知道了,当interrupt发生时,Kernel会暂时打断Process在User Space的运行,转到Kernel Space处理中断。此外,我们知道了interrupt大体可以分为三类,分别是硬件中断,软件中断,还有CPU的Exceptions。

其中硬件中断是硬件设备直接发信号给CPU,比如用户按键盘输入数据。软件中断是程序主动调用CPU的INT指令来触发某一个Interrupt,CPU异常则是CPU在运算过程中发生的各种错误状态。

我们还知道了,Intel CPU架构下,一共有256个编号可以给以上面三种interrupts使用。因此,在操作系统实现方面,大部分工作就是把这些编号和具体的处理这些interrupts的函数给对应起来。处理Interrupts的函数叫做Interrupt Handler

那么编号和实现函数肯定要有一个对应关系,这个对应关系需要一张表格来保存,这张表格叫做IDT,全称就是Interrupt Descriptors Table。而这张表格在哪里呢?这张表格在操作系统启动的时候由操作系统加载到内存里,然后这张表格的起始位置保存在IDTR这个寄存器里面。注意这个寄存器也是个高权限寄存器,Kernel可以访问,而User Space无法访问到的。

关于IDT表格的设置代码,我们可以看下desc.h^1里面相关的代码:

#define load_tr(tr) asm volatile("ltr %0"::"m" (tr))
#define load_ldt(ldt) asm volatile("lldt %0"::"m" (ldt))

可以看到CPU的指令ltrlldt都是和设置IDTR寄存器相关的指令,具体的细节阿男就不在这篇文章里面详述了,大家如果真的对Intel CPU的指令集和架构设计感兴趣,就需要花功夫阅读Intel的官方手册Intel® 64 and IA-32 Architectures Developer's Manual^2,非常厚的一本手册,但是写得非常好,大家自己下载PDF留一份,经常看一看,收获会非常大。

关于IDT表格的默认内容,我们在前一篇文章中讲解过了,分别在traps.hirq_vectors.h里面有定义。我们这次再回顾一下arch/x86/include/asm/irq_vectors.h^3。注意和硬件架构相关的代码,往往具体的实现有差异,所以Linux在kernel代码里面会把不同架构的不同代码用arch/然后后面加上具体的架构名字,比如x86。这次我们来看看irq_vectors.h里面的注释:

/*
 * Linux IRQ vector layout.
 *
 * There are 256 IDT entries (per CPU - each entry is 8 bytes) which can
 * be defined by Linux. They are used as a jump table by the CPU when a
 * given vector is triggered - by a CPU-external, CPU-internal or
 * software-triggered event.
 *
 * Linux sets the kernel code address each entry jumps to early during
 * bootup, and never changes them. This is the general layout of the
 * IDT entries:
 *
 *  Vectors   0 ...  31 : system traps and exceptions - hardcoded events
 *  Vectors  32 ... 127 : device interrupts
 *  Vector  128         : legacy int80 syscall interface
 *  Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts
 *  Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts
 *
 * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
 *
 * This file enumerates the exact layout of them:
 */

上面这段代码告诉我们Linux是如何使用IDT的,比如0到31号中断时system traps,32到127时设备中断,128是system calls,等等。

其中有一个128号中断,也就是十六进制的0x80号软件中断是所有system calls的入口。也就是说0x80号中断对应system calls的handler function,然后这个handler再根据寄存器里面,程序请求的system call编号来执行相应的system call function。那么为什么文档里说这个128号是legacy int80 syscall interface呢?所谓legacy就是过时的,会被淘汰的。因为新的Intel x86_64 CPU,也就是64位的CPU架构里,提供了一个更为直接的指令,叫做syscall,这个指令比int 0x80更高效。

转载于:https://my.oschina.net/u/3195023/blog/823360

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值