• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
梦想照进灵魂
博客园    首页    新随笔    联系   管理    订阅  订阅
Syscall

Syscall




|---------------------------------------------------| |---------------------------------------------------|
| |----------------------| |----------------------| | | |----------------------| |----------------------| |
| |                      | |                      | | | |                      | |                      | |
| |                      | |                      | | | |                      | |                      | |
| |       read    ---------------> read API   -------------->   syscall    ------------>  sys_read      | |
| |                      | |                      | | | |                      | |                      | |
| |                      | |                      | | | |                      | |                      | |
| |                      | |                      | | | |                      | |                      | |
| |----------------------| |----------------------| | | |----------------------| |----------------------| |
|         App                       C lib           | |     syscall layer             read operation      |
|---------------------------------------------------| |---------------------------------------------------|

                       用户空间                                             内核空间



除异常和陷入外,它是用户空间访问内核空间的唯一合法入口(dev/proc/sys文件系统均通过syscall实现)。

下面以sys_fork()作为例子讲解(作为一个人不得不感叹fork的神奇):

1    系统调用机制

    1) 系统调用号

        每个系统调用有唯一且不可回收的系统调用号。

其中arm进入内核态是通过SWI指令(USR-->SVC)实现的, 详见《ARM Architecture Reference Manual》

                A2.6.4 Software Interrupt exception(S3C2440 属于ARM9TDMI ARMv4T)。

R14_svc = address of next instruction after the SWI instruction
SPSR_svc = CPSR
CPSR[4:0] = 0b10011    /* Enter Supervisor mode */
CPSR[5] = 0            /* Execute in ARM state */
                       /* CPSR[6] is unchanged */
CPSR[7] = 1            /* Disable normal interrupts */
                       /* CPSR[8] is unchanged */
CPSR[9] = CP15_reg1_EEbit
/* Endianness on exception entry */
if high vectors configured then
    PC = 0xFFFF0008
else
    PC = 0x00000008

To return after performing the SWI operation, use the following instruction to restore the PC
(from R14_svc) and CPSR (from SPSR_svc) and return to the instruction following the SWI:
    MOVS PC,R14

arch/arm/kernel/calls.S

/* 0 */		CALL(sys_restart_syscall)
		CALL(sys_exit)
		CALL(sys_fork_wrapper)
		CALL(sys_read)
		CALL(sys_write)
/* 5 */		CALL(sys_open)


    2)调用号和参数传递


关于如何传递对应的参数 struct pt_regs *regs,如何从C中调用汇编,会在Compliers中讨论。


arch/arm/include/asm/ptrace.h

/*
 * This struct defines the way the registers are stored on the
 * stack during a system call.  Note that sizeof(struct pt_regs)
 * has to be a multiple of 8.
 */
struct pt_regs {
	long uregs[18];
};

#define ARM_cpsr	uregs[16]
#define ARM_pc		uregs[15]
#define ARM_lr		uregs[14]
#define ARM_sp		uregs[13]
#define ARM_ip		uregs[12]
#define ARM_fp		uregs[11]
#define ARM_r10		uregs[10]
#define ARM_r9		uregs[9]
#define ARM_r8		uregs[8]
#define ARM_r7		uregs[7]
#define ARM_r6		uregs[6]
#define ARM_r5		uregs[5]
#define ARM_r4		uregs[4]
#define ARM_r3		uregs[3]
#define ARM_r2		uregs[2]
#define ARM_r1		uregs[1]
#define ARM_r0		uregs[0]
#define ARM_ORIG_r0	uregs[17]


arch/arm/kernel/entry-common.S

这个R0是struct pt_regs *regs?自己没看明白,希望哪位大侠告知下 (ATPCS)

entry-header.S (arch\arm\kernel):#define S_OFF		8

sys_fork_wrapper:
		add	r0, sp, #S_OFF
		b	sys_fork 



2    系统调用实现(策略)

arch/arm/kernle/sys_arm.c

/* Fork a new task - this creates a new program thread.
 * This is called indirectly via a small wrapper
 */
asmlinkage int sys_fork(struct pt_regs *regs)
{
#ifdef CONFIG_MMU
	return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
#else
	/* can not support in nommu mode */
	return(-EINVAL);
#endif
}

kernel/fork.c

/*
 *  Ok, this is the main fork-routine.
 *
 * It copies the process, and if successful kick-starts
 * it and waits for it to finish using the VM if required.
 */
long do_fork(unsigned long clone_flags,
	      unsigned long stack_start,
	      struct pt_regs *regs,
	      unsigned long stack_size,
	      int __user *parent_tidptr,
	      int __user *child_tidptr)
{
	struct task_struct *p;
	int trace = 0;
	long nr;

	/*
	 * Do some preliminary argument and permissions checking before we
	 * actually start allocating stuff
	 */
	if (clone_flags & CLONE_NEWUSER) {
		if (clone_flags & CLONE_THREAD)
			return -EINVAL;
		/* hopefully this check will go away when userns support is
		 * complete
		 */
		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) ||
				!capable(CAP_SETGID))
			return -EPERM;
	}

	/*
	 * We hope to recycle these flags after 2.6.26
	 */
	if (unlikely(clone_flags & CLONE_STOPPED)) {
		static int __read_mostly count = 100;

		if (count > 0 && printk_ratelimit()) {
			char comm[TASK_COMM_LEN];

			count--;
			printk(KERN_INFO "fork(): process `%s' used deprecated "
					"clone flags 0x%lx\n",
				get_task_comm(comm, current),
				clone_flags & CLONE_STOPPED);
		}
	}

	/*
	 * When called from kernel_thread, don't do user tracing stuff.
	 */
	if (likely(user_mode(regs)))
		trace = tracehook_prepare_clone(clone_flags);

	p = copy_process(clone_flags, stack_start, regs, stack_size,
			 child_tidptr, NULL, trace);
	/*
	 * Do this prior waking up the new thread - the thread pointer
	 * might get invalid after that point, if the thread exits quickly.
	 */
	if (!IS_ERR(p)) {
		struct completion vfork;

		trace_sched_process_fork(current, p);

		nr = task_pid_vnr(p);

		if (clone_flags & CLONE_PARENT_SETTID)
			put_user(nr, parent_tidptr);

		if (clone_flags & CLONE_VFORK) {
			p->vfork_done = &vfork;
			init_completion(&vfork);
		}

		audit_finish_fork(p);
		tracehook_report_clone(regs, clone_flags, nr, p);

		/*
		 * We set PF_STARTING at creation in case tracing wants to
		 * use this to distinguish a fully live task from one that
		 * hasn't gotten to tracehook_report_clone() yet.  Now we
		 * clear it and set the child going.
		 */
		p->flags &= ~PF_STARTING;

		if (unlikely(clone_flags & CLONE_STOPPED)) {
			/*
			 * We'll start up with an immediate SIGSTOP.
			 */
			sigaddset(&p->pending.signal, SIGSTOP);
			set_tsk_thread_flag(p, TIF_SIGPENDING);
			__set_task_state(p, TASK_STOPPED);
		} else {
			wake_up_new_task(p, clone_flags);
		}

		tracehook_report_clone_complete(trace, regs,
						clone_flags, nr, p);

		if (clone_flags & CLONE_VFORK) {
			freezer_do_not_count();
			wait_for_completion(&vfork);
			freezer_count();
			tracehook_report_vfork_done(p, nr);
		}
	} else {
		nr = PTR_ERR(p);
	}
	return nr;
}


3    Linux下添加一个系统调用

posted on 2012-08-18 21:43  梦想照进灵魂  阅读(526)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3