Learn how NT initializes

In November, I began this two-part series on the Windows NT boot process. I described the way NT's Setup program prepares a hard disk for a boot by placing NT code in the disk's Master Boot Record (MBR) and boot sectors. When the system boots, the NT code loads the NTLDR boot file and executes the file's code. NTLDR is responsible for the pre-NT Kernel portion of the boot; part of NTLDR's responsibility is to prepare a data structure with information about the system and to construct the HKEY_LOCAL_MACHINE\HARDWARE and HKEY_LOCAL_MACHINE\SYSTEM Registry keys. NTLDR later gives this information to the Kernel, together with images for hal.dll and the boot-start device drivers.

This month, I resume my description of the boot process at the point at which NTLDR has finished its role in the boot by calling the NT Kernel's entry point. I'll walk you through the rest of the boot process, including the initialization steps each Executive subsystem takes. I'll describe how and when device drivers from each of the start categories--­Boot, System, and Auto--­initialize. I'll conclude by describing how the Kernel finishes a boot by loading user-mode code that presents the logon screen display and launches the Win32 subsystem. The sidebar "Windows 2000 and the Boot," page 60, explains how the NT boot process will change in Windows 2000 (Win2K--­formerly NT 5.0).

Initializing the Kernel and Executive Subsystems
The NT Kernel goes through two phases in its boot process: phase 0 and phase 1. Phase 0 initializes just enough of the Kernel and Executive subsystems so that basic services required for the completion of initialization become operational in phase 1. NT keeps interrupts disabled during phase 0 and enables them before phase 1. Most Executive subsystems implement their initialization code by having one function take a parameter that identifies which phase is executing.

The function responsible for orchestrating phase 0 is called ExpInitializeExecutive. This function starts by calling the hardware abstraction layer (HAL) function HallnitSystem. HallnitSystem gives proprietary versions of the HAL that various OEMs develop a chance to gain system control before NT performs significant initialization. One HallnitSystem responsibility is to prepare the system interrupt controller for interrupts and to configure the clock tick interrupt. When HallnitSystem returns control, ExpInitializeExecutive proceeds by honoring the /BURNMEMORY BOOT.INI switch (if the switch is present in the selection the user made in the boot.ini file for which installation to boot) and discarding the amount of memory the switch specifies. Next, ExpInitializeExecutive calls initialization routines for the Memory Manager, Object Manager, Security Reference Monitor, and Process Manager. The Memory Manager gets the ball rolling by constructing page tables and internal data structures that are necessary to provide basic memory services. The Memory Manager builds and reserves an area for the system file cache and creates memory areas for the paged and nonpaged pools. The other Executive subsystems, the Kernel, and the device drivers use these two memory pools for allocating their data structures.

After the Memory Manager finishes phase 0, ExpInitializeExecutive prints the text Microsoft (R) Windows NT (TM) Version 4.0 (Build 1381) to the initial blue screen you see during a boot. Build 1381 is the build number for NT 4.0 without service packs. For NT 4.0 with service packs applied, text similar to Service Pack 3 follows the build number on the initial blue screen. The system obtains the service pack number from HKEY_LOCAL_MACHINE\SYSTEMCurrentControlSet\Control\Windows\CSDVersion, where the number is encoded as a hexadecimal value that can identify interim service packs (e.g., Service Pack 1a).

During phase 0 of Object Manager initialization, NT defines the objects that are necessary to construct the Object Manager namespace so that other subsystems can insert objects into it. NT also creates a handle table so that resource tracking can begin. The Security Reference Monitor initializes the token type object and then uses the object to create and prepare the first token for assignment to the initial process. The last Executive subsystem to initialize in phase 0 is the Process Manager. The Process Manager performs most of its initialization in phase 0, defining the process and thread object types and setting up lists to track active processes and threads. The Process Manager also creates a process object for the initial process and names it Idle. As its last step, the Process Manager creates the System process and launches a thread for this process that will direct phase 1 initialization in the Kernel's Phase1Initialization function.

When control returns to it, ExpInitializeExecutive has become a thread in the Idle process and immediately becomes the system's idle thread. ExpInitializeExecutive sets its priority to 0 (the lowest possible) and begins executing a loop that will run only if no other thread in the system can run.

Phase 1 starts when Phase1Initialization calls the HAL to prepare the system to accept interrupts from devices and to enable interrupts. Phase1Initialization notes the time and stores it as the time the system booted. Up to this point, only one CPU has been active. In a symmetric multiprocessing (SMP) system, the boot process has left other CPUs off. Now, with the aid of the HAL, Phase1Initialization turns on the remaining CPUs. NT prints text similar to 2 System Processors \[128 MB Memory\] Multiprocessor Kernel to the blue screen after all CPUs have initialized.

Phase1Initialization continues by calling every Executive subsystem in the order Table 1 shows, so that they can execute phase 1 initialization. The order in which Phase1Initialization calls the subsystems is important because of system interdependencies. For example, the Executive must define type objects like mutexes, semaphores, events, and timers because other subsystems use these objects.

Driver Initialization
The I/O Manager's initialization is particularly interesting, because it is dur-ing phase 1 initialization that the boot drivers that NTLDR loaded finally start. When you or NT installs a device driver, the driver's Setup script or program can direct NT to define three Registry values in the driver's Registry key in addition to the Start value. These values are Group, Tag, and DependOnGroup. The first two values further refine the decision as to when the I/O Manager should initialize the driver, and the I/O Manager uses the third value when deciding whether to start a particular driver.

Before the I/O Manager initializes the boot drivers, it sorts them according to their Group values and sends drivers with no Group value to the end of the list. The Registry value HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder determines group precedence in the sorting process. Screen 1 shows ServiceGroupOrder values. Groups at the top of the list have higher precedence than groups at the bottom of the list have.

After the I/O Manager sorts drivers by group, it sorts the drivers within each group according to the Tag values defined in the drivers' Registry keys. Drivers without a tag go to the end of the list in their group. You might assume that the I/O Manager initializes drivers with lower-number tags before drivers with higher-number tags, but that isn't necessarily the case. The Registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList defines tag precedence within a group; with this key, Microsoft and device driver developers can take liberties with redefining the integer number system.

After the I/O Manager finishes sorting drivers, it traverses the lists it has made and initializes each driver according to its place on the list. However, if a driver has a DependOnGroup value, the I/O Manager will not load that driver unless it has already loaded at least one driver that belongs to the specified group. The DependOnGroup value makes it easy to define a driver that must not load if its operation requires another driver that isn't present on the system.

As the I/O Manager initializes each driver, it checks the return status of the driver's initialization function. If a driver reports an error, the action the I/O Manager takes depends on the ErrorControl value in the driver's Registry key. Table 2 shows possible ErrorControl values and the actions the I/O Manager takes when a driver with a particular value reports an error. In some cases, an error causes NT to reboot and try a previous version of the Registry's Control subkey in an attempt to boot successfully.

Immediately after initializing the boot drivers, the I/O Manager loads and initializes all drivers marked as SERVICE_SYSTEM_START (system start). The I/O Manager processes the system-start driver initialization order and dependencies in the same way it processed the order for the boot-start drivers. Thus, the only difference between boot-start drivers and system-start drivers is that NTLDR preloads the boot-start drivers and NT initializes them first. When the boot-start drivers (specifically, the file system and disk drivers responsible for the system partition) are active, the I/O Manager can use them to load the system-start drivers.

As device drivers initialize during the boot, they work in a restricted environment: NTLDR and the Configuration Manager have defined only the HKEY_LOCAL_MACHINE\SYSTEM and HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION parts of the Registry, and boot drivers cannot access files on the disk. After the I/O Manager initializes the system-start drivers, it calls the HAL to define the drive-letter mappings, in which it links drive letters to the partitions the letters reference. For example, C:\ might be linked to \harddisk\0\partition1. The HAL honors any drive-letter assignments a user makes using Disk Administrator, and reads this information from HKEY_LOCAL_MACHINE\SYSTEM\Disk.

At the end of the Phase1Initialization function, the NT Kernel and Executive subsystems are fully operational. The function's last action is to launch the Session Manager Subsystem (SMSS, which is in \winnt\system32\smss.exe) user-mode process. SMSS is responsible for creating the user-mode environment that provides the visible interface to NT.

SMSS, CSRSS, and Winlogon
SMSS is like any other user-mode process except for two things: First, NT considers SMSS a trusted part of the OS. Second, SMSS is a native application. Because it's a trusted OS component, SMSS can perform actions few other processes can perform, such as creating security tokens. Because it's a native application, SMSS doesn't use Win32 APIs--­it uses only core Executive APIs known collectively as NT's Native API. SMSS doesn't use the Win32 APIs because the Win32 subsystem isn't executing when SMSS launches. In fact, one of SMSS's tasks is to start the Win32 subsystem.

SMSS first processes commands in the Registry value HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Session Manager\BootExecute. Typically, this value contains one command to run the CHKDSK disk consistency checking application. As CHKDSK runs, it prints two periods on the screen for each partition it examines. SMSS creates page files after CHKDSK runs so that larger applications can begin to execute. Then, SMSS calls the Configuration Manager Executive subsystem to finish initializing the Registry, fleshing the Registry out to include all its keys. To do so, the Configuration Manager loads the Registry hives for the HKEY_LOCAL_MACHINE\SAM, HKEY_LOCAL_MACHINE\SAM\SECURITY, and HKEY_LOCAL_MACHINE\SOFTWARE keys. The Configuration Manager looks in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hivelist key to find out where the hives are located on disk.

SMSS then loads the win32k.sys device driver, which implements the kernel-mode portion of the Win32 subsystem. SMSS determines the location of win32k.sys and other components it loads by looking for their paths in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Session Manager. Finally, SMSS launches csrss.exe and winlogon.exe. CSRSS is the user-mode portion of the Win32 subsystem, and Winlogon is the logon manager.

Shortly after win32k.sys starts, it switches the screen to graphics mode. A little later, Winlogon starts the Services subsystem (\winnt\system32\services.exe), which loads all services and device drivers marked Auto Start. (The Services subsystem is also known as the Service Control Manager--­SCM.) Auto Start drivers and services can specify a dependency on a specific service by including a DependOnService value in their Registry keys in a manner similar to the way boot drivers use the DependOnGroup value. The SCM sorts and then initializes the Auto Start drivers and services according to their group and tag values in the same way the I/O Manager sorts the boot- and system-start drivers.

After the SCM initializes the Auto Start services and drivers, it deems the boot successful. The Registry subkey HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet becomes the Last Known Good control set, because the system booted successfully to this point. Earlier in the boot, NT made a copy of this subkey and named the copy HKEY_LOCAL_MACHINE\SYSTEM\CLONE. Any changes drivers make to the current control set during the boot do not change the CLONE subkey copy. The SCM copies the CLONE subkey to another control set subkey (e.g., HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001), and the SCM marks that control set subkey as Last Known Good. The SCM marks the subkey by setting the HKEY_LOCAL_MACHINE\SYSTEM\Select\LastKnownGood value to specify the three-digit identifier at the end of the control set's subkey name (e.g., 001). If a user chooses to boot to the Last Known Good menu during the first steps of a boot, or if a driver returns a severe or critical error, the system uses the Last Known Good profile subkey as HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet. Doing so increases the chances that the system will boot successfully, because at least one previous boot using the Last Known Good profile was successful.

At approximately the time the Services subsystem is starting networking services, Winlogon presents users with the initial logon dialog box. That action brings us to the end of the boot process.

Shutdown
In contrast to the boot process, system shutdown is straightforward. First, the Win32 subsystem informs all Windows applications that the system is going down. Most applications exit voluntarily, and Winlogon stops any stragglers. Winlogon is in charge of finishing the shutdown process by calling the Executive subsystem function NtShutdownSystem. This function calls the I/O Manager, the Configuration Manager, the Memory Manager, and then the I/O Manager again, and informs them that they should prepare for the shutdown.

The first time NtShutdownSystem calls the I/O Manager, the I/O Manager sends shutdown I/O packets to all device drivers that have requested shutdown notification. This action gives device drivers a chance to perform any special processing their device might require before NT exits. The Configuration Manager flushes any modified Registry data to disk, and the Memory Manager writes all modified pages containing file data back to their respective files. If the option to clear the paging file at shutdown is enabled, the Memory Manager clears the paging file at this time. The second time NtShutdownSystem calls the I/O Manager, the I/O Manager informs the file system drivers that the system is shutting down. Finally, if the system's user specified a reboot after the shutdown, the system calls the HAL to reboot the computer.

We've arrived at shutdown for this month's column. This two-column series about the boot process is a roadmap with visual cues to the operations that take place behind the scenes when your system boots. Table 3 presents a summary of boot-process components with their execution modes and responsibilities. Understanding the details of the boot process helps you to diagnose problems that can arise during a boot, and gives you insight into the way NT pulls itself up by its bootstraps.