进程栈──进程运行时自身的堆栈。
进程表──存储进程状态信息的数据结构。 (在c语言中就是全局变量,在内核程序中把全局变量地址赋值给esp就是栈了)
内核栈──进程调度模块(很复杂的中断程序处理本身任务使用的栈)运行时使用的堆栈。
进程A本身运行时,esp指向本身进程设置的堆栈某个位置;
中断发生后,特权级也会发生变化从ring1跳到ring0,esp变成TSS预先设置好的ring0的esp的值(其实就是要求为进程表中进程A表项的最高地址,这个时候进行压栈处理,就会覆盖进程A表项的所有内容,达到了随时保存进程A的状态);这个时候如果中断程序进行堆栈操作就是破坏进程表数组;
在中断处理程序中设置把esp指向内核栈,这个时候中断处理程序就可以随便使用堆栈了;
中断处理程序:
ALIGN 16
hwint00: ; Interrupt routine for irq 0 (the clock). 这个时候从ring1跳到ring0,通过TSS的0级esp指回进程A的进程A表项
sub esp, 4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx
mov esp, StackTop ; 切到内核栈
inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符
mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259
push clock_int_msg
call disp_str
add esp, 4
mov esp, [p_proc_ready] ; 离开内核栈 指回进程表项开始的地方
lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax ;为下次从ring1跳到ring0做准备
pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp, 4
iretd