现在的位置: 首页 >> 操作系统 >> FreeBSD >> FreeBSD 5内核源代码分析之系统调用过程
添加时间:2005-8-21 来源:网教中国 作者:
FreeBSD 5内核源代码分析之系统调用过程


if (p->p_sysent->sv_mask)
code &= p->p_sysent->sv_mask;

对系统调用号做一些调整和限制。

代码:

if ( code >= p->p_sysent->sv_size)
callp = &p->p_sysent->sv_table[0];
else
callp = &p->p_sysent->sv_table[_code];

得到系统调用的函数入口。

代码:

narg = callp->sy_narg & SYF_ARGMASK;

得到该系统调用的参数个数。

代码:

/*
* copyin and the ktrsyscall()/ktrsysret() code is MP-aware
*/
if (params != NULL && narg != 0)
error = copyin(params, (caddr_t)args,
(u_int)(narg * sizeof(int)));
else
error = 0;

将参数从用户态拷贝到内核态的args中。

代码:

#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, narg, args);
#endif

/*
* Try to run the syscall without Giant if the syscall
* is MP safe.
*/
if ((callp->sy_narg & SYF_MPSAFE) == 0)
mtx_lock(&Giant);

如果该系统调用不是MP安全的,则获取全局锁。

代码:

if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame.tf_edx;

STOPEVENT(p, S_SCE, narg);

PTRACESTOP_SC(p, td, S_PT_SCE);

error = (*callp->sy_call)(td, args);
}

调用具体的系统调用。
这里,之所以要间接地使用一个系统调用函数表,是因为模拟其他操作系统的
需要。同一个系统调用在不同的操作系统里"系统调用号"是不同的,当运行其他
操作系统的应用程序时,因为其编译结果是用其他操作系统的"系统调用号",
此时需要转换到相应的FreeBSD的"系统调用号"上来,使用系统调用函数表就可以
方便地作到这一点。

代码:

switch (error) {
case 0:
frame.tf_eax = td->td_retval[0];
frame.tf_edx = td->td_retval[1];
frame.tf_eflags &= ~PSL_C;
break;

Great,调用成功,设置返回值,并清除carry bit,用户态的libc要根据carry bit
判断系统调用是否成功。

代码:

case ERESTART:
/*
* Reconstruct pc, assuming lcall $X,y is 7 bytes,
* int 0x80 is 2 bytes. We saved this in tf_err.
*/
frame.tf_eip -= frame.tf_err;
break;

系统调用返回ERESTART,内核要尝试重新执行系统调用,因此需要将返回用户空间后的
%eip后退,具体后退几个字节,跟系统调用的进入方式有关,如果是通过int 0x80进入的,
由于int 0x80指令的长度为两个字节,因此回退2字节,如果是通过lcall $X,y方式进入
内核的,由于lcall $X,y指令的长度为7个字节,因此回退7字节。具体几个字节,在刚进入
时已经压到堆栈上了(前述pushl $2即是)。

代码:

case EJUSTRETURN:
break;

default:
if (p->p_sysent->sv_errsize) {
if (error >= p->p_sysent->sv_errsize)
error = -1; /* XXX */
else
error = p->p_sysent->sv_errtbl[error];
}
frame.tf_eax = error;
frame.tf_eflags |= PSL_C;
break;
}

如果系统调用返回其他错误的话,则在进程的一个错误对应表中转换错误号。
并设置carry bit,以便libc知道。

代码:

/*
* Release Giant if we previously set it.
*/
if ((callp->sy_narg & SYF_MPSAFE) == 0)
mtx_unlock(&Giant);

释放全局锁。



上一页 [1] [2] [3] [4]  下一页


代码:

/*
* Traced syscall.
*/
if ((orig_tf_eflags & PSL_T) && !(orig_tf_eflags & PSL_VM)) {
frame.tf_eflags &= ~PSL_T;
trapsignal(td, SIGTRAP, 0);
}
上一篇:FreeBSD 5内核源代码分析之copyin()实现原理 下一篇:FreeBSD 5 内核源代码分析之中断处理
大部分文章摘自网上,如有侵犯您的权益请与我们联系,我们会第一时间进行处理,谢谢! [ 打印文章 ] [ 关闭窗口 ]
推荐文章
·FreeBSD handbook中文版 9 配制F
·FreeBSD 升级系统
·Ports & Package
·FreeBSD kernel 编译大法(二)ker
·FreeBSD 上使用Kerberos 5认证
·FreeBSD 5.x 中 gbfs 的修正,及
·FreeBSD 安装Linuxigd
·FreeBSD 使用cvsd创建安全的cvs
·FreeBSD trafcount命令介绍
·FreeBSD入门安装及汉化
相关文章
·FreeBSD 5内核源代码分析之copyi
最新文章
·FreeBSD连载(94):基于NAT的负载
·FreeBSD连载(93):反向代理负载
·FreeBSD连载(92):基于DNS的负载
·FreeBSD连载(91):提升静态网页
·FreeBSD连载(90):单服务器性能
·FreeBSD连载(89):CGI和SSI的安
·FreeBSD连载(88):安全连接方式S
·FreeBSD连载(87):基于用户的访
·FreeBSD连载(86):对IP地址和域
·FreeBSD连载(85):配置Apache服(
Google