您的位置:首页 > 运维架构 > Linux

linux内核分析之system_call.s

2015-10-20 21:48 495 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: