How a Virtual Address Space Is Partitioned

[Previous] [Next]

Each process's virtual address space is split into partitions. The address space is partitioned based on the underlying implementation of the operating system. Partitions vary slightly among the different Windows kernels. Table 13-1 shows how each platform partitions a process's address space.

As you can see, the 32-bit Windows 2000 kernel and 64-bit Windows 2000 kernel have nearly identical partitions; what differs are the partition sizes and locations. On the other hand, you can see that the partitions under the Windows 98 kernel are rather different. Let's examine how the system uses each of these partitions.

Table 13-1. How a process's address space is partitioned

Partition 32-Bit Windows 2000
(x86 and Alpha)
32-Bit Windows 2000
(x86 w/3 GB User-Mode)
64-Bit Windows 2000
(Alpha and IA-64)
Windows 98
NULL-Pointer Assignment 0x00000000
0x0000FFFF
0x00000000
0x0000FFFF
0x00000000'00000000
0x00000000'0000FFFF
0x00000000
0x00000FFF
DOS/16-bit Windows Application Compatibility NA NA NA 0x00001000
0x003FFFFF
User-Mode 0x00010000
0x7FFEFFFF
0x00010000
0xBFFEFFFF
0x00000000'00010000
0x000003FF'FFFEFFFF
0x00400000
0x7FFFFFFF
64-KB Off-Limits 0x7FFF0000
0x7FFFFFFF
0xBFFF0000
0xBFFFFFFF
0x000003FF'FFFF0000
0x000003FF'FFFFFFFF
NA
Shared Memory-Mapped File (MMF) NA NA NA 0x80000000
0xBFFFFFFF
Kernel-Mode 0x800000000
0xFFFFFFFF
0xC0000000
0xFFFFFFFF
0x00000400'00000000
0xFFFFFFFF'FFFFFFFF
0xC0000000
0xFFFFFFFF

NOTE
Microsoft is actively working on 64-bit Windows 2000. As I write this, however, the system is still under development. You should use the information in this book regarding 64-bit Windows 2000 to influence the design and implementation of your current projects. However, be aware that the details of what I describe in this chapter are quite likely to change by the time 64-bit Windows 2000 ships. With respect to IA-64 (64-bit Intel Architecture) memory management, the specific virtual address ranges for partitions and the system's page size are also likely to change.

Null-Pointer Assignment Partition (Windows 2000 and Windows 98)

This partition of the process's address space, is set aside to help programmers catch NULL-pointer assignments. If a thread in your process attempts to read from or write to a memory address in this partition, the CPU raises an access violation. Protecting this partition is incredibly useful in helping to detect NULL-pointer assignments.

Error checking is often not performed religiously in C/C++ programs. For example, the following code performs no error checking:

 int* pnSomeInteger = (int*) malloc(sizeof(int)); *pnSomeInteger = 5; 

If malloc cannot find enough memory to satisfy the request, it returns NULL. However, this code doesn't check for that possibility—it assumes that the allocation was successful and proceeds to access memory at address 0x00000000. Because this partition of the address space is off-limits, a memory access violation occurs and the process is terminated. This feature helps developers find bugs in their applications.

MS-DOS/16-Bit Windows Application Compatibility Partition (Windows 98 Only)

This 4-MB region of the process's address space is required by Windows 98 in order to maintain compatibility with MS-DOS and 16-bit Windows applications. We should not attempt to read from or write to this partition from our 32-bit Windows applications. Ideally, the CPU should raise an access violation if a thread in our process touches this memory, but for technical reasons, Microsoft was unable to guard this 4 MB of address space.

In Windows 2000, 16-bit MS-DOS and 16-bit Windows applications run in their own address space and cannot be affected by 32-bit applications.

User-Mode Partition (Windows 2000 and Windows 98)

This partition is where the process's private (unshared) address space resides. One process cannot read from, write to, or in any way access another process's data residing in this partition. For all applications, this partition is where the bulk of the process's data is maintained. Because each process gets its own private, unshared partition for data, applications are far less likely to be corrupted by other applications, making the whole system more robust.

Windows 2000
In Windows 2000, all .exe and DLL modules load in this area. Each process might load these DLLs at a different address within this partition (although this is very unlikely). The system also maps all memory-mapped files accessible to this process within this partition.

Windows 98
In Windows 98, the main Win32 system DLLs (Kernel32.dll, AdvAPI32.dll, User32.dll, and GDI32.dll) load in the Shared Memory-Mapped File Partition. The .exe and all other DLL modules load in this user-mode partition. The shared DLLs will be at the same virtual address for all processes, but the other DLLs can load these DLLs at different addresses within the user-mode partition (although this is unlikely). Also, in Windows 98, memory-mapped files never appear in the user-mode partition.

When I first looked at my 32-bit process's address space, I was surprised to see that the amount of usable address space was less than half of my process's overall address space. After all, does the kernel-mode partition really need the top half of the address space? Actually, the answer is yes. The system needs this space for the kernel code, device driver code, device I/O cache buffers, non-paged pool allocations, process page tables, and so on. In fact, Microsoft is squeezing the kernel into this 2-GB space. In 64-bit Windows 2000, the kernel finally gets the room it truly needs.

Getting a 3-GB User-Mode Partition in x86 Windows 2000

Over the years, there has been a large outcry from developers for a larger user-mode address space. Microsoft, being attentive to this need, has allowed the x86 version of Windows 2000 Advanced Server and Windows 2000 Data Center to increase the user-mode partition to 3 GB. To have all processes use a 3-GB user-mode partition and a 1-GB kernel-mode partition, you need to append the /3GB switch to the desired entry in your system's BOOT.INI file. The "32Bit Windows 2000 (x86 w/3GB User-mode)" column in Table 13-1 shows how the address space looks when the /3GB switch is used.

Before Microsoft added the /3GB switch, an application could never see a memory pointer where the high bit was set. Some creative developers took it upon themselves to use this high bit as a flag that had meaning only to their applications. Then when the application accessed the memory address, code executed that cleared the high bit of the pointer before the memory address was used. Well, as you can imagine, when an application runs in a 3-GB user-mode environment, the application fails in a blaze of fire.

Microsoft had to create a solution that allowed this application to work in a 3-GB environment. When the system is about to run an application, it checks to see if the application was linked with the /LARGEADDRESSAWARE linker switch. If so, the application is claiming that it does not do anything funny with memory addresses and is fully prepared to take advantage of a 3-GB user-mode address space. On the other hand, if the application was not linked with the /LARGEADDRESSAWARE switch, the operating system reserves the 1-GB area between 0x80000000 and 0xBFFFFFFF. This prevents any memory allocations from being created at a memory address whose high bit is set.

Note that the kernel was squeezed tightly into a 2-GB partition. When using the /3GB switch, the kernel is barely making it into a 1-GB partition. Using the /3GB switch reduces the number of threads, stacks, and other resources that the system can create. In addition, the system can only use a maximum of 16 GB of RAM vs. the normal maximum of 64 GB because there isn't enough virtual address space in kernel mode to manage the additional RAM.

NOTE
An executable's LARGEADDRESSAWARE flag is checked when the operating system creates the process's address space. The system ignores this flag for DLLs. DLLs must be written to behave correctly in a 3-GB user-mode partition or their behavior is undefined.

Getting a 2-GB User-Mode Partition in 64-bit Windows 2000

Microsoft realizes that many developers will want to port their existing 32-bit applications to a 64-bit environment as quickly and easily as possible. However, there is a lot of source code in which pointers are assumed to be 32-bit values. Simply rebuilding the application will cause pointer truncation errors and improper memory accesses.

However, if the system could somehow guarantee that no memory allocations would ever be made above 0x00000000'7FFFFFFF, the application would work fine. Truncating a 64-bit address to a 32-bit address when the high 33 bits are 0 causes no problem whatsoever. The system can provide this guarantee by running the application in an address space sandbox that limits a process's usable address space to the bottom 2 GB.

By default, when you invoke a 64-bit application, the system reserves all the user-mode address space starting at 0x0000000'80000000. This ensures that all memory allocations are created in the bottom 2 GB of the 64-bit address space. This is the address space sandbox. For most applications, this is more than enough address space anyway. To allow a 64-bit application to access its full 4-TB (terabyte) user-mode partition, the application must be built using the /LARGEADDRESSAWARE linker switch.

NOTE
An executable's LARGEADDRESSAWARE flag is checked when the operating system creates the process's 64-bit address space. The system ignores this flag for DLLs. DLLs must be written to behave correctly in a full 4-TB user-mode partition or their behavior is undefined.

64-KB Off-Limits Partition (Windows 2000 Only)

This 64-KB partition just above the user-mode partition is off-limits, and any attempt to access memory in this partition causes an access violation. Microsoft reserves this partition because doing so makes implementing the operating system easier for Microsoft. When you pass the address of a block of memory and its length to a Windows function, the function validates the memory block before performing its operation. You could easily imagine code like this (running on a 32-bit Windows 2000 system):

 BYTE bBuf[70000]; DWORD dwNumBytesWritten; WriteProcessMemory(GetCurrentProcess(), (PVOID) 0x7FFEEE90, bBuf, sizeof(bBuf), &dwNumBytesWritten); 

For a function like WriteProcessMemory, the memory region being written to is validated by kernel-mode code, which can successfully access memory in the kernel-mode partition (addresses above 0x80000000 on a 32-bit system). If there is memory at the 0x80000000 address, the above call will succeed in writing data to memory that should be accessible only by kernel-mode code. To prevent this while making the validation of such memory regions fast, Microsoft chose to keep this partition always off-limits; any attempt to read from or write to memory in this region will always cause an access violation.

Shared MMF Partition (Windows 98 Only)

This 1-GB partition is where the system stores data that is shared among all 32-bit processes. For example, the system dynamic-link libraries—Kernel32.dll, AdvAPI32.dll, User32.dll, and GDI32.dll—are all loaded in this address space partition, making them easily available to all 32-bit processes simultaneously. These DLLs are also loaded at the same memory address for every process. In addition, the system maps all memory-mapped files in this partition. Memory-mapped files are discussed in more detail in Chapter 17.

Kernel-Mode Partition (Windows 2000 and Windows 98)

This partition is where the operating system's code resides. The code for thread scheduling, memory management, file systems support, networking support, and all device drivers is loaded in this partition. Everything residing in this partition is shared among all processes. In Windows 2000, these components are completely protected. If you attempt to access memory addresses in this partition, your thread will raise an access violation, causing the system to display a message box to the user and killing your application. See Chapters 23, 24, and 25 for more information about access violations and how to handle them.

Windows 2000
In 64-bit Windows 2000, the 4-TB user-mode partition looks greatly out of proportion to the 16,777,212-TB kernel-mode partition. It's not that the kernel-mode partition requires all of this virtual address space. It's just that a 64-bit address space is enormous and most of that address space is unused. The system allows our applications to use 4 TB and allows the kernel to use what it needs; the majority of the kernel-mode partition is just not used. Fortunately, the system does not require any internal data structures to maintain the unused portions of the kernel-mode partition.

Windows 98
Unfortunately, in Windows 98, the data in this partition is not protected—any application can read from or write to this section, potentially corrupting the operating system.



Programming Applications for Microsoft Windows
Programming Applications for Microsoft Windows (Microsoft Programming Series)
ISBN: 1572319968
EAN: 2147483647
Year: 1999
Pages: 193

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net