- 论坛徽章:
- 13
|
本帖最后由 _nosay 于 2016-10-31 16:55 编辑
http://bbs.chinaunix.net/thread-4255522-1-1.html(续)
通过trap_init()、init_IRQ()函数可以看到内核对0~0x20、0x80以及其它224个门的初始化,接下来一起学习穿过这些门后的完整执行过程,取三个具有代表意义的门:
① set_trap_gate(14, &page_fault);
② set_system_gate(SYSCALL_VECTOR, &system_call);
③ set_intr_gate(vector, interrupt); // i=3时,vector=0x20+3
- set_intr_gate(vector, interrupt);
i=3时,该函数将0x23号门设置为中断门,穿过这道门时,会执行到interrupt[3]指向的IRQ0x03_interrupt()函数:
- asmlinkage void IRQ0x03_interrupt();
- __asm__( \
- "\n" \
- "IRQ0x03_interrupt: \n\t" \
- "pushl $0x03-256 \n\t" \
- "jmp common_interrupt");
复制代码 这段代码将中断号(与中断向量之间有0x20偏移,至于为什么减256,以后自然会知道)压入栈中,跳转到common_interrupt标号处执行:
这是进入中断处理过程之前的"寄存器现场",用于中断完成之后恢复原来的"环境"执行:
通过上述可以看到,底层语言一般能更精确的控制程序逻辑,到此,终于到了我们习以为常的环境了,即do_IRQ()函数中,这个函数主要是执行一串函数,找到当前产生中断的硬件真正需要执行的动作,以及考虑到多CPU、多硬件并发产生同一种中断,将中断响应过程“串行化”的过程:
(开发过稍复杂的多进程或多线程软件后,肯定理解“可重入函数”、“进程/线程安全函数”这些概念:比如同一个函数在多进程或多线程中执行,并且函数中会读写某些全局资源,那么就要通过加锁等措施保证可重入,或者说进程/线程安全,而串行化是保证硬件驱动工程师注册的函数,不可能执行到途中被打断暂停,而又从头开始执行,为中断函数的编写减轻了负担)
- ENTRY(ret_from_intr)
- GET_CURRENT(%ebx)
- movl EFLAGS(%esp),%eax # mix EFLAGS and CS
- movb CS(%esp),%al
- testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
- jne ret_with_reschedule
- jmp restore_all
复制代码 这里根据中断前EFLAGS寄存器、CS段寄存器判断恢复中断前现场前,是否需要进行一次进程调度(详见《Linux内核源代码情景分析》第四章);
然后restore_all恢复中断前的所有寄存器值,包换cs、eip,即CPU恢复到中断前的状态继续执行。
- set_trap_gate(14, &page_fault);
- set_system_gate(SYSCALL_VECTOR, &system_call);
穿过14、SYSCALL_VECTOR门的与穿过中断门过程基本一致:保存现场→执行中断处理函数→恢复现场。
区别:
① 0~0x20是专用门,不用像进入中断门之后是“一串”函数,system_call()面对的是多种系统调用,通过寄存器传来的系统调用号区别,do_IRQ()面对的是多种硬件,通过产生中断硬件区别;
② 进入system_call()之前,orig_eax处传的是系统调用号,do_IRQ()之前,orig_eax处传的是中断号(-256);
③ 系统调用肯定是从用户态切换到内核态,需要将ss从用户栈切换到内核栈(一定要保证更改ss寄存器的时机,要保证在用户栈的值,在定要在修改ss之前压栈)
好,到此暂且先忽略宽度,长度上又向前跨了一步,但还是没有到达终点。
对于中断门,不是已经看到do_IRQ()从“一串”函数中找到相匹配的执行了么 ,不是到终点了么 ,不是胜利了么?
穿越中断门时,CPU会自动将中断关闭,那么从中断门"出来"之前,该CPU就不响应中断了(其它CPU还是可以,否则do_IRQ()函数中就不需要IRQ_INPROGRESS、IRQ_PENDING标记了),造成中断丢失,所以特别对于单CPU系统,就希望关中断时间能尽量短一些(否则比如一个报文大老远传过来,结果由于网卡丢包严重,而导致网络中需要大量重传,是多么的不和谐),从而do_IRQ()找到的最终函数,可能只是最终任务最关键的部分,然后很快就返回了,而剩余要执行的部分称为“bottom half”,不需要访问公共资源,即不需要考虑可重入,可以在开中断时"不慌不忙"的执行。就如同很忙的时候脑筋比较乱,当想起一件事时就先记下来,有空了再去做一样。
关于“bottom half”及其扩展,下次再一起学习 。
|
|