📄 system_call.s
字号:
mov eax,10h ;// ds,es 置为指向内核数据段。 mov ds,ax mov es,ax mov eax,17h ;// fs 置为指向局部数据段(出错程序的数据段)。 mov fs,ax push ret_from_sys_call ;// 把下面调用返回的地址入栈。 jmp _math_error ;// 执行C 函数math_error()(kernel/math/math_emulate.c,37);//// int7 -- 设备不存在或协处理器不存在(Coprocessor not available)。;// 如果控制寄存器CR0 的EM 标志置位,则当CPU 执行一个R_ESC 转义指令时就会引发该中断,这样就;// 可以有机会让这个中断处理程序模拟R_ESC 转义指令(169 行)。;// CR0 的TS 标志是在CPU 执行任务转换时设置的。TS 可以用来确定什么时候协处理器中的内容(上下文);// 与CPU 正在执行的任务不匹配了。当CPU 在运行一个转义指令时发现TS 置位了,就会引发该中断。;// 此时就应该恢复新任务的协处理器执行状态(165 行)。参见(kernel/sched.c,77)中的说明。;// 该中断最后将转移到标号ret_from_sys_call 处执行下去(检测并处理信号)。align 4_device_not_available: push ds push es push fs push edx push ecx push ebx push eax mov eax,10h ;// ds,es 置为指向内核数据段。 mov ds,ax mov es,ax mov eax,17h ;// fs 置为指向局部数据段(出错程序的数据段)。 mov fs,ax push ret_from_sys_call ;// 把下面跳转或调用的返回地址入栈。 clts ;// clear TS so that we can use math mov eax,cr0 test eax,4h ;// EM (math emulation bit);// 如果不是EM 引起的中断,则恢复新任务协处理器状态,
je goto_math_state_restore;// 执行C 函数math_state_restore()(kernel/sched.c,77)。 push ebp push esi push edi call _math_emulate ;// 调用C 函数math_emulate(kernel/math/math_emulate.c,18)。 pop edi pop esi pop ebp ret ;// 这里的ret 将跳转到ret_from_sys_call(101 行)。goto_math_state_restore:
jmp _math_state_restore
;//// int32 -- (int 0x20) 时钟中断处理程序。中断频率被设置为100Hz(include/linux/sched.h,5),;// 定时芯片8253/8254 是在(kernel/sched.c,406)处初始化的。因此这里jiffies 每10 毫秒加1。;// 这段代码将jiffies 增1,发送结束中断指令给8259 控制器,然后用当前特权级作为参数调用;// C 函数do_timer(long CPL)。当调用返回时转去检测并处理信号。align 4_timer_interrupt: push ds ;// save ds,es and put kernel data space push es ;// into them. %fs is used by _system_call push fs push edx ;// we save %eax,%ecx,%edx as gcc doesn't push ecx ;// save those across function calls. %ebx push ebx ;// is saved as we use that in ret_sys_call push eax mov eax,10h ;// ds,es 置为指向内核数据段。 mov ds,ax mov es,ax mov eax,17h ;// fs 置为指向局部数据段(出错程序的数据段)。 mov fs,ax inc dword ptr _jiffies;// 由于初始化中断控制芯片时没有采用自动EOI,所以这里需要发指令结束该硬件中断。 mov al,20h ;// EOI to interrupt controller ;//1 out 20h,al ;// 操作命令字OCW2 送0x20 端口。;// 下面3 句从选择符中取出当前特权级别(0 或3)并压入堆栈,作为do_timer 的参数。 mov eax,dword ptr [R_CS+esp] and eax,3 ;// %eax is CPL (0 or 3, 0=supervisor) push eax;// do_timer(CPL)执行任务切换、计时等工作,在kernel/shched.c,305 行实现。 call _do_timer ;// 'do_timer(long CPL)' does everything from add esp,4 ;// task switching to accounting ... jmp ret_from_sys_call;//// 这是sys_execve()系统调用。取中断调用程序的代码指针作为参数调用C 函数do_execve()。;// do_execve()在(fs/exec.c,182)。align 4_sys_execve: lea eax,[R_EIP+esp] push eax call _do_execve add esp,4 ;// 丢弃调用时压入栈的R_EIP 值。 ret;//// sys_fork()调用,用于创建子进程,是system_call 功能2。原形在include/linux/sys.h 中。;// 首先调用C 函数find_empty_process(),取得一个进程号pid。若返回负数则说明目前任务数组;// 已满。然后调用copy_process()复制进程。align 4_sys_fork: call _find_empty_process ;// 调用find_empty_process()(kernel/fork.c,135)。 test eax,eax js l2 push gs push esi push edi push ebp push eax call _copy_process ;// 调用C 函数copy_process()(kernel/fork.c,68)。 add esp,20 ;// 丢弃这里所有压栈内容。l2: ret;//// int 46 -- (int 0x2E) 硬盘中断处理程序,响应硬件中断请求IRQ14。;// 当硬盘操作完成或出错就会发出此中断信号。(参见kernel/blk_drv/hd.c)。;// 首先向8259A 中断控制从芯片发送结束硬件中断指令(EOI),然后取变量do_hd 中的函数指针放入edx;// 寄存器中,并置do_hd 为NULL,接着判断edx 函数指针是否为空。如果为空,则给edx 赋值指向;// unexpected_hd_interrupt(),用于显示出错信息。随后向8259A 主芯片送EOI 指令,并调用edx 中;// 指针指向的函数: read_intr()、write_intr()或unexpected_hd_interrupt()。_hd_interrupt: push eax push ecx push edx push ds push es push fs mov eax,10h ;// ds,es 置为内核数据段。 mov ds,ax mov es,ax mov eax,17h ;// fs 置为调用程序的局部数据段。 mov fs,ax;// 由于初始化中断控制芯片时没有采用自动EOI,所以这里需要发指令结束该硬件中断。 mov al,20h out 0A0h,al ;// EOI to interrupt controller ;//1 ;// 送从8259A。 jmp l3 ;// give port chance to breathel3: jmp l4 ;// 延时作用。l4: xor edx,edx xchg edx,dword ptr _do_hd ;// do_hd 定义为一个函数指针,将被赋值read_intr()或;// write_intr()函数地址。(kernel/blk_drv/hd.c);// 放到edx 寄存器后就将do_hd 指针变量置为NULL。 test edx,edx ;// 测试函数指针是否为Null。 jne l5 ;// 若空,则使指针指向C 函数unexpected_hd_interrupt()。 mov edx,dword ptr _unexpected_hd_interrupt ;// (kernel/blk_drv/hdc,237)。l5: out 20h,al ;// 送主8259A 中断控制器EOI 指令(结束硬件中断)。 call edx ;// "interesting" way of handling intr. pop fs ;// 上句调用do_hd 指向的C 函数。 pop es pop ds pop edx pop ecx pop eax iretd;//// int38 -- (int 0x26) 软盘驱动器中断处理程序,响应硬件中断请求IRQ6。;// 其处理过程与上面对硬盘的处理基本一样。(kernel/blk_drv/floppy.c)。;// 首先向8259A 中断控制器主芯片发送EOI 指令,然后取变量do_floppy 中的函数指针放入eax;// 寄存器中,并置do_floppy 为NULL,接着判断eax 函数指针是否为空。如为空,则给eax 赋值指向;// unexpected_floppy_interrupt (),用于显示出错信息。随后调用eax 指向的函数: rw_interrupt,;// seek_interrupt,recal_interrupt,reset_interrupt 或unexpected_floppy_interrupt。_floppy_interrupt: push eax push ecx push edx push ds push es push fs mov eax,10h ;// ds,es 置为内核数据段。
mov ds,ax
mov es,ax
mov eax,17h ;// fs 置为调用程序的局部数据段。
mov fs,ax
mov al,20h ;// 送主8259A 中断控制器EOI 指令(结束硬件中断)。 out 20h,al ;// EOI to interrupt controller ;//1 xor eax,eax xchg eax,dword ptr _do_floppy ;// do_floppy 为一函数指针,将被赋值实际处理C 函数程序,;// 放到eax 寄存器后就将do_floppy 指针变量置空。 test eax,eax ;// 测试函数指针是否=NULL? jne l6 ;// 若空,则使指针指向C 函数unexpected_floppy_interrupt()。 mov eax,dword ptr _unexpected_floppy_interruptl6: call eax ;// "interesting" way of handling intr. pop fs ;// 上句调用do_floppy 指向的函数。 pop es pop ds pop edx pop ecx pop eax iretd;//// int 39 -- (int 0x27) 并行口中断处理程序,对应硬件中断请求信号IRQ7。;// 本版本内核还未实现。这里只是发送EOI 指令。_parallel_interrupt: push eax mov al,20h out 20h,al pop eax iretdend
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -