Licensed Memory in 32-Bit Windows Vista

Though computers with 4GB of RAM are not yet—in 2009 when this article was written!—the typical purchase for home or business use, they are readily available from major manufacturers and it won’t be long before they are the typical purchase. But there are problems. You don’t have to stand for long in a computer shop to hear a sales assistant talk of 4GB as some sort of limit for 32-bit operating systems, and it won’t be long before this sales patter develops into outright promotion of 64-bit Windows as the only way to get past this limit. Some sense of this can be seen already in manufacturers’ advertising materials, as in the following fine print from Dell:

The total amount of available memory will be less than 4GB. The amount less depends on the actual system configuration. To fully utilise 4GB or more of memory requires a 64-bit enabled processor and 64-bit operating system, available on selected systems only.

Let me stress now that I do not complain about Dell’s statement. Its first two sentences are correct for all 32-bit editions of Windows Vista exactly as configured by Microsoft and installed by Dell. In the last sentence, I might quibble that the talk of a 64-bit processor is superfluous since the machine on offer does have such a processor, but otherwise the sentence is correct because of the word fully. Yet although Dell’s statement is true, it is not the whole truth: there is something that Microsoft does not tell you, and perhaps does not tell Dell.

That 32-bit editions of Windows starting with Windows Vista are limited to 4GB is not because of any technical constraint on 32-bit operating systems. The 32-bit editions of Windows Vista and Windows 7 all contain code for using physical memory above 4GB. Microsoft just doesn’t license you to use that code.

Well, to say it that way is perhaps to put words in Microsoft’s mouth, especially if you interpret me as saying why Microsoft has done it. Please be sure to understand that I am just telling you what Microsoft has done and how Microsoft has done it. I can’t know why Microsoft has done it, though I will later ask why Microsoft hasn’t explained it clearly or allowed for independent testing of what little Microsoft says of it.

I say the restriction to 4GB is a licensing issue because that’s how Microsoft’s programmers evidently have thought of it. The 4GB limit is retrieved from the registry by calling a function named ZwQueryLicenseValue, which is itself called from an internal procedure which Microsoft’s published symbol files name as MxMemoryLicense. If you remove this check for the licensed memory limit then a restriction to 4GB is demonstrably not enforced by other means.

Inasmuch as the software models the thoughts of those who write it, licensing is plainly the one and only mechanism of the restriction. Yet I must admit that I have not found where Microsoft says directly that 32-bit Windows Vista is limited to 4GB only by licensing. The supposed License Agreement doesn’t even mention the word memory. What, really, is going on?

Demonstration

Put aside for now the fine print of what it means to “fully utilise” and ask what’s even possible. Especially if you’re one of the many who believe that 32-bit operating systems can’t by definition use more than 4GB of RAM, what do you expect to see for the System Properties in the original 32-bit Windows Vista on a machine with 8GB of RAM? Click on the snapshot if you want it full-size and hi-fi:

System Properties Showing 8189MB of RAM

No, this image is not a mock-up, though the red rectangle is my addition to highlight that this 32-bit operating system which ordinarily finds only 3069MB of RAM on this machine seems happy to have 8189MB. Windows will use all this memory, too, not that I have any ordinary need for it to do so.

The next picture is as much a record of my unimaginativeness as of 32-bit Windows Vista actually using (very nearly) all the installed 8GB. An entirely ordinary test program writes 1GB of data from a single memory block to a file and reads the file back into that same memory block. That takes a while, even on a fast machine. By the time that eight instances are running concurrently, all the physical memory is in use:

Task Manager Record of Using 8GB of RAM

Of course, there are contrivances and caveats.

Contrivance

To get these pictures without contrivance, you would need a license upgrade from Microsoft, which Microsoft shows no sign of offering. The license data that would have to be upgraded is protected in various ways from being tampered with, and I certainly do not mean for anyone to try changing it, even for testing.

Instead, to simulate having new license data from Microsoft, I have modified the kernel just enough so that it ignores the two license values that set memory limits, and I have started Windows in Test Mode so that it tolerates a kernel that no longer has Microsoft’s digital signature. Neither of these steps is meant for general use.

I am not solving for you the problem of how to have 32-bit Windows Vista use all your 4GB or more of physical memory without Microsoft’s permission. Neither am I saying that 32-bit Windows Vista is a better (or worse) option than 64-bit for using all your 4GB of memory. I am just demonstrating that despite what Microsoft and many others say to the contrary, 32-bit Windows Vista actually can use all the RAM that you can feasibly install. The code for doing it is already in the product that Microsoft sells you. There is no need to bring in any code from a different edition of Windows or to make 32-bit Windows Vista believe it is anything other than 32-bit Windows Vista.

All that needs to be changed are two pieces of registry data whose sole purpose is to specify how much memory Microsoft permits you to use. No code needs to be changed even by one byte, but to prove this point I have to patch the code because Microsoft protects the data. If you want that this should work for you without contrivance, then pester Microsoft for an upgrade of the license data or at least for credible, detailed reasoning of its policy for licensing your use of your computer’s memory in 32-bit Windows Vista.

Caveats

As for caveats, you should know that although I study software, I do not have the testing resources of a software or hardware manufacturer. I don’t know of anything that misbehaves now that Windows finds all this memory that it ordinarily overlooks. Indeed, since Microsoft is apparently happy to license the use of physical memory above 4GB on 32-bit Windows Vista SP1 when rebadged as Windows Server 2008, I would be astonished if there is any misbehaviour in Windows itself. But I can’t swear that everything works correctly in every detail and I especially can’t answer for behaviour that is not in the Windows code.

With one exception, my test installation is just the original 32-bit Windows Vista Ultimate from MSDN discs, with all Windows features installed, but with no real-world additions of applications or drivers that aren’t distributed with Windows or of devices that didn’t come with the machine. Applications ought not matter, as argued below, but drivers may. This is where my one exception comes from: some of my tests failed until I updated the display driver (from NVIDIA). That’s as good a reminder as any that when I say 32-bit Windows Vista has working code for using memory above 4GB, I talk of what Microsoft has written for Windows, not of what you add to your Windows installation from who knows where.

Truth?

Still, even with contrivances and caveats, how can it be that I—or you after following my directions if you want to test what I say—can get anywhere near to producing such pictures? After all, for the page The system memory that is reported in the System Information dialog box in Windows Vista is less than you expect if 4GB of RAM is installed, Microsoft states plainly that “for Windows Vista to use all 4GB of memory … an x64 (64-bit) version of Windows Vista must be used.” The pictures above show just as plainly that this statement by Microsoft cannot be entirely truthful.

Even if you’re perfectly happy to upgrade to 64-bit Windows Vista—and for all you’re to know from reading this article, I’m among you on that point—I ask that you focus on whether Microsoft is open and truthful, and on whether the rest of the industry has been suitably vigilant on your behalf for assessing what Microsoft says about Microsoft’s products. Even if you don’t care about that for this issue, you may for another. The more that technology companies get away with half-truths and the exploitation of ignorance even on one issue, the more they can drift into it as their standard practice.

What is the truth, then? When someone says some such thing as that 32-bit Windows Vista is technically, physically, logically, architecturally, fundamentally or otherwise incapable of using all your 4GB or more of RAM, what can they mean?

There is already on the Internet and elsewhere an awful lot of rubbish to read about this question. Hardly any of it would be worth citing even if I didn’t want to spare the authors the embarrassment.

A surprising number of people who claim some sort of attention as expert commentators would have you believe that using more than 4GB of memory is mathematically impossible for any 32-bit operating system because 2 to the power of 32 is 4G and a 32-bit register can’t form an address above 4GB. If nothing else, these experts don’t know enough history: 2 to the 16 is only 64K and yet the wealth of Microsoft is founded on a 16-bit operating system that from its very first version was designed to use 640KB of RAM plus other memory in a physical address space of 1MB.

Some remember this history and add seemingly plausible qualifications that exceeding 4GB is possible only at the price of nasty hacks that require everyone—well, all programmers—to jump through hoops. Fortunately, Intel’s processors are a lot more advanced than the 8086 from all those years ago. Though 4GB is an obvious mathematical limit on the memory that any single 32-bit program can use without special coding, it was passed long ago as a limit for the system and multiple programs in total.

Physical Address Extension

Old hands may already have groaned at the preceding heading. The means for a 32-bit operating system to use physical addresses above 4GB was built into Intel’s 32-bit processors well over a decade ago1 and has been supported by Microsoft since Windows 2000. If you haven’t heard of it, or haven’t thought that it applies to Windows Vista, then one reason may be that Microsoft has mostly advertised it only as a feature of the server editions such as Windows 2000 Server and Windows Server 2003, and only then for the more expensive levels with names like Enterprise and Datacenter. However, even Windows 2000 Professional can be configured, without contrivance, to access memory above 4GB by using Physical Address Extension (PAE). This is old technology. It’s also widely and deeply misunderstood technology, arguably more than any other in the history of personal computing.

The essence of PAE is that the 32-bit registers used by 32-bit instructions in a 32-bit operating system do not in practice address physical memory. This is because of very old technology called paging. From at least as long ago as when Windows 3.0 Enhanced Mode established Windows as the operating system to replace DOS, no software running on any real-world operating system gets to address memory directly except very early during system initialisation. The 32-bit register with which a program or driver or the operating system itself addresses memory holds what is called a linear address.2 The processor translates linear addresses to physical addresses by looking through page tables, which are configured by the operating system. The layout of linear address space need have nothing to do with the layout of physical address space. This is how a DLL, for instance, can be loaded at an address not far below 2GB even on a machine that has only a few megabytes of RAM. Pages are typically small, just 4KB each. Two neighbouring pages in linear address space can come from opposite ends of physical memory. It’s all up to the operating system’s memory manager and almost all of us, both users and programmers, take this paging mechanism completely for granted.

For the 80386 in 1985, each page table entry (PTE) was 32 bits and allowed only for translating a 32-bit linear address to a 32-bit physical address. However, there is nothing fundamental to that. What’s fundamental is only that every linear address must either map to a physical address or be not-present. There is no reason at all that the linear and physical address spaces must be the same size. With a suitably different translation algorithm, the physical address space can be as big as Intel wants to allow. This theoretical point, which I expect was appreciated at Intel from the outset, got its real-world implementation in the P6 family of processors, beginning with the Pentium Pro in 1995. Since then, with only very few exceptions, Intel’s processors that are suitable for running 32-bit Windows all have enough address lines for accessing 64GB of memory and all support a translation algorithm for using all that memory in 32-bit code. PAE is this alternative translation algorithm.

The practical outcome for 32-bit operating systems in general is that although any one instruction can form addresses for only 4GB of linear address space, those 4GB can be drawn together page by page from all over any size of physical address space as and when the need arises. For Windows in particular, the design is that the linear address space changes for each process. In 32-bit Windows, a process’s user-mode code is allowed between 2GB and 3GB of linear address space (depending on the increaseuserva boot option), and the remainder of the 4GB is reserved for use by kernel-mode code. Both 32-bit and 64-bit Windows can use all of physical memory, including above 4GB, but each 32-bit Windows application on 32-bit Windows has at most 3GB of linear address space through which to access physical memory.

The difference between that and the “fully utiltise” in Dell’s fine print seems very fine to me, especially while I don’t have any real-world applications that need (or even use) as much as half a GB for each running instance. Until software that uses memory by the gigabyte becomes common for ordinary use outside of specialised contexts, this difference from full utility does not of itself justify a rush to 64-bit Windows—and certainly not of disturbing a working, trusted installation of 32-bit Windows.

If you have a 32-bit Windows program that wants more than its 2GB or 3GB, then upgrading to a 64-bit version of that program to run on 64-bit Windows is your only path ahead. If you’re buying a new computer and new applications, then getting 64-bit Windows and 64-bit applications is obviously the way of the future.

Meanwhile, if your concern is only that the system and all your 32-bit applications may together use all your 4GB or more, then keeping your 32-bit operating system would at least be an option for you if Microsoft would provide you with license data to let you use the PAE support that Microsoft has already coded into the product.

An Ugly Hack?

Some commentators seem to have trouble grasping the naturalness of a physical address space that is larger than the linear address space. Perhaps they have been distracted by paging’s historical role as technology for dealing with a shortage of physical memory. Perhaps they have in mind the history of MS-DOS, which was kept alive for many years with ever more ways that programmers might write new code to access ever more memory than the basic 640KB.

PAE is nothing like that. It is no more a concern to any software than is paging. After all, it is nothing but a variant algorithm for paging. Just as hardly any software is concerned that linear addresses are translated to physical addresses, even less software is affected by how linear addresses are translated to physical addresses. Application-level code and even most system-level code is entirely unconcerned and unaffected. Except for the operating system’s memory manager and for the relatively few drivers that work with physical memory addresses, most notably for Direct Memory Access (DMA), no 32-bit software needs any recoding to benefit from a more-than-32-bit physical address space.

Even kernel-mode drivers don’t need to know anything specific to PAE, much less be written specially to support it. All that’s required is a general awareness that physical memory addresses may be wider than 32 bits and that accommodation of this comes naturally from following the documentation. Far from being an ugly hack, PAE requires pretty much nothing of anyone. Indeed, to write a driver that misbehaves only when memory is present above 4GB, you actually have to work at it, either by programming artificially or by convincing yourself that you don’t need to do all that the documentation spells out.

When working with physical memory addresses, even 32-bit device drivers need to do 64-bit arithmetic. This should be natural since Microsoft’s development kit for device driver programming has recommended it for well over a decade, including to define a 64-bit PHYSICAL_ADDRESS type that is used by all functions that receive or return physical memory addresses. Moreover, this type is a structure whose members are integers. The programmer who wanted, for who knows what reason, to cast a physical address to a pointer could not easily do it in a way that is valid for 64-bit Windows but is invalid for 32-bit Windows when there’s memory above 4GB. With only a few highly contrived exceptions, any errors with a 32-bit driver’s handling of 64-bit physical addresses, e.g., to discard the high 32 bits, would be as much in error if left unfixed in the same device’s 64-bit driver for 64-bit Windows. Whatever such errors may have existed years ago, the natural expectation must be that they are rapidly getting fixed in the latest versions as ever more drivers get revised for 64-bit Windows.

For the particular matter of working with DMA, device drivers need to conform to the long-documented functional requirements for setting up and managing their DMA transfers. In particular, they need to be aware that the DMA functions may succeed only partially, and need to be called again to complete the request. The most significant, but not the only, reason for partial success is that the necessary double buffers could not all be set up. Double buffering is a technology for when a device cannot handle the full range of possible physical memory addresses. For instance, an old type of device (such as a floppy disk drive controller) may be limited to 24-bit physical addresses. To get data from the controller to physical memory above 16MB, the driver must use the DMA functions properly, so that the controller actually reads to a double buffer below 16MB and the DMA functions then copy the data to where it was wanted. A less old type of device (such as an IDE controller) may be limited to 32-bit physical addresses and will need double buffering in any operation that reads or writes to memory above 4GB. Of course, most devices can handle 32-bit physical addresses and increasingly many can handle 64-bit addresses. Either way, their drivers are supposed to use the DMA functionality as if double buffering may turn out to be needed. Some drivers for 32-bit Windows assume that all physical addresses fit 32 bits and that their 32-bit device therefore needs no double buffering. They then take shortcuts with their use of the DMA functions. If these drivers are not fixed, then using physical memory above 4GB will expose the liberty that they have taken with the documented coding model. Note that if the device can handle 32-bit physical memory addresses but not 64-bit, then double-buffering would be required on 64-bit Windows too, and the driver’s faulty assumptions would be just as faulty for 64-bit Windows.

None of this is to say that 32-bit drivers do not exist whose faults are exposed when using memory above 4GB, or even that they never existed in any significant number, but it is to say that the main types of fault must be confronted in the development of a 64-bit driver for the same device, so that retention of these faults in the contemporaneous 32-bit driver is highly implausible and even reckless. If you are worried that faulty drivers (or inadequate hardware, for that matter) make 32-bit Windows Vista with PAE unsafe when using physical memory above 4GB, then you would do well to wonder how 64-bit Windows can be any less unsafe on the same machine.

PAE and Performance

Some commentators say that PAE comes at some hideous cost to performance. Compared with the original algorithm that maps 32-bit linear addresses to 32-bit physical addresses, PAE is slower. It has one extra level to its page tables. Each PTE is twice as big. The operating system therefore has more work to do when preparing and maintaining the page tables, and since the Translation Lookaside Buffer (TLB) has only half the capacity, memory references are more likely to miss the TLB and require additional bus cycles. The reduction in performance is surely measurable. If you have no need to access memory above 4GB and are concerned enough, then you would not enable PAE if performance is all that matters. Note however that Microsoft does not regard this performance cost as worth troubling over (as will be clear shortly, under the heading Data Execution Prevention).

Of course, for access to memory above 4GB, the appropriate comparison is not between using PAE and not using it, but between using PAE on 32-bit Windows and using 64-bit Windows. For this comparison, not only are the PTEs the same size but the algorithms are very similar. To the processor, it’s PAE that is slightly simpler and plausibly quicker, but the memory manager in a 64-bit operating system can benefit from using 64-bit registers when working with the PTEs. These are very fine trade-offs relative to the enormous overheads that embellish some of the wilder misunderstandings of PAE on the Internet.

For a rough-and-ready assessment of these trade-offs, consider Microsoft’s own performance measurement, as given by the Windows Experience Index. Surely this is meant to have some objectivity, even if comparison of ratings for 32-bit and 64-bit Windows may not be strictly fair. On this article’s test machine, the “Memory (RAM)” component of the Windows Experience Index is consistently 5.0 in 64-bit Windows Vista and is just as consistently 5.1 in 32-bit Windows Vista, whether PAE is enabled or not.

Choosing PAE

Whether the memory manager in the Windows kernel uses PAE is configurable through the pae boot option. Indeed, 32-bit Windows Vista is supplied with two kernels:

The two kernels are respectively NTOSKRNL.EXE and NTKRNLPA.EXE, both in the Windows System directory. The loader (WINLOAD.EXE) knows how to set up the linear address space for mapping to physical addresses with or without PAE, but each kernel is specialised to one algorithm for the mapping. The pae option tells the loader which kernel to load.

Data Execution Prevention

If you have a modern machine of the sort that manufacturers are fitting with 4GB of RAM, then you very likely are running the PAE kernel already. This is not so that you can use physical memory above 4GB, else this article would not exist. It is instead to give you what Microsoft calls Data Execution Prevention (DEP). This protects you from programs that try to execute data, whether in error or from (suspected) malice. The connection with PAE is that DEP depends on the NX bit that AMD has defined (and Intel adopted) in 64-bit PTEs, such that DEP can only be enabled if PAE is also enabled. Because Microsoft wants you to benefit from DEP, the typical practice of Windows Vista is to select the PAE kernel if you haven’t specified that you want it and even if you have specified that you don’t want it. If your machine supports DEP, then a necessary condition for disabling PAE is that you also disable DEP by setting nx to AlwaysOff as well as setting pae to ForceDisable.

Physical Memory Map

That you have 4GB of RAM does not mean that all physical memory addresses from zero to 4GB actually do reach any RAM. In practice, much of that range of physical address space, most likely at the top, is given over to such things as the system BIOS and devices. You can get some sense of this by starting the Device Manager, opening the View menu and asking to see “Resources by type” or “Resources by connection” and then expanding Memory. What this gives you, however, is at best only an indication. It tells you that some addresses are used for devices. It doesn’t tell you which addresses actually do have RAM (or ROM, for that matter).

The memory map that matters most for the question of what physical memory the kernel can use is the map that the loader discovers from the firmware. For machines whose firmware is a PC-compatible BIOS, the means of discovery is int 15h function E820h.3 Unfortunately, the loader does not save this map exactly as learnt from the BIOS, which complicates your inspecting this memory map for yourself. However, Windows Vista introduces some undocumented functions with which a kernel-mode driver can get the map fresh from the BIOS. Such a driver for viewing the firmware memory map is presented separately, along with a small console application that reports the results. You will need administrative privilege to load the driver.

Of particular interest once you have the firmware’s memory map for your computer are the ranges that are reported as RAM. This article’s test machine has its 8GB of RAM in four ranges spread through 9GB of address space:

Address Size Remarks
00000000`00000000 00000000`0009FC00 640KB of base RAM, less 1KB as an Extended BIOS Data Area
00000000`00100000 00000000`BFD0AC00 not quite 3GB at 1MB
00000001`00000000 00000001`00000000 4GB at 4GB
00000002`00000000 00000000`40000000 1GB at 8GB

The first 3GB of physical address space has RAM in two ranges because some is lost at the top of the first 1MB (for reasons of compatibility that go all the way back to the original IBM PC) and some more is lost at the end of the 3GB. The next 1GB is so much given over to device memory that instead of wasting RAM at 3GB, hardware remaps the RAM from there to the end of all other RAM, where it shows as the last of the ranges. The total amount of addressable RAM in the first 4GB is 3,143,338KB, i.e., 3069MB and 682KB. On this machine, with its present configuration of hardware, if the kernel is limited to the first 4GB as its physical address space, then 3069MB (and the spare change) is all the RAM that the kernel can possibly use. Get the kernel to recognise physical addresses above 4GB, and it picks up the other 5GB, for a total of 8189MB as shown in the picture.

If the 4th gigabyte were left at 3GB, Windows would have access only to as much of it as does not get overridden. In practice, RAM might show through in various gaps, so that the amount of RAM accessible below 4GB would be more than 3GB but nowhere near 4GB. If you have exactly 4GB of RAM installed, then getting the kernel to use physical addresses above 4GB will be no benefit to you unless some of your 4GB of RAM is remapped above the 4GB address. Whether this remapping is done at present on your particular machine can be checked by using the separately supplied driver. If it is not done, then whether it can be arranged is an issue of hardware configuration. Check your BIOS Setup, read your chipset manual, or consult your computer’s manufacturer.

Of course, for a machine that has exactly 4GB of RAM and has 32-bit Windows Vista pre-installed, you would expect that the manufacturer, having been told by Microsoft that Windows will not see any RAM above 4GB, might not have configured any of the 4GB to be remapped out of sight and into uselessness. You should not be surprised to find that remapping is disabled. Worse, unless the manufacturer anticipates installing other Windows versions on the machine, there is no incentive even to provide for remapping above 4GB as something that you can configure if you want. It may even be that your chipset can’t handle physical memory addresses that are wider than 32 bits. Either way, you don’t have memory above 4GB whatever your operating system. If your chipset does not support remapping, then RAM that is overridden for device memory below 4GB will never be seen as usable RAM by 32-bit Windows even with PAE enabled and is just as much lost to you if you install 64-bit Windows.

License Values

How does it happen, then, that 32-bit Windows Vista is supplied with a PAE kernel which is capable of using memory above 4GB but doesn’t actually use any of that memory? Broadly speaking, there are two mechanisms by which your hardware and firmware can provide for memory above 4GB which Windows will then not try to use. One is that the kernel never learns of any such memory. The other is that the kernel knows the memory is there but deliberately ignores it.

The first of these mechanisms comes about from a boot option, named truncatememory, which tells the loader to discard all pages of physical memory that are not wholly beneath some specified address. Thereafter, the discarded memory may just as well never have been reported by the firmware. When the kernel receives the memory map from the loader, memory at and above the truncatememory cut-off is already long gone from the map.

Of course, most people want all their computer’s memory to get used, and so the truncatememory option is ordinarily not set (even by people who know it exists). By the time the kernel receives the memory map from the loader, the map has been much refined in order to account for how memory is already in use, but it is otherwise intact as a report of physical memory that the kernel can use.4 Very early during the kernel’s initialisation, however, the kernel sets about its own filtering of this memory map. Limits are applied both to the total amount of usable memory and to the maximum physical address. Memory in excess of these limits is discarded, such that although it was passed to the kernel from the loader, it may as well not have been.5

Total Memory

The total amount of memory allowed is taken solely from the license value Kernel-WindowsMaxMemAllowedx86, as read through the undocumented function ZwQueryLicenseValue. The data for this value is a number of MB, so that 0x1000, which is installed for all 32-bit editions of Windows Vista, means 4GB.

Maximum Address

The maximum physical address is calculated as the least of three values: a license limit; a run-time limit; and a hard-coded limit.

For the ordinary kernel, the license value for the maximum physical address is the same as for the total amount of memory, but the PAE kernel has a separate license value, named Kernel-MaxPhysicalPage. Again, the data for this value is a number of MB. Again, all 32-bit editions of Windows Vista are installed with this value set to 0x1000, representing 4GB.

The run-time limit arises from needing to be sure that an array of MMPFN structures can be set up to represent all the pages of physical memory, one structure per 4KB page, from zero up to the maximum physical address. The kernel’s capacity for such an array depends on how much of the linear address space is already in use. This gives the run-time limit on the maximum physical address. It is the size of the largest free block in the kernel’s part of the linear address space, divided by the size of an MMPFN structure (0x18 or 0x1C bytes for the ordinary and PAE kernels, respectively), and then multiplied by the page size.

The preceding calculation also produces an architectural limit on the use of physical memory by 32-bit Windows with a PAE kernel. The largest block of linear address space that is available even this early cannot be as large as 1GB and could be much smaller.6 Even if it is very nearly 1GB, that’s only enough to fit an MMPFN array for a maximum physical address of 128GB (given that the maximum should be a power of two). This limit is hard-coded in the PAE kernel, as is 4GB for the non-PAE kernel.

For the question of whether the kernel in 32-bit Windows Vista will use all the physical memory it learns about from the loader, the hard-coded limit of 4GB is dominant as the maximum address for the ordinary kernel, which truly cannot form addresses for physical memory above 4GB, but the license limit is dominant for the PAE kernel. If you have physical memory above 4GB and wonder how it can be that the PAE kernel does not use that memory, the answer is licensing. Code for using memory above 4GB is present in 32-bit Windows Vista as Microsoft supplies it, but Microsoft prepares license values in the registry so that this code never gets to work with any physical addresses above 4GB.

Transparency

Microsoft is not exactly forward in describing this mechanism by which 32-bit Windows Vista is restricted to 4GB. Especially notable is that the page Memory Limits for Windows Releases doesn’t mention the word license. Some explanation may be that Microsoft takes licensing so much for granted that it is simply left as understood that the stated limits on physical memory are licensing limits.

For the page The system memory that is reported in the System Information dialog box in Windows Vista is less than you expect if 4GB of RAM is installed, Microsoft again does not explicitly let on that all the necessary code for using memory above 4GB is present in the product, but does at least hint at it when saying that “the 32-bit versions of Windows Vista limit the total available memory” to protect users against incompatible drivers. Though no drivers need to know the mechanics of PAE and only a small proportion work at all with physical addresses, they may be indirectly incompatible with PAE because (as explained earlier) they have been coded to an assumption that the physical address space is the same size as the linear address space.

Accept for now that such incompatibilities with PAE have significant effects for significantly many users, and this page of Microsoft’s is still disingenuous. Of course, with DEP enabled as the typical Windows configuration (starting with Windows XP SP2), Microsoft will have needed to limit Windows to the first 4GB of physical address space so that the benefits of DEP are not blown away by problems from third-party drivers that misbehave when memory is present above 4GB. But Microsoft’s published reasoning would be satisfied by arranging that enabling DEP not only enables PAE but also adds by default a truncatememory option to stop the kernel from knowing of any memory above 4GB. It does not of itself explain why the restriction to 4GB has instead been implemented in a way that prohibits the use of memory above 4GB by everyone, even at their own risk or when using computers whose manufacturers test their machines and trust their drivers and are willing to bear the support costs if they’re wrong. (This is not to say that Microsoft ought to allow such usage, just that the reasoning that Microsoft gives for its solution does not of itself compel that solution.)

Anyway, how significant could these incompatibilities be in real-world use of Windows Vista? The drivers that Microsoft talks about are not the sort of things that users install willy-nilly. They are much more the sort that come installed with a new computer, such that they have been tested (or ought to have been) by the manufacturer. They are also the sort of driver to which Microsoft will not give a digital signature unless the driver passes Microsoft’s testing at the Windows Hardware Quality Labs (WHQL). Add that Microsoft’s Device Driver Kit (DDK) for writing device drivers has defined the PHYSICAL_ADDRESS type as 64 bits since at least Windows NT 4.0 and that double-buffering into physical memory below 4GB has been supported since Windows 2000, and you might be forgiven some incredulity that these incompatibilities can now exist in any number, let alone that concern for them explains the forcible crippling of new installations of 32-bit Windows Vista on new computers.

Moreover, as noted earlier, the main types of coding error that are exposed by using memory above 4GB on 32-bit Windows are as much a problem to 64-bit Windows. It is beyond incredible that these errors are retained in 32-bit drivers that have been ported to 64-bit. However significant may have been the problems of 32-bit drivers and hardware for the safe use of memory above 4GB by 32-bit Windows in earlier versions, the natural expectation must therefore be that they are rapidly being eliminated from real-world occurrence by the widespread adaptation of those drivers to support 64-bit Windows Vista. Add that any hardware that won’t support memory above 4GB for use on 32-bit Windows with PAE won’t support it for 64-bit Windows either, and it is a wonder that anyone, inside Microsoft or out, can keep a straight face while saying that an upgrade to 64-bit Windows Vista is obviously safe for using memory above 4GB but enabling PAE on 32-bit Windows Vista (with up-to-date drivers) just as obviously isn’t.

Even Microsoft looks to be uncertain of its ground when talking about these incompatibilities. In the article just cited, which appears to be Microsoft’s main explanation of why 32-bit Windows Vista in particular is limited to using less than 4GB of memory, some paragraphs given as More Information are not even relevant to the question of using memory above 4GB. It simply does not matter that “DEP may cause compatibility issues” with a driver “that performs code generation or that uses other techniques to generate executable code in real time.” A problem from such a driver is resolved by disabling DEP, with no effect on using memory above 4GB. Why is that paragraph even present on Microsoft’s page if not to suggest a greater weight of argument to casual or uninformed readers?

Another paragraph that Microsoft presents as More Information is even worse. It talks of drivers that directly modify the page tables and “cause system instability” because they “expect 32-bit page table entries but receive 64-bit PTEs in PAE mode instead.” Put aside that you, as a security-minded user, ought not want (and hopefully don’t have) such drivers executing on your system even when you have 32-bit PTEs. Consider instead that these drivers will likely do the same mischief when PAE is enabled just for DEP. The PTEs are still 64-bit even if they never hold a physical address above 4GB. These errant drivers will still miscalculate the location of every PTE that they want to modify. If fear of this is an argument against using memory above 4GB, then it is just as much an argument against enabling DEP. Yet Microsoft recommends that DEP should always be enabled.

As Microsoft’s technical arguments for limiting 32-bit Windows Vista to 4GB of physical address space, these are strikingly poor in quality. Add that Microsoft seems nowhere to say outright that 32-bit Windows Vista already has the code for using memory above 4GB, and they look more like the sort of arguments someone might pass off to rationalise a decision made on other grounds.

Of course, I can’t know how Microsoft came to its decision. I just smell something fishy when technical reasons and good engineering do not of themselves compel exactly what Microsoft has implemented, which Microsoft anyway does not present transparently to potential customers. If I had found somewhere reasonably prominent some clear statement by Microsoft that 32-bit Windows Vista has all the necessary code for using memory above 4GB, and that although Microsoft sells the use of that code to customers who pay for server versions of Windows, customers who pay only for client versions have that code disabled because of concern for incompatibilities with third-party drivers—or even because Microsoft just didn’t want to enable it—then this article would not exist. Microsoft’s decision to disable the use of memory above 4GB would stand or fall on the commercial grounds of whether informed customers were troubled enough to complain enough. Instead, the decision stands on ignorance: many customers are left with their mistaken belief that use of memory above 4GB is impossible for any 32-bit operating system, and very few are well enough informed to know that working code for the use of such memory is already in the particular 32-bit operating system known as Windows Vista.

A Marketing Ruse

Perhaps the following, from Pushing the Limits of Windows: Physical Memory by Mark Russinovich at a Microsoft website, ends with a more frank description of Microsoft’s thinking about this 4GB limit than can be found in anything written directly by Microsoft:

Because device vendors now have to submit both 32-bit and 64-bit drivers to Microsoft's Windows Hardware Quality Laboratories (WHQL) to obtain a driver signing certificate, the majority of device drivers today can probably handle physical addresses above the 4GB line. However, 32-bit Windows will continue to ignore memory above it because there is still some difficult to measure risk, and OEMs are (or at least should be) moving to 64-bit Windows where it's not an issue.

See that the difficult-to-measure risk is merely asserted despite an acknowledgement that it seems implausible for new computers. As with Microsoft’s own literature, no comment is ventured about why this particular risk, among all the things that can go wrong with drivers, is so special that it must be handled as a licensing matter rather than disabling it by default but letting users and manufacturers choose for themselves if they trust their hardware and drivers enough for enabling it. Better instead to provide cover for moving consumers to 64-bit Windows faster than they might otherwise go. Just accept it without question and be glad for the new business as consumers who install 64-bit Windows start buying 64-bit applications which they might otherwise do without for a while. Who in the computer industry—whether a manufacturer of hardware or software, or even a commentator whom some might think is an independent analyst—is going to criticise Microsoft for a sleight of hand that brings forward a cycle of upgrades!

Windows With The Lot?

There is much that’s unsatisfactory about Microsoft’s hand-waving over imposing a 4GB limit to 32-bit Windows Vista. If nothing else, when consumers pay for a software product in an edition that the manufacturer describes as Ultimate, they surely have a reasonable expectation that the software is licensed to do everything that its code is capable of. If you buy only the Home Basic edition instead of Home Premium, then you expect to get less software and be licensed to use fewer features. But surely the point to an edition that is called Ultimate is that you get the whole package and are licensed to use it all. If you pay the extra for Ultimate but you’re not licensed for everything that the software can do, then how is Ultimate ultimate?

Note that this is not a case of a manufacturer puffing up a product description. The complaint is not that Ultimate isn’t truly ultimate because it isn’t the last word in what naive consumers might imagine Ultimate could be if only Microsoft would write the code. It’s that Ultimate deliberately is not given the ultimate license to do all that its code is already capable of.

Anti-Competitive Practices

An irony is that the very same driver incompatibilities that Microsoft talks of as a danger to users would surely have been eliminated—long ago—by the natural forces of competition among driver developers and device manufacturers except that Microsoft for many years misled those developers and manufacturers to believe that the 32-bit client editions of Windows could not use memory above 4GB when in fact they could (see below, under the heading Past). That Microsoft now points its finger at the driver writers without acknowledging the part played by its own substantial influence is at best distasteful.

By designing 32-bit Windows for memory above 4GB but licensing all but exotic editions only for memory below 4GB, Microsoft suppressed competition in the subsidiary market of computers that run Windows. Given that Windows Vista is the current representative of a monopoly product, this suppression may count as an anti-competitive practice in terms of some jurisdictions’ laws on monopolistic abuses. Certainly, consumers have been worse off for not having the competition. Especially while 64-bit Windows Vista was not so readily available, very many consumers bought computers with 4GB of RAM but not the whole use of that RAM. True, they will have proceeded with their purchase despite having seen the fine print that informed them of the loss, but they weren’t fully informed, and they arguably have been misinformed about the reason that all their RAM isn’t used.

You May Not Test What We Say

Especially unsatisfactory is that Microsoft says something about its product, and about other people’s products, but uses the licensing mechanism to deny the means to test what’s said. Whatever you think of software licensing, in general or as practised particularly by Microsoft, its use by any software manufacturer to frustrate independent testing of the manufacturer’s claims about a consumer product is a low act.

When Microsoft and others make out that defective drivers are so widespread and dangerous that 32-bit Windows Vista cannot be allowed to use memory above 4GB even as a configurable option, how is anyone to know the truth of it? Nobody can test even one driver’s use of memory above 4GB on 32-bit Windows Vista with the license data that Microsoft supplies for it. The closest that anyone can come is to test with 32-bit Windows Server 2008, which hardly any consumers ever get to see, and which of course was not available until some time after Windows Vista was first released. It is no credit to the computer industry that any manufacturer’s arguments are accepted so widely without independent testing.

Testing the Use of Physical Memory Above 4GB

Even to begin to test whether a particular installation of 32-bit Windows Vista cannot safely use memory above 4GB because of driver incompatibilities, you must somehow side-step the two relevant license values.7 The minimal interference for this purpose is to modify the kernel so that where it presently reads the two relevant license values from the registry, it will instead proceed as if the license values had no effect.

Let me stress that although I have to modify the kernel, using memory above 4GB does not require a change to even one byte of code. That I modify any code here is merely to simulate the provision of different license data by Microsoft. Much as you can buy Windows Vista Home Basic and then upgrade to Home Premium without having to reinstall Windows, you might upgrade to a configuration in which the two license values for memory limits are raised. Because Microsoft protects those license values, this patch is as close to that upgrade as can be arranged unless Microsoft makes the license upgrade available. If you patch the kernel and your tests then show to your satisfaction that your drivers are safe (though perhaps only after you disable defective drivers and install the latest updates from their manufacturers), then a license upgrade from Microsoft is what I intend you to seek.

You should understand now, i.e., before you get further involved, that patching the kernel presents some difficulties in excess of patching an application-level executable. Not only will you need a program with which to change a few bytes in the executable code, you will also need programming tools either to set the checksum in the executable’s header or to sign code.

Very soon after this article’s first publication at this website, other people and teams started to offer programs that automate the steps given below and spare you from needing separate programming tools. My only hand in these offerings is that they draw from what I have written here. Most do not acknowledge their source. Some even claim to have devised their kernel patch independently. (Curiously, none seem to have offered their patch in the two years between the formal release of Windows Vista and this article’s publication. That a search through Google showed little or nothing about the relevant licence values and absolutely nothing like this patch is the main reason that I ever did get round to writing this article after sitting on the information since mid-2007.) I am biased, of course, but if I had to resort to a third-party tool to do what I present below, then I’d suspect as unsafe all those whose authors don’t acknowledge their source. Except for that, I cannot help you choose one over another.

Patch Details

The only executable that is considered here is the PAE kernel, named NTKRNLPA.EXE, from 32-bit editions of Windows Vista (and Windows 7, which may as well be a Windows Vista service pack as far as concerns this article’s subject). The known builds have an internal routine named MxMemoryLicense in which there are two sequences of nearly identical code, one for each relevant license value. Each sequence calls the undocumented function ZwQueryLicenseValue and then tests for failure or for whether the data that has been read for the value is zero. In the known builds, each sequence has the following instructions in common:

Opcode Bytes Instruction
7C xx
jl      default
8B 45 FC
mov     eax,dword ptr [ebp-4]
85 C0
test    eax,eax
74 yy
je      default

At the time of executing, the eax register holds the status code from ZwQueryLicenseValue. The first instruction is the test for failure (indicated by a negative status code). The remaining instructions test whether the retrieved data is zero. In the known builds, the xx and yy placeholders are 0x11 and 0x0A respectively for the first sequence and 0x10 and 0x09 for the second, but even with the placeholders left unresolved, the sequence shown occurs just twice in the whole kernel. This may help you find the patch sites even if you have a different build (such as you may have picked up from Windows Update).

Both occurrences are to be patched the same way. The patch is designed to vary the ordinary execution as little as possible. The kernel is left to call ZwQueryLicenseValue as usual and to test for failure, but the last three of the above instructions are changed so that the kernel proceeds as if the retrieved data is the value that represents 128GB (which is the least value that removes licensing from the kernel’s computation of maximum physical address). Change the 7 bytes starting from 0x8B so that you now have the following instructions:

Opcode Bytes Instruction
B8 00 00 02 00
mov     eax,00020000h
90
nop
90
nop

The following table lists the English-language builds of the PAE kernel for some known releases of 32-bit Windows and gives the file offsets for the two patch sites:

Version Package File Offsets
6.0.6000.16386 Windows Vista 0x003040B1, 0x003040F2
6.0.6001.18000 Windows Vista SP1 0x00309AA3, 0x00309AE4
6.0.6002.18005 Windows Vista SP2 0x0030C43A, 0x0030C47B
6.1.7600.16385 Windows 7 0x0035C243, 0x0035C283
6.1.7601.17514 Windows 7 SP1 0x003605F8, 0x00360638

If you are not completely certain how to interpret file offsets, to check the bytes and to edit them, then do not try to patch the file. Even if you think you know what you are doing, please take care to work on a copy. Use some command such as fc /b to compare your patched copy with the original, and verify that you have changed only the expected bytes.

For the remainder of these directions, I assume that your patched copy is named NTKR128G.EXE.

Checksum

For all executables that are loaded by WINLOAD, as is the kernel, the checksum in the executable’s header must be set correctly. Since patching the kernel will almost certainly have invalidated this stored checksum, you need to reset it. Signing the code, as discussed under the next heading, will do this. If you don’t have tools for signing code, then a suitable tool for setting the checksum is EDITBIN from Microsoft Visual Studio. Its /release switch exists solely to set the checksum. The command to run is

editbin /release ntkr128g.exe 

Digital Signature

It is sometimes said that kernel-mode drivers are not checked for digital signatures in 32-bit Windows, or more accurately that although hashes are computed, drivers are not rejected if the hash is not validated by a signature.8 Although this is broadly true, there are a dozen executables that the loader ordinarily insists be signed properly. The kernel is one of them, of course. It must be signed by a certificate that derives from one of a handful of root certficates whose public keys are hard-coded into the loader. Since patching the kernel will have invalidated Microsoft’s signature, you have to resort to one of the exceptions that are covered by the word “ordinarily” (unless you want to patch the loader too).

One of these exceptions is a Test Mode which Microsoft provides so that drivers can be tested during development. Presumably, this Test Mode also lets Microsoft’s own kernel programmers get their kernel tested while it is still being worked on and is not ready for a proper signature. In patching the kernel to test what will appear to you to be a new kernel-mode feature, you are in essentially the same position, though on a much smaller scale, as Microsoft’s own kernel programmers when they want to test a new build. In this sense, Test Mode is the most appropriate way around the digital signature.

In Test Mode, the loader relaxes its integrity checking such that any root certificate is accepted.9 Provided that you have suitable tools, you can create your own test-signing certificate and test-sign your modified copy of the kernel, such that it will load when you boot Windows with the testsigning option. There is a price however: Test Mode has the detraction of placing small warnings on the desktop.

For suitable tools, with documentation, look in either the Windows Software Development Kit (SDK) or the Windows Driver Kit (WDK). With these, you can make your own certificate by running some such command as

makecert -r -ss my -n "CN=My Own Testing Authority" 

This creates a root certificate for an invented certification authority named My Own Testing Authority and installs it in the Personal certificate store, which is represented by “my” in the command. You can view the new certificate by starting the Certificate Manager (CERTMGR.MSC), which also lets you set a Friendly Name for the certificate if you want to keep it. To sign your modified kernel with this certificate, run the command

signtool sign -s my -n "My Own Testing Authority" ntkr128g.exe 

Note that you do not need administrative privilege for these steps. Also, you can self-sign the kernel on one machine but test it on another. There is no need to transfer the certificate to the test machine. Indeed, there is no more need to keep the certificate. You can delete it from the Personal store either through the user interface of the Certificate Manager or by running the command

certmgr -del -c -s my -n "My Own Testing Authority" 

Booting the Self-Signed Patched Kernel

You now have a modified kernel with which to test your 32-bit Windows Vista for its use of physical memory above 4GB. Copy it to the Windows System directory of the machine that you will test. (For this, you typically will need administrative privilege for the target machine.) Then, provided that you successfully self-signed the kernel, you have to restart that machine with three boot options:

Persistent Test Mode

To set up a persistent test, use the BCDEDIT utility to write the options into the BCD store. It is prudent to work on a copy of the configuration that you want to test. Assuming that you are currently booted into this configuration, running the command

bcdedit /copy {current} /d "Windows Vista Using All My Memory" 

will create a new entry for the boot menu and tell you a GUID which you then reproduce (e.g., by copy and paste) in the commands:

bcdedit /set {guid} pae ForceEnable 
bcdedit /set {guid} kernel ntkr128g.exe 
bcdedit /set {guid} testsigning on 

When you restart the computer, select “Windows Vista Using All My Memory” from the boot menu, and start testing. If you do turn out to have a defective driver and need to identify it and update it, then you can go through any of the usual processes of elimination even while starting in Test Mode. Note in particular that Test Mode is not Safe Mode. You can have the two together: while “Windows Vista Using All My Memory” is selected at the boot menu, just press F8 to open the Advanced Boot Options Menu and then select Safe Mode.

By the way, if you have a defective driver and you proceed to replace it, then be sure to boot into your normal Windows configuration for the downloading and updating. Of course, if the need for this was news to you, then you might better not be trying any of this.

One-Time Test Mode

If you already have an operating system configuration that has PAE enabled, then a less intrusive way to start your tests is to enter the options at the Edit Boot Options Menu. This is admittedly a lot easier if your machine is already configured for booting multiple operating systems (or the one operating system in multiple configurations) so that you ordinarily see a boot menu during startup. At this boot menu, select the configuration that you want to test, then press F10 to open the Edit Boot Options Menu. It is too late to enable PAE here, but the other options can be added in the style of BOOT.INI switches:

/kernel=ntkr128g.exe /testsigning 

Press Enter, and the selected operating system will start with your modified kernel in Test Mode. This method has the advantage of not reconfiguring the selected operating system in any way that lasts, and the corresponding disadvantage that you have to type something every time you want to do the test.

Booting the Patched Kernel With a Bad Signature

The patched kernel can also be booted by disabling the loader’s integrity checking altogether. You cannot set this up entirely with boot options in the BCD store, because the option to disable integrity checking is not permitted to persist. The closest you can get is to disable integrity checking at one or other of the boot menus.

Prepare a boot entry with just the pae and kernel options as above. When you restart the computer, select “Windows Vista Using All My Memory” but press F8 to open the Advanced Boot Options Menu and then select Disable Driver Signature Enforcement.

The alternative with the Edit Boot Options Menu is also available, with the same constraints about PAE being already enabled, but the switches to enter are now:

/kernel=ntkr128g.exe /disable_integrity_checks 

Curiously enough, booting with integrity checking disabled leaves no warnings on the desktop (such as you get from booting in Test Mode). I do not mean to recommend this method of testing. I describe it only for completeness and because it is the only method available if you do not have tools for code-signing but are able to set an executable’s checksum.

Past

Although this article is motivated by the realisation that Microsoft introduced a formal scheme of license values for Windows Vista, two of which stop 32-bit Windows Vista from using memory above 4GB, a few words might usefully be passed about earlier Windows versions.

As noted above, the PAE kernel dates from Windows 2000. Some sources, including Microsoft’s Physical Address Extension, seem to think that the PAE kernel was only for server editions, at least initially. As recently as the January 2007 edition of the MSDN Library on CD, this page of Microsoft’s cited just three “systems that can use PAE to take advantage of physical memory beyond 4GB”:

That was very definitely too small a list, but was surely more about what was intended than what actually was coded and released (if not formally supported). There are two PAE kernels on the installation media for every known release of Windows 2000, Windows XP and Windows Server 2003 (except for Windows 2000 SP2 which seems not to have updated the kernel at all). These each have four kernels:

In practice, Windows is installed with just two kernels, according to whether the machine has one (logical) processor or more. The single-processor kernels have the standard names. The multi-processor kernels are renamed at installation.

As noted above, the kernel in Windows Vista limits memory use by filtering the map of physical memory as received from the loader, so that memory in excess of the limits is discarded before the kernel really starts working with the map. This mechanism dates from at least Windows 2000. At first, there was just the one limit, of total physical memory. A limit on the maximum physical address begins (chronologically) with Windows Server 2003. What’s new for Windows Vista is that the limits to memory usage are defined specifically in the registry, independently of the product type, and are obtained using functions whose names make it unarguable that the discarding of memory in excess of the limits is a licensing issue. In earlier versions than Windows Vista, the memory limits for different product types are hard-coded and the connection with licensing is only indirect.

These hard-coded limits are selected according to the product suite, mostly, but sometimes with an extra dependence on something that Microsoft calls 4GT (and is mostly a matter of whether /3GB is given in the BOOT.INI options). The following table of these limits is taken from the single-processor NTKRNLPA.EXE in each release. There may be errors in transcription, there being only so much time that I am willing to take over finding every last detail for this information. If you want more detail or reliability, try finding it from Microsoft.10

Version Package Total Physical Memory Maximum Physical Address
5.0.2195.1 Windows 2000 32GB if Datacenter without 4GT;
16GB if Datacenter with 4GT;
8GB if Enterprise;
4GB otherwise
none
5.0.2195.1620 Windows 2000 SP1
5.0.2195.5438 Windows 2000 SP3
5.0.2195.6717 Windows 2000 SP4
5.1.2600.0 Windows XP 64GB if Datacenter without 4GT;
16GB if Datacenter with 4GT;
32GB if Enterprise;
2GB if Blade;
4GB otherwise
none
5.1.2600.1106 Windows XP SP1
5.1.2600.2180 Windows XP SP2 16GB if Datacenter with 4GT;
none if Datacenter without 4GT;
none if Enterprise or Blade;
4GB otherwise
5.1.2600.5512 Windows XP SP3
5.2.3790.0 Windows Server 2003 128GB if Datacenter without 4GT;
32GB if Enterprise without 4GT;
16GB if Datacenter or Enterprise with 4GT;
2GB if Blade;
4GB otherwise
16GB if Datacenter or Enterprise with 4GT;
128GB otherwise
5.2.3790.1830 Windows Server 2003 SP1 2GB if Blade;
128GB if Datacenter without 4GT;
64GB if Enterprise without 4GT;
16GB if Datacenter or Enterprise with 4GT;
4GB otherwise
128GB if Blade;
128GB if Datacenter, Enterprise or Terminal Server without 4GT;
16GB if Datacenter, Enterprise or Terminal Server with 4GT;
4GB otherwise
5.2.3790.3959 Windows Server 2003 SP2

Note that for nearly 5 years, i.e., from Windows 2000 up to but not including Windows XP SP2, Microsoft did not actually prohibit the use of memory above 4GB by any editions of its current Windows product, whether for servers or clients. Perhaps those incompatible drivers hadn’t been noticed yet.

Windows XP SP2

Special mention must be made of Windows XP SP2 and SP3. If you were fortunate enough to have 4GB in a machine for running a client version of Windows up to and including Windows XP SP1, and your hardware had memory remapping so that some of your 4GB was above the 4GB address, and your third-party drivers worked correctly with memory above 4GB, then you will have faced an unfortunate side-effect when upgrading to Windows XP SP2: you will have bought a downgrade of how much RAM Microsoft permits you to use. How well did Microsoft disclose this side-effect in advance?

It was disclosed eventually. The Knowledge Base article The amount of RAM reported by the System Properties dialog box and the System Information tool is less than you expect after you install Windows XP Service Pack 2 reports that enabling PAE in Windows XP SP2 does not allow the use of memory above 4GB. It also talks of changes to the HAL. What actually was changed so strains credibility that I had to be goaded into studying it. As much as anyone talks of defective 32-bit drivers that simply assume a 32-bit physical address space, it will forever remain that the most prominent example of such an assumption is what Microsoft itself coded into the 32-bit HAL for Windows XP SP2. The difference is that Microsoft would have us believe that when Microsoft writes code that makes such an ordinarily fautly assumption, it’s not a defect but a defence.

The HAL, meaning Hardware Abstraction Layer, is the component that drivers deal with when getting their DMA to work correctly with the translation between linear and physical addresses for memory. The HAL models DMA operations in terms of abstracted adapters which each have some number of so-called map registers according to whether double-buffering may be needed for transfers that the HAL discovers involve physical memory that is too high for the device to access. Where the Knowledge Base article says “the modified HAL grants unlimited map registers”, what it means is that the modified HAL assumes for itself that double buffering is never required for any DMA operations on a device that can handle 32-bit physical addresses.11

Rather than “reduce driver compatibility issues”, this change makes a certainty of them! You could have a system in which every driver that does DMA is coded correctly for its use of DMA functions, yet the HAL from Windows XP SP2 would ensure that DMA for memory above 4GB misbehaves, just as feared from a buggy driver. Problems with defective DMA by drivers are avoided not by this intrinsically dangerous change to the HAL but by the limit that the kernel introduced on the maximum physical address for memory that the kernel will ever use. The best that can be said for the change to the HAL is that it strips the code of a case that is made redundant by the change to the kernel.

Having seen that some 32-bit drivers assume all physical addresses fit 32 bits and thereby think to escape some coding obligations regarding double buffering for their 32-bit device, Microsoft deliberately adopted the same faulty assumption into the HAL, i.e., into arguably the second most critical executable in all of Windows. A company that can do such a thing is clearly not thinking primarily of its product’s technical integrity.

However it happened, the practical result is that Windows Vista is the first client edition of 32-bit Windows to have all the code for using memory above 4GB but not the permission to use any of this code. Windows XP SP2 and SP3 don’t have the permission either, but they anyway don’t have all the code.

Future

It seems unlikely that Microsoft means to remove (or even change) the license limits on memory use by 32-bit Windows any time soon. For the opportunity provided by the first Windows Vista service pack, Microsoft instead decided to play games with how the amount of physical memory is reported. In several places where earlier Windows versions report the amount of RAM that the kernel recognises as usable, Windows Vista SP1 instead reports the total amount of RAM that is installed. For instance, the System Properties in the original Windows Vista ordinarily reports 3069MB of RAM on this article’s test machine, but the System Properties in Windows Vista SP1 reports 8.00GB. This does not mean, of course, that Windows Vista SP1 actually regards 8GB as usable. RAM that is overridden for hardware support is as lost to Windows Vista SP1 as to the original. RAM in excess of the license limits is discarded by Windows Vista SP1 as by the original. Windows Vista SP1 just doesn’t let these losses show as obviously.

Microsoft does acknowledge this “reporting change” in an article Windows Vista SP1 includes reporting of Installed System Memory (RAM). The title is more accurate than might be understood at first glance: reporting the amount of installed system memory is newly coded as an application-level programming feature in the form of a new Windows API function, named GetPhysicallyInstalledSystemMemory. Several programs that are supplied with Windows Vista SP1 use this new feature. Only one, the System Information program (MSINFO32.EXE), is known to contrast the amount of installed RAM with the amount that the operating system believes is usable.

If you’re reasonably sharp-eyed, you should be wondering if I can be correct where I say, some distance above, that the kernel discards memory in excess of the license values, such that the memory may as well never have been discovered by the loader from the firmware. If the kernel truly does lose all knowledge of the discarded memory, then how is this memory’s existence found by the new function? The answer is of course that the report of installed memory is not obtained directly from the kernel. The kernel’s only involvement is in fetching the raw SMBIOS firmware table, which is then interpreted at application level to discover the amount of installed memory. The SMBIOS table tells such things as that the system board has 8 memory chips at 1GB each. It doesn’t tell anything about how (or if) that RAM is addressable, let alone how much of it is usable by Windows.

When running on earlier Windows versions, programs that want to discover the amount of installed RAM can do their own interpretation of the SMBIOS table, having got it by calling GetSystemFirmwareTable. When running on much earlier Windows versions, there is perhaps no better way than to query Windows Management Instrumentation (WMI) for its knowledge of the SMBIOS table, which is hardly a trivial exercise.12 That such mucking around for one seemingly simple piece of data is now made as easy as calling one API function is very welcome. It’s sadly typical that Microsoft didn’t implement it as a programming feature of its operating system until Microsoft needed it for Microsoft’s purposes. It’s a pity that those purposes in this particular case have an element of disguise.

Of course, there’s a very good argument that the amount of RAM shown in the System Properties ought all along to have been the amount installed. But it hasn’t been all along, and to change it now, just as increasingly many users see the amount shown and wonder why it is so much less than the amount they know to be installed, looks like sharp practice.

Microsoft finally attended to this in Windows 7, which has the System Properties show the amount installed but follow it with the backwards-compatible report of what’s usable.

Windows Server 2008

Perhaps you think that because Microsoft is the only true authority on its own software, there remains some scope for technical issues to explain the prevention of 32-bit Windows Vista from using memory above 4GB. After all, Microsoft’s kernel-mode programmers are surely among the best and brightest and they have access to the source code. How can anyone outside Microsoft be truly certain what code is in Windows? For instance, could it be that although the kernel for 32-bit Windows Vista has some code for using memory above 4GB, it does not have the complete code? Or could it be that the code in 32-bit Windows Vista was merely in transition from Windows Server 2003 to Windows Server 2008 and does not work entirely correctly? Only Microsoft can know.

To some extent, you would be right, but then I say to you: consider Windows Server 2008. For the loader, kernel and HAL in Windows Vista SP1 (and, by the way, for the overwhelming majority of all executables), the corresponding executable in Windows Server 2008 is exactly the same, byte for byte. Yet Microsoft sells 32-bit Windows Server 2008 for use with as much as 64GB of memory. Does Microsoft really mean to say that when it re-badges these same executables as Windows Vista SP1, they suddenly acquire an architectural limit of 4GB? Or is it that a driver for Windows Server 2008 is safe for using with memory above 4GB as long as you don’t let it interact with the identical executables from Windows Vista SP1?

Summary

Microsoft has always limited the amount of memory that Windows will use. Different Windows products have different limits. For 32-bit Windows Vista, the limit of 4GB is unarguably coded as a licensing issue but Microsoft does not say this explicitly in the supposed License Agreement (or anywhere else).

This has not been a problem for consumers until recently because the license limit of 4GB for client editions of Windows, such as Windows XP and Windows Vista, permitted the use of far more memory than many consumers ever thought to dream about. Even now that machines with 4GB of RAM are no rarity, many consumers (including me) typically don’t run enough memory-hungry programs to be using more than one or two gigabytes in total. Yet clearly the day is not far off that 4GB will be a typical installation. Software will inevitably grow to use what’s there. Soon, machines with more than 4GB will not be regarded as giants.

A perception has developed, and even become widespread, that exceeding 4GB requires a mass migration to 64-bit Windows. At best, this perception misunderstands both the design of Intel’s processors and a decade-old development in 32-bit Windows. Although Microsoft itself seems never to say explicitly that 4GB is a barrier for 32-bit Windows in general, Microsoft does say that 32-bit Windows Vista in particular is incapable of using 4GB and that the workaround necessarily includes using 64-bit Windows Vista instead.

The mechanism by which 32-bit Windows Vista is incapable of using memory above 4GB is simply that Microsoft does not license it to use memory above 4GB. The code to use memory above 4GB is already present in the product as shipped. Microsoft just doesn’t license you to use it. Microsoft seems never to say explicitly that this is the mechanism.

Microsoft does say that memory use by 32-bit Windows Vista is limited “to avoid potential driver compatibility issues” but the arguments are weak, especially for new computers with new hardware and new drivers. Moreover, Microsoft does not open its arguments to independent testing, given that the license values are protected from being tampered with. Even for machines on which the incompatibilities are real, they would be avoidable through configurable options that exist anyway. That they must be avoided (or even are better avoided) through the licensing mechanism is again not something that Microsoft seems to have explained anywhere.

A suspicion seems reasonable that Microsoft is at least content to have the mass market perceive 4GB as an architectural limit to 32-bit Windows, so that the inevitable increase in the amount of RAM fitted to a typical computer will itself move the consumer base to 64-bit Windows and thence to the 64-bit applications that users will quickly see as natural purchases for their 64-bit operating system. There are, of course, very good reasons to migrate to 64-bit Windows, but the change should be assessed on its merits, not taken as necessary because staying with 32-bit Windows is closed off as an option. Imposing an artificial limit at an amount of memory that conveniently coincides with a widely believed myth has the look of a marketing ruse to bring forward the migration to 64 bits without fully-informed assessment. Microsoft certainly has not informed, and the rest of the industry has not questioned, how and why 32-bit Windows Vista is constrained to ignore memory above 4GB. This is an abuse that consumers should not have to tolerate. Someone with authority over Microsoft ought investigate whether Microsoft’s descriptions of 32-bit Windows Vista as being incapable of using memory above 4GB are misleading or illegal.


[1] See Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1, Section 3.8, “36-Bit Physical Addressing Using the PAE Paging Mechanism”.

[2] This statement assumes a flat memory model where segmentation is simplified so far that it is ignorable for most practical purposes. Though segmentation was the essential technology for the 8086 to have its 16-bit registers address a 20-bit physical address space, it is irrelevant here.

[3] This BIOS interface is defined in the Advanced Configuration and Power Interface Specification, Section 14, System Address Map Interfaces.

[4] If you want to examine this map with a debugger, including before the kernel initialises its memory management, it may help you to know that the map is a linked list of MEMORY_ALLOCATION_DESCRIPTOR structures to be found via the MemoryDescriptorListHead member of the LOADER_PARAMETER_BLOCK structure whose address is in the KeLoaderBlock variable. These structures are not formally documented, of course, but they are knowable from type information in the public symbols file for the kernel.

[5] The filter is applied in a subroutine that is not named in the public symbols file for the kernel but which is called from near the start of a routine named MmInitNucleus. The limits are read from the registry in a procedure that the symbol files name as MxMemoryLicense.

[6] That there can be no more than 1GB of linear address space available as a single block is because the loader constructs the linear address space such that C0000000 is preset as the address of an array of page table entries for all possible linear addresses. The convenience and efficiency of this for page table management can’t be overstated. It’s done too on 64-bit Windows, which has its array at FFFFF680`00000000. Preset linear addresses are used for other system structures, too, and more on 64-bit Windows than on 32-bit. For instance, on 64-bit Windows the array of MMPFN structures is addressable at FFFFFA80`00000000.

[7] This is perhaps not entirely correct for machines that support hot-add memory. It may be possible to let the kernel discard RAM above 4GB but then add it from a driver by calling MmAddPhysicalMemory as if the discarded memory has been rediscovered as hot-add memory. Further study would be needed, and perhaps then some far-from-trivial coding to test the concept. Note anyway that Microsoft lists MmAddPhysicalMemory among the Memory Manager Routines that “are reserved for system use” and which Microsoft tells programmers “Do not use them in your driver.”

[8] See, for instance, Microsoft’s page Test Signing Driver Packages which says that “Starting with Windows Vista, embedding a signature in a boot-start driver is optional for 32-bit versions of Windows. Although Windows will check if a kernel-mode driver file has an embedded signature, an embedded signature is not required.”

[9] This doesn’t seem to be documented specifically by Microsoft. At the page MakeCert Test Certificate, Microsoft has it that “the test certificate must be installed in the Trusted Root Certification Authorities certificate store and the Trusted Publishers certificate store of the test computer”, which may be true of some kernel-mode drivers but is definitely not true of drivers that are loaded by WINLOAD.

[10] The closest that Microsoft comes to publishing the information in this table seems to be the page Memory Limits for Windows Releases, under its several headings of Physical Memory Limits for various Windows versions. Though that page is Microsoft’s most accurate for the total amount of memory allowed, it says nothing at all about a limit to the maximum physical address. For the latter, Operating Systems and PAE Support leaves the reader to distinguish “4GB of physical address space” from “4GB of physical RAM”, and Physical Address Extension - PAE Memory and Windows has “Total physical address space is limited to 4GB on these versions of Windows” as an asterisk applied to too wide a range of versions. Where these various pages of Microsoft’s differ, e.g., for the maximum amount supported by Windows Server 2003 Datacenter Edition, which is anyone to believe?

[11] The full rule in Windows Vista, as applied in the HalGetAdapter function, is that map registers are not needed for a device if all the following are true: the device supports scatter-gather DMA; the device supports 64-bit physical addresses or there is no memory above 4GB; and the bus is EISA or PCI or there is no memory above 16MB. Before Windows XP SP2, the test is not that there is no memory above 4GB but simply that PAE is not enabled. That’s surely faulty, but what the HAL does for Windows XP SP2 is no better: it simply ignores whether PAE is enabled and takes it as necessarily true that there can be no memory above 4GB. The difference seems likely to be arranged through a macro, which ordinarily tests the relevant variable, named HalpPhysicalMemoryMayAppearAbove4GB since Windows Server 2003 SP1, but treats (or perhaps even defines) the variable as FALSE when compiled for Windows XP SP2 and SP3.

[12] Microsoft’s own words are that “Creating an application for WMI using C++ is by no means a simple procedure.” Rather, those were Microsoft’s words to introduce a page titled Creating a WMI Application Using C++ until at least the January 2007 edition of the MSDN Library on CD.