hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

Bran的内核开辟教程(bkerndev)-07 中断描述符表(IDT)

2019-11-18杂谈搜奇网35°c
A+ A-

中断描述符表(IDT)

  中断描述符表(IDT)用于通知处置惩罚器挪用哪一个中断效劳顺序(ISR)来处置惩罚非常或汇编中的"int"指令。每当装备完成要求并须要效劳事, 中断要求也会挪用IDT条目。非常和ISR将在下一节举行细致的申明。

  每一项IDT都与GDT类似, 二者都有一个基地点, 一个接见标志, 而且都长64bits。这两类描述符表最重要的区分在于这些字段的寄义: 在IDT中的基地点是中断时应挪用的ISR的地点。IDT也没有边境(limit), 而是须要一个指定的段, 该段与给定的ISR地点段雷同。这让处置惩罚器纵然处于差别级别的Ring中, 在发作中断时也能将控制权交给内核。

  IDT条目的接见标志位也和GDT类似。须要一个字段申明描述符是不是存在。描述符特权级别(DPL)用于申明哪一个Ring是给定中断许可运用的最高级别。重要区分在于接见字节的低5位一直为二进制01110, 也就是十进制中的14。下面这张表让你更好地邃晓IDT接见字节。

  • P - 段是不是存在? (1 = Yes)
  • DPL - 哪一个Ring (0~3)

  在你的克己内核目录下建立一个新文件"idt.c"。编辑"build.bat"文件, 增加新的一行gcc敕令编译"idt.c"。末了增加"idt.o"到链接文件列表中。"idt.c"中将会声明一个构造体用于定义每一个IDT条目, 和一个用于加载IDT的特别IDT指针构造体(类似于加载GDT, 但工作量更少), 并声明一个256大小的IDT数组: 这将成为我们的IDT。

idt.c

#include <system.h>

/* 定义IDT条目 */
struct idt_entry
{
    unsigned short base_lo;
    unsigned short sel;        /* 我们的内核段在这里 */
    unsigned char always0;     /* 这将一直为0! */
    unsigned char flags;       /* 依据上表举行设置! */
    unsigned short base_hi;
} __attribute__((packed));  // 不举行对齐优化

struct idt_ptr
{
    unsigned short limit;
    unsigned int base;
} __attribute__((packed));

/* 声明一个有256个条目的IDT, 只管在本教程中我们只会运用前32个。
 * 剩下的存在一点小圈套, 假如任何未定义的IDT被集合, 
 * 将会致使"未处置惩罚的中断(Unhandled Interrupt)"非常,
 * 描述符的"presence"位假如为0, 将生成"未处置惩罚的中断"非常。*/
struct idt_entry idt[256];
struct idt_ptr idtp;

/*该函数在"start.asm"中定义, 用于加载我们的IDT */
extern void idt_load();

  idt_load函数的函数定义在其他文件中, 和gdt_flash一样是运用汇编语言编写的。我们以后将在idt_install中运用建立的IDT指针来挪用lidt汇编操作码。翻开"start.asm"文件, 把下面几行增加到_gdt_flushre背面。

start.asm

; 加载idtp指针所指的IDT到处置惩罚器中
; 这在C文件中声明为"extern void idt_load();"
global _idt_load
extern _idtp
_idt_load:
    lidt [_idtp]
    ret

  设置IDT条目比GDT简朴很多。我们又一个idt_set_gate函数用于吸收IDT索引号、中断效劳顺序基地点、内核代码段以及上表中提到的接见标志。一样, 我们又一个idt_install函数用来设置IDT指针, 并将IDT初始化为默许消灭状况。末了, 我们将经由过程挪用idt_load来加载IDT。在加载IDT后, 我们能够随时将ISR增加到IDT中。本教程将在下一节引见ISR。下面是"idt.c"文件的盈余部份, 请尝试弄邃晓idt_set_gate函数, 它实在很简朴。

idt.c

/* 运用该函数来设置每项IDT*/
void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
    /* 该函数的代码将留给你来完成: 
     * 将参数"base"分为高16位和低16位,
     * 将它们存储在idt[num].base_hi和idt[num].base_lo中
     * 剩下的须要设置idt[num]的其他成员的值 */
}

/* 装置IDT */
void idt_install()
{
    /* 设置IDT指针 */
    idtp.limit = (sizeof (struct idt_entry) * 256) - 1;
    idtp.base = &idt;

    /* 清空全部IDT, 并初始化该片地区为0 */
    memset(&idt, 0, sizeof(struct idt_entry) * 256);

    /* 运用idt_set_gate将ISR增加到IDT中 */

    /* 将处置惩罚器的内部寄存器指向新的IDT */
    idt_load();
}

  末了, 确保在"system.h"中增加idt_set_gateidt_install作为函数原型, 由于我们须要从其他文件(比方"main.c")中挪用这些函数。在main()函数挪用了gdt_install后马上挪用idt_install。这是你应当能够胜利编译你的内核。尝试运用一下你的新内核, 在举行除零之类的非法操作时, 计算机将重置。我们能够经由过程在新的IDT中装置ISR来不活这些非常。

  假如你不知道怎样编写idt_set_gate, 则能够在此处找到本教程的解决方案。

idt.c

void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
    /* 中断顺序的基地点 */
    idt[num].base_lo = (base & 0xFFFF);
    idt[num].base_hi = (base >> 16) & 0xFFFF;

    /* 该IDT运用的段或地区以及接见标志位将在此设置 */
    idt[num].sel = sel;
    idt[num].always0 = 0;
    idt[num].flags = flags;
}
  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
Bran的内核开辟教程(bkerndev)-07 中断描述符表(IDT)

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282255.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>