Перейти к содержимому

Зачем нужна виртуализация адресов озу

  • автор:

Виртуализация памяти. Классы виртуальной памяти

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

· размещение данных (образов процессов или их частей) в запоминающих устрой­ствах разного типа: частично — в оперативной памяти, частично — на диске;

· выбор образов процессов или их частей для перемещения из оперативной памя­ти на диск и обратно;

· перемещение данных между памятью и диском;

· преобразование виртуальных адресов в физические.

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

Виртуализация памяти может быть осуществлена на основе двух подходов — свопинга и механизма виртуальной памяти.

Свопинг (swapping). Между оперативной памятью и диском перемещаются образы процессов Более простой в реализации способ, чем виртуальная память. Однако обла­дает избыточностью при подкачке или выгрузке: часто для активизации процесса или освобождения памяти не требуется перемещение всего образа процесса. Избыточность приводит к замедлению работы системы и неэффективному использованию памяти. Кроме того, невозможно загрузить для выполнения процесс, виртуальное адресное про­странство которого превышает имеющуюся в наличии свободную память.

Как основной механизм управления памятью в современных ОС почти не использует­ся. В некоторых ОС, например, версиях Unix, основанных на коде SVR4, свопинг приме­няется как дополнительный к виртуальной памяти, включающийся только при серьезных перегрузках системы.

Виртуальная память (virtual memory). Между оперативной памятью и диском пе­ремещаются части (сегменты, страницы — см. ниже) образов процессов.

В зависимости от способа структуризации виртуального адресного пространства, опре­деляющего преобразование виртуальных адресов в физические, выделяется три класса виртуальной памяти.

· Страничное распределение. Единицей перемещения между памятью и диском является страница — часть виртуального адресного пространства фиксированного и небольшого объема.

· Сегментное распределение. Единицей перемещения между памятью и диском является сегмент — часть виртуального адресного пространства произвольного объе­ма, содержащая осмысленную с некоторой точки зрения совокупность данных (под­программу, массив и т.д.).

· Сегментно-страничное распределение. Объединяет элементы предыдущих клас­сов. Виртуальное адресное пространство структурируется иерархически: делится на сег­менты, а затем сегменты делятся на страниц. Единицей перемещения между памятью и диском является страница.

Для временного хранения вытесненных на диск сегментов и страниц отводится либо специальная область, либо специальный файл, обычно называемые странич­ным файлом (page file, paging file) или, по традиции, файлом свопинга.

Текущий размер страничного файла влияет на возможности работы ОС следую­щим образом: чем больше файл, тем больше одновременно работающих приложе­ний, но тем медленнее их работа из-за многократной перекачки перемещаемых эле­ментов на диск и обратно.

Размер страничного файла в современных ОС является настраиваемым парамет­ром, который выбирается администратором системы для достижения компромисса между числом одновременно выполняемых приложений и быстродействием системы. Этот размер устанавливается в панели управления, пункт «система», вкладка «до­полнительно» — «параметры быстродействия».

Виртуализация памяти. Классы виртуальной памяти

средств процессора и программных средств ОС и включает решение следующих задач:

· размещение данных (образов процессов или их частей) в запоминающих устрой-

ствах разного типа: частично – в оперативной памяти, частично – на диске;

· выбор образов процессов или их частей для перемещения из оперативной памя-

ти на диск и обратно;

· перемещение данных между памятью и диском;

· преобразование виртуальных адресов в физические.

Решение этих задач осуществляется автоматически, без участия программиста, и

не отображаются в логике работы приложений.

· Виртуализация памяти может быть осуществлена на основе двух подходов –

свопинга и механизма виртуальной памяти.

Свопинг (swapping). Между оперативной памятью и диском перемещаются образы

процессов Более простой в реализации способ, чем виртуальная память. Однако обла-

дает избыточностью при подкачке или выгрузке: часто для активизации процесса или

освобождения памяти не требуется перемещение всего образа процесса. Избыточность

приводит к замедлению работы системы и неэффективному использованию памяти.

Кроме того, невозможно загрузить для выполнения процесс, виртуальное адресное про-

странство которого превышает имеющуюся в наличии свободную память.

Как основной механизм управления памятью в современных ОС почти не использует-

ся. В некоторых ОС, например, версиях Unix, основанных на коде SVR4, свопинг приме-

няется как дополнительный к виртуальной памяти, включающийся только при серьезных

Виртуальная память (virtual memory). Между оперативной памятью и диском пе-

ремещаются части (сегменты, страницы – см. ниже) образов процессов.

В зависимости от способа структуризации виртуального адресного пространства, опре-

деляющего преобразование виртуальных адресов в физические, выделяется три класса

· Страничное распределение. Единицей перемещения между памятью и диском

является страница – часть виртуального адресного пространства фиксированного и

· Сегментное распределение. Единицей перемещения между памятью и диском

является сегмент – часть виртуального адресного пространства произвольного объе-

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

программу, массив и т.д.).

· Сегментно-страничное распределение. Объединяет элементы предыдущих клас-

сов. Виртуальное адресное пространство структурируется иерархически: делится на сег-

менты, а затем сегменты делятся на страницы. Единицей перемещения между памятью

и диском является страница.

Для временного хранения вытесненных на диск сегментов и страниц отводится

либо специальная область, либо специальный файл, обычно называемые странич-

ным файлом (page file, paging file) или, по традиции, файлом свопинга.

Текущий размер страничного файла влияет на возможности работы ОС следую-

щим образом: чем больше файл, тем больше одновременно работающих приложе-

ний, но тем медленнее их работа из-за многократной перекачки перемещаемых эле-

ментов на диск и обратно.

Размер страничного файла в современных ОС является настраиваемым парамет-

ром, который выбирается администратором системы для достижения компромисса

между числом одновременно выполняемых приложений и быстродействием системы.

Этот размер устанавливается в панели управления, пункт «система», вкладка «до-

полнительно» – «параметры быстродействия».

Виртуальное адресное пространство каждого процесса делится на части одинако-

вого, фиксированного для данной системы размера, называемые виртуальными стра-

ницами (virtual pages). В общем случае размер виртуального адресного пространства

не является кратным размеру страницы, поэтому последняя страница каждого про-

цесса дополняется фиктивной областью.

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

зываемые физическими страницами (блоками, кадрами).

Для каждого процесса ОС создает таблицу страниц – информационную структу-

ру, содержащую записи обо всех виртуальных страницах процесса.

Схема страничного распределения памяти приведена на рис. 3.3.

При создании процесса его виртуальные страницы загружаются в оперативную па-

мять; в случае нехватки последней часть виртуальных страниц может быть вытесне-

на на диск. Смежные виртуальные страницы не обязательно располагаются в смежных

Кэширование данных

· Память вычислительной машины, представленная совокупностью запоминающих

устройств (ЗУ) различных видов, может быть иерархизирована по следующим основ-

· время доступа к данным;

· стоимость хранения данных в расчете на один бит.

Конкретные значения этих характеристик изменяются очень быстро, поэтому в

данном случае важны не столько их абсолютные значения, сколько соотношение для

разных типов запоминающих устройств. Иерархия ЗУ приведена на рис. 3.9.

Закономерность такова: чем больше быстродействие, тем больше стоимость хра-

нения данных в расчете на один бит и меньше объем устройства. Кэш-память пред-

ставляет некоторое компромиссное решение этой проблемы.

· Кэш-память (cache) – это способ организации совместного функционирования

двух типов запоминающих устройств, отличающихся временем доступа и стоимос-

тью хранения данных, который позволяет уменьшить среднее время доступа к дан-

ным за счет динамического копирования в “быстрое” ЗУ наиболее часто используе-

мой информации из “медленного” ЗУ.

Механизм кэш-памяти прозрачен для пользователя: все перемещения данных де-

лаются автоматически системными средствами.

Кэш-памятью часто называют не только способ организации работы двух типов

запоминающих устройств, но и одно из устройств – “быстрое” ЗУ. Оно стоит дороже

и, как правило, имеет сравнительно небольшой объем. Медленное ЗУ из этой пары

назовем основной памятью, быстрое представлено кэш-памятью.

· Кэширование – универсальный метод, пригодный для ускорения доступа к опе-

ративной памяти, к диску и другим видам ЗУ. Так, в качестве составляющих пары

«основная память – кэш-память» могут выступать: оперативная память – быстро-

действующая статическая память; система ввода-вывода – буферы в оперативной

памяти (или специальная кэш-память).

Рассмотрим одну из возможных схем кэширования.

Содержимое кэш-памяти представляет собой совокупность записей обо всех заг-

руженных в нее элементах данных из основной памяти. Каждая запись об элемен-

те данных включает в себя:

— значение элемента данных;

— адрес, который этот элемент данных имеет в основной памяти;

— управляющую информацию для реализации алгоритма замещения, обычно – признак

модификации и признак обращения к данным за некоторый последний период времени.

При каждом обращении к основной памяти по физическому адресу просматрива-

ется содержимое кэш-памяти с целью определения, не находятся ли там нужные дан-

ные. Поиск нужных данных осуществляется по содержимому – взятому из запроса

значению поля адреса в оперативной памяти. Далее возможно одно из двух:

· произошло кэш-попадание – данные обнаружены в кэш-памяти; они считываются

из кэш-памяти и результат передается источнику запроса;

· произошел кэш-промах (cache-miss) – нужных данных нет; они считываются из ос-

новной памяти, передаются источнику запроса и одновременно копируются в кэш-память.

Покажем, что среднее время доступа к данным зависит от вероятности попада-

Пусть имеется основное запоминающие устройство со средним временем доступа

к данным t1 и кэш-память, имеющая время доступа t2 (t2<t1). Обозначим через t сред-

нее время доступа к данным в системе с кэш-памятью, а через p -вероятность попа-

дания в кэш. По формуле полной вероятности имеем:

Видно, что среднее время доступа изменяется от среднего времени доступа в основ-

ное ЗУ (при р=0) до среднего времени доступа непосредственно в кэш-память (при р=1).

Таким образом, использование кэш-памяти имеет смысл только при высокой веро-

ятности кэш-попадания. Эта вероятность, в свою очередь, зависит от многих раз-

личных факторов. Тем не менее в реальных системах вероятность попадания в кэш

очень высока и составляет более 0.9. Такое высокое значение вероятности нахож-

дения данных в кэш-памяти связано с наличием у данных объективных свойств: про-

странственной и временной локальности.

Пространственная локальность. Если произошло обращение по некоторому ад-

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

Временная локальность. Если произошло обращение по некоторому адресу, то сле-

дующее обращение по этому же адресу с большой вероятностью произойдет в бли-

На практике в кэш-память считывается не один элемент данных, к которому про-

изошло обращение, а целый блок данных, что увеличивает вероятность попадания в

кэш при последующих обращениях.

· Вытеснение данных их кэша в основную память

В процессе работы содержимое кэш-памяти постоянно обновляется, а значит, пе-

риодически данные должны из нее вытесняться. Вытеснение предполагает объявле-

ние соответствующей области кэша свободной (сброс бита действительности) и, если

вытесняемые данные за время нахождения в кэше были изменены, копирование дан-

ных в основную память.

Методы выбора данных для вытеснения зависят от способа отображения основной

памяти на кэш и базируются на предположениях о свойствах данных. Реально как пра-

вило учитывается интенсивность обращения к данным. В некоторых алгоритмах заме-

щения предусматривается первоочередная выгрузка модифицированных данных.

Из-за непредсказуемости вычислительного процесса ни один алгоритм замещения

данных не может быть максимально быстрым и одновременно гарантировать макси-

мально возможную вероятность кэш-попаданий. Поэтому разработчики ограничивают-

ся рациональными решениями, по крайней мере, не сильно замедляющими работу кэша.

· Согласование данных кэша и основной памяти при записи в последнюю Проблема заключается в том, что при записи данных в основную память их копия в

КЭШе (если она там есть) становится недостоверной. Для решения этой проблемы типич-

Сквозная запись (write through). Если данные по запрашиваемому адресу отсут-

ствуют в кэше, то запись выполняется только в основную память, в противном слу-

чае – одновременно в кэш и основную память.

Обратная запись (write back). Если данные по запрашиваемому адресу отсут-

ствуют в кэше, то запись выполняется только в основную память, в противном слу-

чае – только в кэш-память. Во втором случае устанавливается признак модифика-

ции, указывающий на необходимость записи данных в основную память при вытес-

32. Понятие виртуальной памяти Виртуализация памяти

Виртуализация памяти может быть осуществлена на основе двух различных подходов:

свопинг (swapping) — образы процессов выгружаются на диск и возвращаются в оперативную память целиком;

виртуальная память (virtual memory) — между оперативной памятью и диском перемещаются части (сегменты, страницы и т. п.) образов процессов.

Свопинг представляет собой частный случай виртуальной памяти и, следовательно, более простой в реализации способ совместного использования оперативной памяти и диска. Однако подкачке свойственна избыточность. Перемещение избыточной информации замедляет работу системы, а также приводит к неэффективному использованию памяти. Кроме того, системы, поддерживающие свопинг, имеют еще один очень существенный недостаток: они не способны загрузить для выполнения процесс, виртуальное адресное пространство которого превышает имеющуюся в наличии свободную память. Именно из-за указанных недостатков свопинг как основной механизм управления памятью почти не используется в современных ОС.

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

Аппаратная поддержка очень важна (ниже)

Виртуальная память — это некоторый механизм совместного функционирования оперативной(основной) памяти и внешней памяти. Механизм виртуальной памяти достаточно громоздкий => за такими алгоритмами всегда стоят задержки и снижение производительности. Однако взамен мы можем отвязаться от реалий физической памяти (процессы работают с “иллюзией” использования физической памяти).

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

. В конечном итоге обращение происходит по физическим адресам, и данные (инструкции) хранятся в физ. памяти.

Разные виртуальные адресные пространства отображаются на разные участки физической памяти и поэтому никакой путаницы не происходит.

Структура виртуального адресного пространства

1 подход: плоское виртуальное адресное пространство

весь набор вирт адресов линейны => чтобы добраться до нужного байта, надо знать только одно число. Т.Е. пронумеровали все байты, к байту обращаемся по его номеру и соответственно виртуальным адресом является одно число, символизирующее смещение от начала ВАП (виртуальное адресное пространство) до байта, к которому происходит обращение

2 подход: сегментированное ВАП: придумали следующую конструкцию, что адрес (тогда еще физический) будет храниться в двух компонентах адреса (сегмент и смещение). Сегментированное ВАП это совокупность (набор) сегментов, сегменты — это участки памяти (внутри сегментов байты пронумерованы последовательно. Здесь виртуальным адресом является пара чисел (сегмент и смещение внутри сегмента)

3 подход: гибрид плоского и сегментированного ВАП когда мы имеем в основе плоское ВАП (то есть у каждого байта в пределах ВАП есть свой линейный (последовательный) номер, а на это пространство (плоское) накладывают сегментацию. Появляется возможность один и тот же байт адресовать двумя способами: линейно или сегментировано

Есть два выбора, когда преобразовать виртуальные адреса в физические(ниже рисунок)

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

Организация виртуальной памяти

Привет, Хабрахабр!

В предыдущей статье я рассказал про vfork() и пообещал рассказать о реализации вызова fork() как с поддержкой MMU, так и без неё (последняя, само собой, со значительными ограничениями). Но прежде, чем перейти к подробностям, будет логичнее начать с устройства виртуальной памяти.

Конечно, многие слышали про MMU, страничные таблицы и TLB. К сожалению, материалы на эту тему обычно рассматривают аппаратную сторону этого механизма, упоминая механизмы ОС только в общих чертах. Я же хочу разобрать конкретную программную реализацию в проекте Embox. Это лишь один из возможных подходов, и он достаточно лёгок для понимания. Кроме того, это не музейный экспонат, и при желании можно залезть “под капот” ОС и попробовать что-нибудь поменять.

Введение

Любая программная система имеет логическую модель памяти. Самая простая из них — совпадающая с физической, когда все программы имеют прямой доступ ко всему адресному пространству.
При таком подходе программы имеют доступ ко всему адресному пространству, не только могут “мешать” друг другу, но и способны привести к сбою работы всей системы — для этого достаточно, например, затереть кусок памяти, в котором располагается код ОС. Кроме того, иногда физической памяти может просто не хватить для того, чтобы все нужные процессы могли работать одновременно. Виртуальная память — один из механизмов, позволяющих решить эти проблемы. В данной статье рассматривается работа с этим механизмом со стороны операционной системы на примере ОС Embox. Все функции и типы данных, упомянутые в статье, вы можете найти в исходном коде нашего проекта.

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

Общие идеи

  • Расширение реального адресного пространства. Часть виртуальной памяти может быть вытеснена на жёсткий диск, и это позволяет программам использовать больше оперативной памяти, чем есть на самом деле.
  • Создание изолированных адресных пространств для различных процессов, что повышает безопасность системы, а также решает проблему привязанности программы к определённым адресам памяти.
  • Задание различных свойств для разных участков участков памяти. Например, может существовать неизменяемый участок памяти, видный нескольким процессам.

Аппаратная поддержка

Обращение к памяти хорошо описанно в этой хабростатье. Происходит оно следующим образом:

Таким образом, при обращении программы к тому или иному участку памяти трансляция адресов производится аппаратно. Программная часть работы с MMU — формирование таблиц страниц и работа с ними, распределение участков памяти, установка тех или иных флагов для страниц, а также обработка page fault, ошибки, которая происходит при отсутствии страницы в отображении.

В тексте статьи в основном будет рассматриваться трёхуровневая модель памяти, но это не является принципиальным ограничением: для получения модели с бóльшим количеством уровней можно действовать аналогичным образом, а особенности работы с меньшим количеством уровней (как, например, в архитектуре x86 — там всего два уровня) будут рассмотрены отдельно.

Программная поддержка

  • Выделение физических страниц из некоторого зарезервированного участка памяти
  • Внесение соответствующих изменений в таблицы виртуальной памяти
  • Сопоставление участков виртуальной памяти с процессами, выделившими их
  • Проецирование региона физической памяти на виртуальный адрес

Виртуальный адрес

Page Global Directory (далее — PGD) — таблица (здесь и далее — то же самое, что директория) самого высокого уровня, каждая запись в ней — ссылка на Page Middle Directory (PMD), записи которой, в свою очередь, ссылаются на таблицу Page Table Entry (PTE). Записи в PTE ссылаются на реальные физические адреса, а также хранят флаги состояния страницы.

То есть, при трёхуровневой иерархии памяти виртуальный адрес будет выглядеть так:

Значения полей PGD, PMD и PTE — это индексы в соответствующих таблицах (то есть сдвиги от начала этих таблиц), а offset — это смещение адреса от начала страницы.

В зависимости от архитектуры и режима страничной адресации, количество битов, выделяемых для каждого из полей, может отличаться. Кроме того, сама страничная иерархия может иметь число уровней, отличное от трёх: например, на x86 нет PMD.

Для обеспечения переносимости мы задали границы этих полей с помощью констант: MMU_PGD_SHIFT, MMU_PMD_SHIFT, MMU_PTE_SHIFT, которые в приведённой выше схеме равны 24, 18 и 12 соответственно их определение дано в заголовочном файле src/include/hal/mmu.h. В дальнейшем будет рассматриваться именно этот пример.

На основании сдвигов PGD, PMD и PTE вычисляются соответствующие маски адресов.

Эти макросы даны в том же заголовочном файле.

Для работы с виртуальной таблицами виртуальной памяти в некоторой области памяти хранятся указатели на все PGD. При этом каждая задача хранит в себе контекст struct mmu_context, который, по сути, является индексом в этой таблице. Таким образом, к каждой задаче относится одна таблица PGD, которую можно определить с помощью mmu_get_root(ctx).

Страницы и работа с ними

Размер страницы

В реальных (то есть не в учебных) системах используются страницы от 512 байт до 64 килобайт. Чаще всего размер страницы определяется архитектурой и является фиксированным для всей системы, например — 4 KiB.

С одной стороны, при меньшем размере страницы память меньше фрагментируется. Ведь наименьшая единица виртуальной памяти, которая может быть выделена процессу — это одна страница, а программам очень редко требуется целое число страниц. А значит, в последней странице, которую запросил процесс, скорее всего останется неиспользуемая память, которая, тем не менее, будет выделена, а значит — использована неэффективно.

С другой стороны, чем меньше размер страницы, тем больше размер страничных таблиц. Более того, при отгрузке на HDD и при чтении страниц с HDD быстрее получится записать несколько больших страниц, чем много маленьких такого же суммарного размера.

Отдельного внимания заслуживают так называемые большие страницы: huge pages и large pages [вики] .

Платформа Размер обычной страницы Размер страницы максимально возможного размера
x86 4KB 4MB
x86_64 4KB 1GB
IA-64 4KB 256MB
PPC 4KB 16GB
SPARC 8KB 2GB
ARMv7 4KB 16MB

Действительно, при использовании таких страниц накладные расходы памяти повышаются. Тем не менее, прирост производительности программ в некоторых случаях может доходить до 10% [ссылка] , что объясняется меньшим размером страничных директорий и более эффективной работой TLB.

В дальнейшем речь пойдёт о страницах обычного размера.

Устройство Page Table Entry

В реализации проекта Embox тип mmu_pte_t — это указатель.
Каждая запись PTE должна ссылаться на некоторую физическую страницу, а каждая физическая страница должна быть адресована какой-то записью PTE. Таким образом, в mmu_pte_t незанятыми остаются MMU_PTE_SHIFT бит, которые можно использовать для сохранения состояния страницы. Конкретный адрес бита, отвечающего за тот или иной флаг, как и набор флагов в целом, зависит от архитектуры.

  • MMU_PAGE_WRITABLE — Можно ли менять страницу
  • MMU_PAGE_SUPERVISOR — Пространство супер-пользователя/пользователя
  • MMU_PAGE_CACHEABLE — Нужно ли кэшировать
  • MMU_PAGE_PRESENT — Используется ли данная запись директории

Можно установить сразу несколько флагов:

Здесь vmem_page_flags_t — 32-битное значение, и соответствующие флаги берутся из первых MMU_PTE_SHIFT бит.

Трансляция виртуального адреса в физический

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

Для того, чтобы получить из виртуального адреса физический, необходимо пройти по цепочке таблиц PGD, PMD и PTE. Функция vmem_translate() и производит эти шаги.
Сначала проверяется, есть ли в PGD указатель на директорию PMD. Если это так, то вычисляется адрес PMD, а затем аналогичным образом находится PTE. После выделения физического адреса страницы из PTE необходимо добавить смещение, и после этого будет получен искомый физический адрес.

Пояснения к коду функции.
mmu_paddr_t — это физический адрес страницы, назначение mmu_ctx_t уже обсуждалось выше в разделе “Виртуальный адрес”.

С помощью функции vmem_get_idx_from_vaddr() находятся сдвиги в таблицах PGD, PMD и PTE.

Работа с Page Table Entry

Для работы с записей в таблице страниц, а так же с самими таблицами, есть ряд функций:

Эти функции возвращают 1, если у соответствующей структуры установлен бит MMU_PAGE_PRESENT

Page Fault

Page fault — это исключение, возникающее при обращении к странице, которая не загружена в физическую память — или потому, что она была вытеснена, или потому, что не была выделена.
В операционных системах общего назначения при обработке этого исключения происходит поиск нужной странице на внешнем носителе (жёстком диске, к примеру).

В нашей системе все страницы, к которым процесс имеет доступ, считаются присутствующими в оперативной памяти. Так, например, соответствующие сегменты .text, .data, .bss; куча; и так далее отображаются в таблицы при инициализации процесса. Данные, связанные с потоками (например, стэк), отображаются в таблицы процесса при создании потоков.

Выталкивание страниц во внешнюю память и их чтение в случае page fault не реализовано. С одной стороны, это лишает возможности использовать больше физической памяти, чем имеется на самом деле, а с другой — не является актуальной проблемой для встраиваемых систем. Нет никаких ограничений, делающих невозможной реализацию данного механизма, и при желании читатель может попробовать себя в этом деле 🙂

Выделение памяти

Для виртуальных страниц и для физических страниц, которые могут быть использованы при работе с виртуальной памятью, статически резервируется некоторое место в оперативной памяти. Тогда при выделении новых страниц и директорий они будут браться именно из этого места.
Исключением является набор указателей на PGD для каждого процесса (MMU-контексты процессов): этот массив хранится отдельно и используется при создании и разрушении процесса.
Выделение страниц
Итак, выделить физическую страницу можно с помощью vmem_alloc_page

Функция page_alloc() ищет участок памяти из N незанятых страниц и возвращает физический адрес начала этого участка, помечая его как занятый. В приведённом коде virt_page_allocator ссылается на участок памяти, резервированной для выделения физических страниц, а 1 — количество необходимых страниц.
Выделение таблиц
Тип таблицы (PGD, PMD, PTE) не имеет значения при аллокации. Более того, выделение таблиц производится также с помощью функции page_alloc(), только с другим аллокатором (virt_table_allocator).

Участки памяти (Memory Area)

После добавления страниц в соответствующие таблицы нужно уметь сопоставлять участки памяти с процессами, к которым они относятся. У нас в системе процесс представлен структурой task, содержащей всю необходимую информацию для работы ОС с процессом. Все физически доступные участки адресного пространства процесса записываются в специальный репозиторий: task_mmap. Он представляет из себя список дескрипторов этих участков (регионов), которые могут быть отображены на виртуальную память, если включена соответствующая поддержка.

brk — это самый большой из всех физических адресов репозитория, данное значение необходимо для ряда системных вызовов, которые не будут рассматриваться в данной статье.
ctx — это контекст задачи, использование которого обсуждалось в разделе “Виртуальный адрес”.
struct dlist_head — это указатель на начало двусвязного списка, организация которого аналогична организации Linux Linked List.

За каждый выделенный участок памяти отвечает структура marea

Поля данной структуры имеют говорящие имена: адреса начала и конца данного участка памяти, флаги региона памяти. Поле mmap_link нужно для поддержания двусвязного списка, о котором говорилось выше.

Отображение виртуальных участков памяти на физические (Mapping)

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

Отображение виртуальных участков памяти на физическую память подразумевает внесение соответствующих изменений в иерархию страничных директорий.

Подразумевается, что некоторый участок физической памяти уже выделен. Для того, чтобы выделить соответствующие виртуальные страницы и привязать их к физическим, используется функция vmem_map_region()

В качестве параметров передаётся контекст задачи, адрес начала физического участка памяти, а также адрес начала виртуального участка. Переменная flags содержит флаги, которые будут установлены у соответствующих записей в PTE.

Основную работу на себя берёт do_map_region(). Она возвращает 0 при удачном выполнении и код ошибки — в ином случае. Если во время маппирования произошла ошибка, то часть страниц, которые успели выделиться, нужно откатить сделанные изменения с помощью функции vmem_unmap_region(), которая будет рассмотрена позднее.

Рассмотрим функцию do_map_region() подробнее.

Макросы GET_PTE и GET_PMD нужны для лучшей читаемости кода. Они делают следующее: если в таблице памяти нужный нам указатель не ссылается на существующую запись, нужно выделить её, если нет — то просто перейти по указателю к следующей записи.

В самом начале необходимо проверить, выровнены ли под размер страницы размер региона, физический и виртуальный адреса. После этого определяется PGD, соответствующая указанному контексту, и извлекаются сдвиги из виртуального адреса (более подробно это уже обсуждалось выше).
Затем последовательно перебираются виртуальные адреса, и в соответствующих записях PTE к ним привязывается нужный физический адрес. Если в таблицах отсутствуют какие-то записи, то они будут автоматически сгенерированы при вызове вышеупомянутых макросов GET_PTE и GET_PMD.

Освобождение виртуального участка памяти (Unmapping)

После того, как участок виртуальной памяти был отображён на физическую, рано или поздно её придётся освободить: либо в случае ошибки, либо в случае завершения работы процесса.
Изменения, которые при этом необходимо внести в структуру страничной иерархии памяти, производятся с помощью функции vmem_unmap_region().

Все параметры функции, кроме последнего, должны быть уже знакомы. free_pages отвечает за то, должны ли быть удалены страничные записи из таблиц.

try_free_pte, try_free_pmd, try_free_pgd — это вспомогательные функции. При удалении очередной страницы может выясниться, что директория, её содержащая, могла стать пустой, а значит, её нужно удалить из памяти.

нужны как раз для случая двухуровневой иерархии памяти.

Заключение

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *