Молодогвардейцев 454015 Россия, Челябинская область, город Челябинск 89085842764
MindHalls logo

Сегментная адресация памяти в 32-х разрядных системах

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

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

Под словом «память» я буду подразумевать, конечно же, оперативную память компьютера. О жестком диске речь будет идти только в момент упоминания подкачки.

Деление памяти на сегменты

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

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

Селектор сегмента

Первое из двух чисел в логическом адресе называется селектором, он 16-ти разрядный, среди которых старшие 13 бит являются индексом(порядковым номером) сегмента в таблице дескрипторов. Остальные три бита делятся следующим образом: 1 бит называется TI и указывает на тип дескрипторной таблицы(0 — глобальная, 1 — локальная), еще два бита отданы под RPL — запрашиваемый уровень привилегий.

Селектор в сегментной модели памяти

При обращении к нужному дескриптору RPL будет сравниваться с DPL этого сегмента. Как вы уже могли догадаться, DPL(Descriptor privilege level) это уровень привилегий дескриптора.

Кстати, о доступе. Благодаря делению памяти на сегменты появилась возможность разграничивать права доступа и пресекать подлые попытки переписать чужую память, это стало настоящим прорывом. Всего существует 4 уровня привилегий: 0-2 соответствуют супервизору, при этом на нулевом уровне доступны самые привилегированные действия, 3 — уровень пользователя(пользовательских программ).

Глобальная таблица дескрипторов — GDT

Чуть более подробно об этой таблице. Все сегменты хранятся в определенной структуре, называемой GDT — Global Descriptor Table. Из названия видно, что она представляет из себя простую таблицу. Хранится в оперативной памяти всегда, подгружается при запуске операционной системы, на ее начало указывает специальный регистр GDTR. Кстати, это один из немногих регистров процессора, который хранит в себе физический адрес. И он же хранит размер таблицы, таким образом мы и операционная система всегда можем иметь доступ к нашим сегментам.

Из размерности поля индекса в селекторе можно посчитать максимальное возможное количество дескрипторов в таблице — 213 = 8192 дескриптора.

Размер дескриптора равен 8 байтам или 32 битам. Вот как выглядит такая запись, называемая дескриптором.

Как выглядит сегментный дескриптор

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

Локальная таблица дескрипторов

Кроме GDT еще существует LDT — Local Descriptor Table — которая отвечает за сегменты каждого отдельного процесса. Ссылки на все LDT содержатся в GDT, но в любой локальной таблице не может быть ссылок на другую локальную. А во всем остальном локальные таблицы не отличаются от глобальной.

Трансляция адресов в сегментной модели памяти

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

  1. Первым делом сравниваются RPL селектора и DPL сегмента, если запрашиваемый уровень привилегий меньше или равен уровню доступа сегмента, то доступ разрешен.
  2. Теперь мы должны взять базовый адрес сегмента и прибавить к нему смещение из логического адреса.
  3. Проверить, что полученный физический адрес не выходит за границы сегмента. Для этого существует поле limit в дескрипторе.
  4. Если все условия соблюдены, мы получаем доступ к ячейке памяи по физическому адресу(база сегмента + смещение).

Схематическое изображение.

Трансляция адресов в сегментной модели памяти

Заключение

С появлением дескрипторов отпала сама главная головная боль программистов и ужас системных администраторов — появились права доступа к памяти. Но остались еще подводные камни, достаточно затратно следить за сегментами из-за того, что у них произвольный размер. Побороться с этим вызвалась так называемая «страничная» память. Но о ней уже в следующем выпуске, спасибо за внимание!