Chinaunix首页 | 论坛 | 博客
  • 博客访问: 782866
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 16:10:24

转:http://blog.csdn.net/nerdx/article/details/13612645
  1. //  控制单元对中断信号的处理:  
  2. //      当cpu执行一条指令后,cs和eip包含下一条要执行的指令的逻辑地址,在处理那条指令之前,  
  3. //      控制单元会检查在运行前一条指令时是否发生了一个中断或异常,如果发生了一个中断或异常,  
  4. //      控制单元执行下列操作:  
  5. //          1.确定与中断或异常关联的向量i  
  6. //          2.读入由idtr寄存器指向的IDT表中的第i项  
  7. //          3.从gdtr寄存器获得GDT的基地址,并在GDT中查找,以读取IDT表项中的选择符所标识的段描述符。  
  8. //              这个描述符指定中断或异常处理程序的基地址  
  9. //          4.权限和安全性检查  
  10. //          5.检查是否发生了特权级的变化,也就是说,CPL是否不同于所选择的段描述符的DPL,如果是,  
  11. //          控制单元必须开始使用与新的特权级相关的栈。  
  12. //              5.1 读入tr寄存器,以访问运行进程的TSS段  
  13. //              5.2 用与新特权级相关的栈段和栈指针的正确值装在ss和esp,这些值可以在tss中找到。  
  14. //              5.3 在新的栈中保存ss和esp以前的值,这些值定义了与旧特权级相关的栈的逻辑地址。  
  15. //          6.如果故障已发生,用引起异常的指令地址装载cs和eip寄存器,从而使得这条指令能再次被执行。  
  16. //          7.在栈中保存eflags,cs,及eip的内容。  
  17. //          8.如果异常产生了一个硬件出错码,则将其保存在栈中。  
  18. //          9.装载cs和eip寄存器,其值分别时IDT表中第i项门描述符的段选择符和偏移量字段。这些值给出了  
  19. //          中断或者异常处理程序的第一条指令地址。  
  20. //          10.由中断处理程序,执行中断处理。  
  21. //          11.中断或异常处理完毕后,相应的处理程序必须产生一条iret指令,把控制权转交给被中断的程序,  
  22. //          迫使控制单元:  
  23. //              11.1 用保存在栈中的值装载cs、eip或eflags寄存器。  
  24. //              11.2 检查处理程序的CPL是否等于cs中最低两位的值(这意味着被中断的进程与处理程序运行在  
  25. //              同一特权级),如果是,iret终止执行;否则,转入下一步  
  26. //              11.3 从栈中装载ss和esp寄存器,因此返回到与旧特权级相关的栈。  
  27.   
  28.   
  29. //  中断向量:  
  30. //      1.每个中断和异常是由0~255之间的一个数来标识的,intel将这个8位的无符号整数叫做一个向量。  
  31. //      2.中断向量是Intel从IA-32 CPU角度看到的中断信号划分;中断号则是Linux系统对外部中断的号码分配。   
  32. //          当外设把中断信号递送给PIC时,与之关联的是一个“中断号”(每个中断号对应一条中断线,从软件的角度来看,这两个术语可以混用);  
  33. //          当PIC把这个中断信号发送给CPU时,与之关联的是一个“中断向量”。  
  34. //      3.通常,不可屏蔽中断和异常的中断向量是固定的,而可屏蔽中断的中断向量则可以对中断控制器进行编程来改变。  
  35. //      4.i386 CPU的256个中断向量是这样分配的:  
  36. //          4.1 0~31这一共32个向量用于异常和不可屏蔽中断。  
  37. //          4.2 32~47这一共16个向量用于可屏蔽中断,分别对应于主、从8259A中断控制器的IRQ输入线  
  38. //          4.3 剩余的48~255用于标识软中断  
  39. //      5.Linux全部使用了0~47之间的向量。但对于48-255之间的软中断向量,Linux只使用了其中的一个,即用于实现系统调用的中断向量128(0x80)。  
  40. //          当用户态下的进程执行一条int 0x80汇编指令时,CPU切换到内核态,以服务于系统调用。  
  41.   
  42. //  i386的IDT    
  43. //      i386 CPU的IDT表一共有256项,分别对应每一个中断向量。每一个表项就是一个中断描述符,用以描述相对应的中断向量,中断向量就是该描述符  
  44. //      在IDT中的索引,每一个中断描述符的大小都是8个字节。根据INTEL的术语,中断描述符也称为“门(Gate)”。    
  45.   
  46.   
  47. //  IDT表  
  48. //      idt_table首地址保存在idt寄存器中  
  49. 1.1 struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };  
  50.   
  51. //  CPU异常初始化  
  52. //  调用路径:   start_kernel->trap_init  
  53. //  函数主要任务:  
  54. //      1.初始化apic控制器  
  55. //      2.注册0~19号异常、中断的处理函数,128号系统调用处理程序  
  56. //      3.注册系统调用的处理函数  
  57. //      4.cpu的初始化  
  58.   
  59. //  内核源码:arch/x86/kernel/traps.c  
  60. //            arch/x86/kernel/entry_32.S  
  61. 1.2 void __init trap_init(void)  
  62. {  
  63.     //cpu内部apic控制器  
  64.     init_apic_mappings();  
  65.     //初始化中断、异常、陷阱门描述符  
  66.     set_trap_gate(0,÷_error);  
  67.     set_intr_gate(1,&debug);  
  68.     //不可屏蔽中断  
  69.     set_intr_gate(2,&nmi);  
  70.     //系统中断门  
  71.     set_system_intr_gate(3, &int3);   
  72.     //系统门  
  73.     set_system_gate(4,&overflow);  
  74.     set_system_gate(5,&bounds);  
  75.     //陷阱门  
  76.     set_trap_gate(6,&invalid_op);  
  77.     set_trap_gate(7,&device_not_available);  
  78.     set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);  
  79.     set_trap_gate(9,&coprocessor_segment_overrun);  
  80.     set_trap_gate(10,&invalid_TSS);  
  81.     set_trap_gate(11,&segment_not_present);  
  82.     set_trap_gate(12,&stack_segment);  
  83.     set_trap_gate(13,&general_protection);  
  84.     //缺页中断  
  85.     set_intr_gate(14,&page_fault);  
  86.     set_trap_gate(15,&spurious_interrupt_bug);  
  87.     set_trap_gate(16,&coprocessor_error);  
  88.     set_trap_gate(17,&alignment_check);  
  89.     set_trap_gate(19,&simd_coprocessor_error);  
  90.     //系统调用描述符  
  91.     set_system_gate(SYSCALL_VECTOR,&system_call);  
  92.     //cpu相关的初始化  
  93.     cpu_init();  
  94. }  
  95.   
  96.   
  97. //  set_XXX_gate的设置异常处理函数地址  
  98. //      intr_gate、trap_gate区别在于DPL不同  
  99.   
  100. //  设置中断门描述符  
  101. //  函数主要任务:  
  102. //      在IDT表的第n个表项插入一个中断门  
  103. //          1.1 门中的段选择子设置为内核代码段的段选择子  
  104. //          1.2 偏移量设置为中断处理程序的地址addr  
  105. //          1.3 DPL字段设置为0  
  106. 1.3 void set_intr_gate(unsigned int n, void *addr)  
  107. {  
  108.     _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);  
  109. }  
  110.   
  111.     
  112. //  第一个外设中断(即8259A的IRQ0)所对应的中断向量  
  113. #define FIRST_EXTERNAL_VECTOR 0x20    
  114. //  系统调用的中断向量  
  115. #define SYSCALL_VECTOR 0x80  
  116.   
  117. //  中断初始化  
  118. //  调用路径:start_kernel->init_IRQ  
  119. //  函数主要任务:  
  120. //      1.初始化中断描述符的中断控制器  
  121. //      2.初始化20~255号中断的入口处理函数  
  122. //      3.添加体系结构特定的门  
  123. //      4.初始化时钟中断  
  124. //      5.初始化当前cpu的中断栈  
  125. 2.1 void __init init_IRQ(void)  
  126. {  
  127.     int i;  
  128.   
  129.     //建立中断描述符与中断控制器的联系  
  130.     pre_intr_init_hook();  
  131.   
  132.     //设置20~255号中断的入口函数  
  133.     for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {  
  134.         //从第一个外部中断开始  
  135.         int vector = FIRST_EXTERNAL_VECTOR + i;  
  136.         if (i >= NR_IRQS)  
  137.             break;  
  138.         //中断门描述符  
  139.         if (vector != SYSCALL_VECTOR)   
  140.             set_intr_gate(vector, interrupt[i]);  
  141.     }  
  142.     //添加体系结构特定的门  
  143.     intr_init_hook();  
  144.     //初始化时钟中断  
  145.     setup_pit_timer();  
  146.     //初始化当前cpu的中断栈  
  147.     irq_ctx_init(smp_processor_id());  
  148. }  
  149. //  中断描述符(IRQn描述符)  
  150. //      i8259a使用0~15号IRQ  
  151. 2.2 struct irqdesc irq_desc[NR_IRQS];  
  152.   
  153. //  中断描述符初始化  
  154. //  函数主要任务:  
  155. //      1.禁用所有IRQ  
  156. //      2.0~15号IRQ关联i8259a中断控制器  
  157. //  注:  
  158. //      中断关闭嵌套,当depth=0时,中断开启。  
  159. 2.3 void __init init_ISA_irqs (void)  
  160. {  
  161.     int i;  
  162.     //初始化cpu的apic  
  163.     init_bsp_APIC();  
  164.     //初始化8259a中断控制器  
  165.     init_8259A(0);  
  166.     //8259使用的中断号(IRQn)  
  167.     for (i = 0; i < NR_IRQS; i++) {  
  168.         //初始化时,所有irq关闭  
  169.         irq_desc[i].status = IRQ_DISABLED;  
  170.         //没有驱动注册中断处理例程  
  171.         irq_desc[i].action = NULL;  
  172.         //嵌套深度为1的关闭状态  
  173.         irq_desc[i].depth = 1;  
  174.         //0~16号irq,关联i8259a中断控制器  
  175.         if (i < 16) {  
  176.             irq_desc[i].handler = &i8259A_irq_type;  
  177.         } else {  
  178.             // >16的pci中断,按需分配  
  179.             irq_desc[i].handler = &no_irq_type;  
  180.         }  
  181.     }  
  182. }  
阅读(1408) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~