Writing AIX kernel extensions

Extend your reach

Learn how to use the AIX kernel to build routines to extend functions and create your own system calls, kernel processes, or file systems. The rapid improvements in Power architecture, combined with the enhancements of AIX® Version 5.3, have caused more interest than ever in AIX. This article shows you, with extensive examples, how to tap into the power of kernel extensions on AIX.

Sandesh Chopdekar, Software Engineer, IBM

Photo of Sandesh ChopdekarSandesh Chopdekar works as a Staff Software Engineer for IBM, specializing in distributed filesystems and networking. Prior to joining IBM, Sandesh worked for a subsidiary of Citicorp. He holds a BS degree in chemistry from Mumbai University.



Avinesh Kumar (avineshkarn@in.ibm.com), Software Engineer, IBM

Photo of Avinesh KumarAvinesh Kumar works as a System Software Engineer for the Andrew File System Team at the IBM Software Labs in Pune, India. He works with kernel- and user-level debugging of dumps and crashes, as well as reported bugs on the Linux, AIX, and Solaris platforms. Avinesh has an MCA from the Department of Computer Science at the University of Pune. He is a Linux enthusiast who spends his spare time exploring the Linux kernel on his Fedora Core 6 box.


developerWorks Contributing author
        level

15 August 2006

Also available in Chinese

Introduction

With the introduction of AIX® Version 5.3, coupled with the rapid improvements in Power architecture and its growth in the *nix market, worldwide developers are becoming more interested in AIX. This article helps you get started on developing your own kernel extensions on AIX.

The AIX kernel provides the interface to dynamically extend its functions by using kernel extensions. Kernel extensions are routines added to the kernel to extend its functions. Kernel extensions are an important part of the AIX kernel architecture, and they are similar to dynamically loadable modules available on other platforms, such as Linux®, that add function to the running kernel without the need of a machine reboot.

Kernel extensions run in the kernel protection domain. You might need a kernel extension if, for example, you need to create your own system call, kernel processes, or file system. A kernel extension runs in the same mode as the kernel. If the kernel is running in 64-bit mode, the extension must also be able to run in that mode.

This article is for anyone who wants to write their own kernel extension on AIX. Only a basic understanding of UNIX® programming is required.

The term kernext is occasionally used as an abbreviation for kernel extension, especially in the code.


About kernel extensions

The routines added to extend an AIX kernel might fall into the following categories:

  • System calls
  • Virtual file systems
  • Kernel extension and device driver management kernel services
  • Device drivers

Regardless of the category the routine falls into, they are called kernel extensions.

The life cycle of a kernel extension has the following phases, including:

  • Loading -- This phase loads the kernel extension in kernel memory.
  • Executing -- This phase starts the execution of the kernel extension and calls its entry point. This is the initialization.
  • Communicating -- This phase communicates with the kernel extension. Now the kernel extension is doing its job.
  • Terminating -- This phase terminates the kernel extension.
  • Unloading -- This unloads the kernel extension from memory.

The sysconfig() system call is used to control these phases. sysconfig( needs super-user privileges, and it is the primary application programming interface (API) for managing kernel extensions. Its declaration is:

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() takes a command (cmd) parameter that selects the action the caller wants.

Some common actions are listed in Table 1 below. For the exhaustive list, see /usr/include/sys/sysconfig.h.

Table 1. Common actions
ActionDescription
*) SYS_KLOADLoads a kernel extension object file in kernel memory.
*) SYS_SINGLELOAD Loads a kernel extension object file only if it is not already loaded.
*) SYS_QUERYLOADDetermines if a specified kernel object file is loaded.
*) SYS_KULOAD Unloads a previously loaded kernel object file.
*) SYS_CFGKMODCalls the specified module at its module entry point for configuration purposes.

You can use your own custom command code, provided it is handled properly. You can also use the strload command to load, or unload, a kernel extension. Generally, you have to write your own code to load your kernel extension.

Let's have a look at some of the important structures involved:

Struct cfg_load

This structure is passed to sysconfig() when you load, or unload, a kernel extension. This structure is defined in /usr/include/sys/sysconfig.h as:

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) */
  };

The structure members of struct cfg_load are:

  • path -- This command specifies the pathname of the object file of your kernel extension module.
  • libpath -- This command is the path to be searched for the kernel extension object file. If this field is null, the path field is used instead.
  • Kmid -- This command contains the kernel module ID. Depending on the option, you pass to sysconfig(). It is either filled by sysconfig(), or it has to be passed to sysconfig( ).

The Struct cfg_kmod structure is passed to sysconfig( ) when you invoke the module entry point. Struct cfg_kmod is defined in /usr/include/sys/sysconfig.h as:

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 */
};

The structure members of cfg_kmod are:

  • kmid -- This command specifies the kernel extension module ID, which is returned after a module is loaded.
  • cmd -- This command specifies the command for the module. This can be a user-defined value, or can be taken from <sys/device.h>, as you have done in the example below.
  • mdiptr -- This command is used to pass data to the kernel extension.
  • mdilen -- This command contains the length of the data passed in mdiptr.

Now let's move on to something tangible.


A Hello World kernel extension

You should now be able to start writing a simple "Hello World" kernel extension. You'll write two programs:

To compile the sample code for a Hello World kernel extension, just type make in the directory where you've copied the source code. For obvious security reasons, only the root user can load, or unload, kernel extensions. Since the loaded code runs in kernel mode, it has complete access to anything on the system. Thus, even a setuid program, owned by root, is not enough to load a kernel extension -- you must be logged in as root. See Listing 1 below.

Listing 1. The controller application: 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)nd\n");
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 %d\n", 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 loaded\n");
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 loaded\n");
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 }

Now you need to define variables of type, in particular, struct cfg_kmod and struct cfg_load.

struct  cfg_kmod    opt_kmod;
struct  cfg_load    opt_load, query_load;

Loading the kernel extension

Initially, to load the kernel extension, you need to call sysconfig with the SYS_KLOAD command parameter. You pass opt_load and sizeof(struct cfg_load) as:

sysconfig(SYS_KLOAD,&opt_load,sizeof(struct cfg_load))

After a successful call to sysconfig, you get the kmid, which gets printed on the screen.

You fill up the cfg_load structure with the path for the kernel extension:

opt_load.path = szKernExt;

You set the libpath to NULL because, in this case, you are not depending on any nonsystem defined library:

opt_load.libpath = NULL;

You initialize the kmid field to zero:

opt_load.kmid = 0;

Execute the code, as shown below:

[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

You can view the list of the loaded kernel extension on your system using the genkex command:

[root@aix1] genkex 
Text address     Size File
2ec3000      2d8 ./kernext_hello 
<Snip>

Initializing the kernel extension

After loading your kernel extension, you call sysconfig( ) to invoke its entry point using the CFG_INIT command.

The controller application uses the sysconfig() routine. You fill in the struct cfg_kmod opt_kmod, as shown below:

opt_kmod.kmid = opt_load.kmid;
opt_kmod.cmd = CFG_INIT;
opt_kmod.mdiptr = NULL;
opt_kmod.mdilen = 0;

You'll fill in the kmid field with the identifier of the kernel extension, which you got from your previous call to sysconfig( ).

The CFG_INIT command invokes the entry point for the kernel extension. For now, you aren't passing any arguments to the kernel extension, hence, mdiptr is NULL. Mdilen contains the length of mdiptr.

In the sample kernel extension, we've added routines that print the output in the syslog file. Check the syslog output on your system; it should have output similar to the one below:

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

Querying the kernel extension

You can query whether your extension is loaded or not using struct cfg_load. You can use the query_load variable to do this.

Now fill in the path and libpath values from the opt_load variable and call sysconfig with the command SYS_QUERYLOAD, as shown below:

query_load.path     = opt_load.path;
query_load.libpath  = opt_load.libpath ;
query_load.kmid     = 0;

If the kernel extension is loaded, the kmid field has the kmid of the kernel extension, which is always greater than zero. As shown below, you get the kmid of your kernel extension:

[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

Terminating the kernel extension

To terminate the kernel extension, call sysconfig() with the CFG_TERM command embedded in struct cfg_kmod. Then fill in the opt_kmod variable with the values, as shown below:

opt_kmod.kmid = opt_load.kmid;
opt_kmod.cmd  = CFG_TERM;
opt_kmod.mdiptr = NULL;
 opt_kmod.mdilen = 0;

Now you have the kmid, and you can fill in the command as CFG_TERM, as shown below:

[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
t
KernExtension Terminated

In the syslog output, you would see the lines below:

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

Unloading the kernel extension

To unload your kernel extension, you call sysconfig with the SYS_KULOAD parameter and pass struct cfg_load, which has the path and kmid field filled in, as shown below:

sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)

To unload the kernel extension, use the option "u" and select Enter, as follows:

[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
u
KernExt Successfully Unloaded

Be careful while using sysconfig(); incorrect values for kmid could crash the system (see Listing 2).

Listing 2. Hello World kernel extension: 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  }

A kernel extension has no main() routine; instead it has an entry point, which is invoked by the controller application when the CFG_INIT command is issued using SYS_CFGKMOD with sysconfig().

In the kernel extension sample, you have only one function, the kernel extension entry point, which is hello_init(). The entry point has two arguments and an integer, which is the command parameter passed from sysconfig(), which is embedded in struct cfg_kmod. The other parameter is struct uio, which is used to pass data to the kernel extension. In the Hello World kernext, you are not using struct uio, as shown in the previous section.

By default, the name of the entry point needs to be __start( ). If you specify a different name, as in this case, you need to specify that while building your kernel extension.

The Hello World kernel extension acknowledges receipt of the commands, and it prints them out. It uses bdslog() to print. The first argument to bsdlog is the priority. You are using two flags for the priority:

  • LOG_DEBUG, which tells syslog that this is a debug message
  • LOG_KERN, which tells syslog that this message is from the kernel

To get the log message, make sure that syslogd is configured.

For example, in /etc/syslog.conf, you can add something like:

*.debug         /tmp/syslog.out     rotate size 100k files 4

Then ps –aef | grep syslog, and give it kill –HUP.

The build process in Listing 3 below is the Makefile for the Hello World kernel extension.

Listing 3. Makefile for the Hello World kernel extension
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

In the Makefile, you have two targets: the controller application and the Hello World kernel extension.

The command for the controller application is quite straightforward, where you specify the object file using the -o option:

4     cc -o kctrl kctrl.c

Building a kernel extension

Kernel extensions are compiled, and then linked. As mentioned, if the default entry point of a kernel extension is other than __start, it has to be specified by -e switched to linker ld.

Note that kernel extensions should not be built with cc; ld should be used in the final link step.

To build a 32-bit and a 64-bit version of the kernel extension, use the –q32 and –q64 flags, respectively.

In this case, the kernel extension entry point is not __start(), so use the –e switch to identify the entry point. Since you use symbols exported from the kernel in your kernel extension, you specify that dependency using -bI:/usr/lib/kernex.exp, which points to the file.

AIX provides two libraries, libsys.a and libcsys.a, that can be used by a kernel extension. You can link these two libraries using –lsys and –lcsys switches in your kernel extension.

Supporting 32- and 64-bit

AIX runs in 32- and 64-bit modes, and it has dual-mode kernel extensions. Dual-mode kernel extensions can be used to simplify the loading of kernel extensions that run on both the 32- and 64-bit kernels. A dual-mode kernel extension is an archive file that contains both the 32- and 64-bit versions of the kernel extension as members. When the pathname specified in the sysconfig or kmod_load call is an archive, the loader loads the first archive member whose object mode matches the kernel's execution mode. In the Hello World kernel extension, you make a dual-mode kernel extension out of the 32- and 64-bit kernel extension.

One intricacy of an AIX kernel extension is in the way it identifies kernel extensions. AIX recognizes the kernel extensions based on their path names. If you invoke your kernel extension, use different paths, such as an absolute path (assume you are in the /tmp directory):

[root@aix1] ./kctrl  /tmp/kernext_hello

And again with:

[root@aix1] ./kctrl ./kernext_hello

Both of these instances of kernel extensions will be treated as different kernel extensions by the kernel.


An advanced kernel extension

This section looks at a bit more advanced kernel extension. Kernel extensions can add new system calls to the kernel, or take over existing ones, simply by listing the new system calls in an export file, with the syscall tag attached. When such an extension is loaded, a new copy of the system call table is created.

You'll write two files related to the system call you are going to add to the running kernel. One exports the syscall symbol (demo_syscall.exp) and the other has the definition of the system call (demo_syscall.c) -- one controller program (kctrl.c) to control loading and unloading of the new system call, one sample program (invoke_syscall.c) using the new system call, and one Makefile to build all this, as shown in Listing 4 below.

Listing 4. The demo_syscall.exp file
1 #!/unix
2 demo_syscall syscall

In this file, you just export the system call symbol that you are defining, as shown in Listing 5 below.

Listing 5. System call symbol
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   }

Your new system call is trivial. It simply adds 25 to the argument passed, and it returns the sum (see Listing 6).

Listing 6. Listing of 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)nd\n");
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 %d\n", 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 loaded\n");
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 loaded\n");
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  }

Listing 7 is the controller program that handles loading and unloading of the kernel extension.

Listing 7. Listing of 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 - %d\n",iVal);
17
18
19         return 0;
20 }

This is just a sample program using the new system call.

Listing 8 below is the Makefile to build all the programs of your advanced kernel extension.

Listing 8. Makefile to build all the programs of your advanced kernel extension
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

Resources

Learn

Get products and technologies

  • IBM trial software: Build your next development project with software for download directly from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into AIX and Unix on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=AIX and UNIX
ArticleID=154285
ArticleTitle=Writing AIX kernel extensions
publish-date=08152006