📄 77.html
字号:
<a name='L183'>movl $0x17,%eax # fs 置为指向局部数据段(出错程序的数据段)。
<a name='L184'>mov %ax,%fs
<a name='L185'>pushl $ret_from_sys_call # 把下面调用返回的地址入栈。
<a name='L186'>jmp _math_error # 执行C 函数math_error()(kernel/math/math_emulate.c,37)
<a name='L187'>
<a name='L188'><font color='darkred'>#</font>### int7 -- 设备不存在或协处理器不存在(Coprocessor not available)。
<a name='L189'><i><font color='green'># 如果控制寄存器CR0 的EM 标志置位,则当CPU 执行一个ESC 转义指令时就会引发该中断,这样就</font></i>
<a name='L190'><i><font color='green'># 可以有机会让这个中断处理程序模拟ESC 转义指令(169 行)。</font></i>
<a name='L191'><i><font color='green'># CR0 的TS 标志是在CPU 执行任务转换时设置的。TS 可以用来确定什么时候协处理器中的内容(上下文)</font></i>
<a name='L192'><i><font color='green'># 与CPU 正在执行的任务不匹配了。当CPU 在运行一个转义指令时发现TS 置位了,就会引发该中断。</font></i>
<a name='L193'><i><font color='green'># 此时就应该恢复新任务的协处理器执行状态(165 行)。参见(kernel/sched.c,77)中的说明。</font></i>
<a name='L194'><i><font color='green'># 该中断最后将转移到标号ret_from_sys_call 处执行下去(检测并处理信号)。</font></i>
<a name='L195'>.align 2
<a name='L196'>_device_not_available:
<a name='L197'>push %ds
<a name='L198'>push %es
<a name='L199'>push %fs
<a name='L200'>pushl %edx
<a name='L201'>pushl %ecx
<a name='L202'>pushl %ebx
<a name='L203'>pushl %eax
<a name='L204'>movl $0x10,%eax # ds,es 置为指向内核数据段。
<a name='L205'>mov %ax,%ds
<a name='L206'>mov %ax,%es
<a name='L207'>movl $0x17,%eax # fs 置为指向局部数据段(出错程序的数据段)。
<a name='L208'>mov %ax,%fs
<a name='L209'>pushl $ret_from_sys_call # 把下面跳转或调用的返回地址入栈。
<a name='L210'>clts # clear TS so that we can use math
<a name='L211'>5.5 system_call.s 程序
<a name='L212'>movl %cr0,%eax
<a name='L213'>testl $0x4,%eax # EM (math emulation bit)
<a name='L214'><i><font color='green'># 如果不是EM 引起的中断,则恢复新任务协处理器状态,</font></i>
<a name='L215'>je _math_state_restore # 执行C 函数math_state_restore()(kernel/sched.c,77)。
<a name='L216'>pushl %ebp
<a name='L217'>pushl %esi
<a name='L218'>pushl %edi
<a name='L219'>call _math_emulate # 调用C 函数math_emulate(kernel/math/<a href='../S/70.html#L25' title='Defined at 25 in kernel/math/math_emulate.c.'>math_emulate</a>.c,18)。
<a name='L220'>popl %edi
<a name='L221'>popl %esi
<a name='L222'>popl %ebp
<a name='L223'>ret # 这里的ret 将跳转到ret_from_sys_call(101 行)。
<a name='L224'>
<a name='L225'><font color='darkred'>#</font>### int32 -- (int 0x20) 时钟中断处理程序。中断频率被设置为100Hz(include/linux/sched.h,5),
<a name='L226'><i><font color='green'># 定时芯片8253/8254 是在(kernel/sched.c,406)处初始化的。因此这里jiffies 每10 毫秒加1。</font></i>
<a name='L227'><i><font color='green'># 这段代码将jiffies 增1,发送结束中断指令给8259 控制器,然后用当前特权级作为参数调用</font></i>
<a name='L228'><i><font color='green'># C 函数do_timer(long CPL)。当调用返回时转去检测并处理信号。</font></i>
<a name='L229'>.align 2
<a name='L230'>_timer_interrupt:
<a name='L231'>push %ds # save ds,es and put kernel data space
<a name='L232'>push %es # into them. %fs is used by _system_call
<a name='L233'>push %fs
<a name='L234'>pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
<a name='L235'>pushl %ecx # save those across function calls. %ebx
<a name='L236'>pushl %ebx # is saved as we use that in ret_sys_call
<a name='L237'>pushl %eax
<a name='L238'>movl $0x10,%eax # ds,es 置为指向内核数据段。
<a name='L239'>mov %ax,%ds
<a name='L240'>mov %ax,%es
<a name='L241'>movl $0x17,%eax # fs 置为指向局部数据段(出错程序的数据段)。
<a name='L242'>mov %ax,%fs
<a name='L243'>incl _jiffies
<a name='L244'><i><font color='green'># 由于初始化中断控制芯片时没有采用自动EOI,所以这里需要发指令结束该硬件中断。</font></i>
<a name='L245'>movb $0x20,%al # EOI to interrupt controller #1
<a name='L246'>outb %al,$0x20 # 操作命令字OCW2 送0x20 端口。
<a name='L247'><i><font color='green'># 下面3 句从选择符中取出当前特权级别(0 或3)并压入堆栈,作为do_timer 的参数。</font></i>
<a name='L248'>movl CS(%esp),%eax
<a name='L249'>andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
<a name='L250'>pushl %eax
<a name='L251'><i><font color='green'># do_timer(CPL)执行任务切换、计时等工作,在kernel/shched.c,305 行实现。</font></i>
<a name='L252'>call _do_timer # 'do_timer(long CPL)' does everything from
<a name='L253'>addl $4,%esp # task switching to accounting ...
<a name='L254'>jmp ret_from_sys_call
<a name='L255'>
<a name='L256'><font color='darkred'>#</font>### 这是sys_execve()系统调用。取中断调用程序的代码指针作为参数调用C 函数do_execve()。
<a name='L257'><i><font color='green'># do_execve()在(fs/exec.c,182)。</font></i>
<a name='L258'>.align 2
<a name='L259'>_sys_execve:
<a name='L260'>lea EIP(%esp),%eax
<a name='L261'>pushl %eax
<a name='L262'>call _do_execve
<a name='L263'>addl $4,%esp # 丢弃调用时压入栈的EIP 值。
<a name='L264'>ret
<a name='L265'>5.5 system_call.s 程序
<a name='L266'>
<a name='L267'><font color='darkred'>#</font>### sys_fork()调用,用于创建子进程,是system_call 功能2。原形在include/linux/sys.h 中。
<a name='L268'><i><font color='green'># 首先调用C 函数find_empty_process(),取得一个进程号pid。若返回负数则说明目前任务数组</font></i>
<a name='L269'><i><font color='green'># 已满。然后调用copy_process()复制进程。</font></i>
<a name='L270'>.align 2
<a name='L271'>_sys_fork:
<a name='L272'>call _find_empty_process # 调用find_empty_process()(kernel/fork.c,135)。
<a name='L273'>testl %eax,%eax
<a name='L274'>js 1f
<a name='L275'>push %gs
<a name='L276'>pushl %esi
<a name='L277'>pushl %edi
<a name='L278'>pushl %ebp
<a name='L279'>pushl %eax
<a name='L280'>call _copy_process # 调用C 函数copy_process()(kernel/fork.c,68)。
<a name='L281'>addl $20,%esp # 丢弃这里所有压栈内容。
<a name='L282'>1: ret
<a name='L283'>
<a name='L284'><font color='darkred'>#</font>### int 46 -- (int 0x2E) 硬盘中断处理程序,响应硬件中断请求IRQ14。
<a name='L285'><i><font color='green'># 当硬盘操作完成或出错就会发出此中断信号。(参见kernel/blk_drv/hd.c)。</font></i>
<a name='L286'><i><font color='green'># 首先向8259A 中断控制从芯片发送结束硬件中断指令(EOI),然后取变量do_hd 中的函数指针放入edx</font></i>
<a name='L287'><i><font color='green'># 寄存器中,并置do_hd 为NULL,接着判断edx 函数指针是否为空。如果为空,则给edx 赋值指向</font></i>
<a name='L288'><i><font color='green'># unexpected_hd_interrupt(),用于显示出错信息。随后向8259A 主芯片送EOI 指令,并调用edx 中</font></i>
<a name='L289'><i><font color='green'># 指针指向的函数: read_intr()、write_intr()或unexpected_hd_interrupt()。</font></i>
<a name='L290'>_hd_interrupt:
<a name='L291'>pushl %eax
<a name='L292'>pushl %ecx
<a name='L293'>pushl %edx
<a name='L294'>push %ds
<a name='L295'>push %es
<a name='L296'>push %fs
<a name='L297'>movl $0x10,%eax # ds,es 置为内核数据段。
<a name='L298'>mov %ax,%ds
<a name='L299'>mov %ax,%es
<a name='L300'>movl $0x17,%eax # fs 置为调用程序的局部数据段。
<a name='L301'>mov %ax,%fs
<a name='L302'><i><font color='green'># 由于初始化中断控制芯片时没有采用自动EOI,所以这里需要发指令结束该硬件中断。</font></i>
<a name='L303'>movb $0x20,%al
<a name='L304'>outb %al,$0xA0 # EOI to interrupt controller #1 # 送从8259A。
<a name='L305'>jmp 1f # give port chance to breathe
<a name='L306'>1: jmp 1f # 延时作用。
<a name='L307'>1: xorl %edx,%edx
<a name='L308'>xchgl _do_hd,%edx # do_hd 定义为一个函数指针,将被赋值read_intr()或
<a name='L309'><i><font color='green'># write_intr()函数地址。(kernel/blk_drv/hd.c)</font></i>
<a name='L310'><i><font color='green'># 放到edx 寄存器后就将do_hd 指针变量置为NULL。</font></i>
<a name='L311'>testl %edx,%edx # 测试函数指针是否为Null。
<a name='L312'>jne 1f # 若空,则使指针指向C 函数unexpected_hd_interrupt()。
<a name='L313'>movl $_unexpected_hd_interrupt,%edx # (kernel/blk_drv/hdc,237)。
<a name='L314'>1: outb %al,$0x20 # 送主8259A 中断控制器EOI 指令(结束硬件中断)。
<a name='L315'>call *%edx # "interesting" way of handling intr.
<a name='L316'>pop %fs # 上句调用do_hd 指向的C 函数。
<a name='L317'>pop %es
<a name='L318'>pop %ds
<a name='L319'>5.5 system_call.s 程序
<a name='L320'>popl %edx
<a name='L321'>popl %ecx
<a name='L322'>popl %eax
<a name='L323'>iret
<a name='L324'>
<a name='L325'><font color='darkred'>#</font>### int38 -- (int 0x26) 软盘驱动器中断处理程序,响应硬件中断请求IRQ6。
<a name='L326'><i><font color='green'># 其处理过程与上面对硬盘的处理基本一样。(kernel/blk_drv/floppy.c)。</font></i>
<a name='L327'><i><font color='green'># 首先向8259A 中断控制器主芯片发送EOI 指令,然后取变量do_floppy 中的函数指针放入eax</font></i>
<a name='L328'><i><font color='green'># 寄存器中,并置do_floppy 为NULL,接着判断eax 函数指针是否为空。如为空,则给eax 赋值指向</font></i>
<a name='L329'><i><font color='green'># unexpected_floppy_interrupt (),用于显示出错信息。随后调用eax 指向的函数: rw_interrupt,</font></i>
<a name='L330'><i><font color='green'># seek_interrupt,recal_interrupt,reset_interrupt 或unexpected_floppy_interrupt。</font></i>
<a name='L331'>_floppy_interrupt:
<a name='L332'>pushl %eax
<a name='L333'>pushl %ecx
<a name='L334'>pushl %edx
<a name='L335'>push %ds
<a name='L336'>push %es
<a name='L337'>push %fs
<a name='L338'>movl $0x10,%eax # ds,es 置为内核数据段。
<a name='L339'>mov %ax,%ds
<a name='L340'>mov %ax,%es
<a name='L341'>movl $0x17,%eax # fs 置为调用程序的局部数据段。
<a name='L342'>mov %ax,%fs
<a name='L343'>movb $0x20,%al # 送主8259A 中断控制器EOI 指令(结束硬件中断)。
<a name='L344'>outb %al,$0x20 # EOI to interrupt controller #1
<a name='L345'>xorl %eax,%eax
<a name='L346'>xchgl _do_floppy,%eax # do_floppy 为一函数指针,将被赋值实际处理C 函数程序,
<a name='L347'><i><font color='green'># 放到eax 寄存器后就将do_floppy 指针变量置空。</font></i>
<a name='L348'>testl %eax,%eax # 测试函数指针是否=NULL?
<a name='L349'>jne 1f # 若空,则使指针指向C 函数unexpected_floppy_interrupt()。
<a name='L350'>movl $_unexpected_floppy_interrupt,%eax
<a name='L351'>1: call *%eax # "interesting" way of handling intr.
<a name='L352'>pop %fs # 上句调用do_floppy 指向的函数。
<a name='L353'>pop %es
<a name='L354'>pop %ds
<a name='L355'>popl %edx
<a name='L356'>popl %ecx
<a name='L357'>popl %eax
<a name='L358'>iret
<a name='L359'>
<a name='L360'><font color='darkred'>#</font>### int 39 -- (int 0x27) 并行口中断处理程序,对应硬件中断请求信号IRQ7。
<a name='L361'><i><font color='green'># 本版本内核还未实现。这里只是发送EOI 指令。</font></i>
<a name='L362'>_parallel_interrupt:
<a name='L363'>pushl %eax
<a name='L364'>movb $0x20,%al
<a name='L365'>outb %al,$0x20
<a name='L366'>popl %eax
<a name='L367'>iret
</pre>
<hr>
<a name='BOTTOM'>
<i><font color='green'>/* [<][>][^][v]<a href='#TOP'>[top]</a>[bottom]<a href='../mains.html'>[index]</a><a href='../help.html'>[help]</a> */</font></i>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -