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


25

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

我正在openSUSE计算机上使用此设备。

Answers:


23

您要的是DMA。您需要编写驱动程序来保留此内存。

是的,我意识到您说过您不想让操作系统介入,并且驱动程序成为了操作系统的一部分,但是在没有驱动程序保留的情况下,内核认为所有内存都属于它。(就是说,除非您根据Aaron的回答,告诉内核忽略内存块。)

Rubini,Corbet和Kroah-Hartmann撰写的“ Linux Device Drivers,3 / e ”的第15章(PDF)涵盖了DMA和相关主题。

如果需要HTML版本,可以网上其他地方找到本章的第二版。当心第二版已经超过十年了,它是在内核2.4刚发布时问世的。从那以后,内核的内存管理子系统已经进行了很多工作,因此它可能不再适用。


通过DMA,我可以选择使用哪些物理地址?内核会给我连续的内存块吗?是否保证始终可用?
内森·费尔曼

1
从我指出的PDF页面442开始回答您的问题。
沃伦·杨

24

如果要让操作系统完全忽略它,则需要使用“ memmap” 打个内存孔。请参阅此参考。例如,如果您希望在2GB的空间上达到512M,则可以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"

1
虽然您的答案确实可以直接回答我的问题,但沃伦的答案似乎是解决该问题的更好方法。:-)
内森·费尔曼

1
@WarrenYoung我知道你应该怎么做。我会uint8_t *ptr = 0x8000000以我的示例为准吗?否则可能会出现段错误……嗯,我真的不知道。同样,我知道答案,因为我是设计不佳的PCI卡的最终用户,在该卡中,我必须手动分配低于4G标记的缓冲区,然后告诉驱动程序该空间在哪里;用户空间可能无法实现。
亚伦·马拉斯科

2
只是出于笑容,我对此进行了更深入的研究,看来您需要MMAP_FIXED | MMAP_ANON。如果没有自定义的DMA设备可以玩,我不能说它是否确实满足了OP的要求,但是当我memmap=8M$512M在GRUB中说时,我的CentOS盒愉快地给了我一个8 MB的块,即512 MB 。正如我担心的那样,它甚至不需要root访问。但是,即使这样做做对了,我仍然认为您可能需要驱动程序来处理此类中断。
沃伦·杨

3
@ AaronD.Marasco:不,mmap()在用户级代码看到它们之前将d页清零。这样做是为了安全起见,因此数据不会从一个进程泄漏到下一个进程。使用驱动程序的另一个原因,因为您可能需要在驱动程序加载时保留DMA缓冲区的内容。哦,顺便说一句,mmap()即使没有memmap内核启动选项,任意定位的调用也会成功,至少只要没有人已经在使用您所请求的内存就可以了。引导选项无疑会增加成功的机会,但这并不是绝对必要的。
沃伦·扬

1
@ AaronD.Marasco嗯,好的。有趣。感谢您的链接,这是一本好书。
Woodrow Barlow

5

要在基于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>;
    };
};

0

首先输入此命令,以检查当前设置:

sysctl vm.min_free_kbytes

要更改设置值,请编辑/etc/sysctl.conf。寻找这行:

vm.min_free_kbytes=12888

如果不存在,请创建它(以及您想要的值)。可以接受以下值:

8192
12288
16384
20480

8M非常保守;它可以舒适地位于16M。更改值后,请运行以下命令,无需重新启动:

sudo sysctl -p

2
请不要空白。删除它或将其标记为主持人为您删除。
jasonwryan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.