不同平台的系统调用汇编不一样,powerpc平台通过汇编语句sc来执行系统调用
helloworld的例子(powerpc平台)
- /*
- /opt/montavista41/montavista/cge/devkit/ppc/85xx/bin/ppc_85xx-as -gstabs hello.s -o hello.o
- /opt/montavista41/montavista/cge/devkit/ppc/85xx/bin/ppc_85xx-ld hello.o -o hello
- */
- .data # section declaration - variables only
-
- msg:
- .string "Hello, world!\n"
- len = . - msg # length of our dear string
-
- .text # section declaration - begin code
-
- .global _start
- _start:
-
- # write our string to stdout
-
- li 0,4 # syscall number (sys_write)
- li 3,1 # first argument: file descriptor (stdout)
- # second argument: pointer to message to write
- lis 4,msg@ha # load top 16 bits of &msg
- addi 4,4,msg@l # load bottom 16 bits
- li 5,len # third argument: message length
- sc # call kernel
-
- # and exit
-
- li 0,1 # syscall number (sys_exit)
- li 3,1 # first argument: exit code
- sc # call kernel
helloworld的例子(ia32平台)
- .data # section declaration
-
- msg:
- .string "Hello, world!\n"
- len = . - msg # length of our dear string
-
- .text # section declaration
-
- # we must export the entry point to the ELF linker or
- .global _start # loader. They conventionally recognize _start as their
- # entry point. Use ld -e foo to override the default.
-
- _start:
-
- # write our string to stdout
-
- movl $len,%edx # third argument: message length
- movl $msg,%ecx # second argument: pointer to message to write
- movl $1,%ebx # first argument: file handle (stdout)
- movl $4,%eax # system call number (sys_write)
- int $0x80 # call kernel
-
- # and exit
-
- movl $0,%ebx # first argument: exit code
- movl $1,%eax # system call number (sys_exit)
- int $0x80 # call kernel
系统调用本质上是一个中断向量 《中断相关知识(powerpc版)》
文件linux_2_6_24/arch/ppc/kernel/head_fsl_booke.S
- SET_IVOR(0, CriticalInput);
- SET_IVOR(1, MachineCheck);
- SET_IVOR(2, DataStorage);
- SET_IVOR(3, InstructionStorage);
- SET_IVOR(4, ExternalInput);
- SET_IVOR(5, Alignment);
- SET_IVOR(6, Program);
- SET_IVOR(7, FloatingPointUnavailable);
- SET_IVOR(8, SystemCall);
- SET_IVOR(9, AuxillaryProcessorUnavailable);
- SET_IVOR(10, Decrementer);
- SET_IVOR(11, FixedIntervalTimer);
- SET_IVOR(12, WatchdogTimer);
- SET_IVOR(13, DataTLBError);
- SET_IVOR(14, InstructionTLBError);
- SET_IVOR(15, Debug);
- SET_IVOR(32, SPEUnavailable);
- SET_IVOR(33, SPEFloatingPointData);
- SET_IVOR(34, SPEFloatingPointRound);
- #ifndef CONFIG_E200
- SET_IVOR(35, PerformanceMonitor);
- #endif
- 。。。。省略N多。。。。。
- /* System Call Interrupt */
START_EXCEPTION(SystemCall)
NORMAL_EXCEPTION_PROLOG
EXC_XFER_EE_LITE(0x0c00, DoSyscall)
使用汇编语句sc会产生一个SystemCall中断,接着根据中断向量中的地址去执行handler,即DoSyscall。
有关DoSyscall,它在文件arch/ppc/kernel/entry.S 中定义。
它根据sc执行时所用的系统调用编号来检索系统调用表,进行系统调用。
- _GLOBAL(DoSyscall)
- stw r3,ORIG_GPR3(r1)
- li r12,0
- stw r12,RESULT(r1)
- lwz r11,_CCR(r1) /* Clear SO bit in CR */
- rlwinm r11,r11,0,4,2
- stw r11,_CCR(r1)
- #ifdef SHOW_SYSCALLS
- bl do_show_syscall
- #endif /* SHOW_SYSCALLS */
- rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
- lwz r11,TI_FLAGS(r10)
- andi. r11,r11,_TIF_SYSCALL_T_OR_A
- bne- syscall_dotrace
- syscall_dotrace_cont:
- cmplwi 0,r0,NR_syscalls
- lis r10,sys_call_table@h
- ori r10,r10,sys_call_table@l
- slwi r0,r0,2
- bge- 66f
- lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
- mtlr r10
- addi r9,r1,STACK_FRAME_OVERHEAD
- PPC440EP_ERR42
- blrl /* Call handler */
系统调用表名为 sys_call_table,在 linux_2_6_24/arch/powerpc/kernel/systbl.S 中定义。
linux_2_6_24/include/asm-powerpc/systbl.h
系统调用表包含有实现每个系统调用的函数的地址。
- SYSCALL(restart_syscall)
- SYSCALL(exit)
- PPC_SYS(fork)
- SYSCALL_SPU(read)
- SYSCALL_SPU(write)
- COMPAT_SYS_SPU(open)
- SYSCALL_SPU(close)
- COMPAT_SYS_SPU(waitpid)
- COMPAT_SYS_SPU(creat)
- SYSCALL_SPU(link)
- SYSCALL_SPU(unlink)
- COMPAT_SYS(execve)
- SYSCALL_SPU(chdir)
- COMPAT_SYS_SPU(time)
- SYSCALL_SPU(mknod)
- SYSCALL_SPU(chmod)
当函数调用完毕之后,返回到 DoSyscall(),它把控制权切换给 ret_from_except(在 arch/ppc/kernel/entry.S 中定义)。
它会去检查那些在切换回用户空间之前需要完成的任务。如果没有需要做的事情,那么就通过 restore 函数恢复用户进程的状态,并把控制权交还给用户程序。