转载请标注:http://blog.csdn.net/zgh1988/article/details/7389329
下面我将分别以c和d为例,来讲述单进程切换和多进程切换下的中断处理程序
1、单进程环境下的中断处理程序
2、多进程环境下的中断处理程序
在这里我们只考虑利用时钟中断来进行进程切换。
我们知道进程是运行在ring1环境下的,而中断处理程序是运行在ring0环境下的,让我们想象一下进程切换时的情形。一个进程正在兢兢业业地运行着,这时候时钟中断发生了,特权级从ring1跳到ring0,开始执行时钟中断处理程序,中断处理程序这时调用进程调度模块,指定下一个应用运行的进程,当中断处理程序结束时,下一个进程准备就绪并开始运行,特权级又从ring0跳回到ring1。
下面我们从两个方面来考虑进程切换过程中需要注意什么?(假设此时运行的是进程A)
进入中断处理程序之后,首要任务就是保存进程A的状态信息,以便于将来恢复进程A时使用。在本程序中,进程A的状态信息只包含寄存器内容。由于是单进程环境下的中断,所以在离开中断处理程序之前,要恢复进程A的状态信息,离开中断处理程序之后,就又返回到进程A。
hwint00: …… ;保存原寄存器的内容 pushad push ds push es push fs push gs ……… ;恢复原寄存器的内容 pop gs pop fs pop es pop ds popad …… iretd
中断发生,特权级发生了变化,从ring1(进程A)----- ring0(中断处理程序)-----ring1(进程A)。
首先考虑ring1----ring0,从低特权级(ring1)跳转到高特权级(ring0),需要从TSS中获取es0和esp0。进入到ring0(中断处理程序)之后,我们需要将进程A的状态信息保存到PCB(进程控制块)中,所以在发生中断处理程序之前,我们将TSS中esp0指向进程表。所以在restart函数中,我们看到:
restart: mov esp, [p_proc_ready] ;将进程表首地址赋值给esp lldt [esp + P_LDT_SEL] ;加载PCB中的LDT lea eax, [esp + P_STACKTOP] ;将eax指向PCB中的eax的地址 mov dword [tss + TSS3_S_SP0], eax ;将TSS中的esp0指向PCB中的eax的地址 ;此时esp指向进程表首地址,连续出栈,依次弹出gs, fs, es, ds, edi ;esi, ebp, esp, ebx, edx, ecx, eax。 pop gs pop fs pop es pop ds popad ;此时esp指向eip add esp, 4 iretd
结合图形来分析程序。
我们知道,我们将esp0指向了数据结构PROCESS中STACK_FRAME的eax,所以在时钟中断发后,进入中断处理程序,首先需要保存进程状态信息,即通过一堆push指令来完成,刚好保存到进程的PCB中。也就是PROCESS结构。
hwint00: ; Interrupt routine for irq 0 (the clock). sub esp, 4 ;保存原寄存器的内容 pushad push ds push es push fs push gs mov dx, ss mov ds, dx mov es, dx ;改变屏幕第0行,第0列的字符 ;inc byte[gs:0] ;使主8259接受中断 mov al, EOI out INT_M_CTL, al inc dword[k_reenter] cmp dword[k_reenter], 0 jne .re_enter ;切换到内核栈 mov esp, StackTop ;打开中断 sti ;调用disp_str函数,用来显示“^” push clock_int_msg call disp_str add esp, 4 ;调用delay函数,实现中断嵌套 ;push 1 ;call delay ;add esp, 4 ;关闭中断 cli ;离开内核栈 mov esp, [p_proc_ready] lea eax, [esp + P_STACKTOP] mov dword[tss + TSS3_S_SP0], eax .re_enter: dec dword[k_reenter] ;恢复原寄存器的内容 pop gs pop fs pop es pop ds popad add esp, 4 iretd
在ring0中,我们需要调用进程调度模块,或者显示某些字符,需要使用堆栈,此时的esp指向的是进程表,所以如果对esp进行操作,相当于改变了进程表的内容。所以我们此时需要将esp保存起来,然后将其指向另一块堆栈(即内核栈)即:
mov esp, StackTop。
执行完调度模块,或者显示某些字符之后,我们需要离开内核栈,那么此时我们需要将esp指向何处呢?我们知道,在离开中断处理程序之前,我们需要恢复进程A的状态信息,所以要通过一堆pop指令来完成。于是我们必须将esp赋值为指向进程表的起始地址。即:mov esp, [p_proc_ready]
这时候,我们还需要考虑一个问题,就是我们在离开中断处理程序之前,应该还要完成一个任务,就是赋值TSS中的esp0。所以我们使用
mov esp, [p_proc_ready]
lea eax, [esp + P_STACK_TOP]
mov dword[tss + TSS3_S_SP0], eax
这段代码,与restart中赋值esp0的一模一样。
此时我们完成了ring0 --- ring1的跳转。
hwint00: ; Interrupt routine for irq 0 (the clock). sub esp, 4 ;保存原寄存器的内容 pushad push ds push es push fs push gs mov dx, ss mov ds, dx mov es, dx ;使主8259接受中断 mov al, EOI out INT_M_CTL, al inc dword[k_reenter] cmp dword[k_reenter], 0 jne .re_enter ;切换到内核栈 mov esp, StackTop ;打开中断 sti ;调用clock_handler函数,通过调整p_proc_ready的指向proc_table ;数组中不同的进程。 push 0 call clock_handler add esp, 4 ;关闭中断 cli ;离开内核栈 mov esp, [p_proc_ready] lldt [esp + P_LDT_SEL] lea eax, [esp + P_STACKTOP] mov dword[tss + TSS3_S_SP0], eax .re_enter: dec dword[k_reenter] ;恢复原寄存器的内容 pop gs pop fs pop es pop ds popad add esp, 4 iretd
PUBLIC void clock_handler(int irq) { disp_str("#"); p_proc_ready++; if (p_proc_ready >= proc_table + NR_TASKS) { p_proc_ready = proc_table; } }
全面剖析《自己动手写操作系统》第五章--makefile http://blog.csdn.net/zgh1988/article/details/7338380
全面剖析《自己动手写操作系统》第五章---加载内核kernel.bin http://blog.csdn.net/zgh1988/article/details/7329941
全面剖析《自己动手写操作系统》第五章---Red Hat 9.0 的安装过程 http://blog.csdn.net/zgh1988/article/details/7315676
全面剖析《自己动手写操作系统》第四章---FAT12文件系统 http://blog.csdn.net/zgh1988/article/details/7284834
全面剖析《自己动手写操作系统》第四章---加载Loader.bin http://blog.csdn.net/zgh1988/article/details/7291909
全面剖析《自己动手写操作系统》第三章---进入保护模式 http://blog.csdn.net/zgh1988/article/details/7098981
全面剖析《自己动手写操作系统》第三章---“实模式--保护模式--实模式” http://blog.csdn.net/zgh1988/article/details/7255804
全面剖析《自己动手写操作系统》第三章---堆栈段的工作方式 http://blog.csdn.net/zgh1988/article/details/7256254
全面剖析《自己动手写操作系统》第三章---特权级以及不同特权级代码段之间的跳转 http://blog.csdn.net/zgh1988/article/details/7262901
全面剖析《自己动手写操作系统》第三章---分页机制 http://blog.csdn.net/zgh1988/article/details/7270748
全面剖析《自己动手写操作系统》第三章---中断机制 http://blog.csdn.net/zgh1988/article/details/7276259
全面剖析《自己动手写操作系统》第二章http://blog.csdn.net/zgh1988/article/details/7062065
全面剖析《自己动手写操作系统》第一章http://blog.csdn.net/zgh1988/article/details/7060032
《自己动手写操作系统》读后感http://blog.csdn.net/zgh1988/article/details/7059936