12.3. Virtual Address Spaces
In Windows NT, the virtual address space of the system is divided into two parts: the low 2GB user address space and the high 2GB system space (see Figure 12.2). When the CPU is running in user mode, only pages of the user address space are accessible, so applications cannot interfere with the operating system components that are accessible only in kernel mode. When a user-mode application (such as WINWORD.EXE, NOTEPAD.EXE, and others) calls an API, it first calls into a subsystem DLL. The subsystem DLL API translates the documented function to an undocumented one in the native API set as part of NTDLL.DLL. When necessary, the native API calls the Windows NT executive, and the processor is switched to kernel mode. The Windows NT standard 32-bit linear address space division is illustrated in Figure 12.2.
Figure 12.2. Standard address space division on 32-bit Windows NTbased systems.
The 4GB address space division can be changed by using Windows NT Enterprise Edition and a special boot.ini option. In this case, the user address space is 3GB, which leaves 1GB for the system address space. This is done to support applications that use very large databases and can work more efficiently this way. Windows NT Enterprise Edition address space division (/3GB)4 is illustrated in Figure 12.3.
Figure 12.3. Windows NT Enterprise Edition loaded with the /3GB option.
One of the new features of Windows 2000 on Alpha APX systems is the extension of the VM address space to a total of 32GB, rather than the current 4GB, called VLM5, 6 (see Figure 12.4). The upper user space is not paged and can be used only for data, not for code.
Figure 12.4. The VLM memory layout.
In all of these models, the user address space maps a particular process at a time. Each time a user-mode application is executed, NT creates a virtual address space for the new process. The same virtual address can be used by any number of applications, but the virtual address does not necessarily point to the same physical page in memory. When process A accesses a page at 0x00400000 (the usual base address of applications) process B's page at 0x00400000 may not even be valid at all. Process A cannot interfere with process B by using the same address because it is valid only in its own context. On a single CPU, only one virtual-to-physical mapping can be in use. Each time a particular thread is scheduled for execution, a context switch occurs, changing the actual virtual-to- physical mappings to the process context in which the scheduled thread is running. To provide kernel-mode components (and drivers) with an environment in which they know that their memory references are always valid for the upper 2GB of address space, NT provides a portion of page tables that hold the same information in each context.
The Virtual Memory Manager handles the system address space differently from the user address space. (See Figure 12.5, which illustrates4 a normal system address space layout on IA32.) In that address space, Windows NT's code components are loaded together with all the kernel-mode drivers. Because kernel-mode drivers have the same privilege and view of the system address space, they can interfere with the operating system's code or with one another. A sample list of loaded system components is shown in Listing 12.1.
Listing 12.1. Partial List of Loaded Drivers and Their Base Addresses in a 32-bit Address Space
BaseAddr Name 0x77f60000 \WINNT\system32\NTDLL.DLL 0x80001000 Pcmcia.sys 0x8000b000 Disk.sys 0x80010000 \WINNT\System32\hal.dll 0x80100000 \WINNT\System32\ntoskrnl.exe 0x801e0000 \WINNT\System32\drivers\SCSIPORT.SYS 0x801e8000 \WINNT\System32\Drivers\CLASS2.SYS 0x801ec000 Ntfs.sys 0x80244000 TpPmPort.sys 0xa0000000 \??\C:\WINNT\system32\win32k.sys . 0xf7000000 \SystemRoot\System32\Drivers\Cdfs.SYS . 0xf72f0000 \SystemRoot\System32\Drivers\Cdrom.SYS
Figure 12.5. Normal layout of kernel-mode memory space.
Note that NTDLL.DLL (native API) appears on the loaded driver list. Though this DLL is loaded in user mode, it is strongly related to the transition of several functions to kernel mode. The native API acts as a "middle man."
Probably the most demanding problem of virtual memory management is the paging mechanism. Windows NT has the ability to reclaim pages of memory that are no longer needed. To reclaim a page, the Memory Manager changes individual entries in the page table, marking them as invalid. If the page belongs to an executable and is not a dirty page (a page whose content has changed during execution), nothing else needs to be done but marking the page as invalid. Otherwise the changed page must be written into a file, most likely to the page file (pagefile.sys).
When the page is accessed again, a page fault is generated. Then the actual virtual address is checked, if it is available. If it is mapped in from a file (like most DLLs and applications), the page is read from the particular file in which the data exists. Otherwise, the information from a file or from a page file will be read in, and Windows NT will rerun the instruction that generated the fault.
Windows NT can share a physical page of memory between several processes. This means that several copies of an executable application will not reserve the exact same amount of memory each time. Instead, the same physical pages are seen from all views. When the contents of a page should change, not every process context will change, only the instance that needs the change. This is done by reserving a new physical page and moving the data from the copy-on-write page to the new page. Thus the change happens in the new copy.