Windows 2000 presents arguably the most aggressive attempt at operating system control in the history of computers. This section tours the Windows 2000 architecture, highlighting the features of significant interest to a device driver author. Design Goals for Windows 2000The original goals for Microsoft's NT ("New Technology") operating system took form in early 1989. Interestingly, the original concept for NT did not even include a Windows operating environment. While the NT OS has indeed come a long way since 1989, the five fundamental goals remain intact.
Of course, goals are not reality, and over time, serious compromise of one goal may be necessary to achieve another. NT is an operating system and, as such, is subject to the same sorts of compromises that affect all systems. The remainder of this section describes the delicate balance of solutions that Microsoft OS designers chose to implement their goals. Hardware Privilege Levels in Windows 2000To achieve the robustness and reliability goal, the designers of NT chose a client-server architecture for its core implementation. A user application runs as a client of OS services. The user application runs in a special mode of the hardware known generically as user mode. Within this mode, code is restricted to nonharmful operations. For example, through the magic of virtual memory mapping, code cannot touch the memory of other applications (except by mutual agreement with another application). Hardware I/O instructions cannot be executed. Indeed, an entire class of CPU instructions (designated privileged), such as a CPU Halt, cannot be executed. Should the application require the use of any of these prohibited operations, it must make a request of the operating system kernel. A hardware-provided trap mechanism is used to make these requests. Operating system code runs in a mode of the hardware known as kernel mode. Kernel-mode code can perform any valid CPU instruction, notably including I/O operations. Memory from any application is exposed to kernel-mode code, providing, of course, that the application memory has not been paged out to disk. All modern processors implement some form of privileged vs. nonprivileged modes. Kernel-mode code executes in this privileged context, while user-mode code executes in the nonprivileged environment. Since different processors and platforms implement privileged modes differently, and to help achieve the goal of portability, the OS designers provided an abstraction for user and kernel modes. OS code always uses the abstraction to perform privileged context switches, and thus only the abstraction code itself need be ported to a new platform. On an Intel platform, user mode is implemented using Ring 3 of the instruction set, while kernel mode is implemented using Ring 0. This discussion is relevant to device driver writers in that kernel-mode drivers execute in a privileged context. As such, poorly written device driver code can and does compromise the integrity of the Windows 2000 operating system. Driver writers must take extra care in handling all boundary conditions to ensure that the code does not bring down the entire OS. PortabilityTo achieve the portability goal, NT designers chose a layered architecture for the software, as shown in Figure 1.1. Figure 1.1. The layers of the Windows 2000 operating systemThe Hardware Abstraction Layer (HAL) isolates processor and platform dependencies from the OS and device driver code. In general, when device driver code is ported to a new platform, only a recompile is necessary. How can this work since device driver code is inherently device-, processor-, and platform-specific? Clearly, the device driver code must rely on code (macros) within the HAL to reference hardware registers and buses. In some cases, the device driver code must rely on abstraction code provided in the I/O Manager (and elsewhere) to manipulate shared hardware resources (e.g., DMA channels). Subsequent chapters in this book will explain the proper use of the HAL and other OS services so that device driver code can be platform-independent. ExtendibilityFigure 1.1 also shows an important design concept of Windows 2000 the kernel is separate from a layer known as the Executive. The Windows 2000 kernel is primarily responsible for the scheduling of all thread activity. A thread is simply an independent path of execution through code. To remain independent of other thread activity, a unique thread context must be preserved for each thread. The thread context consists of the CPU register state (including a separate stack and Program Counter), an ID (sometimes called a Thread ID or TID, internally known as a Client ID), a priority value, storage locations local to the thread (Thread Local Storage), and other thread-relevant information. The scheduler's responsibility is to manage which thread should execute at any given time. In a single processor environment, of course, only one thread may actually gain control of the processor at a time. In a multiprocessor environment, different threads may be executing on the different available processors, offering true parallel execution of code. The scheduler assigns a processor to a thread for, at most, a fixed period of time known as the thread time quantum. Processors are assigned to threads primarily based on the thread's priority value. Higher priority threads that become ready to run will preempt a running thread. Since the kernel's prime role is to schedule thread activity, other OS components perform the necessary work of memory, process, security, and I/O management. These components are collectively known as the Executive. The Executive components have been designed (though the I/O Manager itself is a significant exception) as modular software. Over the years, Microsoft has added, deleted, merged, and separated these components as improvements and compromises deemed necessary. A good example would be the addition of the Active Directory Services, which is relatively new to Windows 2000. The notion of keeping the kernel itself small and clean, coupled with the modularization of Executive components, provides the basis for NT's claim to extendibility. The OS has now survived about ten years of revisions, maintenance, and significant feature improvement (a.k.a., creeping elegance). PerformanceWhile the layered approach to software design is often characterized by lackluster performance, attention to fast layer interaction has been a continual effort with the NT design group. First, it should be noted that all the layers described so far execute within the same hardware mode, kernel mode. Therefore, interlayer calls often involve nothing more than a processor CALL instruction. Indeed, HAL usage is often implemented with macros, thus achieving inline performance. Second, there has been a concentrated effort to parallelize as many tasks as possible by allocating threads to different units of work. The Executive components are all multithreaded. Helper routines seldom block or busy-wait while performing their work. This minimizes true idle time on the processor. The performance goals of Windows 2000 impact device driver writers. As user and system threads request service from a device, it is vital that the driver code not block execution. If the request cannot be handled immediately, perhaps because the device is busy or slow, the request must be queued for subsequent handling. Fortunately, I/O Manager routines facilitate this process. Executive ComponentsSince the Executive components provide the base services for the Windows 2000 operating system (other than thread scheduling), their needs and responsibilities are fairly clear. These components are explained in the following sections. SYSTEM SERVICE INTERFACEThis component provides the entry point from user mode to kernel mode. This allows user-mode code to cleanly and safely invoke services of the OS. Depending on the platform, the transition from user mode to kernel mode may be a simple CPU instruction or an elaborate Save and Restore context switch. OBJECT MANAGERAlmost all services offered by the OS are modeled with an object. For example, a user-mode program that needs thread-to-thread synchronization might request a mutex service from the OS. The OS presents the mutex in the form of an OS-based object, referenced from user mode only through a handle. Files, processes, Threads, Events, Memory Sections, and even Registry Keys are modeled with OS-based objects. All objects are created and destroyed by a centralized Object Manager. This allows for uniform access, life spans, and security with all objects. CONFIGURATION MANAGERThe Configuration Manager of Windows 2000 models the hardware and installed software of the machine. A database called the Registry is used to store this model. Device drivers utilize information in the Registry to discover many aspects of the environment in which they are executed. With the introduction of Plug and Play into Windows 2000, the role of the Registry for device drivers has been significantly reduced. PROCESS MANAGERA process is the environment in which threads execute in Windows 2000. Each process maintains a private address space and security identity. In Windows 2000, it is important to note that processes do not run; instead, threads are the unit of execution and the process is a unit of ownership. A process owns one or more threads. The Windows 2000 Process Manager is the Executive component that manages the process model and exposes the environment in which process threads run. The Process Manager relies heavily on other Executive components (e.g., the Object Manager and Virtual Memory Manager) to perform its work. As such, it could be said that the Process Manager simply exposes a higher level of abstraction for other lower-level system services. Device drivers seldom interact with the Process Manager directly. Instead, drivers rely on other services of the OS to touch the process environment. For example, a driver must ensure that a buffer residing with the private address space of a process remains "locked down" during an I/O transfer. Routines within the OS allow a driver to perform this locking activity. VIRTUAL MEMORY MANAGERUnder Windows 2000, the address space of a process is a flat 4 gigabytes (4 GB) (232). Only the lower 2 GB is accessible in user mode. A program's code and data must reside in this lower half of the address space. If the program relies on shared library code (dynamic-link libraries or DLLs), the library code also must reside in the first 2 GB of address space. The upper 2 GB of address space of every process contains code and data accessible only in kernel-mode. The upper 2 GB of address space is shared from process to process by kernel-mode code. Indeed, device driver code is mapped into address space above 2 GB. The Virtual Memory Manager (VMM) performs memory management on behalf of the entire system. For normal user-mode programs, this means allocating and managing address space and physical memory below the 2 GB boundary. If the needed memory for a given process is not physically available, the VMM provides an illusion of memory by virtualizing the request. Needed memory is paged onto a disk file and retrieved into RAM when accessed by a process. In effect, RAM becomes a shared resource of all processes, with memory moving between files on the disk and the limited RAM available on a given system. The VMM also acts a memory allocator in that it maintains heap areas for kernel-mode code. Device drivers can request the VMM to assign dedicated areas of pagable or nonpagable memory for its use. Further, devices that operate using DMA (direct memory access) can assign nonpagable memory as needed to perform data transfers between RAM and a device. Of course, these topics are covered in more detail in subsequent chapters. LOCAL PROCEDURE CALL FACILITYA Local Procedure Call (LPC) is a call mechanism between processes of a single machine. Since this interprocess call must pass between different address spaces, a kernel-mode Executive component is provided to make the action efficient (and possible). Device driver code has no need for the LPC facility. I/O MANAGERThe I/O Manager is an Executive component that is implemented with a series of kernel-mode routines that present a uniform abstraction to user-mode processes for I/O operations. One goal of the I/O Manager is to make all I/O access from user mode device-independent. It should not matter (much) to a user process whether it is accessing a keyboard, a communication port, or a disk file. The I/O Manager presents requests from user-mode processes to device drivers in the form of an I/O Request Packet (IRP). The IRP represents a work order, usually synthesized by the I/O Manager, that is presented to a device driver. It is the job of device drivers to carry out the requested work of an IRP. Much of the remainder of this book is devoted to the proper care and processing of IRPs by device driver code. In effect, the I/O Manager serves as an interface layer between usermode code and device drivers. It is therefore the most important block of code that a device driver must interact with during operation. ACTIVE DIRECTORY SERVICEThe Active Directory Service is somewhat new to Windows 2000. It provides a network-wide namespace for system resources. Previously, the internal names used to identify system resources (disk drive names, printer names, user names, file names) were managed within a restricted space of the OS. It was the responsibility of other OS components (e.g., the networking services) to export names across different protocols. The Active Directory is now a uniform, secure, and standard way to identify system resources. It is based on a hierarchical scheme (strictly defined by a schema) whereby entities are categorized into organization units (OUs), trees, and forests. EXTENSIONS TO THE BASE OPERATING SYSTEMAlthough the Executive components of Windows 2000 define and implement core services of the OS, it might be interesting to note that these services are not directly exposed to user-mode applications. Instead, Microsoft defines several Application Programming Interfaces (APIs) that user-mode code treats as abstractions of OS services. These APIs form different environmental subsystems that application code live within. Currently, the following environmental subsystems are included with Windows 2000.
A given application is tightly coupled to exactly one environmental subsystem. Applications cannot make API calls to other environments. Also, only the Win32 subsystem is native other subsystems emulate their environments and therefore experience various degrees of performance degradation compared to native Win32. Their purpose is compatibility, not speed. Environmental subsystems are generally implemented as separate user-mode processes. They launch as needed to support and host user-mode processes. The environmental subsystem becomes the server for the usermode client. Each request from a client is passed, using the Local Procedure Call Executive component, to the appropriate server process. The server process (i.e., the environmental subsystem) either performs the work to fulfill the request directly or it, in turn, makes a request of the appropriate Executive component. THE WIN32 SUBSYSTEMAs the native API for Windows 2000, the Win32 environmental subsystem is responsible for
Because the Win32 Subsystem holds special status within the system and because of its inherent requirement for high performance, this subsystem is implemented differently from any of the other subsystems. In particular, the Win32 subsystem is split into some components that execute in user mode and some that execute in kernel mode. In general, the Win32 function can be divided into three categories.
Since NT 4.0, USER and GDI functions have been moved to kernel mode. User processes that request GUI services are therefore sent directly to kernel-mode using the System Service Interface, an efficient process. Kernel-mode code that implements USER and GDI functions resides in a module called WIN32K.SYS. The USER and GDI kernel components are illustrated in Figure 1.2. Figure 1.2. USER and GDI kernel components.Conversely, KERNEL functions rely on a standard server process, CSRSS.exe (Client-Server Runtime Subsystem), to respond to user process requests. In turn, CSRSS traps into Executive code to complete the request for such functions. INTEGRAL SUBSYSTEMSIn addition to the Environmental Subsystems, there are also key system components that are implemented as user mode processes. These include
|