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 ; 所有能產生異?;騈MI或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 閱讀(538)
評論(0) 編輯 收藏 引用 所屬分類:
操作系統