03.填充中断向量表IDT,使用中断

news2024/11/20 22:38:46

填充中断描述符表IDT,使用中断

通过初始化中断控制芯片,编码中断函数,实现BIOS中断

操作系统的中断是一种异步事件,用于通知 CPU 某个事件已经发生,例如硬件设备完成数据传输、发生错误或用户发起的系统调用。当操作系统收到中断请求时,它会挂起当前执行的任务,并调用相应的中断处理程序(interrupt handler)来处理该事件。

中断可以被看作是一种硬件通知机制,允许系统在不同的时间点响应外部事件。操作系统会为每个中断请求分配一个唯一的中断号,并通过 IDTInterrupt Descriptor Table)来管理和映射中断处理程序的位置和参数。中断处理程序是由内核编写的低级代码,用于处理特定类型的中断请求,并执行适当的操作,例如更新系统状态、将数据存储到缓存中、读取输入设备等。

在 x86 架构的计算机中,有两种类型的中断:软中断(software interrupt)和硬中断(hardware interrupt)。软中断需要程序员显式地触发,例如通过系统调用调用特定函数;而硬中断是由外部硬件设备发出的,例如键盘、鼠标或磁盘驱动器。硬中断通常采用 IRQ(Interrupt Request)信号进行通信,并由中断控制器(如 8259A)进行控制和管理。

参考:
深入理解Linux中断机制
中断描述符表
可编程中断控制器8259A
《操作系统真相还原》

1.中断向量表IDT

中断描述符

中断描述符表是保护模式下用于存储中断处理程序的数据结构。CPU在接收到中断时,会根据中断向量在中断描述符表中检索对应的描述符。IDT 中的每个条目都称为中断描述符,并由一个 8 字节的描述符来表示。
在这里插入图片描述

  • Offset:描述中断处理程序的入口地址。它是一个 32 位或 64 位值,指向中断处理程序代码的起始地址。
  • Selector:处理程序所在代码段的选择符,指向代码段描述符在 GDT 或 LDT 表中的位置。
  • Type:描述符的类型。它定义了中断门(Interrupt Gate)、陷阱门(Trap Gate)或任务门(Task Gate)等不同类型中断描述符的特性。 DPL:描述符的特权级别。它定义了哪些代码可以使用中断描述符,并为其分配相应的访问权限。D为0则表示16位模式下门,1则为32位的门
    • 0b110:表示中断门(Interrupt Gate)。中断门会将处理器从当前代码转向对应的中断处理程序,并在处理程序执行完毕后返回原来的位置,也就是底层代码不会被中断处理程序修改。
    • 0b111:表示陷阱门(Trap Gate)。陷阱门和中断门类似,不同之处在于它会保留中断发生时的 CPU 状态,并在处理程序返回时重新恢复这些状态。因此,陷阱门常常被用来实现调试器等功能。
    • 0b100:表示任务门(Task Gate)。任务门是一种特殊的中断门,用于实现任务切换。当处理器遇到一个任务门时,会切换到其中指定的任务并开始执行。
  • S:为0表示为系统段,这里必须为0。
  • P:描述符存在位。如果为 0,则该描述符无效,处理器会抛出“未定义操作码”异常并导致中断处理失败。
  • DPL:门特权级。

中断描述符表中的所有描述符共同组成了中断向量表,每个中断向量代表了一种中断类型。当中断发生时,硬件将中断向量号传递给中断描述符表,操作系统就可以使用相应的中断描述符来调用正确的中断处理程序。段描述符中描述的是一片内存区域,而门描述符中描述的是一段代码

// 定义中断门描述符结构体
typedef struct interrupt_gate_t {
    unsigned short offset_low;     // 偏移地址低 16 位 0 ~ 15 位
    unsigned short selector;       // 描述符所在段的选择子
    unsigned char  reserved;       // 保留不用
    unsigned char type:4;          // 任务门/中断门/陷阱门
    unsigned char segment : 1; // segment = 0 表示系统段
    unsigned char DPL:2;    // 特权级
    unsigned char present : 1; // 是否有效
    unsigned short offset_high;      // 偏移地址高 16 位 16 ~ 31 位

} __attribute__((packed)) interrupt_gate_t;

中断向量

Linux 操作系统支持 256 种中断号,其中一部分被保留给操作系统内核使用,另外一部分则可以被用户应用程序或模块使用。

在这里插入图片描述

  • 0-19,是特定的异常与错误
  • 20-31,映射中断控制芯片的IRQ0-IRP15
  • 32-255,用户自定义使用。比如系统调用,都是用的0x80中断

中断向量的作用和选择子类似,它们都用来在描述符表中索引 个描述符。中断向量专用于中断描述符表,其中没有 RPL 字段。
实模式内存分布中,0-0x3ff 的是中断向量表 IVT ,它是实模式下用于存储中断处理程序入口的表。大小为1KB,每个中断向量4B,可以存储256个。
因此对比中断向量表,中断描述符表有两个区别:

  • 中断描述符表地址不限制,在哪里都可以
  • 中断描述符表中的每个描述符用 8字节描述。

CPU内部有个中断描述符寄存器IDTR,,只有寄存器 IDTR指向了 IDT ,当 CPU 接收到中断向量号时才能找到中断向量处理程序,这样中断系统才能正常运作。该寄存器的结构图如下图:
在这里插入图片描述

  • 第0-15位是表界限,即IDT减1,可容纳8192个中段描述符;
  • 第16~47位时IDT的基地址。与GDTR类似。

2.中断执行过程

在这里插入图片描述
寄存器在中断处理过程中的作用说明:

  • EFLAGS 寄存器:EFLAGS 寄存器用来存储 CPU 的标记位,包括进位标志、零标志、符号标志等等。在中断处理过程中,EFLAGS寄存器的部分标记位可能会被修改,以反映中断处理过程中的状态。
  • CS 寄存器:CS(Code Segment)寄存器用于存储当前程序代码段的段选择子。在中断发生时,CPU 会根据中断向量号从 IDT表读取相应的中断描述符,其中包括一个代码段选择子。CPU 根据这个选择子将 CS寄存器的值修改为新的值,以便正确跳转到中断处理程序的代码段。
  • EIP 寄存器:EIP(Instruction Pointer)寄存器用于存储 CPU 下一条指令执行的地址。在中断发生时,CPU会将当前的 EIP 值保存到堆栈中,并将 EIP 设为中断向量所对应的中断处理程序入口地址,以便开始执行中断处理程序。
  • SS 和 ESP 寄存器:在中断处理过程中,CPU 会将当前程序的堆栈指针(ESP)和堆栈段选择子(SS)的值保存到堆栈中,并将 SS 和ESP 的值修改为新的栈段和栈指针。这个新的栈用于存储中断处理程序执行过程中所需要的数据和状态信息。
  • DS 和 ES 寄存器:在中断处理过程中,处理程序可能需要访问其他数据段或额外的数据空间。因此,在进入中断处理程序后,CPU 会自动将DS 和 ES 寄存器的值更新为相应的选择子,以便访问中断服务例程需要的数据段。
  • EAX、EBX、ECX、EDX、EDI 和 ESI寄存器:这些通用寄存器可用于存储各种类型的数据。在中断处理程序运行时,这些寄存器可能用于保存一些状态信息或临时变量,也可能会被修改以存储处理结果。
  • EBP 寄存器:EBP 寄存器常用作堆栈帧指针,在函数调用时保存局部变量和参数。在一个中断处理程序中,EBP可利用它的内容来检查现场保存的数据并调用归还数据的操作。

在 x86 架构的计算机系统中,当中断发生时,CPU 会自动执行一些压栈操作,以保护当前的现场(程序状态,即代码的执行位置和寄存器的值等),并存储关于中断的一些信息。下面是详细说明:

  • 1.SS 和 ESP 寄存器:CPU 首先将 SS(堆栈段选择子)和 ESP(堆栈指针)寄存器的值按照以下方式压入堆栈中:

    • (1)首先将 SS 压入堆栈中。
    • (2)然后将 ESP 压入堆栈中。

    这样做的目的是为了保存当前进程正在使用的堆栈指针和堆栈段选择子,以便在中断处理程序运行结束后可以正确恢复堆栈指针和堆栈段选择子。

  • 2.EFLAGS 寄存器:接下来,CPU 将 EFLAGS 寄存器的值压入堆栈中。EFLAGS 寄存器中存储了各种标志位,如进位标志、零标志、符号标志等等,这些标志位可能在中断处理程序中被修改,因此,在压栈的时候也需要将
    EFLAGS寄存器的值保存到堆栈中,以便在处理完中断后能够恢复现场。

  • 3.CS 和 EIP 寄存器:CPU 接着将 CS(代码段选择子)和 EIP(指令指针)寄存器的值压入堆栈中:

    • (1)首先将 CS 压入堆栈中。
    • (2)然后将 EIP 压入堆栈中。

    这样做的目的是为了保存程序当前的执行状态,以便在中断处理程序运行结束后能够正确返回到中断触发时原来的执行位置。

  • 4.中断向量号:最后,CPU 将中断向量号压入堆栈中,以提供中断处理程序获取中断号的信息。

        +-----------+
ESP ->  |   SS      |  (由于堆栈指针往下移动,所以先把SS存放到了堆栈中)
        +-----------+
        |   ESP     |
        +-----------+
        |   EFLAGS  |
        +-----------+
        |    CS     |
        +-----------+
        |    EIP    |
        +-----------+
        |   Vector  |
        +-----------+

在这里插入图片描述

3.硬件中断 8259a

对于Linux 内核来说,中断信号通常分为两类:硬件中断软件中断(异常)。每个中断是由0-255之间的一个数字来标识。

  • 中断 int0–int31(0x00–0x1f),每个中断的功能由Intel公司固定设定或保留用,属于软件中断,但Intel公司称之为异常。因为这些中断是在CPU执行指令时探测到异常情况而引起的。通常还可分为故障(Fault)和陷阱(traps)两类。
  • 中断 int32-int255(0x20–0xff)可以由用户自己设定。在Linux系统中,则将int32–int47(0x20–0x2f)对应于8259A中断控制芯片发出的硬件中断请求信号IRQ0-IRQ15,并把程序编程发出的系统调用(system_call)中断设置为int128(0x80)。

硬件中断,可由8259a芯片告知CPU。

结构

在这里插入图片描述
8259A 芯片包含两个级联的芯片,主芯片(Master)和从属芯片(Slave)。主芯片负责接收 CPU 发来的中断请求信号,并根据优先级将请求转发到从属芯片或直接处理。从属芯片则负责管理更多的硬件设备请求,并通知主芯片进行处理。主芯片和从属芯片通过一个独立的线路进行连接,以便实现级联。

初始化顺序

  • 1.向 8259A 芯片发送初始化命令字

为了初始化 8259A 芯片,首先需要向主芯片和从属芯片分别发送初始命令字(Initialization Command Word,简称 ICW),以启动初始化过程。ICW 可以通过三个 I/O 端口(0x20、0x21、0xA0、0xA1)进行传输。在向芯片发送 ICW 时,需按照一定的顺序进行,以确保初始化能够成功。

8259A 芯片的初始化顺序如下:
1.向主芯片发送 ICW1;
2.向主芯片发送 ICW2;
3.向从属芯片发送 ICW1(如果启用了级联模式);
4.向从属芯片发送 ICW2(如果启用了级联模式);
5.向主芯片或从属芯片发送 OCW,以设置中断屏蔽掩码,控制芯片的工作状态等;
6.接收来自硬件设备的中断请求。

; 配置8259a芯片,响应中断用
.init_8259a:
    ; 初始化 8259A 主芯片
    ; 发送初始化命令字 ICW1 到端口 0x20
    mov al, 0x11    ; 边沿触发,级联需要发送ICW 4
    out 0x20, al
    ; 发送 ICW2 到端口 0x21(设置主芯片的中断向量表偏移量)
    mov al, 0x20    ; 起始中断向量 0x20~0x27
    out 0x21, al
    ; 发送 ICW3 到端口 0x21(设置主芯片的 IRQ 线路连接方式)
    mov al, 0x04    ; IR2级联从片
    out 0x21, al
    ; 发送 ICW4 到端口 0x21(设置主芯片的工作模式)
    mov al, 0x03    ; 表示x86模式  自动EOI
    out 0x21, al

    ; 初始化 8259A 从芯片
    ; 发送初始化命令字 ICW1 到端口 0xA0
    mov al, 0x11    ; 需要发送ICW 4
    out 0xA0, al
    ; 发送 ICW2 到端口 0xA1(设置从芯片的中断向量表偏移量)
    mov al, 0x28    ; 起始中断向量 0x28
    out 0xA1, al
    ; 发送 ICW3 到端口 0xA1(设置从芯片与主芯片连接方式)
    mov al, 0x02    ; 2号
    out 0xA1, al
    ; 发送 ICW4 到端口 0xA1(设置从芯片的工作模式)
    mov al, 0x03
    out 0xA1, al
  • 2.设置 IRQ 向量表

IRQ 向量表是用于记录中断处理程序入口地址的数据表格,其中记录了每个 IRQ 线路对应的中断向量号。通过将 IRQ 向量表与中断处理程序相关联,可以在收到中断请求时快速地定位到对应的处理程序,并跳转到相应的代码段中执行相应的操作。

  • 3.设置中断屏蔽掩码

中断屏蔽掩码是一个 8 位二进制数,标识每个 IRQ 线路是否被禁止中断。通过设置中断屏蔽掩码,可以控制系统中哪些中断请求可以被接受,哪些中断请求应该被忽略。

  • 4.向 8259A 芯片发送结束命令字

在完成以上初始化操作后,需要向主芯片和从属芯片分别发送结束命令字(End of Initialization Command Word,简称 EOI),以告知 8259A 芯片初始化过程已完成。在结束命令字被发送到芯片后,芯片会开始正常工作,等待接收中断请求信号并向 CPU 发送相应的中断向量。

#define PIC_8259a_M_CTRL    0x20    // 主片的控制端口
#define PIC_8259a_M_DATA    0x21
#define PIC_8259a_S_CTRL    0xa0
#define PIC_8259a_S_DATA    0xa1
#define PIC_8259a_EOI       0x20    // 通知中断控制器中断结束


void send_eoi(int idt_index){
    if (idt_index >= 0x20 && idt_index < 0x28){
        out_byte(PIC_8259a_M_CTRL,PIC_8259a_EOI);
    }else if (idt_index >= 0x28 && idt_index < 0x30){
        out_byte(PIC_8259a_M_CTRL,PIC_8259a_EOI);
        out_byte(PIC_8259a_S_CTRL,PIC_8259a_EOI);
    }
}

4.测试

测试除0中断:

%macro INTERRUPT_HANDLER 1
global interrupt_handler_%1
interrupt_handler_%1:
    pushad

    push dword %1       ; 将中断号压入栈中
    push dword message_%1  ; 将附加信息字符串的地址压入栈中
    call printk         ; 调用 printk 函数输出信息
    add esp, 8          ; 将栈指针移回原来的位置

    push %1
    call exception_handler
    add esp, 4

    popad


    iret

message_%1:
    db 'Interrupt %d occurred', 0x0a, 0
%endmacro
	int a = 10 / 0; // 测试除0中断

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/640693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

栈和队列(栈的应用)[二]

文章目录 栈的应用一、栈在系统中的应用简化路径(leetcode. 71) 二、扩号匹配问题有效的括号(leetcode. 20) 三、字符串去重删除字符串中的所有相邻重复项(leetcode. 1047) 四、逆波兰表达式问题逆波兰表达式求值(leetcode. 150) 总结 栈的应用 递归的实现是栈&#xff1a;每一…

使用腾讯手游助手作为开发测试模拟器的方案---以及部分问题的解决方案-1

目录 前言: 一.目录结构 二.注册表研究 1.HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Tencent\MobileGamePC 2.HKEY_CURRENT_USER\Software\Tencent\MobileGamePC 三.模拟器快捷启动 1.快捷启动命令: 2.启动命令如何放入桌面: 3.adb端口,目前测试均可以使用: 前言: 此…

PyTorch深度学习实战(3)——使用PyTorch构建神经网络

PyTorch深度学习实战&#xff08;3&#xff09;——使用PyTorch构建神经网络 0. 前言1. PyTorch 构建神经网络初体验1.1 使用 PyTorch 构建神经网络1.2 神经网络数据加载1.3 模型测试1.4 获取中间层的值 2. 使用 Sequential 类构建神经网络3. PyTorch 模型的保存和加载3.1 模型…

【框架源码】Spring源码解析之Bean生命周期流程

观看本文前&#xff0c;我们先思考一个问题&#xff0c;什么是Spring的bean的生命周期&#xff1f;这也是我们在面试的时候&#xff0c;面试官常问的一个问题。 在没有Spring之前&#xff0c;我们创建对象的时候&#xff0c;采用new的方式&#xff0c;当对象不在被使用的时候&…

【网络】UDP/TCP网络程序

目录 UDP网络程序 简单通信版本(UDP) 准备工作&#xff08;接口学习、分析&#xff09; 整体代码&#xff08;Server.hpp/Server.cpp/Client.hpp/Client.cpp&#xff09; 添加“婴儿版”业务逻辑 英译汉翻译 my_shell 聊天室 linux和windows通信 TCP网络程序 简单通…

AB32VG1:SDK_AB53XX_V061(3)IO口复用功能的补充资料

文章目录 1.IO口功能复用表格2.功能映射寄存器 FUNCTION03.功能映射寄存器 FUNCTION14.功能映射寄存器 FUNCTION2 AB5301A的官方数据手册很不完善&#xff0c;没有开放出来。我通过阅读源码补充了一些关于IO口功能复用寄存器的资料。 官方寄存器文档&#xff1a;《 AB32VG1_Re…

chatgpt赋能python:Python怎么截屏Windows

Python怎么截屏Windows Python是一种高级编程语言&#xff0c;具有快速开发、易于学习、可移植性强等优点&#xff0c;因此在实现Windows屏幕截图方面也是一种非常强大的工具。 什么是Windows屏幕截图&#xff1f; Windows屏幕截图是将当前屏幕或窗口的图像保存成文件或剪贴…

Android BlueToothBLE入门(二)——设备的连接和通讯(附Demo源码地址)

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为7870字&#xff0c;预计阅读12分钟 前言 接《Android BlueToothBLE入门&#xff08;一&#xff09;——低功耗蓝牙介绍》上篇&#xff0c;这篇文章主要就是来做Demo实现Android两台设备的数据通讯。 实现效…

chatgpt赋能python:Python如何快速处理数据

Python如何快速处理数据 在当今数据爆炸的时代&#xff0c;数据处理已经成为一项非常重要的任务。因此&#xff0c;如何快速、高效地处理数据就成为了每个数据科学家、数据工程师以及数据分析师的必备技能之一。而Python正是其中的佼佼者。 为什么选择Python进行数据处理 Py…

Spring事物失效的八大场景

1.方法内的自调用&#xff1a;spring事物是基于aop的&#xff0c;只要使用代理对象调用某个方法时&#xff0c;spring事物才能生效&#xff0c;而在一个方法内使用this.xxx()时。this并不是代理对象&#xff0c;所以会失效&#xff08;实际上是transaction注解失效&#xff09;…

用程序控制对文本的复制和粘贴pyperclip模块

【小白从小学Python、C、Java】 【等级考试500强双证书考研】 【Python-数据分析】 用程序控制对文本的复制和粘贴 pyperclip模块 选择题 关于下列代码说法错误的是&#xff1f; import pyperclip print(【执行】pyperclip.copy("Python 太强大了&#xff01;")) p…

读发布!设计与部署稳定的分布式系统(第2版)笔记01_生产环境的生存法则

1. 系统“应该”做什么 1.1. 添加所需特性 2. 系统“不应该”做什么 2.1. 崩溃 2.2. 停止响应 2.3. 丢失数据 2.4. 侵犯隐私 2.5. 损失金钱 2.6. 摧毁公司 2.7. “杀死”客户 3. QA部门的测试 3.1. 团队的大部分工作是想方设法地通过测试 3.2. 做了敏捷、务实和自动…

【设计模式与范式:行为型】57 | 观察者模式(下):如何实现一个异步非阻塞的EventBus框架?

上一节课中&#xff0c;我们学习了观察者模式的原理、实现、应用场景&#xff0c;重点介绍了不同应用场景下&#xff0c;几种不同的实现方式&#xff0c;包括&#xff1a;同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞是最经典的实现方式&#xff0c;主要是为了…

GreenPlum分布式集群部署实战

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

GC演变过程、三色标记法、大白话讲解G1

文章目录 GC演变过程并发垃圾回收需要解决的问题怎么确定一个垃圾?并发收集存在的问题 三色标记法CMS垃圾收集器G1垃圾收集器介绍,主要特点优点使用注意点 GC演变过程 在Java中,垃圾收集一直是一个非常重要的组成部分, 到目前为止,垃圾收集器已经有十种了, 在不停的优化. 那为…

GoogleTest之Actions的用法

目录 返回值Actions的组合验证复杂参数mock副作用改变mock对象的行为设置返回类型的默认值使用自定义函数作为Actions 通用示例 namespace mock_action { class Foo { public:virtual ~Foo() {}virtual int& GetBar() 0; // 1virtual int GetPointerValue() 0; //…

Linux CentOS7虚拟机配置静态IP并允许上网的配置方法

文章目录 前言一、开启本地电脑VMnet8二、Linux配置静态IP1. NAT模式设置2. 开启虚拟机登录root用户3. 执行命令设置静态IP4. 重启网卡① 重启网卡 (正常)② 重启网卡 (异常)③ 解决方式&#xff1a;禁用NetworkManager 5. 查看ip6. 本地电脑cmd窗口ping虚拟机7. 虚拟机ping本地…

Golang每日一练(leetDay0095) 第一个错误的版本、完全平方数

目录 278. 第一个错误的版本 First Bad Version &#x1f31f; 279. 完全平方数 Perfect Squares &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日…

springboot的数据访问和数据视图

当使用 Spring Boot 进行数据访问时&#xff0c;我们可以选择使用 MyBatis 或 JPA&#xff08;Java Persistence API&#xff09;来实现增删改查操作。下面我将分别给出使用这两种方式整合数据访问的详细步骤和示例&#xff0c;同时结合 Thymeleaf 实现数据展现。 方式一: 使用…

AI实战营:语义分割与MMSegmentation

目录 OpenMMLab图像分割算法库MMSegmentation 深度学习下的语义分割模型 全卷积网络Fully Convolutional Network 201 ​编辑 上下文信息与PSPNet模型 空洞卷积与DeepLab模型 语义分割算法总结 语义分割 前沿算法 SegFormer K-Net MaskFormer Mask2Former Seg…