编写 AIX 内核扩展
2008-11-10 08:25:17 来源:WEB开发网引言
随着 AIX® Version 5.3 的引入,加之 Power 体系结构的飞快发展和 *nix 市场的增长,全世界的开发人员对 AIX 产生了更大的兴趣。本文将帮助您在 AIX 中着手开发自己的内核扩展。
通过使用内核扩展,AIX 内核提供了动态扩展其功能的接口。内核扩展是添加到内核以扩展其功能的例程。内核扩展是 AIX 内核体系结构中一个重要的部分,并且它们类似于其他平台上的可动态加载的模块,如 Linux®,这些模块可以为运行中的内核添加新的功能,而无需重新启动计算机。
内核扩展运行于内核保护域中。您可能在某些时候需要使用内核扩展,例如,需要创建自己的系统调用、内核进程或文件系统时。内核扩展与内核以相同的模式运行。如果内核运行于 64 位模式,那么扩展也必须能够运行于该模式。
本文面向那些希望在 AIX 中编写自己的内核扩展的读者。仅需要对 UNIX® 编程有基本的了解即可。
术语 kernext 有时用作内核扩展的缩写,尤其是在代码中。
关于内核扩展
添加的用于扩展 AIX 内核的例程可以分为下面的一些类别:
系统调用
虚拟文件系统
内核扩展和设备驱动程序管理内核服务
设备驱动程序
无论例程属于哪个类别,它们都称为内核扩展。
内核扩展的生命周期具有下面一些阶段,具体包括:
加载——这个阶段将内核扩展加载到内核内存中。
执行——这个阶段启动内核扩展的执行,并调用它的入口点。这是初始化过程。
通信——这个阶段与内核扩展进行通信。现在,该内核扩展正在进行它的工作。
终止——这个阶段将终止内核扩展。
卸载——这个阶段将内核扩展从内存中卸载。
sysconfig() 系统调用可用来控制这些阶段。sysconfig() 需要超级用户权限,并且它是管理内核扩展的基本应用程序编程接口 (API)。其声明如下:int sysconfig( (Defined in /usr/include/sys/sysconfig.h )
int cmd, /* function requested: load, unload, etc */
void *parmp, /* addr of struct containing info for cmd */
int parmlen /* length of parmp information */
);
sysconfig() 接受一个命令参数 (cmd),用于选择调用者所需的操作。
下面的表 1 中列举了一些常见的操作。有关完整的列表,请参阅 /usr/include/sys/sysconfig.h。
表 1. 常见操作
操作 | 描述 |
*) SYS_KLOAD | 将内核扩展目标文件加载到内核内存中。 |
*) SYS_SINGLELOAD | 如果尚未加载,则加载内核扩展目标文件。 |
*) SYS_QUERYLOAD | 确定是否加载了指定的内核目标文件。 |
*) SYS_KULOAD | 卸载以前加载的内核目标文件。 |
*) SYS_CFGKMOD | 出于配置的目的,从模块入口点处调用指定的模块。 |
您可以使用自定义命令代码,假设对它进行了正确的处理。您还可以使用 strload 命令加载或卸载内核扩展。通常,您需要编写自己的代码来加载您的内核扩展。
让我们来研究一些重要的结构:Struct cfg_load
当您加载或卸载内核扩展时,该结构将传递到 sysconfig()。这个结构在 /usr/include/sys/sysconfig.h 中定义为:
struct cfg_load
{
caddr_t path; /* ptr to object module pathname */
caddr_t libpath; /* ptr to a substitute libpath */
mid_t kmid; /* kernel module id (returned) */
};
struct cfg_load 的结构成员包括:
path——这个命令指定了您的内核扩展模块目标文件的路径名。
libpath——这个命令是搜索内核扩展目标文件的路径。如果该字段为 null,那么将使用 path 字段。
Kmid——这个命令包括内核模块 ID。根据该选项,传递到 sysconfig()。它可以由 sysconfig() 填充,或者必须将其传递到 sysconfig( )。
当您调用模块入口点时,Struct cfg_kmod 结构被传递到 sysconfig( )。Struct cfg_kmod 在 /usr/include/sys/sysconfig.h 中定义为:struct cfg_kmod {
mid_t kmid; /* module ID of module to call */
int cmd; /* command parameter for module */
caddr_t mdiptr; /* pointer to module dependent info */
int mdilen; /* length of module dependent info */
};
cfg_kmod 的结构成员包括:
kmid——这个命令指定了内核扩展模块 ID,模块加载后将返回该值。
cmd——这个命令为模块指定了命令。这可能是一个用户定义的值,或者可以来自 <sys/device.h>,正如下面的示例中所完成的工作。
mdiptr——这个命令用来将数据传递到内核扩展。
mdilen——这个命令包括 mdiptr 传入的数据的长度。
现在,让我们来研究一些实际的内容。
Hello World 内核扩展
您现在应该可以开始编写简单的“Hello World”内核扩展。您将编写两个程序:
控制器应用程序,用于控制和配置您的内核扩展
实际的 Hello World 内核扩展
要编译 Hello World 内核扩展的示例代码,只需在复制源代码的目录中输入 make。出于一些显著的安全性因素,只有 root 用户才能够加载或卸载内核扩展。因为加载的代码运行于内核模式,所以它可以访问系统中所有的内容。因此,即使是 root 用户拥有的 setuid 程序,也不能够加载内核扩展,您必须以 root 登录。请参见下面的清单 1。
清单 1. 控制器应用程序:kctrl.c
1 /* Controller App */
2
3 #include <stdio.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/sysconfig.h>
9 #include <sys/device.h>
10
11 int main(int argc, char *argv[])
12 {
13 struct cfg_kmod opt_kmod;
14 struct cfg_load opt_load, query_load;
15 struct stat statbuf;
16 char szKernExt[256], c;
17
18 /* Check if the user has appropriate privileges */
19 if (getuid() != 0) {
20 fprintf(stderr, " Not SuperUser.n");
21 exit(EACCES);
22 }
23
24 /* Check arguments */
25 if (argc != 2) {
26 printf ("Usage: %s <kernel_extension>n", argv[0]);
27 exit(EINVAL);
28 }
29
30 strcpy(szKernExt,argv[1]);
31
32 /* Check existence of file */
33 if (stat(szKernExt,&statbuf) != 0) {
34 perror("stat");
35 exit(errno);
36 }
37
38 /* Fill up the cfg_load structure */
39 opt_load.path = szKernExt; /* file name */
40 opt_load.libpath = NULL; /* no library */
41 opt_load.kmid = 0;
42
43 /* Perform various operations on the kernel extension */
44 while(1) {
45
46 fprintf (stderr, "n Enter choice, (l)oad, (u)nload, (i)nit, (t)erm,
(q)uery or (e)ndn");
47
48 while((c = getchar()) < 'a' && c > 'z') ; /* discard garbage */
49
50 switch(c) {
51
52 case 'l': /* load a kernel extension */
53
54 /* load kernel extension request */
55 if (sysconfig(SYS_KLOAD,&opt_load,sizeof(struct cfg_load)))
56 perror("sysconfig(SYS_KLOAD)"); /* print error message */
57 else /* otherwise */
58 printf("Extension Successfully loaded, kmid is %dn", opt_load.kmid);
59
60 break;
61
62 case 'i': /* Initialize a KernExt */
63
64 /* Initialize the kernel extension */
65 opt_kmod.kmid = opt_load.kmid;
66 opt_kmod.cmd = CFG_INIT;
67 opt_kmod.mdiptr = NULL;
68 opt_kmod.mdilen = 0;
69 if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct cfg_kmod)))
70 perror("sysconfig(SYS_CFGKMOD)"); /* print error message */
71 else
72 printf(" Extension Initialized n");
73
74 break;
75
76 /* Unload kernel extension */
77 case 'u':
78 /* Check if KernExt is loaded */
79 if (opt_load.kmid == 0)
80 printf("kernel Extension not loadedn");
81 else {
82 if (sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)))
83 perror("sysconfig(SYS_KULOAD)");
84 else
85 fprintf(stderr, "KernExt Successfully Unloaded n");
86 }
87
88 break;
89
90 /* Terminate the kernel extension */
91 case 't':
92
93 /* Check if KernExt is loaded */
94 if (opt_load.kmid == 0)
95 fprintf(stderr, "Extension not loadedn");
96 else {
97 opt_kmod.kmid = opt_load.kmid;
98 opt_kmod.cmd = CFG_TERM; /* Terminate the kernel extension */
99 opt_kmod.mdiptr = NULL;
100 opt_kmod.mdilen = 0;
101 if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct cfg_kmod)))
102 perror("sysconfig(SYS_CFGKMOD)"); /* print error */
103 else
104 fprintf(stderr, " KernExtension Terminated n");
105 }
106
107 break;
108
109
110 /* query kernel extension existence */
111 case 'q':
112
113 query_load.path = opt_load.path;
114 query_load.libpath = opt_load.libpath ;
115 query_load.kmid = 0;
116
117 if (sysconfig(SYS_QUERYLOAD,&query_load,sizeof(struct cfg_load)))
118 perror("sysconfig(SYS_QUERYLOAD)");
119 else
120 {
121 if(query_load.kmid > 0)
122 fprintf(stderr, " Extension is loaded, with kmid %d n",
query_load.kmid);
123 else
124 fprintf(stderr, " Extension is not loaded n");
125 }
126
127 break; /* done */
128
129
130 case 'e':
131 exit(0);
132
133
134 default:
135 fprintf(stderr, "Incorrect option n");
136 break;
137 }
138 getchar();
139 }
140
141 return 0;
142 }
现在您需要定义一些变量,特别是 struct cfg_kmod 和 struct cfg_load 类型的变量。struct cfg_kmod opt_kmod;
struct cfg_load opt_load, query_load;
加载内核扩展
首先,要加载内核扩展,您需要调用带 SYS_KLOAD 命令参数的 sysconfig。传递 opt_load 和 sizeof(struct cfg_load):sysconfig(SYS_KLOAD,&opt_load,sizeof(struct cfg_load))
在成功调用 sysconfig 之后,您可以得到 kmid,并显示在屏幕上。
使用内核扩展的路径填充 cfg_load 结构:opt_load.path = szKernExt;
将 libpath 设置为 NULL,因为在本示例中,并不依赖于任何非系统定义的库:opt_load.libpath = NULL;
将 kmid 字段初始化为 0:opt_load.kmid = 0;
如下所示,执行其代码:[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
l
Extension Successfully loaded, kmid is 49033924
使用 genkex 命令,您可以查看系统中已加载的内核扩展的列表:[root@aix1] genkex
Text address Size File
2ec3000 2d8 ./kernext_hello
<Snip>
初始化内核扩展
在加载了内核扩展之后,调用 sysconfig( ) 以使用 CFG_INIT 命令调用其入口点。
控制器应用程序使用了 sysconfig() 例程。如下所示,填充 struct cfg_kmod opt_kmod:opt_kmod.kmid = opt_load.kmid;
opt_kmod.cmd = CFG_INIT;
opt_kmod.mdiptr = NULL;
opt_kmod.mdilen = 0;
将内核扩展的标识符填入 kmid 字段,在上一次调用 sysconfig( ) 时可以获得该内核扩展标识符。
CFG_INIT 命令为内核扩展调用入口点。现在,没有向内核扩展传递任何参数,因此,mdiptr 为 NULL。Mdilen 包含 mdiptr 的长度。
在示例内核扩展中,我们添加了将输出结果打印到 syslog 文件的例程。检查您系统中的 syslog 输出,它的输出应该与下面所示类似:
Apr 3 08:22:40 aix1 kern:debug unix: Enter hello_init:: command = 0x1
Apr 3 08:22:40 aix1 kern:debug unix: Initializing Hello World KernExt
查询内核扩展
您可以使用 struct cfg_load 来查询扩展是否已经加载。您可以使用 query_load 变量来完成该任务。
现在,根据 opt_load 变量的值填充 path 和 libpath,并调用带 SYS_QUERYLOAD 参数的 sysconfig 命令,如下所示:query_load.path = opt_load.path;
query_load.libpath = opt_load.libpath ;
query_load.kmid = 0;
如果该内核扩展已加载,那么 kmid 字段中包含了这个内核扩展的 kmid,其值始终大于 0。如下所示,您得到了该内核扩展的 kmid:[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
q
Extension is loaded, with kmid 49033924
终止内核扩展
要终止内核扩展,可以使用嵌入在 struct cfg_kmod 中的 CFG_TERM 命令来调用 sysconfig()。然后,如下所示,将相应的值填入 opt_kmod 变量:opt_kmod.kmid = opt_load.kmid;
opt_kmod.cmd = CFG_TERM;
opt_kmod.mdiptr = NULL;
opt_kmod.mdilen = 0;
现在已经有了 kmid,可以将 CFG_TERM 填入该命令,如下所示:[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
t
KernExtension Terminated
在 syslog 的输出中,您将看到下面的几行内容:Apr 3 08:22:43 fsaix9 kern:debug unix: Enter hello_init:: command = 0x2
Apr 3 08:22:43 fsaix9 kern:debug unix: Terminating Hello World KernExt
卸载内核扩展
要卸载内核扩展,可以调用带 SYS_KULOAD 参数的 sysconfig,并且传递 struct cfg_load,该结构已填入了 path 和 kmid 字段,如下所示:sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)
要卸载内核扩展,可以使用选项“u”并选择 Enter,如下所示:[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
u
KernExt Successfully Unloaded
在使用 sysconfig() 时请多加小心,不正确的 kmid 值可能会使系统崩溃(请参见清单 2)。
清单 2. Hello World 内核扩展:kernext_hello.c
1 /* A Hello World Kernel Extension */
2 #include <errno.h>
3 #include <syslog.h>
4 #include <sys/device.h>
5
6
7
8 int hello_init(int cmd, struct uio *uio)
9 {
10
11 bsdlog(LOG_DEBUG | LOG_KERN, "Enter hello_init::? command = 0x%x n",cmd);
12
13 if (cmd == CFG_INIT)
14 bsdlog(LOG_DEBUG | LOG_KERN, " Initializing Hello World KernExt n");
15 else if (cmd == CFG_TERM)
16 bsdlog(LOG_DEBUG | LOG_KERN, " Terminating Hello World KernExt n");
17 else
18 bsdlog(LOG_DEBUG | LOG_KERN, " Unknown command to Adv KernExt n");
19
20
21 return 0;
22 }
内核扩展没有 main() 例程,相反,它包含一个入口点,当通过 sysconfig() 使用 SYS_CFGKMOD 发出 CFG_INIT 命令时,控制器应用程序将调用这个入口点。
在这个内核扩展示例中,只有一个函数,即内核扩展入口点 hello_init()。该入口点有两个参数,其中包括一个整数,该整数是从 sysconfig() 传入的嵌入在 struct cfg_kmod 中的命令参数。另一个参数是 struct uio,它用于将数据传递到该内核扩展。在 Hello World 内核扩展中,没有像前面的部分那样使用 struct uio。
在缺省情况下,入口点的名称必须是 __start( )。如果要指定另一个名称,如本示例所示,您需要在编译您的内核扩展时加以指定。
Hello World 内核扩展告知收到相应的命令,并将其打印出来。它使用 bdslog() 进行打印。bsdlog 的第 1 个参数是优先级。这里使用了两种标志来表示优先级:
LOG_DEBUG 告诉 syslog,这是一则调试消息
LOG_KERN 告诉 syslog,这则消息来自内核
要获得日志消息,请确保配置了 syslogd。
例如,在 /etc/syslog.conf 中,可以添加如下内容:*.debug /tmp/syslog.out rotate size 100k files 4
然后添加 ps –aef | grep syslog,并对其提供 kill –HUP。
下面的清单 3 中的编译过程是用于 Hello World 内核扩展的 Makefile。
清单 3. Hello World 内核扩展的 Makefile
1 all: kernext_hello kctrl
2
3 kctrl: kctrl.c
4 cc -o kctrl kctrl.c
5
6
7 kernext_hello: kernext_hello.c
8 cc -q32 -o kernext_hello32.o -c kernext_hello.c
9 ld -b32 -o kernext_hello32 kernext_hello32.o -e hello_init
-bI:/usr/lib/kernex.exp -lsys -l csys
10 cc -q64 -o kernext_hello64.o -c kernext_hello.c
11 ld -b64 -o kernext_hello64 kernext_hello64.o -e hello_init
-bI:/usr/lib/kernex.exp -lsys -l csys
12 rm -f kernext_hello
13 ar -X32_64 -r -v kernext_hello kernext_hello32 kernext_hello64
14
15 clean:
16 rm -f *.o kernext_hello kernext_hello32 kernext_hello64 kctrl 2> /dev/null
在这个 Makefile 中,有两个目标:控制器应用程序和 Hello World 内核扩展。
用于控制器应用程序的命令非常简单,其中使用 -o 选项指定了目标文件:4 cc -o kctrl kctrl.c
编译内核扩展
先对内核扩展进行编译,然后进行连接。正如前面提到的,如果内核扩展的缺省入口点不是 __start,那么必须使用带 -e 开关的连接程序 ld 对其进行指定。
请注意,该内核扩展不应该使用 cc 进行编译,应该在最后的连接步骤中使用 ld。
要编译 32 位和 64 位版本的内核扩展,可以分别使用 –q32 和 –q64 标志。
在本示例中,内核扩展入口点不是 __start(),所以使用 –e 开关标识该入口点。因为您在内核扩展中使用了从内核导出的符号,所以需要使用 -bI:/usr/lib/kernex.exp 指定这个依赖关系,该依赖关系可以指向相应的文件。
AIX 提供了两个库 libsys.a 和 libcsys.a,内核扩展可以使用这两个库。您可以使用 –lsys 和 –lcsys 开关将这两个库连接到您的内核扩展。
支持 32 和 64 位
AIX 运行于 32 和 64 位模式,并且它具有双模式 内核扩展。双模式内核扩展可用于简化运行于 32 和 64 位内核的内核扩展的加载。双模式内核扩展是一个存档文件,其中包含了 32 和 64 位版本的内核扩展作为其成员。当 sysconfig 或 kmod_load 调用中指定的路径名为存档时,加载器将加载目标模式与内核的执行模式相匹配的第 1 个存档成员。在 Hello World 内核扩展中,您建立了 32 和 64 位内核扩展的双模式内核扩展。
AIX 内核扩展的复杂之处在于它识别内核扩展的方式。AIX 根据内核扩展的路径名来辨认这些内核扩展。如果您使用不同的路径来调用内核扩展,如绝对路径(假设您位于 /tmp 目录):[root@aix1] ./kctrl /tmp/kernext_hello
而下一次使用相对路径:[root@aix1] ./kctrl ./kernext_hello
那么这两个内核扩展的示例将被内核作为不同的 内核扩展对待。
高级内核扩展
本部分内容将研究更高级一些的内核扩展。通过将新的系统调用列举到一个导出文件,并附加上 syscall 标签,内核扩展可以为内核添加新的系统调用或接管现有的系统调用。当加载这样的扩展时,将创建系统调用表的新副本。
您将编写两个与将添加到运行中的内核的系统调用有关的文件。一个用来导出系统调用符号 (demo_syscall.exp),另一个包含系统调用的定义 (demo_syscall.c),即控制器程序 (kctrl.c),用来控制新的系统调用的加载和卸载,一个使用新的系统调用的示例程序 (invoke_syscall.c),而一个编译所有这些程序的 Makefile,如下面的清单 4 所示。
清单 4. demo_syscall.exp 文件
1 #!/unix
2 demo_syscall syscall
在这个文件中,仅导出了正在定义的系统调用符号,如下面的清单 5 所示。
清单 5. 系统调用符号
1 /* A bit advanced kernext */
2
3 #include <stdio.h>
4 #include <errno.h>
5 #include <syslog.h>
6 #include <sys/device.h>
7
8 int demo_syscall_init(int cmd, struct uio *uio)
9 {
10 int iErr = 0;
11
12 bsdlog(LOG_DEBUG | LOG_KERN, "demo_syscall_init:? command = 0x%x n",cmd);
13
14 if (cmd == CFG_INIT) {
15
16 bsdlog(LOG_DEBUG | LOG_KERN, " Loading Adv KernExt n");
17 if(iErr = pincode(demo_syscall_init))
18 return iErr;
19
20 } else if (cmd == CFG_TERM) {
21
22 bsdlog(LOG_DEBUG | LOG_KERN, " UnLoading Adv KernExt n");
23 if(iErr = unpincode(demo_syscall_init))
24 return iErr;
25
26 } else {
27 bsdlog(LOG_DEBUG | LOG_KERN, " Unknown command to Adv KernExt n");
28 return -1;
29 }
30
31 return 0;
32 }
33
34 /* Implementation of the demo syscall */
35 demo_syscall(int arg)
36 {
37 return(arg + 25);
38 }
新的系统调用非常简单。它仅仅只是将传入的参数加上 25,然后返回这个和(请参见清单 6)。
清单 6. kctrl.c 的清单
1 /* Controller App for KernExt */
2
3 #include <stdio.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/sysconfig.h>
9 #include <sys/device.h>
10
11 int main(int argc, char *argv[])
12 {
13 struct cfg_kmod opt_kmod;
14 struct cfg_load opt_load, query_load;
15 struct stat statbuf;
16 char szKernExt[256], c;
17
18 /* Check if the user has appropriate privileges */
19 if (getuid() != 0) {
20 fprintf(stderr, " Not SuperUser.n");
21 exit(EACCES);
22 }
23
24 /* Check arguments */
25 if (argc != 2) {
26 printf ("Usage: %s <kernel_extension>n", argv[0]);
27 exit(EINVAL);
28 }
29
30 strcpy(szKernExt,argv[1]);
31
32 /* Check existence of file */
33 if (stat(szKernExt,&statbuf) != 0) {
34 perror("stat");
35 exit(errno);
36 }
37
38 /* Fill up the cfg_load structure */
39 opt_load.path = szKernExt; /* file name */
40 opt_load.libpath = NULL; /* no library */
41 opt_load.kmid = 0;
42
43 /* Perform various operations on the kernel extension */
44 while(1) {
45
46 fprintf (stderr, "n Enter choice, (l)oad, (u)nload, (i)nit, (t) erm,
(q)uery or (e)ndn");
47
48 while((c = getchar()) < 'a' && c > 'z') ; /* discard garbage */
49
50 switch(c) {
51
52 case 'l': /* load a kernel extension */
53
54 /* load kernel extension request */
55 if (sysconfig(SYS_KLOAD,&opt_load,sizeof(struct cfg_load)))
56 perror("sysconfig(SYS_KLOAD)"); /* print error message */
57 else
58 printf("Extension Successfully loaded, kmid is %dn", opt_load.kmid);
59
60 break;
61
62 case 'i': /* Initialize a KernExt */
63
64 /* Initialize the kernel extension */
65 opt_kmod.kmid = opt_load.kmid;
66 opt_kmod.cmd = CFG_INIT;
67 opt_kmod.mdiptr = NULL;
68 opt_kmod.mdilen = 0;
69 if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct cfg_load)) )
70 perror("sysconfig(SYS_CFGKMOD)"); /* print error message */
71 else
72 printf(" Extension Initialized n");
73
74 break;
75
76 /* Unload kernel extension */
77 case 'u':
78 /* Check if KernExt is loaded */
79 if (opt_load.kmid == 0)
80 printf("kernel Extension not loadedn");
81 else {
82 if (sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)))
83 perror("sysconfig(SYS_KULOAD)");
84 else
85 fprintf(stderr, "KernExt Successfully Unloaded n");
86 }
87
88 break;
89
90 /* Terminate the kernel extension */
91 case 't':
92
93 /* Check if KernExt is loaded */
94 if (opt_load.kmid == 0)
95 fprintf(stderr, "Extension not loadedn");
96 else {
97 opt_kmod.kmid = opt_load.kmid;
98 opt_kmod.cmd = CFG_TERM; /* Terminate the kernel extension */
99 opt_kmod.mdiptr = NULL;
100 opt_kmod.mdilen = 0;
101 if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct cfg_kmod)))
102 perror("sysconfig(SYS_CFGKMOD)"); /* print error */
103 else
104 fprintf(stderr, " KernExtension Terminated n");
105 }
106
107 break;
108
109
110 /* query kernel extension existence */
111 case 'q':
112
113 query_load.path = opt_load.path;
114 query_load.libpath = opt_load.libpath ;
115 query_load.kmid = 0;
116
117 if (sysconfig(SYS_QUERYLOAD,&query_load,sizeof(struct cfg_load)))
118 perror("sysconfig(SYS_QUERYLOAD)");
119 else
120 {
121 if(query_load.kmid > 0)
122 fprintf(stderr, " Extension is loaded, with kmid %d n",
query_load.kmid);
123 else
124 fprintf(stderr, " Extension is not loaded n");
125 }
126 break;
127
128 case 'e':
129 exit(0);
130
131
132 default:
133 fprintf(stderr, "Incorrect option n");
134 break;
135 }
136 getchar();
137 }
138
return 0;
140 }
清单 7 是处理内核扩展加载和卸载的控制器程序。
清单 7. invoke_syscall.c 的清单
1 /* Call the implemented Demo system call */
2 #include <stdio.h>
3
4 int main()
5 {
6 int iVal = 0;
7
8 fprintf(stderr, " Invoking demo syscall n");
9
10 if ( (iVal = demo_syscall(99)) < 0)
11 {
12 perror("demo_syscall error");
13 exit(1);
14 }
15
16 fprintf(stderr, " Got Value - %dn",iVal);
17
18
19 return 0;
20 }
这只是一个使用新的系统调用的示例程序。
下面的清单 8 是编译高级内核扩展中所有程序的 Makefile。
清单 8. 编译高级内核扩展中所有程序的 Makefile
1 all: demo_syscall invoke_syscall kctrl
2
3 kctrl: kctrl.c
4 cc -o kctrl kctrl.c
5
6 invoke_syscall: invoke_syscall.c
7 cc -o invoke_syscall -bI:demo_syscall.exp invoke_syscall.c
8
9 demo_syscall: demo_syscall.c
10 cc -q32 -o demo_syscall32.o -qlist -qsource -c demo_syscall.c
11 mv demo_syscall.lst demo_syscall32.lst
12 ld -b32 -o demo_syscall32 demo_syscall32.o -e demo_syscall_init
-bI:/usr/lib/kernex.exp -bE:demo_syscall.exp -lsys -l csys
13 cc -q64 -o demo_syscall64.o -qlist -qsource -c demo_syscall.c
14 mv demo_syscall.lst demo_syscall64.lst
15 ld -b64 -o demo_syscall64 demo_syscall64.o -e demo_syscall_init
-bI:/usr/lib/kernex.exp -bE:demo_syscall.exp -lsys -l csys
16 rm -f demo_syscall
17 ar -X32_64 -r -v demo_syscall demo_syscall32 demo_syscall64
18
19 clean:
20 rm -f *.o invoke_syscall demo_syscall demo_syscall32 demo_syscall64 kctrl
demo_syscall64.lst demo_syscall32.lst 2> /dev/null
更多精彩
赞助商链接