WinixJ---kernel/int.s文件详解(上)

WinixJ---kernel/int.s文件详解(上)

int.s文件的核心功能是对中断进行设置,不过这里把一些中断处理程序也放进来,而且还把其他文件中用到的一些库函数放到这儿,目的是为了方便,不需再在lib/目录下重新建立asmlib.s类似的文件。由于该文件比较长,所有分两部分解析。

 

  1  % include  " asm/int.sh "
  2 
  3  extern  boot_heartbeat
  4  extern  pre_schedule
  5  extern  validate_buffer
  6  extern  sys_call_table
  7  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  8  ; 到处中断向量表和中断描述符表寄存器
  9  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 10  global idt
 11  global idtr
 12 
 13  global set_idt
 14  global sys_call
 15 
 16  global out_byte
 17  global in_byte
 18  global read_port
 19  global write_port
 20  global install_int_handler
 21  global uninstall_int_handler
 22  global install_sys_call_handler
 23  global enable_hwint
 24  global disable_hwint
 25 
 26  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 27  ; 处理器能够处理的默认中断和异常
 28  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 29  global divide_error
 30  global debug_exception
 31  global nmi
 32  global breakpoint_exception
 33  global overflow
 34  global bounds_check
 35  global inval_opcode
 36  global copr_not_available
 37  global double_fault
 38  global copr_seg_overrun
 39  global inval_tss
 40  global segment_not_present
 41  global stack_exception
 42  global general_protection
 43  global page_fault
 44  global copr_error
 45  global exception
 46 
 47  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 48  ; 可屏蔽的硬件中断
 49  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 50  global int_clock
 51  global int_keyboard
 52  global int_serial_port2
 53  global int_serial_port1
 54  global int_lpt2
 55  global int_floppy
 56  global int_lpt1
 57  global int_rtc
 58  global int_ps_2_mouse
 59  global int_fpu_fault
 60  global int_at_win
 61  global int_default
 62 
 63  [SECTION .text]
 64  set_idt:
 65      ; 对8259A主片写入ICW1
 66      push  0x11
 67      push MASTER_CTL_8259
 68      call out_byte
 69      add esp,  4   *   2
 70 
 71      ; 对8259A从片写入ICW1
 72      push  0x11
 73      push SLAVE_CTL_8259
 74      call out_byte
 75      add esp,  4   *   2
 76 
 77      ; 设置8259A主片的中断入口地址,为IRQ0_IV
 78      push IRQ0_IV
 79      push MASTER_CTL_MASK_8259
 80      call out_byte
 81      add esp,  4   *   2
 82 
 83      ; 设置8259A从片的中断入口地址,为IRQ8_IV
 84      push IRQ8_IV
 85      push SLAVE_CTL_MASK_8259
 86      call out_byte
 87      add esp,  4   *   2
 88 
 89      ; 向8259A主片写入ICW3,表明IR2处级联了从片
 90      push  0x4
 91      push MASTER_CTL_MASK_8259
 92      call out_byte
 93      add esp,  4   *   2
 94 
 95      ; 向8259A从片写入ICW3,表明从片是连接在主片的IR2处
 96      push  0x2
 97      push SLAVE_CTL_MASK_8259
 98      call out_byte
 99      add esp,  4   *   2
100 
101      ; 向8259A主片写入ICW4
102      push  0x1
103      push MASTER_CTL_MASK_8259
104      call out_byte
105      add esp,  4   *   2
106 
107      ; 向8259A从片写入ICW4
108      push  0x1
109      push SLAVE_CTL_MASK_8259
110      call out_byte
111      add esp,  4   *   2
112 
113      ; 屏蔽8259A主片的所有硬件中断
114      push  0xff
115      push MASTER_CTL_MASK_8259
116      call out_byte
117      add esp,  4   *   2
118 
119      ; 屏蔽8259A从片的所有硬件中断
120      push  0xff
121      push SLAVE_CTL_MASK_8259
122      call out_byte
123      add esp,  4   *   2
124 
125      ; 除零错误(内核态允许的中断)
126      ; 指令div or idiv
127      push PRIVILEGE_KERNEL
128      push divide_error
129      push INT_GATE_386
130      push DIVIDE_IV
131      call init_idt
132      add esp,  4   *   4
133 
134      ; 调试异常(内核态允许的中断)
135      push PRIVILEGE_KERNEL
136      push debug_exception
137      push INT_GATE_386
138      push DEBUG_IV
139      call init_idt
140      add esp,  4   *   4
141 
142      ; 非屏蔽中断(内核态允许的中断)
143      push PRIVILEGE_KERNEL
144      push nmi
145      push INT_GATE_386
146      push NMI_IV
147      call init_idt
148      add esp,  4   *   4
149 
150      ; 调试断点异常(用户态允许的中断)
151      ; 指令int3
152      push PRIVILEGE_USER
153      push breakpoint_exception
154      push INT_GATE_386
155      push BREAKPOINT_IV
156      call init_idt
157      add esp,  4   *   4
158 
159      ; 溢出异常(用户态允许的中断)
160      ; 指令into
161      push PRIVILEGE_USER
162      push overflow
163      push INT_GATE_386
164      push OVERFLOW_IV
165      call init_idt
166      add esp,  4   *   4
167 
168      ; 越界错误(内核态允许的中断)
169      ; linux将其设置为用户态也允许的中断
170      ; 指令bound
171      push PRIVILEGE_KERNEL
172      push bounds_check
173      push INT_GATE_386
174      push BOUNDS_IV
175      call init_idt
176      add esp,  4   *   4
177 
178      ; 无效操作码错误(内核态允许的中断)
179      ; 主要由ud2或无效指令引起
180      push PRIVILEGE_KERNEL
181      push inval_opcode
182      push INT_GATE_386
183      push INVAL_OP_IV
184      call init_idt
185      add esp,  4   *   4
186 
187      ; 设备不可用 / 无数学协处理器(内核态允许的中断)
188      ; 浮点数或wait / fwait指令
189      push PRIVILEGE_KERNEL
190      push copr_not_available
191      push INT_GATE_386
192      push COPROC_NOT_IV
193      call init_idt
194      add esp,  4   *   4
195 
196      ; 双重错误(内核态允许的中断)
197      ; 所有能产生异常或NMI或intr的指令
198      push PRIVILEGE_KERNEL
199      push double_fault
200      push INT_GATE_386
201      push DOUBLE_FAULT_IV
202      call init_idt
203      add esp,  4   *   4
204 
205      ; 386机器不再产生此种异常
206      push PRIVILEGE_KERNEL
207      push copr_seg_overrun
208      push INT_GATE_386
209      push COPROC_SEG_IV
210      call init_idt
211      add esp,  4   *   4
212 
213      ; 无效TSS错误(内核态允许的中断)
214      ; 任务切换或访问TSS段时
215      push PRIVILEGE_KERNEL
216      push inval_tss
217      push INT_GATE_386
218      push INVAL_TSS_IV
219      call init_idt
220      add esp,  4   *   4
221 
222      ; 段不存在错误(内核态允许的中断)
223      ; 加载段寄存器或访问系统段时
224      push PRIVILEGE_KERNEL
225      push segment_not_present
226      push INT_GATE_386
227      push SEG_NOT_IV
228      call init_idt
229      add esp,  4   *   4
230 
231      ; 堆栈段错误(内核态允许的中断)
232      ; 堆栈段操作或加载ss时
233      push PRIVILEGE_KERNEL
234      push stack_exception
235      push INT_GATE_386
236      push STACK_FAULT_IV
237      call init_idt
238      add esp,  4   *   4
239 
240      ; 常规保护错误(内核态允许的中断)
241      ; 内存或其他保护检验时
242      push PRIVILEGE_KERNEL
243      push general_protection
244      push INT_GATE_386
245      push PROTECTION_IV
246      call init_idt
247      add esp,  4   *   4
248 
249      ; 页错误(内核态允许的中断)
250      ; 内存访问时
251      push PRIVILEGE_KERNEL
252      push page_fault
253      push INT_GATE_386
254      push PAGE_FAULT_IV
255      call init_idt
256      add esp,  4   *   4
257 
258 
259      ;;;;;;;;;;;;;;;;注意这里0x0f号中断保留,未使用
260 
261 
262      ; x87FPU浮点错误(内核态允许的中断)
263      ; x87FPU浮点指令或WAIT / FWAIT指令
264      push PRIVILEGE_KERNEL
265      push copr_error
266      push INT_GATE_386
267      push COPROC_ERR_IV
268      call init_idt
269      add esp,  4   *   4


以上代码虽然比较长,但是任务很简单主要完成的有:
1、设置8259A,80X86架构里面内置有两片8259A,通过设置达到如下效果:分为主8259A和从8259A,从片连接在主片的IRQ2引脚上;设置主片的IRQ0引脚(时钟中断)的中断号为IRQ0_IV(0x20),从8259A的IRQ0引脚的中断号为IRQ8_IV;然后设置默认屏蔽所有的主片和从片的中断(这样是为了在初始化对应的硬件的时候再打开对应中断);
2、设置0~15号中断向量,这些中断向量都是Intel规定的中断;设置中断的核心函数是init_idt,该函数稍后会讲解。

  1      ; 从0x20开始到中断向量表尾部,统一初始化成默认的中断处理程序
  2      mov ecx, IRQ0_IV
  3      push PRIVILEGE_KERNEL
  4      push int_default
  5      push INT_GATE_386
  6  init_rest:
  7      push ecx
  8      call init_idt
  9      pop ecx
 10      inc ecx
 11      cmp ecx,  255
 12      jna init_rest
 13      add esp,  4   *   3
 14 
 15      ; 全部中断向量入口程序加载完成之后便加载中断描述符表
 16      lidt [idtr] ; 加载中断描述符表
 17      ret
 18 
 19  init_idt:
 20      mov eax, [esp  +   4   *   1 ] ; 中断向量号
 21      mov ebx, [esp  +   4   *   2 ] ; 描述符类型(中断门 / 调用门 / 陷阱门)
 22      mov ecx, [esp  +   4   *   3 ] ; 中断处理程序入口
 23      mov edx, [esp  +   4   *   4 ] ; 特权级
 24      mov esi, idt
 25      shl eax,  3
 26      add esi, eax ; 中断向量号乘以8然后加上idt基地址就能找到对用中断向量号的idt描述符
 27      mov word [esi], cx
 28      add esi,  2
 29      mov word [esi],  0x8  ; CS段描述符
 30      add esi,  2
 31      mov  byte  [esi],  0x0
 32      add esi,  1
 33      shl edx,  5
 34      and bl,  0x0f
 35      or bl,  0x80
 36      or bl, dl
 37      mov  byte  [esi], bl
 38      add esi,  1
 39      shr ecx,  16
 40      mov word [esi], cx
 41      ret
 42      
 43  ; 在发生中断时,eflags、cs、eip将自动被压入栈中
 44  ; 如果有出错码的话,那么出错码紧接着继续被压入栈中(同样被自动压入栈中)
 45  ; 如果有堆栈切换,也就是说有特权级变化,那么原ss和esp将被压入内层堆栈,之后才是eflags、cs、eip
 46  ; 从中断或者异常中返回时必须用iretd,它与ret不同的时它会改变eflags的值
 47  divide_error:
 48      push  0xffffffff
 49      push DIVIDE_IV
 50      jmp exception
 51 
 52  debug_exception:
 53      push  0xffffffff
 54      push DEBUG_IV
 55      jmp exception
 56 
 57  nmi:
 58      push  0xffffffff
 59      push NMI_IV
 60      jmp exception
 61 
 62  breakpoint_exception:
 63      push  0xffffffff
 64      push BREAKPOINT_IV
 65      jmp exception
 66 
 67  overflow:
 68      push  0xffffffff
 69      push OVERFLOW_IV
 70      jmp exception
 71 
 72  bounds_check:
 73      push  0xffffffff
 74      push BOUNDS_IV
 75      jmp exception
 76 
 77  inval_opcode:
 78      push  0xffffffff
 79      push INVAL_OP_IV
 80      jmp exception
 81 
 82  copr_not_available:
 83      push  0xffffffff
 84      push COPROC_NOT_IV
 85      jmp exception
 86 
 87  double_fault:
 88      push DOUBLE_FAULT_IV
 89      jmp exception
 90 
 91  copr_seg_overrun:
 92      push  0xffffffff
 93      push COPROC_SEG_IV
 94      jmp exception
 95 
 96  inval_tss: ; 系统将出错码自动压栈
 97      push INVAL_TSS_IV
 98      jmp exception
 99 
100  segment_not_present: ; 系统将出错码自动压栈
101      push SEG_NOT_IV
102      jmp exception
103 
104  stack_exception: ; 系统将出错码自动压栈
105      push STACK_FAULT_IV
106      jmp exception
107 
108  general_protection: ; 系统将出错码自动压栈
109      push PROTECTION_IV
110      jmp $
111      jmp exception
112 
113  page_fault: ; 系统将出错码自动压栈
114      push PAGE_FAULT_IV
115      jmp exception
116 
117  copr_error:
118      push  0xffffffff
119      push COPROC_ERR_IV
120      jmp exception
121 
122  exception:
123      add esp,  4   *   2  ; 跳过出错码和向量号
124      cli
125      hlt ; 我们目前不处理错误,只要出错就让机器hlt
126      ;iretd
127 


上面这段代码主要完成的工作有:
1、初始化从0x20-0xff的所有中断向量,使得这些中断向量均指向默认的中断处理函数int_default;
2、init_idt函数的实现,该函数有如下形式:void init_idt(int iv, int privil, void *fun, int descr_type); 接受的四个参数依次是中断向量号,该中断特权级,中断处理函数,描述符类型(是中断门or调用门or陷阱门);该函数通过设置对应IDT中的描述符项的属性完成设置。
3、0x00-0x0f的中断处理函数的实现,其实这些函数都跳转到(不是调用,是直接跳转)exception函数,该函数直接将系统hlt,意思是我们的系统目前不支持例如除零错误等的异常中断。

你可能感兴趣的:(WinixJ---kernel/int.s文件详解(上))