174 inc dword [k_reenter] 175 cmp dword [k_reenter], 0 176 jne .1 ;重入进入.1 177 178 mov esp, StackTop ; 切到内核栈 179 push .restart_v2 jmp .2 .1: push .restart_reenter_v2 .2 180 sti 181 182 push 0 183 call clock_handler 184 add esp, 4 185 186 cli ret;对应前面的push语句 .restart_v2: 188 mov esp, [p_proc_ready] ; 离开内核栈; 189 lldt [esp + P_LDT_SEL] 190 lea eax, [esp + P_STACKTOP] 191 mov dword [tss + TSS3_S_SP0], eax 192 193 .restart_reenter_v2: ; 如果(k_reenter != 0),会跳转到这里 194 dec dword [k_reenter] ; k_reenter--; 195 pop gs ; ┓ 196 pop fs ; ┃ 197 pop es ; ┣ 恢复原寄存器值 198 pop ds ; ┃ 199 popad ; ┛ 200 add esp, 4 201
21 PUBLIC void clock_handler(int irq) 22 { 23 disp_str("#"); 24 ticks++; 25 26 if (k_reenter != 0) { 27 disp_str("!"); 28 return; 29 } 30 31 p_proc_ready++; 32 33 if (p_proc_ready >= proc_table + NR_TASKS) { 34 p_proc_ready = proc_table; 35 } 36 }
54 k_reenter = -1; 55 56 p_proc_ready = proc_table; 57 58 restart(); 59 60 61 while(1){}
353 restart: 354 mov esp, [p_proc_ready] 355 lldt [esp + P_LDT_SEL] 356 lea eax, [esp + P_STACKTOP] 357 mov dword [tss + TSS3_S_SP0], eax 358 restart_reenter: dec dword [k_reenter];由于这一句,我们需要将k_reenter的初始值从-1改成0 359 pop gs 360 pop fs 361 pop es 362 pop ds 363 popad 364 add esp, 4 365 iretd
193 save: 194 sub esp, 4 195 pushad ; ┓ 196 push ds ; ┃ 197 push es ; ┣ 保存原寄存器值 198 push fs ; ┃ 199 push gs ; ┛ 200 mov dx, ss 201 mov ds, dx 202 mov es, dx 203 204 mov eax,esp 205 206 inc dword [k_reenter] 207 cmp dword [k_reenter], 0 208 jne .1 209 210 mov esp, StackTop ; 切到内核栈 211 push restart 212 jmp .2 213 .1: 214 push restart_reenter 215 .2: 216 jmp [eax+RETADR-P_STACKBASE]中断处理程序的部分内容:
158 hwint00: ; Interrupt routine for irq 0 (the clock). 159 160 ;inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 161 call save 162 mov al, EOI ; ┓reenable master 8259 163 out INT_M_CTL, al ; ┛这里,我们注意到一个很奇怪的call指令——没有以ret结尾。为什么呢?想一想,ret从堆栈中弹出返回地址赋值给eip;但是由于这里,esp在call指令中发生了变化,所以没法用ret进行返回,需要使用jmp,就是call指令的下一条指令的地址作为call过程的返回地址。
160 call save 161 162 in al,INT_M_CTLMASK 163 or al,1 164 out INT_M_CTLMASK,al 165 166 mov al, EOI ; ┓reenable master 8259 167 out INT_M_CTL, al ; ┛ 168 169 sti 170 push 0 171 call clock_handler 172 add esp, 4 173 174 cli 175 in al,INT_M_CTLMASK 176 and al,0xFE 177 out INT_M_CTLMASK 178 179 ret
150 ; 中断和异常 -- 硬件中断 151 ; --------------------------------- 152 %macro hwint_master 1 153 call save 154 in al, INT_M_CTLMASK ; ┓ 155 or al, (1 << %1) ; ┣ 屏蔽当前中断 156 out INT_M_CTLMASK, al ; ┛ 157 mov al, EOI ; ┓置EOI位 158 out INT_M_CTL, al ; ┛ 159 sti ; CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断 160 push %1 ; ┓ 161 call [irq_table + 4 * %1] ; ┣ 中断处理程序;很显然,irq_table是一个函数指针组成的数组,我们在global.c中对他加以定义 162 pop ecx ; ┛ 163 cli 164 in al, INT_M_CTLMASK ; ┓ 165 and al, ~(1 << %1) ; ┣ 恢复接受当前中断 166 out INT_M_CTLMASK, al ; ┛ 167 ret 168 %endmacro
int i; for(i=0;i<NR_IRQ;i++LL) irq_table[i]=surious_irq;
44 PUBLIC void put_irq_handler(int irq, t_pf_irq_handler handler) 45 { 46 disable_irq(irq);这一句是必须的——进行中断处理之前,先关对应中断 47 irq_table[irq] = handler; 48 }
这里,你看到,我们使用了一个中断使能函数disable_irq,我们接下来看它和另外一个函数enable_irq的结构体。
123 ; ======================================================================== 124 ; void disable_irq(int irq); 125 ; ======================================================================== 126 ; Disable an interrupt request line by setting an 8259 bit. 127 ; Equivalent code for irq < 8: 128 ; out_byte(INT_CTLMASK, in_byte(INT_CTLMASK) | (1 << irq)); 129 ; Returns true iff the interrupt was not already disabled. 130 ; 131 disable_irq: 132 mov ecx, [esp + 4] ; irq 133 pushf 134 cli 135 mov ah, 1 136 rol ah, cl ; ah = (1 << (irq % 8)) 137 cmp cl, 8 138 jae disable_8 ; disable irq >= 8 at the slave 8259 139 disable_0: 140 in al, INT_M_CTLMASK 141 test al, ah 142 jnz dis_already ; already disabled? 143 or al, ah 144 out INT_M_CTLMASK, al ; set bit at master 8259 145 popf 146 mov eax, 1 ; disabled by this function 147 ret 148 disable_8: 149 in al, INT_S_CTLMASK 150 test al, ah 151 jnz dis_already ; already disabled? 152 or al, ah 153 out INT_S_CTLMASK, al ; set bit at slave 8259 154 popf 155 mov eax, 1 ; disabled by this function 156 ret 157 dis_already: 158 popf 159 xor eax, eax ; already disabled 160 ret 161相应的enable的代码我们省略,请读者自行看书讲解。
57 p_proc_ready = proc_table; 58 59 put_irq_handler(CLOCK_IRQ, clock_handler); /* 设定时钟中断处理程序 */ 60 enable_irq(CLOCK_IRQ); /* 让8259A可以接收时钟中断 */ 61 62 restart();在init_8259A中屏蔽所有的中断:out_byte(INT_M_CTLMASK,0xFF).