[ Bottom of Page | Previous Page | Next Page | Contents | Index | Library Home | Legal | Search ]

Kernel Extensions and Device Support Programming Concepts

Understanding Kernel Extension Symbol Resolution

The following information is provided to assist you in understanding kernel extension symbol resolution:

Exporting Kernel Services and System Calls

A kernel extension provides additional kernel services and system calls by specifying an export file when it is link-edited. An export file contains a list of symbols to be added to the kernel name space. In addition, symbols can be identified as system calls for 32-bit processes, 64-bit processes, or both.

In an export file, symbols are listed one per line. These system calls are available to both 32- and 64-bit processes. System calls are identified by using one of the syscall32, syscall64 or syscall3264 keywords after the symbol name. Use syscall32 to make a system call available to 32-bit processes, syscall64 to make a system call available to 64-bit processes, and syscall3264 to make a system call available to both 32- and 64-bit processes. For more information about export files, see ld Command in AIX 5L Version 5.2 Commands Reference, Volume 3.

When a new kernel extension is loaded by the sysconfig or kmod_load subroutine, any symbols exported by the kernel extension are added to the kernel name space, and are available to all subsequently loaded kernel extensions. Similarly, system calls exported by a kernel extension are available to all user programs or shared objects subsequently loaded.

Using Kernel Services

The kernel provides a set of base kernel services to be used by kernel extensions. Kernel extensions can export new kernel services, which can then be used by subsequently loaded kernel extensions. Base kernel services, which are described in the services documentation, are made available to a kernel extension by specifying the /usr/lib/kernex.imp import file during the link-edit of the extension.

Note
Link-editing of a kernel extension should always be performed by using the ld command. Do not use the compiler to create a kernel extension.

If a kernel extension depends on kernel services provided by other kernel extensions, an additional import file must be specified when link-editing. An import file lists additional kernel services, with each service listed on its own line. An import file must contain the line #!/unix before any services are listed. The same file can be used both as an import file and an export file. The #!/unix line is ignored when a file is used as an export file. For more information on import files, see ld command in AIX 5L Version 5.2 Commands Reference, Volume 3.

Using System Calls with Kernel Extensions

A restricted set of system calls can be used by kernel extensions. A kernel process can use a larger set of system calls than a user process in kernel mode. System Calls Available to Kernel Extensions specifies which system calls can be used by either type of process. User-mode processes in kernel mode can only use system calls that have all parameters passed by value. Kernel routines running under user-mode processes cannot directly use a system call having parameters passed by reference.

The second restriction is imposed because, when they access a caller's data, system calls with parameters passed by reference access storage across a protection domain. The cross-domain memory services performing these cross-memory operations support kernel processes as if they, too, accessed storage across a protection domain. However, these services have no way to determine that the caller is in the same protection domain when the caller is a user-mode process in kernel mode. For more information on cross-domain memory services, see Cross-Memory Kernel Services.

Note: System calls must not be used by kernel extensions executing in the interrupt handler environment.

System calls available to kernel extensions are listed in /usr/lib/kernex.imp, along with other kernel services.

Loading and Unloading Kernel Extensions

Kernel extensions can be loaded and unloaded by calling the sysconfig function from user applications. A kernel extension can load another kernel extension by using the kmod_load kernel service, and kernel extensions can be unloaded by using the kmod_unload kernel service.

Loading Kernel Extensions

Normally, kernel extensions that provide new system calls or kernel services only need to be loaded once. For these kernel extensions, loading should be performed by specifying SYS_SINGLELOAD when calling the sysconfig function, or LD_SINGLELOAD when calling the kmod_load function. If the specified kernel extension is already loaded, a second copy is not loaded. Instead, a reference to the existing kernel extension is returned. The loader uses the specified pathname to determine whether a kernel extensions is already loaded. If multiple pathnames refer to the same kernel extension, multiple copies can be loaded into the kernel.

If a kernel extension can support multiple instances of itself (particularly its data), it can be loaded multiple times, by specifying SYS_KLOAD when calling the sysconfig function, or by not specifying LD_SINGLELOAD when calling the kmod_load function. Either of these operations loads a new copy of the kernel extension, even when one or more copies are already loaded. When this operation is used, currently loaded routines bound to the old copy of the kernel extension continue to use the old copy. Subsequently loaded routines use the most recently loaded copy of the kernel extension.

Unloading Kernel Extensions

Kernel extensions can be unloaded. For each kernel extension, the loader maintains a use count and a load count. The use count indicates how many other object files have referenced some exported symbol provided by the kernel extension. The load count indicates how many explicit load requests have been made for each kernel extension.

When an explicit unload of a kernel extension is requested, the load count is decremented. If the load count and the use count are both equal to 0, the kernel extension is unloaded, and the memory used by the text and data of the kernel extension is freed.

If either the load count or use count is not equal to 0, the kernel extension is not unloaded. As processes exit or other kernel extensions are unloaded, the use counts for referenced kernel extensions are decremented. Even if the load and use counts become 0, the kernel extension may not be unloaded immediately. In this case, the kernel extension's exported symbols are still available for load-time binding unless another kernel extension is unloaded or the slibclean command is executed. At this time, the loader unloads all modules that have both load and use counts of 0.

Using Private Routines

So far, symbol resolution for kernel extensions has been concerned with importing and exporting symbols from and to the kernel name space. Exported symbols are global in the kernel, and can be referenced by any subsequently loaded kernel extension.

Kernel extensions can also consist of several separately link-edited modules. This is particularly useful for device drivers, where a kernel extension contains the top (pageable) half of the driver and a dependent module contains the bottom (pinned) half of the driver. Using a dependent module also makes sense when several kernel extensions use common routines. In both cases, the symbols exported by the dependent modules are not added to the global kernel name space. Instead, these symbols are only available to the kernel extension being loaded.

When link-editing a kernel extension that depends on another module, an import file should be specified listing the symbols exported by the dependent module. Before any symbols are listed, the import file should contain one of the following lines:

#! path/file

or

#! path/file(member)
Note
This import file can also be used as an export file when building the dependent module.

Dependent modules can be found in an archive file. In this case, the member name must be specified in the #! line.

While a kernel extension is being loaded, any dependent modules are only loaded a single time. This allows modules to depend on each other in a complicated way, without causing multiple instances of a module to be loaded.

Note
The loader uses the pathname of a module to determine whether it has already been loaded. Another copy of the module can be loaded if different path names are used for the same module.

The symbols exported by dependent modules are not added to the kernel name space. These symbols can only be used by a kernel extension and its other dependent modules. If another kernel extension is loaded that uses the same dependent modules, these dependent modules will be loaded a second time.

Understanding 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 a 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.

This special treatment of archives only applies to an explicitly loaded kernel extension. If a kernel extension depends on a member of another archive, the kernel extension must be link-edited with an import file that specifies the member name.

Using Libraries

The operating system provides the following two libraries that can be used by kernel extensions:

libcsys Library

The libcsys.a library contains a subset of subroutines found in the user-mode libc.a library that can be used by kernel extensions. When using any of these routines, the header file /usr/include/sys/libcsys.h should be included to obtain function prototypes, instead of the application header files, such as /usr/include/string.h or /usr/include/stdio.h. The following routines are included in libcsys.a:

libsys Library

The libsys.a library provides the following set of kernel services:

When using these services, specify the -lsys flag at link-edit time.

User-provided Libraries

To simplify the development of kernel extensions, you can choose to split a kernel extension into separately loadable modules. These modules can be used when linking kernel extensions in the same way that they are used when developing user-level applications and shared objects. In particular, a kernel module can be created as a shared object by linking with the -bM:SRE flag.. The shared object can then be used as an input file when linking a kernel extension. In addition, shared objects can be put into an archive file, and the archive file can be listed on the command line when linking a kernel extension. In both cases, the shared object will be loaded as a dependent module when the kernel extension is loaded.

[ Top of Page | Previous Page | Next Page | Contents | Index | Library Home | Legal | Search ]