Как программно получить размер страницы ядра Linux

Я работаю над модулем Linux для IA64. Моя текущая проблема заключается в том, что драйвер использует макросы PAGE_SIZE и PAGE_SHIFT для распределения страниц dma. Проблема, с которой я сталкиваюсь, заключается в том, что машина, компилирующая драйвер, не та, которая нужна для запуска драйвера. Таким образом, если PAGE_SIZE на компилирующей машине составляет 2 ^ 14 КБ, а на целевой машине — 2 ^ 16 КБ, драйвер не работает.

Я не хочу превращать этот вопрос в вопрос о «лучшей практике» компиляции модулей на машинах, на которых эти модули не запущены. Я понимаю вопросы по этому поводу. Я обнаружил, что люди в основном используют getpagesize() или sysconf(_SC_PAGE_SIZE). Эти два параметра отсутствуют в заголовках ядра ia64, поэтому я не могу их использовать. Есть ли другой способ получить среду выполнения PAGE_SIZE?

Варианты, которые я рассматриваю:

  • Чтение какого-то файла в /proc?
  • системный вызов?
  • Другая функция, которая позволяет мне вычислить PAGE_SIZE по выводу (например, ORDER, getpageshift и т. д.)?
  • Другой?

person Freddy    schedule 03.02.2011    source источник
comment
Вы говорите, что PAGE_SIZE настраивается для архитектуры IA64, а не фиксируется? Я думал, что PAGE_SIZE исправлено для данной архитектуры (например, всегда 4096 для x86).   -  person Craig McQueen    schedule 10.04.2013
comment
IA64 действительно поддерживает несколько размеров страниц: informit.com/articles/article. aspx?p=29961&seqNum=3   -  person mdd    schedule 24.03.2015


Ответы (7)


Попробуйте использовать утилиту getconf, которая позволит вам легко получить размер страницы.

getconf PAGESIZE
person vetri    schedule 01.10.2012
comment
Я не думаю, что это отвечает на вопрос OP, но это полезная информация, поскольку sysconf(_SC_PAGESIZE) возвращает 4K на linuxia64 (в то время как mprotect не работает на странице, не выровненной по границе 16K). - person Peeter Joot; 29.11.2014
comment
мой x86-64 возвращает только 4k, но у него есть страницы 4k, 2M и 1G. - person ctrl-alt-delor; 03.08.2019

Один из приблизительных методов — прочитать /proc/meminfo и проверить размер Mapped (в моем случае это 52544 КБ на данный момент), а затем проверить nr_mapped в /proc/vmstat (в моем случае это 131136 на данный момент). Наконец PAGE_SIZE = Mapped/nr_mapped. Иногда это дает вам точное значение (как в текущем примере, который я цитировал), а иногда — приблизительное, но очень близкое. Надеюсь это поможет!

person Pavan Manjunath    schedule 07.06.2011
comment
Я не нашел Mapped/nr_mapped даже близко к тому, что предоставил getconf PAGESIZE - person MCP; 20.06.2018

Один из способов узнать размер страницы — получить его из smaps для процесса.

Например:

cd /proc/1
grep -i pagesize smaps

KernelPageSize:        4 kB
MMUPageSize:           4 kB
person ria    schedule 28.02.2018
comment
Любопытно, что с помощью вашего трюка я вижу 4 kB на ARM, но внутри arch/arm/include/asm/page.h работающего ядра это #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) и, очевидно, это составляет 1024 байта при проверке из моего драйвера, как уже было предложено в определении page.h. Что дает? - person 0xC0000022L; 31.10.2019

Если вы пытаетесь собрать модуль ядра, вам понадобятся по крайней мере заголовки ядра, настроенные для ядра, на котором будет работать модуль. Они будут определять макросы размера страницы, которые вам нужны. Если у вас нет правильно настроенных заголовков, ядро ​​​​откажется загружать ваш модуль.

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

person JayM    schedule 09.02.2011
comment
Это не проблема исходников ядра. Речь идет о загрузке модуля, скомпилированного на машине, для запуска на другой машине (оба имеют одинаковую версию ядра, но настроены по-разному). Я не хочу перекомпилировать новую конфигурацию, потому что PAGE_SIZE изменился. Я хочу получить этот параметр от ядра как API, а не как MACRO (который решается во время компиляции). - person Freddy; 17.03.2011
comment
‹‹И нет ничего плохого в том, чтобы скомпилировать модуль на одной машине для запуска на другой, даже если это другая архитектура. Вам просто нужно собрать правильный исходный код ядра. ........... ИМЕННО СУТЬ - person kumar; 10.05.2011
comment
PAGE_SIZE очень важен и требуется для модуля при создании самого модуля. - person kumar; 10.05.2011

Вот что я наконец сделал:

  • Переработайте мой текущий модуль, чтобы он взял новый параметр модуля с именем page_shift и использовал его для вычисления PAGE_SIZE (PAGE_SIZE = 1 << PAGE_SHIFT)
  • Создана оболочка загрузчика модулей, которая получает текущую систему PAGE_SHIFT с помощью getconf API из libc. Эта оболочка получает текущий системный сдвиг страницы и передает его в качестве параметра модуля.

Сейчас модуль без проблем грузится на разных архитектурах с разным PAGE_SIZE.

person Freddy    schedule 03.08.2011
comment
Нубский вопрос. Не могли бы вы рассказать немного больше о обертке, которая использует API getconf? Я имею в виду, вызывали ли вы команду getconf внутри функции popen() или что-то в этом роде. Немного больше света над ним будет супер оценено. - person Dr. Xperience; 07.12.2016

Я боюсь, что это невозможно сделать, так как размер страницы определяется как часть ядра. Знание размера страницы требуется в случае цепочки инструментов, которую вы также используете для компиляции модуля ядра.

Так что, по крайней мере, с текущей архитектурой ядра это невозможно.

person kumar    schedule 10.05.2011

Вы можете просто запустить тест, просто mmap файл с разными смещениями и посмотреть, какой из них не работает. Хотя это может раздражать в модуле ядра, но, возможно, есть какой-то другой подобный тест, который вы могли бы использовать.

person Justin Cormack    schedule 03.02.2014