linux内核分析之system_call.s

来源:互联网 发布:出货数据怎么做模板 编辑:程序博客网 时间:2024/05/16 16:04

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
 iret

sys_execve系统调用
.align 2
_sys_execve:
 取中断调用前的指令指针寄存器的值,存入eax
 lea EIP(%esp),%eax
 该地址作为_do_execve函数的参数
 pushl %eax
 call _do_execve
 恢复堆栈
 addl $4,%esp
 ret

fork系统调用
.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

0 0
原创粉丝点击