Intereting Posts
Как я могу запретить редактируемые команды перезаписывать оригинал? Или вернуть изменения? Как сделать раздел, который отделен от ОС? Диспетчер отображения на нескольких страницах мостовое взаимодействие с kvm Как вы можете изменить команду форматирования, используемую человеком? Как перечислить n-й самый младший файл (без разбора ls!) Linux-приложение на основе Linux Linux Автоматически экспортировать переменную в каждый сеанс ssh Самый быстрый и самый основной способ заменить «\ r \ n» на «\ n» в файле? Как исправить загрузчик GRUB (Windows 10 не работает) Проверка семантической целостности файловой системы Как изменить данную строку терминала? Как рассчитать сумму данных, имеющих один и тот же идентификатор в первом столбце? Когда sh является символической ссылкой на bash или тире, bash ограничивает себя соблюдением POSIX, поэтому он должен быть на 100% совместим с sh? Как скопировать установленное приложение на другой компьютер, на котором отсутствуют инструменты сборки?

Цитата по управлению памятью ядра Linux

Мне невероятно тяжело разобраться в этом отрывке из книги драйверов устройств Linux (извините за текст, насыщенный постом):

Ядро (в архитектуре x86, в конфигурации по умолчанию) разделяет виртуальное адресное пространство размером 4 ГБ между пользовательским пространством и kernelм; один и тот же набор отображений используется в обоих контекстах. Типичный разделитель выделяет 3 ГБ для пространства пользователя и 1 ГБ для пространства ядра.

Хорошо понял.

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

Что это значит? Код и структуры данных ядра также не находятся в «виртуальной памяти, которая сопоставлена ​​с физическим адресным пространством». Иначе, где эти коды и структуры данных вообще хранятся?

Или это говорит о том, что ядру необходимо виртуальное адресное пространство для отображения случайных данных, не связанных с kernelм, с которыми оно работает через драйверы, IPC или что-то еще?

Ядро не может напрямую манипулировать памятью, которая не отображается в адресное пространство ядра. Другими словами, ядру нужен собственный виртуальный адрес для любой памяти, к которой он должен непосредственно обращаться.

Это правда? Если kernel ​​работает в контексте процесса (обрабатывая системный вызов), таблицы страниц процесса все равно будут загружены, так почему же kernel ​​не может непосредственно считывать память процесса пользовательского режима?

Таким образом, в течение многих лет максимальный объем физической памяти, который мог обрабатывать kernel, был объемом, который мог быть отображен в часть ядра виртуального адресного пространства, минус пространство, необходимое для самого кода ядра.

Хорошо, если мое понимание в цитате № 2 верно, это имеет смысл.

В результате системы Linux на базе x86 могут работать с максимальной физической нагрузкой чуть менее 1 ГБ.

???? Это похоже на полный не sequitur. Почему он не может работать с 4 ГБ памяти и просто отображать разные вещи в 1 ГБ пространства, доступного для ядра по мере необходимости? Как пространство ядра всего лишь ~ 1 ГБ означает, что система не может работать с 4 ГБ? Это не должно быть все сопоставлено сразу.

    Почему он не может работать с 4 ГБ памяти и просто отображать разные вещи в 1 ГБ пространства, доступного для ядра по мере необходимости?

    Это возможно, это то, что HIGHMEM конфигурации HIGHMEM делают для памяти, которая не подходит для непосредственного отображения. Но когда вам нужно получить доступ к произвольному расположению в памяти, это сделать гораздо проще , если вы можете указать на него напрямую, не настраивая отображение каждый раз. Для этого вам нужна область виртуальной памяти, которая всегда отображается на всю физическую память, и этого нельзя сделать, если виртуальное адресное пространство меньше физической.

    Прямой доступ также быстрее, vm/highmem.txt в документации ядра говорит:

    Стоимость создания временных отображений может быть довольно высокой. Арка должна манипулировать таблицами страниц ядра, данными TLB и / или регистрами MMU.

    Конечно, вы можете получить доступ к памяти запущенного процесса через отображение пространства пользователя, и, возможно, вы можете избежать необходимости доступа к памяти других процессов. Но если есть какие-либо большие структуры данных в ядре (например, кеш страниц), было бы хорошо иметь возможность использовать всю память для них.

    Все это является своего рода переключением банков , которое использовалось на 16-битных машинах и в системах 386/486 в эпоху DOS ( HIMEM.SYS ). Я не думаю, что кому-то особенно нравился такой доступ к памяти, даже тогда, так как это делает вещи довольно трудными, если вам нужно, чтобы несколько областей физической памяти были «открыты» одновременно. Переход к 32-разрядным, а затем к 64-разрядным системам устраняет эту проблему.

    Если kernel ​​работает в контексте процесса (обрабатывая системный вызов), таблицы страниц процесса все равно будут загружены, так почему же kernel ​​не может непосредственно считывать память процесса пользовательского режима?

    Формулировка «адресное пространство ядра» в этом контексте не должна интерпретироваться как противоположность адресному пространству пользователя. Вместо этого подразумевается, что память, к которой kernel ​​должно обращаться, должна быть сопоставлена ​​с некоторыми виртуальными адресами. Это то, что автор книги пытается сделать здесь. Таким образом, «адресное пространство ядра» – это целое отображение.

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

    Вы должны продолжать читать немного дальше, смотрите внимательно.

    Однако остается ограничение на то, сколько памяти может быть напрямую отображено с помощью логических адресов. Только самая низкая часть памяти (до 1 или 2 ГБ, в зависимости от аппаратного обеспечения и конфигурации ядра) имеет логические адреса, [2] остальные (высокая память) не имеют. Прежде чем получить доступ к определенной странице с большим объемом памяти, kernel ​​должно настроить явное виртуальное отображение, чтобы сделать эту страницу доступной в адресном пространстве ядра. Таким образом, многие структуры данных ядра должны быть размещены в нехватке памяти; высокая память, как правило, зарезервирована для страниц процессов пользовательского пространства.


    Если kernel ​​работает в контексте процесса (обрабатывая системный вызов), таблицы страниц процесса все равно будут загружены, так почему же kernel ​​не может непосредственно считывать память процесса пользовательского режима?

    оно делает

    https://www.quora.com/Linux-Kernel-How-does-copy_to_user-work


    Также может быть полезно понять, что обычное использование kmalloc() для выделения структур в ядре возвращает память, которая находится в пределах прямого отображения ~ 1 ГБ. Так что это просто и понятно.

    (Компромисс заключается в том, что он вносит сложность в виде этих различных типов распределений.

    Если бы вы хотели, чтобы стандартные kmalloc() могли использовать более 25% ОЗУ, вы бы делали что-то довольно требовательное … В более специализированных случаях вы можете установить флаг GFP_HIGHMEM, отображать и отображать память по мере необходимости. Но официальный ответ таков: вы просто не должны пытаться запускать такую ​​требовательную рабочую нагрузку на устаревших 32-битных системах, укомплектованных более чем 30-битной физической памятью).

    Если вы действительно заинтересованы в этой конкретной детали, я заметил две другие вещи.

    1. Ограничение в 1 ГБ накладывает ограничение на ОЗУ, но оно немного выше.

    https://www.redhat.com/archives/rhl-devel-list/2005-January/msg00092.html

    Небольшое прибегание к поиску указывает на то, что исправление 4G: 4G необходимо для систем с большим объемом оперативной памяти (например, 32 ГБ или более), поскольку таблицы памяти ядра масштабируются с размером физической памяти, а система 32 ГБ использует 0,5 ГБ для таблица, половина пространства ядра, доступного для системы 3G: 1G. Система на 64 ГБ не загружается, потому что для таблицы нужна вся память ядра.

    Патч 4G: 4G – это другое дело, но вы, вероятно, можете его игнорировать, он не в основной Linux.

    Похоже, что это ограничение также было преодолено, поскольку теперь возможно включить CONFIG_HIGHMEM64G (на i386, то есть 32-битном). Наверное, лучше не полагаться на это. Или слишком много думать о том, что он должен делать.

    2. Прямое отображение не является строго необходимым для таблиц страниц.

    Во многих популярных руководствах и пошаговых руководствах по написанию ОС используется умопомрачительный прием, называемый «рекурсивные таблицы страниц».

    https://www.google.co.uk/search?q=recursive+page+tables

    Linux не использовал этот подход, поэтому традиционный Linux проще для понимания. Прямое сопоставление «малой памяти» ~ 1 ГБ устанавливается в исходной таблице страниц и никогда не изменяется. И таблицы страниц размещаются изнутри “нехватки памяти”.

    (Вы думаете о том, что сейчас делает CONFIG_HIGHMEM64G? Прекратите, это плохо для вас.)

    Я полагаю, что Линус просто не думал о рекурсивном трюке. У IIRC есть и другие недостатки, связанные с отсутствием прямого сопоставления хорошего размера, но я не уверен насчет конкретных примеров.

    Я говорю “традиционный Linux”. Я еще не слышал, действительно ли KPTI был объединен для 32-битного … но в любом случае, KPTI не должен менять общую идею. Как только вы переключаетесь с пользователя на таблицы страниц ядра, kernel ​​может получить доступ к прямому отображению. Процесс переключения – это какая-то удивительная черная магия, но она просто выполняется при каждом переключении контекста. Таблицы страниц пользовательского пространства не include прямое отображение, но пользовательское пространство не имеет и не должно получать доступ к таблицам страниц и т. Д., Так что все в порядке.