linux课程设计指导文档

发布时间 : 星期一 文章linux课程设计指导文档更新完毕开始阅读

.long 2b,4b; \\ .previous

ENTRY(ret_from_fork) pushl êx

call schedule_tail GET_THREAD_INFO(?p) popl êx jmp syscall_exit

这里主要完成现场恢复并返回。

ENTRY(system_call) pushl êx

# save orig_eax

SAVE_ALL

GET_THREAD_INFO(?p)

# system call tracing in operation /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(?p) jnz syscall_trace_entry cmpl $(nr_syscalls), êx jae syscall_badsys syscall_call:

call *sys_call_table(,êx,4) movl êx,EAX(%esp) # store the return value

syscall_exit: cli # make sure we don't miss an interrupt # setting need_resched or sigpending

# between sampling and the iret

movl TI_flags(?p), ìx

testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work

7

restore_all:

movl EFLAGS(%esp), êx

# mix EFLAGS, SS and CS

# Warning: OLDSS(%esp) contains the wrong/random values if we # are returning to the kernel.

# See comments in process.c:copy_thread() for details. movb OLDSS(%esp), %ah movb CS(%esp), %al

andl $(VM_MASK | (4 << 8) | 3), êx cmpl $((4 << 8) | 3), êx je ldt_ss

# returning to user-space with LDT SS

restore_nocheck: RESTORE_REGS addl $4, %esp 1: iret

这一段中,主要是完成调用。eax放置的是系统调用号,因为eax有可能被使用,所以先保存其值。call *sys_call_table(,êx,4)这一句是计算调用的入口。

其中,sys_call_table是LINUX的系统调用表,它存在目录arch/i386/kernel/ sys_call_table.S 下。

.data

ENTRY(sys_call_table)

.long sys_restart_syscall /* 0 - old \ .long sys_exit .long sys_fork .long sys_read .long sys_write .long sys_open

/* 5 */

?? ??

.long sys_mq_timedreceive /* 280 */

8

.long sys_mq_notify .long sys_mq_getsetattr .long sys_ni_syscall .long sys_waitid .long sys_ni_syscall .long sys_add_key .long sys_request_key .long sys_keyctl

/* 285 */ /* available */ /* reserved for kexec */

.代表当前地址,sys_call_table代表数组首地址。这个表依次保存所有系统调用的函数指针,以方便总的系统调用处理函数(system_call)进行索引。

调用具体的实现在kernel/sys.c中。

asmlinkage long sys_getuid16(void) {

return hig2lowuid(current_uid); }

刚才我们提到,这一指令使用中断/异常向量号128(即16进制的80)将控制权转移给内核,那么中断向量是怎么形成的。它的定义在(arch/i386/kernel/traps.c)中。

void __init trap_init(void) {

??

set_trap_gate(0,÷_error); set_trap_gate(1,&debug); set_intr_gate(2,&nmi);

set_system_gate(3,&int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op);

9

set_trap_gate(7,&device_not_available); set_trap_gate(8,&double_fault);

set_trap_gate(9,&coprocessor_segment_overrun); set_trap_gate(10,&invalid_TSS);

set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); set_intr_gate(14,&page_fault);

set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); set_trap_gate(18,&machine_check);

set_trap_gate(19,&simd_coprocessor_error); set_system_gate(,&system_call);

?? }

上一句就是设置system_call的值。SYSCALL_VECTOR的值就是0X80.

那么概括起来,系统调用的过程大致如下: (1) 系统调用初始化: 在

traps.c中,系统在初始化程序

trap_init()中,通过调用

set_system_gate(0x80,*system_call)完成中断描述表的填充。这样当每次用户执行指令int 0x80时,系统能把控制转移到entry.S中的函数中去。

(2) 系统调用执行:

system_call会根据用户传进来系统调用号,在系统调用表 system_call中寻找到相应偏移地址的内核处理函数,进行相应的处理。当然在这个过程之前,要保存环境(SAVE_ALL)。

(3) 系统调用的返回

系统调用处理完毕后,通过sys_call_exit返回。返回之前,程序会检查一些变量,

10

联系合同范文客服:xxxxx#qq.com(#替换为@)