Linux源码—异常

xiaoxiao2021-02-28  142

(本文部分参考了《Linux内核源代码情景分析》) 内核对页面异常处理时,是从 do_page_fault()开始的。本文主要介绍内核对页面异常的响应过程,也就是从发生异常至 CPU 到达do_page_fault()之间的那一段路程,以及从 do_page_fault()返回之后到 CPU 返回到用户空间这一段路程。 Linux 内核在初始化阶段完成了对页式虚存管理的初始化以后,便调用 trap_int()和 init_IRQ()两个函数进行中断机制的初始化。其中 trap_init()主要是对一些系统保留的中断向量的初始化,而 init_IRQ()则主要是用于外设的中断。在trap_init()中可清楚看到为页面异常设置的中断门指向程序入口 page_fault:

void __init trap_init(void) { ... set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); set_trap_gate(14,&page_fault); set_trap_gate(15,&spurious_interrupt_bug); ... }

当发生页面异常时,CPU 穿过中断门以后就直接到达了 page_fault()。 CPU 因异常而穿过中断门的过程,包括堆栈的变化,与因外设中断而引起的过程基本上是一样的。需要注意的是,异常在保护现场时还需要把出错代码压栈(但不是所有异常都产生出错代码)。代码如下:

/* 寻址的页不在内存,相应的页表项为空。或者违反了一种分页保护机制。 */ ENTRY(page_fault) pushl $do_page_fault jmp error_code

这里的跳转目标 error_code 就好像外设中断处理中的 common_interrupt 一样,是各种异常处理所共用的程序入口。而将服务程序 do_page_fault()的地址压入堆栈,则为具体的服务程序做好了准备。 程序入口 error_code 的代码如下:

error_code: /* 保存高级C函数会用到的寄存器到栈中,请参见高级C函数的 */ pushl %ds pushl
转载请注明原文地址: https://www.6miu.com/read-20970.html

最新回复(0)