Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2112669
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-08-29 18:10:10

1.1 中断的基本认识
1.1.a Intel x86共支持256种向量中断,可分为两大类:异常和中断。
    异常又分为故障(Fault)和陷阱(Trap),它们的共同特点是既不使用中断控制器,又不能被屏蔽。
    中断又分为外部可屏蔽中断(INTR)和外部非屏蔽中断(NMI),所有I/O设备产生的中断请求(IRQ)均引起屏蔽中断,而紧急的事件(如硬件故障)引起的故障产生非屏蔽中断。  
1.1.b Linux对256个向量的分配如下:
     0~31对应于异常和非屏蔽中断。 
      32~47(即由I/O设备引起的中断)分配给屏蔽中断。 
      48~255的向量用来标识软中断。Linux只用了其中的一个(即128或0x80向量)用来实现系统调用。
1.2 代码
1.2.1 不用《操作系统真相还原》代码的原因
没有看懂 第7章中断代码里面, intr_entry_table 是怎么样与 宏里面的 intr%1entry 对应起来的?
这个地方实在理解不了,为啥放在section .data里面就可以自动初始化了?看起来就有点悬。

  1. a. 
  2. intr0x00entry 
  3. intr0x01entry 
  4. ...
  5. intr0x20entry 
  6. 怎么就会初始化了 数组 intr_entry_table[IDT_DESC_CNT]

  7. b.
  8. 要初始化数组intr_entry_table,得有
  9. intr_entry_table[0] = intr0x00entry ;
  10. intr_entry_table[1] = intr0x01entry ;
  11. ...
  12. intr_entry_table[0x20] = intr0x20entry ;

  13. 才行,但是没有看到

  14. c. 
  15. 从debug的结果上肯定是, 
  16. intr0x00entry 
  17. intr0x01entry 
  18. ...
  19. intr0x20entry 
  20. 初始化了数组intr_entry_table
  21. 利用的编译器对section的data段的处理,但总感觉这个不是那么靠谱。
1.3 代码
结合了《Orange'S:一个操作系统的实现》与 《操作系统真相还原》这两本书的代码
  1. cong@msi:/work/os/code/7int$ tree
  2. .
  3. ├── boot
  4. │   ├── loader.S
  5. │   └── mbr.S
  6. ├── include
  7. │   ├── interrupt.h
  8. │   ├── io.h
  9. │   ├── print.h
  10. │   └── stdint.h
  11. ├── kernel
  12. │   ├── interrupt.c
  13. │   ├── kernel.S
  14. │   └── main.c
  15. ├── lib
  16. │   ├── printf.c
  17. │   └── put_char.S
  18. └── Makefile
1.3.1 在interrupt.c中定义
  1. cong@msi:/work/os/code/7int$ cat kernel/interrupt.c
  2. #include "interrupt.h"
  3. static gate_desc idt[IDT_DESC_CNT];

  4. void exception_handler(int vec_no,int err_code,int eip,int cs,int eflags)
  5. {
  6.     printf("vec_no=%d,err_code=%d\n", vec_no, err_code);
  7.     printf("eip=0x%x,cs=0x%x,eflags=0x%x\n",eip, cs, eflags);
  8.     return ;
  9. }
  10. /* 初始化可编程中断控制器8259A */
  11. static void pic_init(void)
  12. {
  13.     /* 初始化主片 */
  14.     outb (PIC_M_CTRL, 0x11); // ICW1: 边沿触发,级联8259, 需要ICW4.
  15.     outb (PIC_M_DATA, 0x20); // ICW2: 起始中断向量号为0x20,也就是IR[0-7] 为 0x20 ~ 0x27.
  16.     outb (PIC_M_DATA, 0x04); // ICW3: IR2接从片.
  17.     outb (PIC_M_DATA, 0x01); // ICW4: 8086模式, 正常EOI

  18.     /* 初始化从片 */
  19.     outb (PIC_S_CTRL, 0x11); // ICW1: 边沿触发,级联8259, 需要ICW4.
  20.     outb (PIC_S_DATA, 0x28); // ICW2: 起始中断向量号为0x28,也就是IR[8-15] 为 0x28 ~ 0x2F.
  21.     outb (PIC_S_DATA, 0x02); // ICW3: 设置从片连接到主片的IR2引脚
  22.     outb (PIC_S_DATA, 0x01); // ICW4: 8086模式, 正常EOI

  23.     /* 打开主片上IR0,也就是目前只接受时钟产生的中断 */
  24.     outb (PIC_M_DATA, 0xfe);
  25.     outb (PIC_S_DATA, 0xff);

  26.     printf("pic_init done\n");
  27. }
  28. /* 创建中断门描述符 */
  29. static void make_idt_desc(gate_desc* p_gdesc, uint8_t attr, intr_handler function) {
  30.     p_gdesc->func_offset_low_word = (uint32_t)function & 0x0000FFFF;   -->中断入口地址的低16位
  31.     p_gdesc->selector = SELECTOR_K_CODE;                      -->选择子统一为内核代码段的选择子
  32.     p_gdesc->dcount = 0;
  33.     p_gdesc->attr = attr;
  34.     p_gdesc->func_offset_high_word = ((uint32_t)function & 0xFFFF0000) >> 16;   -->中断入口地址的高16位
  35. }

  36. //将中断处理函数的地址放进idt中,并初始化idt
  37. static void idt_desc_init(void)
  38. {
  39.     make_idt_desc(&idt[INT_VECTOR_DIVIDE], IDT_DESC_ATTR_DPL0, divide_error);
  40.     make_idt_desc(&idt[INT_VECTOR_DEBUG], IDT_DESC_ATTR_DPL0, single_step_exception);
  41.     make_idt_desc(&idt[INT_VECTOR_NMI], IDT_DESC_ATTR_DPL0, nmi);
  42.     make_idt_desc(&idt[INT_VECTOR_BREAKPOINT], IDT_DESC_ATTR_DPL0, breakpoint_exception);
  43.     make_idt_desc(&idt[INT_VECTOR_OVERFLOW], IDT_DESC_ATTR_DPL0, overflow);
  44.     make_idt_desc(&idt[INT_VECTOR_BOUNDS], IDT_DESC_ATTR_DPL0, bounds_check);
  45.     make_idt_desc(&idt[INT_VECTOR_INVAL_OP], IDT_DESC_ATTR_DPL0, inval_opcode);
  46.     make_idt_desc(&idt[INT_VECTOR_COPROC_NOT], IDT_DESC_ATTR_DPL0, copr_not_available);
  47.     make_idt_desc(&idt[INT_VECTOR_DOUBLE_FAULT], IDT_DESC_ATTR_DPL0, double_fault);
  48.     make_idt_desc(&idt[INT_VECTOR_COPROC_SEG], IDT_DESC_ATTR_DPL0, copr_seg_overrun);
  49.     make_idt_desc(&idt[INT_VECTOR_INVAL_TSS], IDT_DESC_ATTR_DPL0, inval_tss);
  50.     make_idt_desc(&idt[INT_VECTOR_SEG_NOT], IDT_DESC_ATTR_DPL0, segment_not_present);
  51.     make_idt_desc(&idt[INT_VECTOR_STACK_FAULT], IDT_DESC_ATTR_DPL0, stack_exception);
  52.     make_idt_desc(&idt[INT_VECTOR_PROTECTION], IDT_DESC_ATTR_DPL0, general_protection);
  53.     make_idt_desc(&idt[INT_VECTOR_PAGE_FAULT], IDT_DESC_ATTR_DPL0, page_fault);
  54.     make_idt_desc(&idt[INT_VECTOR_COPROC_ERR], IDT_DESC_ATTR_DPL0, copr_error);
  55.     //timer interrupt
  56.     make_idt_desc(&idt[INT_VECTOR_IRQ0], IDT_DESC_ATTR_DPL0, timer_int);
  57. }

  58. /* 完成有关中断的所有初始化工作*/
  59. void idt_init(void)
  60. {
  61.     idt_desc_init(); // 初始化中断描述符表
  62.     pic_init(); // 初始化8259A

  63.     /* 加载idt */
  64.     uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t)(uint32_t)idt << 16));
  65.     asm volatile("lidt %0" : : "m" (idt_operand));
  66.     printf("idt_init done\n");
  67. }

1.3.2 中断处理函数
  1. cong@msi:/work/os/code/7int$ cat kernel/kernel.S
  2. extern    exception_handler

  3. [bits 32]
  4. [section .text]    ; 代码在此
  5. global    divide_error
  6. global    single_step_exception
  7. global    nmi
  8. global    breakpoint_exception
  9. global    overflow
  10. global    bounds_check
  11. global    inval_opcode
  12. global    copr_not_available
  13. global    double_fault
  14. global    copr_seg_overrun
  15. global    inval_tss
  16. global    segment_not_present
  17. global    stack_exception
  18. global    general_protection
  19. global    page_fault
  20. global    copr_error
  21. global timer_int    

  22. ; 中断和异常 -- 异常
  23. divide_error:
  24.     push    0xFFFFFFFF    ; no err code
  25.     push    0             ; vector_no    = 0
  26.     jmp    exception
  27. single_step_exception:
  28.     push    0xFFFFFFFF    ; no err code
  29.     push    1             ; vector_no    = 1
  30.     jmp    exception
  31. nmi:
  32.     push    0xFFFFFFFF    ; no err code
  33.     push    2             ; vector_no    = 2
  34.     jmp    exception
  35. breakpoint_exception:
  36.     push    0xFFFFFFFF    ; no err code
  37.     push    3             ; vector_no    = 3
  38.     jmp    exception
  39. overflow:
  40.     push    0xFFFFFFFF    ; no err code
  41.     push    4             ; vector_no    = 4
  42.     jmp    exception
  43. bounds_check:
  44.     push    0xFFFFFFFF    ; no err code
  45.     push    5             ; vector_no    = 5
  46.     jmp    exception
  47. inval_opcode:
  48.     push    0xFFFFFFFF    ; no err code
  49.     push    6             ; vector_no    = 6
  50.     jmp    exception
  51. copr_not_available:
  52.     push    0xFFFFFFFF    ; no err code
  53.     push    7             ; vector_no    = 7
  54.     jmp    exception
  55. double_fault:
  56.     push    8             ; vector_no    = 8
  57.     jmp    exception
  58. copr_seg_overrun:
  59.     push    0xFFFFFFFF    ; no err code
  60.     push    9             ; vector_no    = 9
  61.     jmp    exception
  62. inval_tss:
  63.     push    10             ; vector_no    = A
  64.     jmp    exception
  65. segment_not_present:
  66.     push    11             ; vector_no    = B
  67.     jmp    exception
  68. stack_exception:
  69.     push    12             ; vector_no    = C
  70.     jmp    exception
  71. general_protection:
  72.     push    13             ; vector_no    = D
  73.     jmp    exception
  74. page_fault:
  75.     push    14             ; vector_no    = E
  76.     jmp    exception
  77. copr_error:
  78.     push    0xFFFFFFFF     ; no err code
  79.     push    16             ; vector_no    = 10h
  80.     jmp    exception
  81. timer_int:
  82.     push 0xFFFFFFFF
  83.     push 32
  84.     jmp exception

  85. exception:
  86.     call    exception_handler
  87.     ; 如果是从片上进入的中断,除了往从片上发送EOI外,还要往主片上发送EOI
  88.     mov al,0x20 ; 中断结束命令EOI
  89.     out 0xa0,al ; 向从片发送
  90.     out 0x20,al ; 向主片发送
  91.     add    esp, 4*2    ; 让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS
  92.     iret
1.3.3 main中打开中断
  1. cong@msi:/work/os/code/7int$ cat kernel/main.c
  2. #include "print.h"
  3. #include <interrupt.h>
  4. extern void put_test(void);
  5. int main(void)
  6. {
  7.     int a=3;
  8.     put_char('k');
  9.     put_test();
  10.     printf("a=%d\n",a);
  11.     idt_init();
  12.     asm volatile("sti");
  13.     while(1)
  14.     {
  15.     }
  16.     return 0;
  17. }
1.4 
如果是hlt的话 c之后
(0) [0x000000001963] 0008:c0001963 (unk. ctxt): nop                       ; 6690

如果是iret的话 c之后
(0) [0x00000000153c] 0008:c000153c (unk. ctxt): jmp .-2 (0xc000153c)      ; ebfe

1.5 代码打包
7int.rar(下载后改名为7int.tar.gz)
阅读(1039) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~