Bran的内核开发为什么上不了bet356_bet356 下载安装_bet356黑钱(bkerndev)-07 中断描述符表(IDT)

转载 Raina_RLN 2019/11/4 21:14:33

中断描述符表中断描述符表用于告诉处理器调用哪个中断服务程序来处理异常或汇编中的指令。每当设备完成请求并需要服务事中断请求也会调用条目。异常和将在下一节进行详细的说明。每一项都与相似两者都有一个基地址一个访问标志而且都

中断描述符表(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 

/* 定义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, 尽管在本为什么上不了bet356_bet356 下载安装_bet356黑钱中我们只会使用前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中。本为什么上不了bet356_bet356 下载安装_bet356黑钱将在下一节介绍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, 则可以在此处找到本为什么上不了bet356_bet356 下载安装_bet356黑钱的解决方案。

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;
}

上一篇:数字麦克风PDM信号采集与STM32 I2S接口应用(三)

下一篇:这一次,彻底理解Promise源码思想

赞(0)

共有 条评论 网友评论

验证码: 看不清楚?
    IT文章导航
    扫一扫关注最新编程为什么上不了bet356_bet356 下载安装_bet356黑钱