DRAFT: Take more than your usual care.

Memory Limit for Hibernation Support

In most Windows versions, support for hibernation is lost if physical memory is present above some maximum address. Microsoft documents this in a Knowledge Base article You cannot put a computer that has more than 4GB of memory into hibernation in Windows XP, in Windows Server 2003, in Windows Vista, or in Windows Server 2008.

As so often, Microsoft’s details are not quite correct. For one thing, the limit is not to the amount of memory but to the highest physical memory address, which distinction the article leaves to a Note. More significantly, some of the cited versions have no limit and others have a significantly raised limit. The article was perhaps extended to newer versions without getting up-to-date information from the programmers. This documentation error might pass as unremarkable except that Microsoft’s details are repeated around the Internet as if verified, and may become accepted as truth until more people actually do have 4GB of RAM and start seeing for themselves.

A quick summary of the memory limits follows:

Version Maximum Physical Address for Hibernation Support
Windows XP SP2 and SP3
Windows Server 2003 SP1 and SP2
4GB
32-bit Windows Vista
32-bit Windows 7
none
64-bit Windows Vista
64-bit Windows 7
16TB

The limit in question is coded as a test that the Windows kernel applies near the end of its internal routine PopFilterCapabilities. If this test fails, then all the kernel’s reports of system power capabilities will mark the S4 sleep state, i.e., hibernation, as unsupported. The way this will be seen most readily at user-interface level is that the Power applet in the Control Panel will not show a tab for Hibernation. (It should perhaps be stressed that the converse is unsound. If the tab is shown, then the test was passed, but this can’t mean that hibernation is sure to work.)

This notion of disabling hibernation support on a system that fails a capabilities test is as old as hibernation itself. However, the test was not originally implemented as a memory limit. Instead, the original Windows 2000 disables hibernation if the kernel is using the CPU feature known as Physical Address Extension (PAE). This feature allows a 32-bit processor to map its 32-bit linear address space into a larger physical address space. For any version of 32-bit Windows to know of any memory at or above 4GB, you need to have PAE enabled and be running the PAE kernel. However, the converse is not true. You can enable PAE (wastefully) even if all your memory is below 4GB, but among the consequences is that you lose hibernation support. This original behaviour persists not only through all known Windows 2000 service packs but also in Windows XP up to and including SP1.

It is unclear whether the test ought all along to have been for memory outside a 32-bit physical address space or for the PAE feature that allows the use of such memory. Microsoft’s early programming of PAE support is sometimes confused about the distinction, such that it can go wrong if PAE is enabled even while all memory fits into 4GB. Microsoft will have needed to straighten this out before Windows could use another CPU feature which happens to be available only if PAE is enabled, namely page-level protection against executing instructions in memory that looks intended only for data. This is highly beneficial protection no matter how much memory is present. Its introduction would mean that enabling PAE would no longer be wasteful—indeed, would be desirable—even if all memory is below 4GB. The link between PAE and hibernation had to be rethought.

Mutation of the hibernation test into a memory limit begins (chronologically) with the original Windows Server 2003. This version mostly retains the PAE test, but with a refinement. Support for hibernation is withdrawn if PAE is enabled, as before, except if all the following are true:

In practice therefore, if you enable PAE on the original Windows Server 2003, you still lose hibernation support if you have too much memory. Exactly what Microsoft intended for AMD processors is unclear—the NOEXECUTE option is not documented for the original Windows Server 2003—but there is in this test the first sign of a memory limit for hibernation.

Simplification to testing only for memory begins with Windows XP SP2 and Windows Server 2003 SP1 (both 32-bit and 64-bit). For these versions, hibernation is disabled if the kernel knows of any physical memory at or above 4GB.

This test is removed altogether from 32-bit Windows Vista, including its service packs and therefore also the original Windows Server 2008. Let it be stressed: these 32-bit Windows versions have no memory limit for hibernation. A memory limit is retained for 64-bit Windows Vista, but the maximum physical address is raised to 16TB. (This is the most memory that can be spanned by an array of 4KB pages using a 32-bit index.)

Windows 7, and therefore also Windows Server 2008 R2, changes the code so that hibernation is disabled if any of several system power logging entries are present. Logging entries were introduced with version 5.2, i.e., Windows Server 2003. Every logging entry has a formally defined reason. The reason for having too high a physical memory address is documented symbolically as SPSD_REASON_MEMORYLIMIT. No logging entry for this reason is ever inserted by the 32-bit kernel for Windows 7, which means that 32-bit Windows 7 also has no memory limit for hibernation. For 64-bit Windows 7, the kernel inserts a memory-limit logging entry if any physical memory is found at or above 16TB.

Note that logging entries can be inserted from outside the kernel, via the exported (but undocumented) ZwPowerInformation function, using the SystemPowerLoggingEntry value for the POWER_INFORMATION_LEVEL.