本文共 4760 字,大约阅读时间需要 15 分钟。
1. 系统调用处理底层程序,通过int 0x80进行系统调用
2. 时钟,硬盘,软盘中断处理程序信号,子进程结束
SIG_CHLD = 17定义了从系统调用返回时各个寄存器在堆栈中的偏移值
(ret_from_sys_call)EAX = 0x00
EBX = 0x04 ECX = 0x08 EDX = 0x0C FS = 0x10 ES = 0x14 DS = 0x18 EIP = 0x1C CS = 0x20 EFLAGS = 0x24 OLDESP = 0x28 OLDSS = 0x2C下面是定义task结构中各个成员的偏移值
进程状态 state = 0 时间片 counter = 4 优先级 priority = 8 信号位图 signal = 12 sigaction的结构数组,一共是32项,每项16个字节 sigaction = 16 受阻塞的信号位图 blocked = (33*16)sigaction结构中各个成员的偏移值
sa_handler = 0 sa_mask = 4 sa_flags = 8 sa_restorer = 12系统调用总数
nr_system_calls = 72.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve .globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt.globl _device_not_available, _coprocessor_error
系统调用出错,-1作为返回值
如果超过了系统调用总数72就会 返回-1 .align 2 bad_sys_call: movl $-1,%eax iret对任务重新调度,先把_shedule函数返回地址
ret_from_sys_call压入堆栈 .align 2 reschedule: pushl $ret_from_sys_call jmp _schedule系统调用
.align 2 _system_call: 对系统调用号进行有效性检查 cmpl $nr_system_calls-1,%eax ja bad_sys_call 将数据段,附加段和fs段寄存器入栈保存 ds和es段将指向内核数据段 fs将指向局部数据段 push %ds push %es push %fs 将参数入栈,系统调用的参数ebx,ecx,edx pushl %edx pushl %ecx pushl %ebx es,ds段指向内核数据段 movl $0x10,%edx mov %dx,%ds mov %dx,%es 使fs指向用户数据段 movl $0x17,%edx &nbs`;mov %dx,%fs 查表,进行系统调用 call _sys_call_table(,%eax,4) 将系统调用返回值入栈 pushl %eax 当前任务的地址放入eax中 movl _current,%eax 进程状态是不是就绪 cmpl $0,state(%eax) 如果不是就执行进程调度程序 jne reschedule 看时间片是不是用完 cmpl $0,counter(%eax) 如果用完,执行进程调度程序 je reschedule 系统调用返回处 ret_from_sys_call: 将当前任务的数据结构地址放入eax中 movl _current,%eax 看看当前任务是不是任务0 cmpl _task,%eax 如果是立即返回中断处理程序 je 3f 0x0f:局部描述符表中,第一个表项,DPL为3,代码段 看看当前代码段是否与之相等,来判断是否为用户任务 cmpw $0x0f,CS(%esp) 如果不是,立即返回中断 jne 3f 0x17:�%8 部描述附表中,第二个表项,DPL为3,数据段 看看是不是用户数据段 cmpw $0x17,OLDSS(%esp) 如果不是,立即返回中断处理程序 jne 3f 此时eax为当前任务的地址,将当前任务的信号位图放入ebx中 movl signal(%eax),%ebx 将当前任务的受阻塞的信号位图放入ecx movl blocked(%eax),%ecx 从当前任务的信号位图中清除受阻塞的信号集合 notl %ecx andl %ebx,%ecx 选择受阻塞信号的最小值,放入ecx中 bsfl %ecx,%ecx 如果没有信号需要处理,结束中断处理程序 je 3f 从信号位图中复位该信号 btrl %ecx,%ebx 重置信号位图 movl %ebx,signal(%eax) 将要处理的信号+1 incl %ecx 将要处理的信号压栈 pushl %ecx 调用信号处理函数 call _do_signal 返回值存入eax中 popl %eax 返回中断处理程序 3: popl %eax popl %ebx popl %ecx popl %edx pop %fs pop %es pop %ds iretsys_execve系统调用
.align 2 _sys_execve: 取中断调用前的指令指针寄存器的值,存入eax lea EIP(%esp),%eax 该地址作为_do_execve函数的参数 pushl %eax call _do_execve 恢复堆栈 addl $4,%esp retfork系统调用
.align 2 _sys_fork: 首先查找是否有可用的pid call _find_empty_process 如果没有就直接返回 testl %eax,%eax js 1f 否则调用_copy_process程序 push %gs pushl %esi pushl %edi pushl %ebp pushl %eax call _copy_process 调用返回,恢复堆栈 addl $20,%esp 1: ret以下是几个中断处理程序的定义,在这里不做详细介绍
硬盘中断处理程序 _hd_interrupt: pushl %eax pushl %ecx pushl %edx push %ds push %es push %fs movl $0x10,%eax mov %ax,%ds mov %ax,%es movl $0x17,%eax mov %ax,%fs movb $0x20,%al outb %al,$0xA0 # EOI to%2 interrupt controller #1 jmp 1f # give port chance to breathe 1: jmp 1f 1: xorl %edx,%edx xchgl _do_hd,%edx testl %edx,%edx jne 1f movl $_unexpected_hd_interrupt,%edx 1: outb %al,$0x20 call *%edx # "interesting" way of handling intr. pop %fs pop %es pop %ds popl %edx popl %ecx popl %eax iret软盘驱动程序
_floppy_interrupt: pushl %eax pushl %ecx pushl %edx push %ds push %es push %fs movl $0x10,%eax mov %ax,%ds mov %ax,%es movl $0x17,%eax mov %ax,%fs movb $0x20,%al outb %al,$0x20 # EOI to interrupt controller #1 xorl %eax,%eax xchgl _do_floppy,%eax testl %eax,%eax jne 1f movl $_unexpected_floppy_interrupt,%eax 1: call *%eax # "interesting" way of handling intr. pop %fs pop %es pop %ds popl %edx popl %ecx popl %eax iret并口中断处理程序
_parallel_interrupt: pushl %eax movb $0x20,%al outb %al,$0x20 popl %eax iret处理器错误,int 16
.align 2 _coprocessor_error: push %ds push %es push %fs pushl %edx pushl %ecx pushl %ebx pushl %eax movl $0x10,%eax mov %ax,%ds mov %ax,%es movl $0x17,%eax mov %ax,%fs pushl $ret_from_sys_call jmp _math_error设备不存在错误,int 7
.align 2 _device_not_available: push %ds push %es push %fs pushl %edx pushl %ecx pushl %ebx pushl %eax movl $0x10,%eax mov %ax,%ds mov %ax,%es movl $0x17,%eax mov %ax,%fs pushl $ret_from_sys_call clts movl %cr0,%eax testl $0x4,%eax je _math_state_restore pushl %ebp pushl %esi pushl %edi call _math_emulate popl %edi popl %esi popl %ebp ret时钟中断处理程序
.align 2 _timer_interrupt: push %ds # save ds,es and put kernel data space push %es # into them. %fs is used by _system_call push %fs pushl %edx # we save %eax,%ecx,%edx as gcc doesn't pushl %ecx # save those across function calls. %ebx pushl %ebx # is saved as we use that in ret_sys_call pushl %eax movl $0x10,%eax mov %ax,%ds mov %ax,%es movl $0x17,%eax mov %ax,%fs incl _jiffies movb $0x20,%al # EOI to interrupt controller #1 outb %al,$0x20 movl CS(%esp),%eax andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor) pushl %eax call _do_timer # 'do_timer(long CPL)' does everything from addl $4,%esp # task switching to accounting ... jmp ret_from_sys_call转载地址:http://syxbn.baihongyu.com/