Первым шагом в запуске системы является перенос загрузчиком образа ядра с диска или из сети в физическую память машины. Образ загрузки ядра во многом сходен с образом любого другого процесса; он содержит сегмент кода, сегмент инициализированных данных и сегмент неинициализированных данных. Загрузчик помещает ядро непрерывно в начале физической памяти. В отличие от процесса пользователя, страницы которого загружаются в память по требованию, код и данные для ядра считываются в память полностью. За этими двумя сегментами загрузчик обнуляет область памяти, равную размеру сегмента неинициализированной памяти ядра. После загрузки ядра загрузчик передает управление по начальному адресу, указанному в исполняемом образе ядра. Когда ядро начинает выполнение, оно выполняется с выключенным MMU. Соответственно вся адресация осуществляется с использованием прямых физических адресов.
Первой задачей, предпринимаемой ядром, является установка pmap ядра и любых других структур данных, необходимых для описания виртуального адресного пространства ядра. На PC начальная установка включает выделение и инициализацию каталогов и таблиц страниц, которые отображают статически загруженный образ ядра и отображенное в память адресное пространство ввода/вывода, выделяя для страниц таблиц страниц ядра фиксированный объем памяти, выделяя и инициализируя структуру пользователя и стек ядра для начального процесса, резервируя особые области для адресного пространства ядра и инициализируя систематизированные критические внутренние структуры данных pmap. После осуществления этого можно включить MMU. После подключения MMU ядро начинает работать в контексте нулевого процесса.
После того как ядро начало работать в своем виртуальном адресном пространстве, оно продолжает инициализировать оставшуюся часть системы. Оно определяет размер физической памяти, затем вызывает pmap_bootstrap() и vmjpage_startup() для установки начальных структур данных pmap, для выделения структур vm_page и для создания небольших пулов памяти фиксированного размера, которые распределители памяти ядра могут использовать таким образом, что они могут начать отвечать на запросы выделения памяти. Затем оно делает вызов для установки машинно-независимой части системы виртуальной памяти. Оно завершает вызовом pmapinit(), который выделяет все ресурсы, необходимые для управления множеством адресных пространств пользователя, и синхронизирует структуры данных виртуальной памяти ядра более высокого уровня с pmap ядра.
Pmapjnit() выделяет минимальное количество зарезервированной (wired) памяти для использования страницами таблицы страниц ядра. Пространство таблиц страниц динамически расширяется процедурой pmap_growkernel() по мере необходимости в ходе работы ядра. После выделения она никогда не освобождается. Ограничение на размер адресного пространства ядра выбирается во время загрузки. На PC ядру обычно предоставляется максимум 1 Гбайт адресного пространства.
В 4.4BSD память, управляемая буферным кешем, была отделена от памяти, управляемой системой виртуальной памяти. Поскольку все страницы виртуальной памяти использовались для отображения областей процессов, было целесообразно создать инвертированную таблицу страниц. Эта таблица представляла собой массив структур pventry. Каждая pventry описывала одну трансляцию адреса и включала виртуальный адрес, указатель на связанную с этим виртуальным адресом структуру pmap, ссылку для соединения в цепь нескольких элементов, отображающих этот физический адрес, и дополнительную информацию, специфичную для элементов, отображающих страницы таблицы страниц. Построение выделенной таблицы было разумно, поскольку pmap ссылался на все действительные страницы, некоторые даже имели несколько отображений.
С поглощением в FreeBSD буферного кеша системой виртуальной памяти многие страницы памяти используются для кеширования файловых данных, которые не отображены в адресное пространство какого-либо процесса. Поэтому предварительное выделение таблицы структур pv_entry является расточительным, поскольку многие из них не были бы использованы. Поэтому FreeBSD выделяет структуры pventry по требованию, когда страницы отображаются в адресное пространство процесса.
На рисунке показаны ссылки pv_entry для набора страниц, имеющих по одному отображению. Назначением структур pvjentry является идентификация адресного пространства, которое отобразило страницу. Машинно-зависимая часть каждой структуры vm_page содержит заголовок списка структур pv_entry и число элементов в этом списке. На рисунке объект использует страницы 5, 18 и 79. Заголовки списков в машинно-зависимых структурах этих структур vm_page указывали бы каждый на отдельную структуру pv_entry, обозначенную на рисунке номером ссылающейся на нее структуры vm_page. На рисунке не показано, что каждая структура физического отображения поддерживает также список всех структур pv_entry, которые на нее ссылаются.
Каждая pv_entry может ссылаться лишь на одно физическое отображение. Когда объект начинает разделяться двумя или более процессами, каждая физическая страница памяти становится отображенной в два или более наборов таблиц страниц. Для отслеживания этих множественных ссылок модуль pmap должен создать цепочки структур pv_entry, как показано на рисунке ниже.

Копирование при записи является примером необходимости нахождения всех отображений страницы, поскольку для него требуется установить атрибут только для чтения для таблиц страниц во всех процессах, разделяющих этот объект. Модуль pmap может реализовать этот запрос, обходя список страниц, связанных с объектом, который должен получить атрибут копирования при записи. Для каждой страницы он проходит список структур pventry этой страницы. Затем он делает соответствующее изменение в элементе таблицы страниц, связанной с каждой структурой pv entry.

Системе со множеством разделяемых объектов может потребоваться множество структур pv_entry, которые могут использовать чрезмерное количество памяти ядра. Альтернативой было бы хранение списка, связанного с каждым объектом всех структур vmjnap_entry, ссылающихся на него. Когда возникает необходимость в изменении отображения всех ссылок на страницу, ядро могло бы обойти этот список, проверяя адресное пространство, связанное с каждым vm_map_entry, на предмет содержания ссылки на эту страницу. Для каждой найденной страницы оно могло бы сделать соответствующее изменение.
Структуры pv_entry занимают больше памяти, но снижают время, необходимое для осуществления обычных операций. Например, рассмотрите систему, запустившую тысячи процессов, которые все разделяют общую библиотеку. Без списка pv_entry изменение атрибута страницы на копирование при записи потребовало бы проверки всех тысяч процессов. Со списком pv_entry нужно было бы проверить лишь те процессы, которые используют эту страницу.
- 15/11/2010 23:40 - Управление внутренними структурами данных
- 13/11/2010 07:13 - Управление информацией об использовании страницы
- 11/11/2010 20:28 - Изменение для отображений атрибутов доступа и резервирования
- 09/11/2010 09:04 - Операции, определенные пейджером
- 08/11/2010 13:50 - Выделение и освобождение отображения
- 05/11/2010 00:51 - Завершение процесса
- 04/11/2010 18:14 - Роль модуля pmap
- 02/11/2010 21:26 - Переносимость
- 02/11/2010 12:16 - Процесс подкачки
- 01/11/2010 22:58 - Подкачка процессов