This document explains how to reserve a segment of the physical memory (RAM) for exclusive use, and then access it using WinDriver, on Windows or Linux.

Important Note

  • In most cases, there is no need to resort to this method in order to reserve segments of memory for exclusive use. Normally, you can lock a safe Direct Memory Access (DMA) buffer (e.g., using WinDriver’s DMA APIs) and then access the buffer from your driver. The method described in this document should be used only in rare cases of “memory-intensive” driver projects and only when the required memory block cannot be locked using standard methods, such as allocation of a contiguous DMA buffer.
  • When using this method, take special care not to write to the wrong memory addresses, so as to avoid system crashes, etc.

  • The relevant device must have an INF file installed


  • This document is organized as follows:

    1. Reserving the desired amount of RAM
      • On Windows Vista and newer
      • On Windows Server 2003 and earlier
      • On Linux
    2. On Windows – Calculating the base address of the reserved memory
    3. Using WinDriver to access reserved memory


    1. Reserving the desired amount of RAM
    2. Pay Attention: reserving too much space may result in degraded OS performance.

      • Windows Vista and newer
      • Run the command line as an administrator, and use the BCDEdit utility to set the value of removememory to the number of MB you wish to reserve. Upon successful completion, BCDEdit will display a success message. To complete reservation, reboot the PC.

        bcdedit /set removememory specify_size_in_MB

        For Example:

        bcdedit /set removememory 10

      • Windows Server 2003 and earlier
      • Modify the boot.ini file on your PC to add a burnmemory parameter, to the relevant windows configuration.

        /burnmemory= specify_size_in_MB

        For example in Windows XP:

        multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP, Enterprise" /fastdetect /NoExecute=OptIn /burnmemory=100

      • Linux
        1. Run the following command to view a list of the physical memory ranges on your machine

          dmesg | grep BIOS

          This produces entries as in the following sample output. usable identifies memory sections that are used by Linux

          [ 0.000000] BIOS-e820: 0000000000000000 - 000000000009f800 (usable)
          [ 0.000000] BIOS-e820: 000000000009f800 - 00000000000a0000 (reserved)
          [ 0.000000] BIOS-e820: 00000000000f0000 - 0000000000100000 (reserved)
          [ 0.000000] BIOS-e820: 0000000000100000 - 000000007dce0000 (usable)
          [ 0.000000] BIOS-e820: 000000007dce0000 - 000000007dce3000 (ACPI NVS)
          [ 0.000000] BIOS-e820: 000000007dce3000 - 000000007dcf0000 (ACPI data)
          [ 0.000000] BIOS-e820: 000000007dcf0000 - 000000007dd00000 (reserved)
          [ 0.000000] BIOS-e820: 00000000c0000000 - 00000000d0000000 (reserved)
          [ 0.000000] BIOS-e820: 00000000fec00000 - 0000000100000000 (reserved)
        2. Edit the boot-loader command line to instruct the Linux kernel to boot with less memory in the desired address range. For example, the following line from the sample dmesg output shown above

          [ 0.000000] BIOS-e820: 0000000000100000 - 000000007dce0000 (usable)

          indicates that there is a ~1.95GB address range, starting at address 0x100000, that is used by Linux. To reserve ~150MB of memory at the end of this range for DMA, on a machine with a GRUB boot loader, add the following to the grub file

          GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} mem=1800M [email protected]"

          This instructs Linux to boot with ~1,800MB (“mem=1800M“) starting at address 0x100000 (“@1M“).
          Reconfigure GRUB to apply the changes:

          sudo grub-mkconfig -o /boot/grub/grub.cfg
        3. Reboot Linux
        4. Run the command

          dmesg | grep BIOS\|user

          to see the available physical memory ranges. The output should include a BIOS-provided physical RAM mappings section with the BIOS-.... lines from the original dmesg output, and a new user-defined RAM mappings section with user: ... lines indicating the actual available physical memory ranges (based on user definitions).
          The user entry for the memory range you modified in the previous steps should be missing the portion you reserved. For example, for the original BIOS mappings and boot-loader changes examples provided in the previous steps, the new output should look like similar to this:

          [ 0.000000] BIOS-provided physical RAM map:
          [ 0.000000] BIOS-e820: 0000000000000000 - 000000000009f800 (usable)
          [ 0.000000] BIOS-e820: 000000000009f800 - 00000000000a0000 (reserved)
          [ 0.000000] BIOS-e820: 00000000000f0000 - 0000000000100000 (reserved)
          [ 0.000000] BIOS-e820: 0000000000100000 - 000000007dce0000 (usable)
          [ 0.000000] BIOS-e820: 000000007dce0000 - 000000007dce3000 (ACPI NVS)
          [ 0.000000] BIOS-e820: 000000007dce3000 - 000000007dcf0000 (ACPI data)
          [ 0.000000] BIOS-e820: 000000007dcf0000 - 000000007dd00000 (reserved)
          [ 0.000000] BIOS-e820: 00000000c0000000 - 00000000d0000000 (reserved)
          [ 0.000000] BIOS-e820: 00000000fec00000 - 0000000100000000 (reserved) [ 0.000000] user-defined physical RAM map:
          [ 0.000000] user: 0000000000000000 - 000000000009f800 (usable)
          [ 0.000000] user: 000000000009f800 - 00000000000a0000 (reserved)
          [ 0.000000] user: 00000000000f0000 - 0000000000100000 (reserved)
          [ 0.000000] user: 0000000000100000 - 0000000070900000 (usable)
          [ 0.000000] user: 000000007dce0000 - 000000007dce3000 (ACPI NVS)
          [ 0.000000] user: 000000007dce3000 - 000000007dcf0000 (ACPI data)
          [ 0.000000] user: 000000007dcf0000 - 000000007dd00000 (reserved)
          [ 0.000000] user: 00000000c0000000 - 00000000d0000000 (reserved)

          Comparing the following line from the BIOS-provided mapping section:

          [ 0.000000] BIOS-e820: 0000000000100000 - 000000007dce0000 (usable)

          with the following line from the user-defined mapping section:

          [ 0.000000] user: 0000000000100000 - 0000000070900000 (usable)

          shows that the original ~1.95GB memory range — 0x100000 – 0x7dce0000 was reduced to a ~1.75GB range — 0x100000–0x70900000. The memory in address range 0x70900000 – 0x7dce0000 is no longer available because it has been reserved in the previous steps, allowing you to use this range for DMA.

    3. Calculating the base address
    4. To acquire the base address of the reserved memory segment on Windows, you must first determine the physical memory mapping on your PC and retrieve the base address and length (in bytes) of the highest address space used by the operating system. Then add the length of this address space to its base address to receive the base address of your reserved memory segment:
      Reserved memory base address =
      Highest OS physical memory base address + length of the highest OS memory base address

      To verify the size of your reserved memory block, compare the length of the highest OS address space, before and after modifying boot configuration to reserve the memory. This can be done as follows:

      1. Open the registry (Start –> Run –> regedit.exe)
      2. Navigate to the registry key:
        HKEY_LOCAL_MACHINE\HARDWARE\RESOURCEMAP\System Resources\Physical Memory\.Translated
        This key is of type REG_RESOURCE_LIST and holds information regarding the physical memory mapping on your PC. To view a parsed version of the mapped addresses, double-click on the Translated key, select the relevant resource from the Resource Lists dialog, and double-click on the resource (or select Display…) in order to display the resources dialog, which contains a list of all memory address ranges for the selected resource. The base address for your reserved physical memory block is calculated by locating the highest base address in the list and adding to it the length of the relevant address space.
        For example, for the following Resources dialog, the highest base address is 0x1000000 and the length of the address space that begins at this address is 0x1eff0000, so the base address of the reserved memory is 0x1fff0000.

        reserved memory base address = 0x1000000 + 0x1eff0000 = 0x1fff0000

    5. Using WinDriver with reserved memory
    6. Once you acquire the physical base address of the memory segment that you reserved, you can easily access it using WinDriver, as you would any memory on an ISA card.You can use WinDriver’s DriverWizard to test the access to the memory you reserved: Use the wizard to create a new ISA project, define the new memory item according to the information you acquired in the previous step(s), then proceed to access the memory with the wizard. You can also use DriverWizard to generate a sample diagnostics application that demonstrates how to lock and access the reserved memory region using WinDriver’s API.The following code segment demonstrates how you can define and lock the physical memory using WinDriver’s WDC API. The handle returned by the sample LockReservedMemory() function can be used to access the memory using WinDriver’s WDC memory access APIs, defined in the WinDriver/include/wdc_lib.h header file.

      There may be differences between the API in your version of WinDriver and that used in the following example (such as differences in field names and/or types).


      LockReservedMemory: Returns a WDC handle for accessing the reserved memory block.
      Parameters:
      pReservedRegionBase: The physical base address of the reserved memory region (as calculated in the previous step)
      qwReservedRegionLength: The length (in bytes) of the reserved memory region.

      /************/
      Note:
      The function uses the high-level WDC APIs. You can implement similar code using the low-level WD_CardRegister() API — see the WinDriver User's Manual for details.
      /************/
      WDC_DEVICE_HANDLE LockReservedMemory(PHYS_ADDR pReservedRegionBase, UINT64 qwReservedRegionLength)
      {

      printf( “Failed opening a WDC device handle.
      Error 0x%lx — %s\n”, dwStatus,
      Stat2Str(dwStatus));
      return NULL;

      }
      /* Return the handle to the reserved memory */
      return hDev;

      }


      /*
      SetMemoryItem: Initializes a WDC device information structure for a specified memory region.
      Parameters:
      pDeviceInfo: Pointer to a resources information structure
      pPhysAddr: The memory region’s physical base address
      qwBytes: The memory region’s length, in bytes
      */
      void SetMemoryItem(WD_CARD *pDeviceInfo, PHYS_ADDR pPhysAddr, UINT64 qwBytes)
      {