在第五部分中,我们将看到一个在理论上和使用上都与GDT非常相似的表格,我们将其称为IDT。 IDT代表 中断说明表 y是用于处理发生的中断的表。 例如,某人除以0,负责处理的函数被调用。 这些功能是ISR(中断服务程序)。 因此,让我们创建IDT并添加一些ISR。
首先,我们将声明与IDT对应的结构:
struct Entry{
uint16_t base_low;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
可以看出,如果将它与GDT进行比较,则Ptr的结构是相同的,而Entry则是非常相似的。 因此,放置条目(SetGate)和安装(Install)的功能非常相似。
void ND::IDT::SetGate(uint8_t num,uint32_t base,uint16_t sel, uint8_t flags)
{
idt[num].base_low=(base & 0xFFFF);
idt[num].base_high=(base >> 16) & 0xFFFF;
idt[num].sel=sel;
idt[num].always0=0;
idt[num].flags=flags;
}
安装:
idtptr.limit=(sizeof(struct ND::IDT::Entry)*256)-1;
idtptr.base=(uint32_t)&idt;
ND::Memory::Set(&idt,0,sizeof(struct ND::IDT::Entry)*256);
ND::IDT::Flush();
如果我们看一下,将会看到install函数使用了我们在另一篇文章中声明的ND :: Memory :: Set函数。 我们还可以理解我们还没有对SetGate进行任何调用,而我们调用了ND :: IDT :: Flush,对于此功能,我们再次使用了asm volatile语句:
asm volatile("lidtl (idtptr)");
如果一切顺利,我们进行了美学安排,则应如下所示:
好的,现在让我们开始用中断填充RTD。 在这里,我将只创建一个,其余的将是相同的。 我要除以零休息。 众所周知,数学不能将数字除以0。如果在处理器中发生这种情况,则会生成一个异常,因为它无法继续。 在IDT中,列表(0)中的第一个中断对应于此事件。
我们将其添加到IDT的Install函数中的内存设置和刷新之间:
ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);
回调函数将是ND :: ISR :: ISR1,这很简单,尽管我们必须使用ASM:
void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}
ND_ISR_Common我们将其定义为C语言函数,为保存文件并提高可读性,我们可以使用extern«C»{}:
extern "C"
void ND_ISR_Common()
{
asm volatile(
"pusha \n"
"push %ds \n"
"push %es \n"
"push %fs \n"
"push %gs \n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_ISR_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}
ASM中的这段代码可能有点难以理解,但这是因为我们将在C中声明一个结构来访问由中断生成的数据。 显然,如果您不想这样做,则可以在ND :: ISR :: ISR1或类似的名称中调用内核恐慌。 该结构具有以下形状:
struct regs{
uint32_t ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss;
};
最后,我们执行ND_ISR_Handler函数(也具有C链接),在该函数中,我们根据错误列表中的错误显示了内核崩溃和对错误的简短描述。
extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}
很好,有了这个,我们已经能够处理这种中断。 对于其余的中断,除了有一些返回参数,我们将使用reg结构来获取它,否则会发生类似的情况。 但是,您可能想知道我们如何知道它是否真的有效。 为了测试它是否有效,我们将在ND :: IDT :: Install()之后引入一个简单的代码行:
int sum=10/0;
如果我们编译它会给我们一个警告,如果我们尝试执行它会得到一个漂亮的屏幕:
我去了LFS,它更加连续。
神圣的...无论如何,这些教程都是不错的。
很好,我从一开始就一直在关注它。 您可以将代码附加到每个预告片上吗?
您拥有GitHub上所有可用的源代码: http://github.com/AdrianArroyoCalle/next-divel 您可以从那里下载ZIP,TAR.GZ或仅使用git。
哈哈哈很好! 批准! 🙂