--------------------------------------------------------
构建外中断处理框架
--------------------------------------------------------
我们这节试图为每个外部中断都设置相同的中断处理流程!
// -------------------------------------
%macro hwint_master 1
call save
in al, INT_M_CTLMASK
or al, (1<<%1)
out INT_M_CTLMASK, al
mov al, EOI
out INT_M_CTL, al
sti
push %1
call [irq_table + 4 * %1]
pop ecx
cli
in al, INT_M_CTLMASK
and al, ~(1<<%1)
out INT_M_CTLMASK, al
ret
%endmacro
// -------------------------------------
// -------------------------------------
save:
pushad ; ┓
push ds ; ┃
push es ; ┣ 保存原寄存器值
push fs ; ┃
push gs ; ┛
mov dx, ss
mov ds, dx
mov es, dx
mov eax, esp ; eax = 进程表起始地址
inc dword [k_reenter] ; k_reenter++;
cmp dword [k_reenter], 0 ; if(k_reenter ==0)
jne .1 ; {
mov esp, StackTop ; mov esp, StackTop <-- 切换到内核栈
push restart ; push restart
jmp [eax + RETADR - P_STACKBASE] ; return;
.1: ; } else { 已经在内核栈,不需要再切换
push restart_reenter ; push restart_reenter
jmp [eax + RETADR - P_STACKBASE] ; return;
; }
// -------------------------------------
// -------------------------------------
restart:
mov esp, [p_proc_ready]
lldt [esp + P_LDT_SEL]
lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax
restart_reenter:
dec dword [k_reenter]
pop gs
pop fs
pop es
pop ds
popad
add esp, 4
iretd
// -------------------------------------
分析分析:
1,内核栈只设置一次(后面的重入中断将使用这次设置的内核栈)
2,防止了同类型中断的重入
3,重入不意味着非法,而是需求
4,巧妙地解决了时钟中断和其余外部中断的共存(公用一个处理机制)
- 如果当前有一个有效的时钟中断再绿色区域执行,那么时钟中断以外的所有中断都可以打断打断这个有效时钟中断,那些打断者也只在绿色的区域中执行自己类型的中断处理函数时可以被除自己类型之外的中断打断!
- 如果当前有一个非时钟中断的有效中断在绿色区域执行,那么时钟中断进来之后将不能发生调度(发生一个无效的调度)
- 如果当前有一个非时钟中断的有效中断在绿色区域执行,且没有其余中断打扰,那么它将执行一次非有效的任务切换(如下红色部分):
restart:
mov esp, [p_proc_ready]
lldt [esp + P_LDT_SEL]
lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax
restart_reenter:
执行结果:
这几句代码真的是太奇妙了,非人哉!!!下一节我们试试系统调用...