`
bmabma
  • 浏览: 27182 次
  • 性别: Icon_minigender_1
  • 来自: 济南
最近访客 更多访客>>
社区版块
存档分类
最新评论

linux内核中断、异常、系统调用的分析以及实践

 
阅读更多

linux内核中断、异常、系统调用的分析以及实践
2010年12月03日
  报告内容
  中断是由间隔定时器和和I/O设备产生的。
  异常则是由程序的错误产生,或者由内核必须处理的异常条件产生。第一种情况下,内核通过发送一个信号来处理异常;第二种情况下,内核执行恢复异常需要的所有步骤,或对内核服务的一个请求。
  中断和异常改变处理器执行的指令顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应。它们提供了一种特殊的方式,使处理器转而去执行正常控制流之外的代码。
  中断是异步的,由硬件随机产生,在程序执行的任何时候可能出现。异常是同步的,在(特殊的或出错的)指令执行时由CPU控制单元产生。
  每个中断和异常由0~255之间的一个数(8位)来标识,Intel称其为中断向量(vector)。非屏蔽中断的向量和异常的向量是固定的,可屏蔽中断的向量可以通过对中断控制器的编程来改变。
  Linux对中断描述符进行了如下分类:
  1.中断门
  用户态的进程不能访问的一个中断门(特权级为0),所有的中断都通过中断门激活,并全部在内核态。由set_intr_gate()函数负责在IDT表项中插入一个中断门。
  2.系统门
  用户态的进程可以访问的一个陷阱门(特权级为3),通过系统门来激活4个linux异常处理程序,它们的向量是3,4,5和128。因此,在用户态下可以发布int3,into,bound和int $0x80四条汇编指令。由set_system_gate ()函数负责在IDT表项中插入一个系统门。
  3.陷阱门
  用户态的进程不能访问的一个陷阱门(特权级为0),大部分linux异常处理程序通过陷阱门激活。由set_trap_gate ()函数负责在IDT表项中插入一个陷阱门。
  三个门均调用了_set_gate宏,代码如下:
  #define _set_gate(gate_addr,type,dpl,addr) \
  do { \
  int __d0, __d1; \
  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
  "movw %4,%%dx\n\t" \          //将转化后的dpl值存进dx寄存器
  "movl %%eax,%0\n\t" \          //将eax寄存器的值存进gate_addr,即idt_table+n处
  "movl %%edx,%1" \
  :"=m" (*((long *) (gate_addr))), \
  "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
  :"i" ((short) (0x8000+(dpl输入引脚相连,中断控制器与CPU的INTR引脚相连。
  下面将分析一下内核处理中断的步骤和代码。
  内核启用中断以前,必须把IDT表的初始地址装到idtr寄存器,并初始化表中的每一项,这个动作是在初始化系统时,由arch/i386/kernel/head.S中的Startup_32()函数完成。
  setup_idt:
  lea ignore_int,%edx
  movl $(__KERNEL_CS lock);       //自旋锁,在单处理系统中没有作用
  /*
  *应答PIC的中断,并禁用这条IRQ线。(为串行处理同类型中断)
  */
  desc->handler->ack(irq);      //应答
  status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);  //设置IRQ线状态
  status |= IRQ_PENDING; /* we _want_ to handle it */
  action = NULL;           //在真正开始工作之前,检查相关标志位
  if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
  action = desc->action;
  status &= ~IRQ_PENDING; /* we commit to handling */
  status |= IRQ_INPROGRESS; /* we are handling it */
  }
  desc->status = status;
  if (!action)          //action为null则跳出
  goto out;
  for (;;) {
  spin_unlock(&desc->lock);             //释放中断自旋锁
  handle_IRQ_event(irq, &regs, action);    //在循环中执行中断服务例程
  spin_lock(&desc->lock);               //执行完一次则上锁
  if (!(desc->status & IRQ_PENDING))
  break;
  //若PENDING标志位清0,则循环结束,中断不进一步传递给另一个CPU
  desc->status &= ~IRQ_PENDING;
  }
  desc->status &= ~IRQ_INPROGRESS;      //清除IRQ_INPROGERSS标志位
  out:
  desc->handler->end(irq); 
  /*
  *调用主IRQ描述符的end方法,单处理系统上相应的
  *end_8259A_irq()函数重新激活IRQ线,允许处理同类型中断
  */
  spin_unlock(&desc->lock);               //为do_IRQ释放自旋锁
  if (softirq_pending(cpu))              //检查下半部分是否执行
  do_softirq();
  return 1;
  } 
  handle_IRQ_evnet()函数依次调用这些设备例程:
  int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
  {
  ……
  irq_enter(cpu, irq);
  /*调用irq_enter方法增加正执行CPU的irq_stat元素的__local_irq_count字段*/
  ……
  if (!(action->flags & SA_INTERRUPT))
  __sti();     //如果SA_INTERRUPT标志被清0,用sti指令打开本地中断
  do {
  status |= action->flags;
  action->handler(irq, action->dev_id, regs);
  action = action->next;
  } while (action);    //循环执行每个中断的中断服务例程
  if (status & SA_SAMPLE_RANDOM)
  add_interrupt_randomness(irq);
  __cli();          //用cli指令打开本地中断
  irq_exit(cpu, irq);
  /*调用irq_exit方法减少正执行CPU的irq_stat元素的__local_irq_count字段*/
  return status;
  } 
  异常:
  异常可以是由程序错误产生,或者由内核必须处理的异常条件产生的。linux下发生异常,内核会自动产生一个异常中断。在这异常中断处理程序中会判断异常来自用户程序或者内核,如果是发生在用户程序,内核通过发送一个信号来处理异常,,再根据异常信号的回调函数通知用户程序发生异常。如果发生在内核里面,那么内核执行恢复异常需要的所有步骤(例如缺页),或对内核服务的一个请求,即会搜索内核模块的异常结构表,找到相应的处理调用地址,修改异常中断的返回地址为异常处理的地址,中断返回的时候程序就跳到异常处理程序处理执行了。
  异常处理有一个标准的结构,由三部分组成:
  1.在内核态堆栈中保存大多数寄存器的内容
  2.调用C语言的函数
  3.通过ret_from_exception()从异常处理程序退出
  为了利用异常,必须对IDT进行初始化,使得每个被确认的异常都有一个异常处理程序。Trap_init()函数是将一些最终值插入到IDT表中的非屏蔽中断及异常表项中。这是由set_trap_gate和set_system_gate宏实现该IDT表项的初始化。
  void __init trap_init(void)
  {
  ……
  set_trap_gate(0,&divide_error);      // set_trap_gate()函数设置陷阱门
  set_trap_gate(1,&debug);
  set_intr_gate(2,&nmi);
  set_system_gate(3,&int3);           // set_system_gate()函数设置系统门
  set_system_gate(4,&overflow);
  set_system_gate(5,&bounds);
  set_trap_gate(6,&invalid_op);
  set_trap_gate(7,&device_not_available);
  set_trap_gate(8,&double_fault);
  set_trap_gate(9,&coprocessor_segment_overrun);
  set_trap_gate(10,&invalid_TSS);
  set_trap_gate(11,&segment_not_present);
  set_trap_gate(12,&stack_segment);
  set_trap_gate(13,&general_protection);
  set_intr_gate(14,&page_fault);
  set_trap_gate(15,&spurious_interrupt_bug);
  set_trap_gate(16,&coprocessor_error);
  set_trap_gate(17,&alignment_check);
  set_trap_gate(18,&machine_check);
  set_trap_gate(19,&simd_coprocessor_error);
  set_system_gate(SYSCALL_VECTOR,&system_call);
  // SYSCALL_VECTOR=0x80,即十进制128
  ……
  } 
  在/arch/i386/kernel/entry.S中我们可以看到每个为异常处理程序定义入口,如page_fault的入口如下:
  ENTRY(page_fault)
  pushl $ SYMBOL_NAME(do_page_fault)    //执行的实体
分享到:
评论

相关推荐

    Linux 内核-中断和系统调用.pdf

    北大计算机系考研资料 增补资料3:北大操作系统大题最长考内容——之中断和系统调用,一般的教材不包括,但重要且常考

    Linux内核源代码情景分析 (上下册 高清非扫描 )

    丛书名: Linux内核源代码情景分析 出版社:浙江大学出版社 目录 第1章 预备知识 1.1 Linux内核简介. 1.2 Intel X86 CPU系列的寻址方式 1.3 i386的页式内存管理机制 1.4 Linux内核源代码中的C语言代码 1.5 Linux...

    Linux内核情景分析之三中断和函数调用

    Linux内核情景分析之三中断和函数调用 Linux内核情景分析之三中断和函数调用

    linux内核分析 MOOC

    然后开始分析Linux内核源代码,从系统调用陷入内核,进程调度与进程切换,最后返回到用户态进程,通过仔细分析梳理这一过程,并推广到硬件中断、缺页异常等内核执行路径,最终能从本质上把握Linux内核的实质,乃至在...

    深入分析Linux内核源码.chm

    1.4 分析Linux内核的意义 1.5 Linux内核结构 1.6 Linux内核源代码 1.7 Linux内核源代码分析工具 第二章 Linux运行的硬件基础 2.1 i386的寄存器 2.2 内存地址 2.3 段机制和描述符 2.4 分页机制 2.5 Linux中的分页机制...

    linux内核源代码情景分析

    《linux内核源代码情景分析》(非扫描电子版本) 第1章 预备知识 1.1 Linux内核简介 1.2 Intel X86 CPU系列的寻址方式 1.3 i386的页式内存管理机制 1.4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的...

    LINUX内核经典面试题

    LINUX内核经典面试题 ,20) 如何加载、卸载一个模块? 21) 模块和应用程序分别运行在什么空间? 22) Linux中的浮点运算由应用程序实现还是内核实现? 23) 模块程序能否使用可链接的库函数? 24) TLB中缓存的是什么...

    linux 内核源代码分析

    第3章 中断、异常和系统调用 3.1 X86 CPU对中断的硬件支持 3. 2 中断向量表IDT的初始化 3. 3 中断请求队列的初始化 3. 4 中断的响应和服务 3. 5 软中断与Bottom Half 3.6 页面异常的进入和返回 3. 7 时钟...

    实验五Linux系统调用的编程技术

    系统调用是通过软中断向内核发出了中断请求, int 指令的执行就会触发一个中断请求。 libc 函数库定义的一些 API 内部使用了系统调用的封装例程,其主要目的是发布系统调用,使程序员在写代码时不需要用汇编指令和...

    LINUX内核修炼之道

    第二个层次讨论了内核中系统初始化、系统调用、中断处理、进程管理及调度、内存管理、文件系统以及设备驱动等主要部分,目的是希望读者以兴趣为导向,寻找一个子系统或模块,对其代码深入钻研和分析。第三个层次介绍...

    深入分析Linux内核源码

    深入分析Linux内核源码 前言 第一章 走进linux 1.1 GNU与Linux的成长 1.2 Linux的开发模式和运作机制 1.3走进Linux内核 1.3.1 Linux内核的特征 1.3.2 Linux内核版本的变化 1.4 分析Linux内核的意义 ...

    Linux内核源代码分析视频课-视频教程网盘链接提取码下载.txt

    然后开始分析Linux内核源代码,从系统调用陷入内核,进程调度与进程切换,最后返回到用户态进程,通过仔细分析梳理这一过程,并推广到硬件中断、缺页异常等内核执行路径,最终能从本质上把握Linux内核的实质,乃至在...

    LINUX内核源代码情景分析

    第3章 中断、异常和系统调用 3.1 X86 CPU对中断的硬件支持 3. 2 中断向量表IDT的初始化 3. 3 中断请求队列的初始化 3. 4 中断的响应和服务 3. 5 软中断与Bottom Half 3.6 页面异常的进入和返回 3. 7 时钟...

    Linux 2.6内核标准教程(部分)

    然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析;在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这...

    《Linux内核分析与应用》课件(个人整理)

    《Linux内核分析与应用》课件,概述、内存寻址、进程管理、内存管理、中断、系统调用、内核同步、文件系统、设备驱动等共九章

    Linux2.6内核标准教程(共计8-- 第1个)

    然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU...

    《Linux内核修炼之道》精华版之方法论

    第二个层次讨论了内核中系统初始化、系统调用、中断处理、进程管理及调度、内存管理、文件系统以及设备驱动等主要部分,目的是希望读者以兴趣为导向,寻找一个子系统或模块,对其代码深入钻研和分析。第三个层次介绍...

    linux 2.6内核标准教程

    然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析;在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU这...

    Linux内核情景分析

    《LINUX内核源代码情景分析(下册)》图书目录如下: -------------------------------------------------------------------------------- 第 7章 基于socket的进程间通信 7.1 系统调用socket() 7.2 函数sys—...

    Linux内核修炼之道 doc

    第二个层次讨论了内核中系统初始化、系统调用、中断处理、进程管理及调度、内存管理、文件系统以及设备驱动等主要部分,目的是希望读者以兴趣为导向,寻找一个子系统或模块,对其代码深入钻研和分析。第三个层次介绍...

Global site tag (gtag.js) - Google Analytics