Unlike other operating systems, NT uses the registry (i.e., a database of configuration infor-mation), to store and retrieve information on drivers to be loaded at either system initialization time or at a later time. NT can successfully initialize by looking at the information stored under each individual key (registered under
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet \Services). Each subkey under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services describes a "Service" (your driver) that may be started as a part of the NT initialization process. Each of the registered Services contains named values that describe the service’s load requirements and dependencies. This is where the NT driver writer can specify load time, and also assign Services to Groups assuring an orderly load with respect to other Services on the system.
Now that you have a basic understanding of what capabilities you have, let’s delve into the specifics.
Figure 1 illustrates the values that can make up an entry for a driver in the HKEY_LOCAL_MACHINE\Current
ControlSet\Services tree. As you can see, NT supports a variety of values, which allow the registrar the ability to control all aspects of driver loading. The values for the key and their storage types are as follows:
- Service Name – This contains the unique name you associate with your service. It usually is the name of the ".SYS" file that this service is contained in. We’ll talk more about this later.
- Type –Allows the registrar to define the type of service that this entry represents.
- Start –Allows the registrar to indicate when in the boot process this service should be started.
- ErrorControl – Used to indicate what NT should do in the event that this driver fails to load.
- ImagePath – Points to location where the Image for this service is to be loaded. If this value is not present the load defaults to directory %SYSTEMROOT%\SYSTEM32\DRIVERS. This value is ignored if the system is a Boot Start or System Start service.
- Group – This value allows the registrar to indicate that this service belongs to a collection of services. Putting a collection of services into a group is convenient method to classify services by their functionality, some examples being "SCSI DISK Class", "SCSI MiniPort", "File System", etc.
- DependOnGroup – Indicates that this service depends on the functionality of at least one service in the specified group being loaded and initialized before this service can be loaded. An example for a service in the "SCSI Disk Class" group would be a dependency on the "SCSI MiniPort" group being loaded first.
- DependOnService – This value identifies specific services that must be loaded before this service is loaded.
- DisplayName – Permits the registrar to have a service name other than the name of the driver to aid in readability. This name will be displayed in the control panel services display.
- Tag – This value works in conjunction with the "Group" value and the GroupOrderList key located under the HKEY\LocalMachine\CurrentControlSet\Services\Control key to control the loading order of your driver within the group that it belongs. This value will be explained in more gory detail later on in this article.
Out of the values defined above, the three most common for use in registering a driver are the Type, Start, and ErrorControl values. The Type value describes the type of driver defined by this key; The Start value indicates when the driver loads; Finally, the ErrorControl value tells the system what to do if the driver does not load. Let’s describe each of these values in more detail.
The Type, which is defined as a REG_DWORD, allows the writer to define the type of driver being loaded. The Windows NT 4.0 Resource Kit defines the options for this entry as follows:
- 0x01 - Kernel Device Driver
- 0x02 - File System Driver, which is also a Kernel Device Driver
- 0x04 - Set of arguments for an adapter
- 0x10 - A Win32 program that can be started by the Service Controller and that
obeys the service control protocol. This type of Win32 service runs in
a process by itself.
- 0x20 - A Win32 service that can share a process with other Win32 services.
Only the first two values are of interest to NT device driver writers. Which one do you use? Well, it should be obvious, if you’re doing a normal Kernel Device Driver then you use 0x01, while if you’re implementing a File System Driver then you use 0x02. Picking 0x02 has some implications in regards to the Start value, of which driver writers should be aware (See the following section for more information).
The Start value (defined as a REG_DWORD), allows the driver writer to control when the driver (service) is loaded during system initialization. Permissible values for Start are defined as follows:
- 0x00 - Boot Start - Loaded by the boot loader during the startup sequence. Drivers loaded during this stage are usually lowest level drivers that need to gain access to hardware at the earliest moments of booting. Drivers loaded during this phase are loaded sequentially (we’ll talk more about load order later on).
- 0x01 - System Start - Loaded during the load sequence of NT kernel initialization. These drivers typically rely on the services provided by the drivers loaded during the Boot Start phase. Drivers loaded during this phase are also loaded sequentially.
- 0x02 - Auto Load - Loaded or started automatically at system startup. Drivers loaded during this phase are loaded in parallel.
- 0x03 - Load On Demand - The user manually starts the driver from the command line or programmatically via the ServiceControl API.
- 0x04 - Disabled - The driver is not to be started under any condition. File System drivers are the one exception to the Start value. They are loaded even if they have a Start value of 0x04.
The value of this entry (defined as a REG_DWORD), determines how an error occurring with the load of this driver affects the startup of the system. The values for ErrorControl are as follows:
- 0x00 - Ignore - The error is ignored, is not reported and the system continues to boot normally.
- 0x01 - Normal - The error that occurred is reported, and the system continues to boot normally.
- 0x02 - Severe - When the kernel detects an error in this device driver or service, it switches to the LastKnownGood control set, and the startup process starts again. If the control set being used is already LastKnownGood, the error is ignored and processing continues.
- 0x03 - Critical - The same procedure as Severe (0x2) is used, with the exception that if the LastKnownGood control set is already being used, the startup process stops and a failure error message is displayed.
What is LastKnownGood? This is part of the registry subkey HKEY_LOCAL_MACHINE\SYSTEM that determines which control set is used during startup. A control set is a set of system configuration information, such as device drivers and services to load and start. A system usually has at least 2 control sets (sometimes more), depending on how often you modify system settings or have problems with booting. The registry subkey HKEY_LOCAL_MACHINE\SYSTEM\Select identifies how the control sets are used and determines which key is used during setup. For a more in depth understanding of these, the reader should Windows NT 4.0 Resource Kit documentation.
As mentioned above, Type, Start, and ErrorControl are the values that we suggest you need to intelligently register your driver. Now let’s move onto describing the more advanced fields that a driver writer can use to have much more control over the load order of a driver: Group, ImagePath, DependOnGroup, DependOnService.
When a writer creates a driver entry in the registry, he has the option of defining a Group (of type REG_SZ), to which his driver belongs. A Group is typically defined as a collection of services that provide the same class of functionality. NT predefines its known Service Groups in the HKEY_LOCAL_MACHINE\CurrentControlSet\Control\ServiceGroupOrder subkey. Some examples of Groups are "File Systems", "Class Drivers, "Mini Port Drivers", etc. Driver writers can add to this subkey, but must be careful when inserting new groups so as to preserve the basic system load process. Drivers within a Group usually have the same Start value, but can additionally contain a Tag value, which helps define the load order of this driver within the Group that it is a part of.
Figure 2 – Current members of the HKEY_LOCAL_MACHINE\CurrentControlSet\Control\ServiceGroupOrderKey
Figure 3 – HKEY_LOCAL_MACHINE\CurrentControlSet\Control\GroupOrderList
How do Tag and Group work together to determine when a driver starts? To understand this, we must first explain the GroupOrderList key located under the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control key (See Figure 3). This key contains values whose names correspond to Groups contained within the ServiceGroupOrder key (See Figure 2), which we explained earlier. For each Group defined under this key the type of the data is REG_BINARY and the format of an entry is as follows: The first long word (32 bit) value is the number of long word entries that follow. Each subsequent long word contains a number that corresponds to a driver’s Tag value. The order of the values within this list, corresponding to a driver’s Tag value, represents the order that the drivers will be loaded in. For example suppose there is an OSR group defined within the Group OrderList, whose contents are 00000002000000FF00000001. This REG_BINARY data would be interpreted to mean that there are 2 entries in the list and the driver, who is a member of group OSR (specified in the Group key) and has a TAG value of 000000FF, will load first. The next member of group OSR that has a TAG value of 00000001 will load second. Any other members of group OSR that are left and have a START value which matches the current load phase, will be loaded in alphabetical order.
Driver writers are allowed to create new GroupOrderList values as well as modify existing values. However, you should take great care in insuring that they know what they’re doing. Error caused when modifying the values could result in a non-bootable system.
The other aspect that you should be aware of is that the GroupOrderList is only used during Boot Start (0x01) and System Start (0X02). Services that are part of the Auto Load (0x03) phase are loaded in parallel.
The ImagePath value (of type REG_EXPAND_SZ), gives the registrar the ability to identify the path and filename of the service to be loaded. However, the use of this key has some restrictions. Drivers that have a Start value of either Boot Start (0x01) or System Start (0x02) must reside in the %SYSTEMROOT%\SYSTEM32\Drivers directory. Drivers that have any other Start value can reside in any directory on the local disks or network drives and are not supported.
A driver writer specifies the DependOnGroup value (of type REG_SZ), whenever their driver relies on services provided by another Service Group. At least one service from the group must be loaded before your service is loaded. This field contains the name of the Group that this driver relies upon. The use of this value prevents a driver from being loaded if the service that it depends on is not currently loaded. The DependOnGroup is only used doing for drivers that have a Start value of 0x01 (Boot Start) or 0x02 (System Start).
A driver writer specifies the DependOnService value whenever their driver relies on specific services being loaded before this service is loaded.
Services that are not part of a group are loaded in alphabetic order after all other processing for the Start phase has completed.
If you enter your driver keys and values into the registry manually, you will not be able to start your service until you reboot NT. If, however, you use the CreateService Win32 API, you will be able to register and start your service at will.
Dazed and confused? Does the thought of manual Registry key modification strike fear in your heart? Well, never fear OSRLoader is here! Located on the OSR free utilities page, OSRLoader allows the discerning driver writer the ability to easily modify or create almost all registry entries contained within this article (OSRLoader does not currently support adding an entry to the ServiceGroup Order list…it’s not difficult, we just haven’t gotten around to it). Anyway, spend the time to download it and you’ll be glad you did.