WEB开发网
开发学院操作系统Linux/Unix 编写 AIX 内核扩展 阅读

编写 AIX 内核扩展

 2008-11-10 08:25:17 来源:WEB开发网   
核心提示:引言随着 AIX® Version 5.3 的引入,加之 Power 体系结构的飞快发展和 *nix 市场的增长,编写 AIX 内核扩展,全世界的开发人员对 AIX 产生了更大的兴趣,本文将帮助您在 AIX 中着手开发自己的内核扩展,清单 6. kctrl.c 的清单1 /* Controller App fo

引言

随着 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

Tags:编写 AIX 内核

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接