Как зарезервировать блок памяти из ядра Linux?

26

У меня есть устройство, которому нужен блок памяти, зарезервированный исключительно для него, без вмешательства ОС. Есть ли способ сообщить BIOS или ОС, что блок памяти зарезервирован, и он не должен его использовать?

Я использую это устройство на машине openSUSE.

Натан Феллман
источник

Ответы:

24

То, что вы просите, называется DMA. Вам необходимо написать драйвер, чтобы зарезервировать эту память.

Да, я понимаю, что вы сказали, что не хотите вмешиваться ОС, и драйвер становится частью ОС, но в отсутствие резервирования драйвера ядро ​​считает, что вся память принадлежит ему. (Если вы не скажете ядру игнорировать блок памяти, согласно ответу Аарона, то есть.)

Глава 15 (PDF) « Драйверов устройств Linux, 3 / e » Рубини, Корбета и Кроа-Хартманна посвящена DMA и смежным темам.

Если вам нужна HTML-версия этого, я нашел версию второго издания этой главы в Интернете. Помните, что 2-й редакции уже более десяти лет, она вышла, когда появилось новое ядро ​​2.4. С тех пор была проделана большая работа над подсистемой управления памятью ядра, поэтому она может не очень хорошо применяться.

Уоррен Янг
источник
С помощью DMA я могу выбрать, какие физические адреса использовать? Даст ли ядро ​​непрерывный блок памяти? Это гарантированно всегда будет доступно?
Натан Феллман
1
Ответы на ваши вопросы начинаются на странице 442 PDF, на который я вам указывал.
Уоррен Янг
25

Если вы хотите, чтобы ОС полностью игнорировала это, вам нужно сделать дыру в памяти, используя « memmap.» Смотрите эту ссылку . Например, если вы хотите 512M на барьере 2 ГБ, вы можете поставить " memmap=512M$2G" в командной строке вашего ядра.

Вам нужно будет проверить, dmesgчтобы найти непрерывное отверстие для кражи, чтобы не топать ни на каких устройствах; это зависит от вашей материнской платы + карты.

Это не рекомендуемый способ сделать что-то - см. Ответ Уоррена Янга о том, как правильно это сделать (драйверы ядра + DMA). Я отвечаю на тот вопрос, который вы задали. Если вы планируете сделать это для конечных пользователей, они будут ненавидеть вас, если вы сделаете это с ними ... поверьте мне, это единственная причина, по которой я знал этот ответ.


Изменить: Если вы используете grub2 w / grubby (например, 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, но мой процессор CentOS с радостью дал мне блок 8 МБ при 512 МБ, когда я сказал memmap=8M$512Mв GRUB. Это даже не требует root-доступа, как я и опасался. Но даже если это делает правильно, я все же думаю, что вам, вероятно, понадобится драйвер для обработки прерываний и тому подобное.
Уоррен Янг
3
@ AaronD.Marasco: Нет, mmap()страницы будут обнулены до того, как код пользователя увидит их. Это сделано для безопасности, чтобы данные не передавались из одного процесса в другой. Еще одна причина использовать драйвер, поскольку вам может потребоваться сохранить содержимое буфера DMA во время загрузки драйвера. И, кстати, произвольно расположенный mmap()вызов завершается успешно даже без memmapопции загрузки ядра, по крайней мере, до тех пор, пока никто не использует память, расположенную там, где вы просили. Вариант загрузки, несомненно, увеличивает шансы на успех, но это не является строго необходимым.
Уоррен Янг
1
@ AaronD. Мараско хм, ладно. интересный. спасибо за эту ссылку, это хорошо читать.
Вудроу Барлоу
5

Чтобы зарезервировать блок памяти из ядра в Linux на основе ARM, вы также можете использовать 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

8М чрезвычайно консервативен; это может сидеть в 16M удобно. Как только вы измените значение, запустите это, и перезагрузка не требуется:

sudo sysctl -p
Михаил Мрозек
источник
2
Пожалуйста, не очищайте свои сообщения; либо удалите его, либо пометите его для удаления модератором.
Джейсонвриан