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

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

原文地址:https://www.cnblogs.com/raina/p/11791971.html

时间: 2024-10-01 19:07:12

Bran的内核开发教程(bkerndev)-07 中断描述符表(IDT)的相关文章

Bran的内核开发教程(bkerndev)-01 介绍

介绍 ??内核开发不是件容易的事,这是对一个程序员编程能力的考验.开发内核其实就是开发一个能够与硬件交互和管理硬件的软件.内核也是一个操作系统的核心,是管理硬件资源的逻辑. ??处理器或是CPU是内核需要管理的最重要的系统资源之一.内核对其的管理体现在:给特定操作分配时间,并允许在另一个调度事件发生时中断任务或进程.也就是多任务处理(multitasking).多任务处理的实现方式有: 协作式多任务处理(cooperative multitasking):当程序自身想要放弃处理下一个可执行进程或

Bran的内核开发教程(bkerndev)-03 内核初步

内核初步 ??在这节教程, 我们将深入研究一些汇编程序, 学习创建链接脚本的基础知识以及使用它的原因.最后, 我们将学习如何使用batch(批处理)文件自动汇编.编译和链接这个最基本的受保护模式下的内核.本教程假定你已经安装了NASM和GCC, 并且了解一点点x86汇编语言. 内核入口 ??内核的入口点是当引导程序(bootloader)调用内核时最先执行的代码段.这段代码一直以来几乎都是使用汇编编写的, 因为有些工作如设置新的栈, 加载新的GDT.IDT或寄存器, 你简单地使用C语言根本没法做

Bran的内核开发指南_中文版

http://www.cnblogs.com/liloke/archive/2011/12/21/2296004.html 最近在看<orange’s>一书,有点想自己写一个轻量级OS的想法,设计和架构上会参照orang’s和Linux 0.11 kernel. 这个网站,上面的资料对于我这样的新手无疑是一份宝贵的财富啊.它详细介绍了内核程序必不可少的几大模块,并且对于每一个模块都有一些代码示例.看着文章代码,边做边学,真是一件愉快的事情 本来还想翻译成中文献给大家,不过google了一下,已

IDT系列:(一)初探IDT,Interrupt Descriptor Table,中断描述符表

原文:  IDT系列:(一)初探IDT,Interrupt Descriptor Table,中断描述符表 IDT,Interrupt Descriptor Table,中断描述符表是CPU用来处理中断和程序异常的. 一.有关IDT的基本知识 1.中断时一种机制,用来处理硬件需要向CPU输入信息的情况. 比如鼠标,键盘等. 2.中断和异常的产生是随机的,在CPU正常运行过程中随时可能产生.CPU的中断处理机制 3.中断可以由硬件产生(称为外部中断),也可以由软件产生(称为内部中断),在程序中写入

Linux内核设计基础(十)之内核开发与总结

(1)Linux层次结构: (2)Linux内核组成: 主要由进程调度(SCHED).内存管理(MM).虚拟文件系统(VFS).网络接口(NET)和进程间通信(IPC)等5个子系统组成. (3)与Unix的差异: Linux支持动态加载内核模块 支持对称多处理(SMP)机制 Linux内核可以抢占 Linux内核并不区分线程和其他的一般进程 Linux提供具有设备类的面向对象的设备模型.热插拔事件,以及用户空间的设备文件系统(sysfs) (4)内核开发的特点: 内核编程时既不能访问C库也不能访

ArcGIS Runtime for Android开发教程V2.0(1)基本概念

原文地址: ArcGIS Runtime for Android开发教程V2.0(1)基本概念 - ArcGIS_Mobile的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/arcgis_mobile/article/details/8113183   1.基本概念 1.1 Android简介         2007年11月,Google推出移动操作系统Android,并宣称Android是首个为移动终端打造的真正开放和完整的移动操作系统.自此,基于And

apklug插件托管服务开发教程之按条件查询云端插件-01

以一个简单的输出程序为例: #include<iostream> #include<cstring> #include<cstdio> using namespace std; class point { public: int a,b,c; }; point p; void fuc() { for(int i=1;i<=10;++i) { ++p.a; ++p.b; ++p.c; cout<<p.a<<' '<<p.b<

Unity多玩家网络游戏开发教程1章Unity带有网络功能

Unity网络多玩家游戏开发教程第1章Unity自带网络功能 Unity拥有大量的第三方插件.专门提供了对网络功能的支持. 可是.大部分开发人员第一次接触到的还是Unity自带的网络功能.也就是大家常常说到的Unity Networking API.这些API是借助于组件NetworkView发挥作用的,而它能够简化开发人员大量的网络功能编码任务.本文选自<Unity网络多玩家游戏开发教程(大学霸内部资料)> NetworkView组件 在Unity中,NetworkView组件用于处理游戏在

Android内核开发:系统分区与镜像文件的烧写

本文是<Android内核开发>系列的第五篇文章,本文重点介绍如何把编译输出的镜像文件烧写到Android设备中. 玩过刷机的朋友肯定对fastboot这个工具并不陌生,它是Android SDK中提供的一种开发工具,支持通过USB线将手头的镜像文件更新/烧录到Android设备中,常用的fastboot烧录过程如下: fastboot flash boot boot.img fastboot flash system system.img fastboot flash userdata us