随笔-80  评论-24  文章-0  trackbacks-0

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,意思是我们的系统目前不支持例如除零错误等的异常中断。

posted on 2012-02-14 00:21 myjfm 阅读(507) 评论(0)  编辑 收藏 引用 所属分类: 操作系统

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理