中断子系统

中断的定义

中断分为两类:

  • 同步中断,由CPU内部错误生成 - exception(异常)

异常又分为:

  • fault (错误):可纠正的错误,比如page fault。发生异常后,执行完异常的处理函数后,返回到发生错误的那条指令,重新执行。
  • trap(陷阱):在陷阱指令执行后立即报告;用于调试,GDB的实现依赖。在这种情况下,中断信号的作用是通知调试程序一条特殊指令已被执行。之后会返回到下一条指令
  • abort(终止):严重错误,比如硬件错误等,发生了这种异常,就切换到异常中止处理程序,中止当前进程。
  • Programmed exception:应用程序主动请求发出的,由指令int/int3触发。比如:用户程序调用系统调用时,执行int指令陷入内核。
  • 异步中断,来自设备的外部中断 - interrupt(中断)

中断分为:

  • 可屏蔽中断:来自IO的中断都是可屏蔽的
  • 不可屏蔽中断:NMI,一般是硬件故障。

类别

原因

异步/同步

返回行为

中断

来自I/O设备的信号

异步

总是返回到下一条指令

陷阱

有意的异常

同步

总是返回到下一条指令

故障

潜在可恢复的错误

同步

返回到当前指令

终止

不可恢复的错误

同步

不会返回

中断向量

每个中断或者异常由0-255的数来标识,这就是中断向量。NMI和exception的中断向量是固定的,可屏蔽中断的中断向量是变化的。

x86发布了20多种异常,这些异常的中断向量是固定的,定义在CPU的SPEC中,见Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1 6.5.1 Call and Return Operation for Interrupt or Exception Handling Procedures

每种异常都对应一个异常处理函数。定义在arch/x86/include/asm/idtentry.h 中。

每个异常处理函数执行时,会给引起异常的进程发一个信号。

向量号

异常代号

描述

来源

异常处理函数

信号

0

#DE

Divide Error

DIV and IDIV instructions.

divide_error()

SIGFPE

1

#DB

Debug

Any code or data referenc.

debug()

SIGTRAP

2

NMI Interrupt

Non-maskable external interrupt.

nmi()

None

3

#BP

Breakpoint

INT3 instruction.

int3()

SIGTRAP

4

#OF

Overflow

INTO instruction.

overflow()

SIGSEGV

5

#BR

BOUND Range Exceeded

BOUND instruction.

bounds()

SIGSEGV

6

#UD

Invalid Opcode (Undefined Opcode)

UD instruction or reserved opcode.

invalid_op()

SIGILL

7

#NM

Device Not Available (No Math Coprocessor)

Floating-point or WAIT/FWAIT instruction.

device_not_available()

None

8

#DF

Double Fault

Any instruction that can generate an exception, an NMI, or an INTR.

doublefault_fn()

None

9

#MF

CoProcessor Segment Overrun (reserved)

Floating-point instruction.

coprocessor_segment_overrun()

SIGPE

10

#TS

Invalid TSS

Task switch or TSS access.

invalid_tss()

SIGSEGV

11

#NP

Segment Not Present

Loading segment registers or accessing system segments.

segment_not_present()

SIGBUS

12

#SS

Stack Segment Fault

Stack operations and SS register loads.

stack_segment

SIGBUS

13

#GP

General Protection

Any memory reference and other protection checks.

general_protection()

SIGSEGV

14

#PF

Page Fault

Any memory reference.

page_fault()

SIGSEGV

15

Reserved

16

#MF

Floating-Point Error (Math Fault)

Floating-point or WAIT/FWAIT instruction.

coprocessor_error()

SIGFPE

17

#AC

Alignment Check

Any data reference in memory.

alignment_check()

SIGSEGV

18

#MC

Machine Check

Error codes (if any) and source are model dependent.

machine_check()

None

19

#XM

SIMD Floating-Point Exception

SIMD Floating-Point Instruction

simd_coprocessor_error()

SIGFPE

20

#VE

Virtualization Exception

EPT violations

virtualization_exception()

21

#CP

Control Protection Exception

The RET, IRET, RSTORSSP, and SETSSBSY instructions can

generate this exception. When CET indirect branch tracking

is enabled, this exception can be generated due to a

missing ENDBRANCH instruction at the target of an indirect

call or jump.

control_protection()

22-31

Reserved

32-255

Maskable Interrupts

External interrupt from INTR pin or INT n instruction.

硬件结构

  1. 外部PIC芯片(早期架构)

PIC:可编程中断控制器(Programmable Interrupt),x86的PIC是独立于CPU的一块芯片,嵌入式领域的SoC一般在芯片内集成。

外部设备连接到PIC上,PIC的INT引脚连接CPU的INTR引脚。

  1. 外设将RQ信号线连接到PIC的输入引脚(IRQ0-IRQ7)。
  2. 当外设发起中断时,它通过自己的IRQ线向PIC发送一个电信号。
  3. PIC接收这个请求,决定其优先级。
  4. PIC然后通过INTR,Interrupt Request向CPU发送一个信号,告诉CPU“有一个中断需要处理”。
  5. CPU在执行完当前指令后,如果允许中断,会通过另一条线INTA(Interrupt Acknowledge)向PIC发送一个确认信号。
  6. PIC收到确认后,会将该设备对应的中断向量号放到数据总线上。
  7. CPU读取这个向量号,然后在中断描述符表(IDT) 中查找对应的条目,找到处理这个中断的服务函数地址,并跳转过去执行。
  8. 执行完毕后,会通知PIC中断处理已完成。

  1. APIC(现代架构)

为了支持多处理器系统(SMP),APIC产生了。APIC包含两个部分:

  • LAPIC:本地APIC,内置在CPU。每个CPU core有一个专属的LAPIC,负责处理
    • CPU本地产生的中断,如IPI,定时器中断等
    • 接收I/O APIC发来的中断消息,并将其传递给core执行。
  • I/O APIC:CPU外置的一个芯片。负责收集所有外设的中断请求,将中断以消息的形式发送给一个或多个core的LAPIC。

中断描述符表(IDT)

IDT, Interrupt Descriptor Table。当中断或者异常来临,CPU通过中断号IDT中查找到对应的entry得到中断或异常的处理函数的入口地址

IDT可以放在内存的任何地方,把IDT的基地址填入CPU的Interrupt Descriptor Table Register(中断描述表寄存器),CPU就能找到它。内核启动后,在允许中断发生前,必须使用 lidt 汇编指令初始化IDT。

Linux对IDT的初始化的代码

在arch/x86/kernel/head_64.S中:

startup_64_setup_gdt_idt定义在arch/x86/boot/startup/gdt_idt.c中。它的任务是在内核切换到虚拟地址运行前,设置GDT和IDT。调用startup_64_load_idt对IDT进行设置。

创建好描述符然后调用native_load_idt,使用lidt指令初始化idtr。

门描述符(Gate Descriptors)

参考Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 6.11 IDT DESCRIPTORS.

Intel为了让控制CPU在不同的特权级对代码段的访问,CPU提供了4种门描述符,IDT可能包含除call gate外的三种门描述符。

  • Call gates(调用门):可能存在于GDT和LDT中,不能存在于IDT。这里跳过。
  • Trap gates(陷阱门):和中断门一样,不过用于处理异常。
  • Interrupt gates(中断门):用于中断处理,当中断来到,跳转到描述符中的处理函数的地址执行。
  • Task gates(任务门):用于task切换。当中断来临用一个进程取代当前的进程。

Linux下对门描述符的细分

刚刚说的那三个类型的中断描述符是Intel制定的,Linux在这些描述符上进行了二创,并进行了更细的分类。

  • 中断门(interrupt gate:本质是Intel中断门,DPL(标识特权级)字段为0。Linux所有的中断处理程序都通过中断门激活,并全部在内核态。
  • 系统门(system interrupt gate):本质是Intel中断门,DPL为3。用户态可以访问。通过系统门可以激活3个Linux异常处理程序,它们的向量是3、4和128(0x80)。所以在用户态下,可以通过into、bound、int 0x80陷入内核。
  • Interrupt gate with interrupt stack:本质是Intel中断门,DPL为0,ist不为0。

问:啥是IST

  • 任务门(Task gate:本质是Intel任务门,DPL为0。对Double fault异常是通过任务门触发的。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值