如何从 Linux 内核中保留一块内存?

Nat*_*man 26 linux kernel memory hardware

我有一个设备需要一块专门为它保留的内存块,而没有操作系统的干预。有什么方法可以告诉 BIOS 或操作系统保留一块内存,并且不能使用它?

我在 openSUSE 机器上使用这个设备。

Aar*_*sco 25

如果您希望操作系统完全忽略它,您需要使用“ memmap.”来制造内存漏洞。请参阅此参考。例如,如果你想要 512M 的 2GB 屏障,你可以memmap=512M$2G在你的内核命令行上加上“ ”。

您需要检查您的位置dmesg以找到一个连续的洞来窃取,这样您就不会踩踏任何设备;这是特定于您的主板+卡的。

不是推荐的做事方式 - 请参阅 Warren Young 的答案以了解如何正确执行此操作(内核驱动程序 + DMA)。我正在回答你问的确切问题。如果你打算为最终用户做这个,如果你对他们这样做,他们会讨厌你......相信我,这是我知道这个答案的唯一原因。


编辑:如果您使用带有 grubby 的 grub2(例如 CentOS 7),您需要确保转义 $\之前应该有单$。例子:

$ 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"
Run Code Online (Sandbox Code Playgroud)

  • @AaronD.Marasco:不,`mmap()`'d 的页面在用户代码看到它们之前被清零。这样做是为了安全,因此数据不会从一个进程泄漏到下一个进程。使用驱动程序的另一个原因,因为您可能需要在驱动程序加载时保留 DMA 缓冲区的内容。哦,顺便说一句,即使没有 `memmap` 内核引导选项,任意位置的 `mmap()` 调用也会成功,至少只要没有人已经在使用位于您要求的位置的内存。引导选项无疑会增加成功的机会,但这并不是绝对必要的。 (3认同)
  • 只是为了咧嘴笑,我对此进行了深入研究,看来您需要`MMAP_FIXED | MMAP_ANON`。这里没有自定义 DMA 设备可以使用,我不能说它是否真的满足了 OP 的要求,但是当我在 GRUB 中说“memmap=8M$512M”时,我的 CentOS 机器很高兴地给了我 512 MB 的 8 MB 块. 它甚至不需要 root 访问权限,就像我担心的那样。但即使这确实做了正确的事情,我仍然认为您可能需要一个驱动程序来处理中断等。 (2认同)

War*_*ung 24

您要求的称为 DMA。您需要编写一个驱动程序来保留此内存。

是的,我知道您说过您不希望操作系统进行干预,并且驱动程序成为操作系统的一部分,但是在没有驱动程序保留的情况下,内核认为所有内存都属于它。(除非你告诉内核忽略内存块,按照 Aaron 的回答,就是这样。)

Rubini、Corbet 和 Kroah-Hartmann 所著的“ Linux 设备驱动程序,3/e ”的第 15 章(PDF)涵盖了 DMA 和相关主题。

如果你想要这个的 HTML 版本,我在网上其他地方找到了该章节的第二版。请注意,第 2 版现在已经有十多年的历史了,它是在内核 2.4 是新版本时问世的。从那时起,在内核的内存管理子系统上有很多工作,所以它可能不再适用。


小智 6

要在基于 ARM 的 Linux 的内核中保留一块内存,您还可以使用reserved-memory设备树 (dts) 文件中的节点。在内核文档(参见此处)中,有一个示例:

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>;
    };
};
Run Code Online (Sandbox Code Playgroud)