[ Next Article | Previous Article | Book Contents | Library Home | Legal | Search ]
Kernel Extensions and Device Support Programming Concepts

Understanding Kernel Extension Binding

The following information is provided to assist you in understanding kernel extension binding.

Base Kernel Services - the /unix Name Space

The kernel provides a set of base kernel services to be used by kernel extensions. These services, which are described in the services documentation, are made available to a kernel extension by specifying the kernex.exp kernel export file as an import file during the link-edit of the extension. The link-edit operation is performed by using the ld command.

A kernel extension provides additional kernel services and system calls by supplying an export file when it is link-edited. This export file specifies the symbols to be added to the /unix name space, which is the global kernel name space. Symbols that name system calls to be exported must specify the SYSCALL keyword next to the symbol in the export file.

A kernel extension provides additional kernel services and system calls by supplying an export file when it is link-edited. This export file specifies the symbols to be added to the /unix name space, which is the global kernel name space. Symbols that name system calls to be exported must specify one of the SYSCALL, SYSCALL32, SYSCALL64, or SYSCALL3264 keywords next to the symbol in the export file.

The kernel extension export file must also have #!/unix as its first entry. The export file can then be used by other extensions as an import file. The #!/unix as the first entry in an import file specifies that the imported symbols are to come from the /unix name space. This entry is ignored when used in an export file. The same file can be used both as the export file for the kernel extension providing the symbols and as the import file for another extension importing one or more of the symbols.

When a new kernel extension is loaded by the sysconfig subroutine, any symbols defined in the extension export file at link-edit time are added to the /unix kernel name space. The loader can also load additional object files into the kernel to resolve symbols referenced by the new extension. Because these exported symbols are only used to resolve references required during loading of the new extension, these additional object files will not have their own exported symbols added to the name space.

In other words, the kernel name space cannot be expanded without the explicit loading of a kernel object file specifying one or more exported symbols. The symbols added to the kernel name space are available to any subsequently loaded kernel object file as an imported symbol.

An object file explicitly loaded into the kernel exporting symbols into the kernel name space is shared by all kernel extensions. Normally, only one copy of the object file exists in the kernel.

Using System Calls with Kernel Extensions

A restricted set of 32-bit 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 the caller is in the same protection domain when the caller is a user-mode process in kernel mode.

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

Kernel extensions can bind to a restricted set of base system calls. Binding is done by specifying the syscalls.exp system call export file as an import file when the kernel extension is link-edited. When loading object files into the kernel, the loader needs no protection domain switch to access system calls from the kernel. It binds the system call imports to the function descriptor that provides direct access to the system call. For user-mode programs, the loader binds system call references to a set of function descriptors invoking the system call handler to switch protection domains.

Loading System Calls and Kernel Services

Kernel extensions that provide new system calls or kernel services normally place only a single copy of the routine and its static data in the kernel. When this is the case, use SYS_SINGLELOAD sysconfig operation to load the kernel extension. Because it only loads a new copy if one does not already exist in the kernel, this operation ensures that only a single copy is loaded. For this type of kernel extension, an updated version of the object file is loaded into the kernel only when the current copy has no users and has been unloaded.

If a kernel extension can support multiple versions of itself (particularly its data), the SYS_KLOAD sysconfig operation can be used. This operation loads a new copy of the object file even when one or more copies are already loaded. When this operation is used, currently loaded routines bound to the old copy of the object file continue to use the old copy. Any new routines (loaded after the new copy was loaded) are bound to the most recently loaded copy of the kernel extension.

Unloading System Calls and Kernel Services

Kernel extensions that provide new system calls or kernel services can also be unloaded. For each object file loaded, the loader maintains a usage count and a load count. The usage 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 object file.

When an explicit unload of a kernel extension is requested, the load count is decremented. If the load count and the usage count are both equal to 0, the object file is unloaded. However if either the load count or usage count is not equal to 0, the object file is not unloaded. When programs end, the usage counts for kernel extensions that the programs referenced are adjusted. However, no unload of these kernel extensions is performed when the program ends, even if the load and usage counts become 0.

As a result, even though its load count has been decremented to 0 (due to unload requests) and its usage count has reached 0 (because of program terminations), a kernel extension can remain loaded. In this case, the kernel extension's exported symbols are still available for load-time binding unless another unload request for any object file is received. If an explicit unload request (for any program, shared library, or kernel extension) is received, the loader unloads all object files that have both load and usage counts of 0.

The slibclean command, which unloads all object files with load and use counts of 0 (zero), can be used to remove object files that are no longer used from both the shared library region and the kernel. Periodically invoking this command reduces the effects of memory fragmentation in the shared library and kernel text regions by removing object files that are no longer required.

Using Private Routines

The other discussions of kernel extension binding have been concerned with importing and exporting symbols from and to the /unix global kernel name space. These symbols are global in the kernel and can be referenced by any routine in the kernel.

Kernel extensions can also consist of several separately link-edited object files that are bound at load time. This is particularly useful for device drivers, where one object file contains the top (pageable) half of the driver and a second object file contains the bottom (pinned) half of the driver. Load-time binding is useful where several kernel extensions use common routines provided in a separate object file.

In both cases, the symbols exported by the private object files should not be added to the global kernel name space. If it is to have certain symbols exported to the global kernel name space and use other symbols only to resolve references to other private object files, the kernel extension should be divided into separately link-edited object files. (One object file would contain the symbols to be exported to the kernel name space, while the other would contain the exported symbols that are considered private.)

For object files that reference each other's symbols, each file should use the other's export file as its own import file during link-edit. The export file for the object file providing the services should specify #! path/file as the first entry in the export file, where path specifies the directory path to the object file. This provides the exported symbols at load time. This entry is ignored when used as an export file. When used as an import file, however, the entry tells the loader where to find the object file that resolves the imported symbols at load time.

The object file that exports symbols to the kernel name space must specify #!/unix as the first entry in its export file. This allows the export file to be used as an import file by other kernel extensions. The object file containing the symbols to be exported to the kernel name space must be the one explicitly loaded into the kernel with the sysconfig subroutine. The loader then loads other private object files, as necessary, to resolve imported symbols required for the load.

When, during the same explicit load request, the loader encounters an imported symbol that is resolved by an already loaded object file, the loader does not load a new copy. Instead, it resolves the symbol to the copy of the already loaded object file. This allows for cross-resolving symbols between two or more object files loaded as a result of the same explicit load request.

Note: The loader hashes the path and file name of the object file to determine whether the file has already been loaded during this explicit load request. Another copy of the object file can be loaded if differing path names are used for the same object file and the two names do not hash to the same value.

Object files loaded automatically due to symbol resolution do not have their own exported symbols added to the kernel name space. These symbols remain private to the two or more object files loaded with an explicit load request. In this way, the kernel allows object files to have cross-dependent symbol references, and the loader will correctly resolve them.

Note however that when two separate explicit load requests have private symbols resolved by the same object file, two copies of that object file are loaded into the kernel. Each explicit load resolves its symbols to its own private copy of the object file. The private object files can also be combined into libraries with the ar (archive) command.

Using Libraries

A library is a collection of previously link-edited object files or import files and is created by using the ar (archive) command. Each object file or import file within the archive (library) is referred to as a member. Program management allows a member (or object file) to be designated as shared when it is link-edited. Libraries with or without shared objects can be created and used by kernel extensions. However, due to the different programming requirements in the kernel, library services provided for user-mode applications generally should not be used by kernel extensions.

When it resolves a symbol to a library member (or object file) not designated as shared, the linkage editor (ld command) binds the required object file into the output object file so that the references will resolve. However, when symbols are resolved to a library member (or object file) designated as shared, the shared object file is not included in the output object file. Instead, the linkage editor adds information to the loader section of the output object file. The loader uses this information at load time to find the location of the shared object file that resolves the symbol.

When these shared object files (normally in libraries) are referenced by user-mode programs, the loader checks the shared library region to determine if the object file is in the shared library region. If it is, the references are resolved to the object file in the shared library region. If the object file has not already been loaded, the will loads it into the shared library region if the file permissions allow it. In this way, common or shared object files used by user-mode applications can be shared by all user-mode programs in the system.

Unlike user mode, the kernel does not provide a shared library region. Therefore, when a kernel extension that refers to a shared object file is loaded, the loader loads a new copy of the shared object file into the kernel to be used to resolve all references to the object file during the explicit kernel extension load request. However, within the same explicit load request, all references to the same object file are resolved to the single copy of the object loaded for the current load request.

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

libcsys Library

The libcsys library is a subset of subroutines found in the user-mode libc library that can be used by kernel extensions and consists of the following subroutines:

The memccpy, memcmp, memcpy, and memmove memory subroutines are low-level subroutines that the bcmp, bcopy and ovbcopy subroutines use and can be called directly when path length is critical. These subroutines are defined in the libc library. The subroutines can be bound to the kernel export by specifying libcsys.a as a library when link-editing the kernel extension.

libsys Library

The libsys library provides the following set of kernel services:

These kernel services, used by the extension, must be bound to the kernel extension. The kernel services are described as libsys services in their respective descriptions.

These services can be bound to the kernel extension by specifying libsys.a as an import library when link-editing kernel extension.

Note: The string routines implemented in libcsys.a contain processor specific code to enhance performance. These routines access the "_system_configuration" structure to determine the processor type. If a kernel extension uses the string routines in libcsys.a, then a definition for the "_system_configuration" structure must be provided. One way to accomplish this is by specifying -bI:/lib/syscalls.exp on the link-edit command line.

Related Information

Alphabetical List of Kernel Services.

Understanding Execution Environments.

Using Kernel Processes.

Accessing User-Mode Data While in Kernel Mode.

Understanding Locking.

Understanding Exception Handling.

The sysconfig subroutine.

The ld command, the ar command.


[ Next Article | Previous Article | Book Contents | Library Home | Legal | Search ]