模拟Linus Torvalds:从0(V​​)创建您自己的操作系统

在第五部分中,我们将看到一个在理论上和使用上都与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)");

如果一切顺利,我们进行了美学安排,则应如下所示:

NextDivel-RTD

好的,现在让我们开始用中断填充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;

如果我们编译它会给我们一个警告,如果我们尝试执行它会得到一个漂亮的屏幕:

NextDivel-ISR


到此为止,我认为这是最广泛但功能齐全的文章之一。


发表您的评论

您的电子邮件地址将不会被发表。 必填字段标有 *

*

*

  1. 负责数据:MiguelÁngelGatón
  2. 数据用途:控制垃圾邮件,注释管理。
  3. 合法性:您的同意
  4. 数据通讯:除非有法律义务,否则不会将数据传达给第三方。
  5. 数据存储:Occentus Networks(EU)托管的数据库
  6. 权利:您可以随时限制,恢复和删除您的信息。

  1.   中型

    我去了LFS,它更加连续。

  2.   埃利奥时间3000

    神圣的...无论如何,这些教程都是不错的。

  3.   sc

    很好,我从一开始就一直在关注它。 您可以将代码附加到每个预告片上吗?

    1.    阿德里安·阿罗约街

      您拥有GitHub上所有可用的源代码: http://github.com/AdrianArroyoCalle/next-divel 您可以从那里下载ZIP,TAR.GZ或仅使用git。

  4.   细微的

    哈哈哈很好! 批准! 🙂