【动手实现操作系统】三:中断

中断类型

保护模式下中断分为三种

  • 错误Fault: ⼀种可被更正的异常, ⼀旦被更正, 程序可以不失连续性地继续执⾏, 中断程序返回地址为产⽣ Fault 的指令
  • 陷阱Trap: 发⽣ Trap 的指令执⾏之后⽴刻被报告的异常, 也允许程序不失连续性地继续执⾏, 但中断程序返回地址是产⽣ Trap 之后的那条指令
  • 终止Abort: Abort 异常不总是精确报告发⽣异常的位置, 它不允许程序继续执⾏, ⽽是⽤来报告严重错误
IDT

IDT(Interuption Descriptor Table) ,类似于中断向量表,但比中断向量表有更丰富的信息。
在保护模式下,每个中断(Exception,Interrupt,Software Interrupt)都由⼀个 8-Bits 的向量来标识,其为中断向量,8-Bits表示⼀共有256个中断向量;与 256 个中断向量对应,IDT 中存有 256 个
表项,表项称为⻔描述符(Gate Descriptor),每个描述符占 8 个字节。
⻔描述符可以分为3种

  • Task Gate,Intel设计⽤于任务切换,现代操作系统中⼀般不使⽤
  • Interrupt Gate,跳转执⾏该中断对应的处理程序时, EFLAGS 中的 IF 位会被硬件置为 0,即关中断,以避免嵌套中断的发⽣
  • Trap Gate,跳转执⾏该中断对应的处理程序时, EFLAGS 中的 IF 位不会置为 0,也就是说,不关中断
    下图展示了 Interrupt Gate 8个字节表示的信息
    在这里插入图片描述
    其中SELECTOR是段描述符(16位),OFFSET是地址偏移量(要加载的EIP的),DPL表示权限。下图展示了Trap Gate 8个字节表示的信息
    在这里插入图片描述
    二者的区别就是第39位的值。
机制

中断到来之后,基于中断向量,IA-32硬件利⽤IDT与GDT这两张表寻找到对应的中断处理程序,并从当前程序跳转执⾏。
若中断源为int 等指令产⽣的软中断,IA-32硬件处理该中断时还会⽐较产⽣该中断的程序的CPL与该中断对应的⻔描述符的DPL字段,若CPL数值上⼤于DPL,则会产⽣General Protect Fault,即#GP异常

实现

这里用结构体来表示门描述符

struct GateDescriptor {
	uint32_t offset_15_0      : 16;
	uint32_t segment          : 16;
	uint32_t pad0             : 8;
	uint32_t type             : 4;
	uint32_t system           : 1;
	uint32_t privilege_level  : 2;
	uint32_t present          : 1;
	uint32_t offset_31_16     : 16;
};

然后表示一个门描述符需要具体给出三个值:SELECTOR,OFFSET和DPL:

#define SEG_KCODE   1           // Kernel code
#define INTERRUPT_GATE_32   0xE
#define TRAP_GATE_32        0xF
/* 初始化一个中断门(interrupt gate) */
static void setIntr(struct GateDescriptor *ptr, uint32_t selector, uint32_t offset, uint32_t dpl) {
	ptr->offset_15_0 = offset & 0xFFFF;
	ptr->segment = selector << 3;
	ptr->pad0 = 0;
	ptr->type = INTERRUPT_GATE_32;
	ptr->system = FALSE;
	ptr->privilege_level = dpl;
	ptr->present = TRUE;
	ptr->offset_31_16 = (offset >> 16) & 0xFFFF;
}

/* 初始化一个陷阱门(trap gate) */
static void setTrap(struct GateDescriptor *ptr, uint32_t selector, uint32_t offset, uint32_t dpl) {
	ptr->offset_15_0 = offset & 0xFFFF;
	ptr->segment = selector << 3;
	ptr->pad0 = 0;
	ptr->type = TRAP_GATE_32;
	ptr->system = FALSE;
	ptr->privilege_level = dpl;
	ptr->present = TRUE;
	ptr->offset_31_16 = (offset >> 16) & 0xFFFF;
}

这样我们就可以定义具体的IDT了,比如定义中断向量为0x21的键盘中断和中断向量为0x80的软件中断。

#define NR_IRQ 256
/* IDT表的内容 */
struct GateDescriptor idt[NR_IRQ];
void irqEmpty();
void irqSyscall();
void irqKeyboard();

void initIdt() {
	int i;
	/* 为了防止系统异常终止,所有irq都有处理函数(irqEmpty)。 */
	for (i = 0; i < NR_IRQ; i ++) {
		setTrap(idt + i, SEG_KCODE, (uint32_t)irqEmpty, DPL_KERN);
	}
	/*
	 * init your idt here
	 * 初始化 IDT 表, 为中断设置中断处理函数
	 */
	/* Exceptions with error code */
	// ...
	setIntr(idt + 0x21, SEG_KCODE, (uint32_t)irqKeyboard, DPL_KERN);
	setIntr(idt + 0x80, SEG_KCODE, (uint32_t)irqSyscall, DPL_USER); // for int 0x80, interrupt vector is 0x80, Interruption is disabled

	/* 写入IDT */
	saveIdt(idt, sizeof(idt));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值