手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>网站运营>建站经验>列表

阅读笔记:如何给OpenSolaris增加一个系统调用

来源:互联网 作者:west263.com 时间:2008-04-16
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!

Note that declaring a buffer of 1024 bytes on the stack is a very bad thing to do in the kernel. We have limited stack space, and a stack overflow will result in a panic. We also don't check that the length of the string was less than our scratch space. But this will suffice for illustrative purposes. The cmn_err() function is the simplest way to display messages from the kernel.

注:
8. 第2步,实现系统调用函数。为避免修改Makefile,作者选择了在getpid.c文档里来增加新调用schrock,实现比较简单,就是在 console输出一个指定的字符 串。
9. 这个函数声明了一个1024字节的buffer,这个buffer是要在kernel的stack中分配的,由于kernel的stack空间是很有限 的,分配这么大的一个buffer是很不好的,stack的溢出是会导致系统panic的。通常,为避免耗尽kernel的stack,局部变量和嵌套函 数调用都要考虑占用stack的资源问 题。
10. 查看OpenSolaris的源代码能够看到,copyinstr()这 个函数是从用户空间将以空字符终止的字符串拷贝到内核空间中,函数原型如下:

copyinstr(const char *uaddr, char *kaddr, size_t maxlength,
size_t *lencopied);
其中,第1,2个参数分别是位于用户空间的源串和内核空间的目的串;第3个参数是目的串的长度;第4个参数写回实际拷贝的长度。
11. cmn_err()相 当于Linux的printk(),能够把内核消息输出到console上。

3. Adding an entry to the syscall table

We need to place an entry in the system call table. This table lives in sysent.c, and makes heavy use of macros to simplify the source. Our system call takes a single argument and returns an integer, so we'll need to use the SYSENT_CI macro. We need to add a prototype for our syscall, and add an entry to the sysent and sysent32 tables:

int     rename();
void rexit();
int schrock();
int semsys();
int setgid();

/* ... */

/* 54 */ SYSENT_CI("ioctl", ioctl, 3),
/* 55 */ SYSENT_CI("uadmin", uadmin, 3),
/* 56 */ SYSENT_CI("schrock", schrock, 1),
/* 57 */ IF_LP64(
SYSENT_2CI("utssys", utssys64, 4),
SYSENT_2CI("utssys", utssys32, 4)),

/* ... */

/* 54 */ SYSENT_CI("ioctl", ioctl, 3),
/* 55 */ SYSENT_CI("uadmin", uadmin, 3),
/* 56 */ SYSENT_CI("schrock", schrock, 1),
/* 57 */ SYSENT_2CI("utssys", utssys32, 4),

注:
12. 第3步,在系统调用表里增加一项。这个表就在sysent.c里, 为简化源代码这里使用了很多宏定义。
13. sysent和sysent32用 来存放系统调用表,可在sysent.c找 到如下说明:
/*
* This table is the switch used to transfer to the appropriate
* routine for processing a system call. Each row contains the
* number of arguments expected, a switch that tells systrap()
* in trap.c whether a setjmp() is not necessary, and a pointer
* to the routine.
*/
能够看出,事实上这个表里有每个系统调用的名称,该调用处理函数的指针,更有入口参数的个数。
sysent32用 于64位内核时,存放32位系统到调用的表结构。

14. 由于新增的调用返回值个数为1,且类型为int,在LP64和ILP32模式下都是32位的,因此使用宏SYSENT_CI,在sysent.c可 以找到相关的定义:
/* returns a 64-bit quantity for both ABIs */
#define SYSENT_C(name, call, narg) \
{ (narg), SE_64RVAL, NULL, NULL, (llfcn_t)(call) }

/* returns one 32-bit value for both ABIs: r_val1 */
#define SYSENT_CI(name, call, narg) \
{ (narg), SE_32RVAL1, NULL, NULL, (llfcn_t)(call) }

/* returns 2 32-bit values: r_val1 & r_val2 */
#define SYSENT_2CI(name, call, narg) \
{ (narg), SE_32RVAL1|SE_32RVAL2, NULL, NULL, (llfcn_t)(call) }
能够看到,根据系统调用的返回值的类型及个数,能够使用不同的宏定义,对于本例,需要使用SYSENT_CI。
SYSENT_CI的参数中,第1个是调用名字符串,第2个是函数指针llfcn指向的处理函数,第3个参数是参数的个数,因此除在sysent和sysent32表 中增加相应的项外,还需要声明一下schrock()函数。

4. /etc/name_to_sysnum

At this point, we could write a program to invoke our system call, but the point here is to illustrate everything that needs to be done to integrate a system call, so we can't ignore the little things. One of these little things is /etc/name_to_sysnum, which provides a mapping between system call names and numbers, and is used by dtrace(1M), truss(1), and friends. Of course, there is one version for x86 and one for SPARC, so you will have to add the following lines to both the intel and SPARC versions:

ioctl                   54

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!