23

I have a device that needs a block of memory that is reserved solely for it, without the OS intervening. Is there any way to tell BIOS or the OS that a block of memory is reserved, and it must not use it?

I am using this device on an openSUSE machine.

23

What you're asking for is called DMA. You need to write a driver to reserve this memory.

Yes, I realize you said you didn't want the OS to intervene, and a driver becomes part of the OS, but in absence of a driver's reservation, the kernel believes all memory belongs to it. (Unless you tell the kernel to ignore the memory block, per Aaron's answer, that is.)

Chapter 15 (PDF) of "Linux Device Drivers, 3/e" by Rubini, Corbet and Kroah-Hartmann covers DMA and related topics.

If you want an HTML version of this, I found the second-edition version of the chapter elsewhere online. Beware that the 2nd edition is over a decade old now, having come out when kernel 2.4 was new. There's been a lot of work on the memory management subsystem of the kernel since those days, so it may not apply very well any more.

  • With DMA can I choose what physical addresses to use? Will the kernel give me a contiguous block of memory? Is it guaranteed to be always available? – Nathan Fellman May 2 '12 at 4:15
  • 1
    Your questions are answered starting on page 442 of the PDF I pointed you to. – Warren Young May 2 '12 at 4:34
24

If you want the OS to totally ignore it, you need to make a memory hole using "memmap." See this reference. For example, if you want 512M at the 2GB barrier, you can put "memmap=512M$2G" on your kernel command line.

You will need to check your dmesg to find a contiguous hole to steal so you don't stomp on any devices; that is specific to your motherboard+cards.

This is not the recommended way to do things - see Warren Young's answer for how to properly do it (kernel drivers + DMA). I'm answering the exact question you asked. If you plan on making this for end users, they will hate you if you do this to them... trust me, that's the only reason I knew this answer.


Edit: If you are using grub2 w/ grubby (e.g. CentOS 7), you need to make sure to escape the $. There should be a single \ before $. Example:

$ sudo -v
$ sudo grubby --update-kernel=ALL --args=memmap='128M\\$0x57EF0000'
$ sudo grubby --info $(sudo grubby --default-kernel) | grep memmap
args="ro crashkernel=auto ... memmap=128M\$0x57EF0000"
  • 1
    While your answer does answer my question directly, Warren's answer seems to be the better way to go about it. :-) – Nathan Fellman May 2 '12 at 6:32
  • 1
    @WarrenYoung I have no idea what you are supposed to do with it. I would guess "uint8_t *ptr = 0x8000000" with my example? Or that may segfault... Huh, I really don't know. Again, I knew the answer because I was an end user of a poorly designed PCI card where I had to manually allocate a buffer below the 4G mark and then tell a driver where that space was; it may not be possible from userland. – Aaron D. Marasco May 2 '12 at 10:14
  • 2
    Just for grins, I looked a little deeper into this, and it appears you need MMAP_FIXED | MMAP_ANON. Without a custom DMA device here to play with, I can't say if it actually does what the OP wanted, but my CentOS box happily gave me an 8 MB block at 512 MB when I said memmap=8M$512M in GRUB. It doesn't even require root access, as I had feared it might. But even if this does do the right thing, I still think you'll probably need a driver to handle interrupts and such. – Warren Young May 2 '12 at 13:05
  • 3
    @AaronD.Marasco: No, mmap()'d pages are zeroed before userland code gets to see them. It's done for security, so that data doesn't leak from one process to the next. Another reason to use a driver, since you might need to preserve the contents of the DMA buffer at driver load time. Oh and by the way, the arbitrarily-located mmap() call succeeds even without the memmap kernel boot option, at least as long as no one is already using memory located where you asked. The boot option doubtless increases the chances of success, but it's not strictly necessary. – Warren Young May 3 '12 at 17:42
  • 1
    @AaronD.Marasco hmm, okay. interesting. thank you for that link, it's a good read. – Woodrow Barlow Mar 21 '17 at 14:10
4

To reserve a block of memory from the kernel in ARM based Linux, you can also use a reserved-memory node in your device tree (dts) file. In kernel documentation (see here), there is an example:

memory {
    reg = <0x40000000 0x40000000>;
};

reserved-memory {
    #address-cells = <1>;
    #size-cells = <1>;
    ranges;

    /* global autoconfigured region for contiguous allocations */
    linux,cma {
        compatible = "shared-dma-pool";
        reusable;
        size = <0x4000000>;
        alignment = <0x2000>;
        linux,cma-default;
    };

    display_reserved: framebuffer@78000000 {
        reg = <0x78000000 0x800000>;
    };

    multimedia_reserved: multimedia@77000000 {
        compatible = "acme,multimedia-memory";
        reg = <0x77000000 0x4000000>;
    };
};
0

First enter this command, to check your current setting:

sysctl vm.min_free_kbytes

To change the set value, edit /etc/sysctl.conf. Look for the line:

vm.min_free_kbytes=12888

If it doesn't exist, create it (along with your desired value). The following values are acceptable:

8192
12288
16384
20480

8M is extremely conservative; it can sit at 16M comfortably. Once you change the value, run this and no reboot is needed:

sudo sysctl -p
  • 2
    Please don't blank your posts; either delete it or flag it for a moderator to remove for you. – jasonwryan Jan 24 '13 at 8:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.