Chinaunix首页 | 论坛 | 博客
  • 博客访问: 335194
  • 博文数量: 89
  • 博客积分: 5152
  • 博客等级: 大校
  • 技术积分: 1155
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-25 15:12
文章分类

全部博文(89)

文章存档

2012年(1)

2011年(5)

2010年(14)

2009年(69)

我的朋友

分类: LINUX

2009-04-12 20:12:28

System call 是透過中斷來呼叫,而在 x86 系統的架構中,32-255 是所謂的 maskable interrupts 即使用者定義的中斷。Linux 在 i386 上實作system call可透過以下 2 個機制:

˙ lcall7/lcall27(call gates,呼叫閘道)
˙ int 0x80(software interrupt.軟體中斷)

Linux 應用程式使用 int 指令來觸發 0x80 號軟體中斷,其它作業系統像是 Solaris 的應用程式,則是使用 lcall7。在開機時,IDT是由arch/i386/kernel/traps.c:trap_init() 做初始化的設定:

void __init trap_init(void)
{
#ifdef CONFIG_EISA
if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
EISA_bus = 1;
#endif

#ifdef CONFIG_X86_LOCAL_APIC
init_apic_mappings();
#endif

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);
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(SYSCALL_VECTOR,&system_call);

/*
* default LDT is a single-entry callgate to lcall7 for iBCS
* and a callgate to lcall27 for Solaris/x86 binaries
*/
set_call_gate(&default_ldt[0],lcall7);
set_call_gate(&default_ldt[4],lcall27);

/*
* Should be a barrier for any external CPU state.
*/
cpu_init();

#ifdef CONFIG_X86_VISWS_APIC
superio_init();
lithium_init();
cobalt_init();
#endif
}

由以上的程式碼可以看出,0x80 號中斷向量會指到 system_call 進入點的位址。system_call 位於 arch/i386/kernel/entry.S

ENTRY(system_call)
	pushl %eax			# save orig_eax
	SAVE_ALL
	GET_CURRENT(%ebx)
	testb $0x02,tsk_ptrace(%ebx)	# PT_TRACESYS
	jne tracesys
	cmpl $(NR_syscalls),%eax
	jae badsys
	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
	movl %eax,EAX(%esp)		# save the return value
ENTRY(ret_from_sys_call)
	cli				# need_resched and signals atomic test
	cmpl $0,need_resched(%ebx)
	jne reschedule
	cmpl $0,sigpending(%ebx)
	jne signal_return

0x80 號中斷裡有很多 system call service routine,每個 system call service routine 的位址是經由 sys_call_table 查表得知。要呼叫 system call 時,必須告訴 Linux kernel 該 system call 的編號。System call 的編號透過 %eax 暫存器來傳遞給 Linux kernel。

例如 sys_open 這個 system call 的編號為 5。因此當我們呼叫 sys_open() 時,就要指定 %eax 暫存器的值為5。

--jollen

阅读(695) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~