Наверх Системное программирование
Предыдущий раздел Оглавление Следующий раздел

4.6.2. Сегментация со страничной организацией памяти

Основа виртуальной памяти системы x86 состоит их двух таблиц: локальной таблицы дескрипторов (Local Descriptor Table (LDT)) и глобальной таблицы дескрипторов (Global Descriptor Table (GDT)). У каждой программы есть собственная таблица LDT, но глобальная таблица дескрипторов, которую совместно используют все программы в компьютере, всего одна. В таблице LDT описываются сегменты, локальные для каждой программы, включая код этих программ, их данные, стек и т.д., а в таблице GDT описываются системные сегменты, включая саму операционную систему.

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

Рис

Рис. 4.12. Селектор системы Pentium

Один из битов селектора несет информацию о том, является ли данный сегмент локальным или глобальным (то есть к какой таблице дескрипторов он относится, локальной или глобальной). Следующие 13 битов определяют номер записи в таблице дескрипторов, поэтому в каждой из этих таблиц не может содержаться более чем 8 Кбайт сегментных дескрипторов. Остальные 2 бита имеют отношение к защите и будут рассмотрены позже. Дескриптор 0 запрещен. Его можно без всякой опаски загрузить в сегментный регистр, чтобы обозначить, что этот сегментный регистр в данный момент недоступен. Попытка им воспользоваться приведет к системному прерыванию.

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

Чтобы облегчить определение местоположения дескриптора, был искусно подобран формат селектора. Сначала на основе бита 2 селектора выбирается локальная или глобальная таблица дескрипторов. Затем селектор копируется во внутренний рабочий регистр, и значения трех младших битов устанавливаются в 0. Наконец, к этой копии прибавляется адрес одной из таблиц, LDT или GDT, чтобы получить прямой указатель на дескриптор. Например, селектор 72 ссылается на запись 9 в глобальной таблице дескрипторов, которая расположена по адресу в таблице GDT + 72.

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

Рис

Рис. 4.13. Дескриптор сегмента кода в системе Pentium.
Сегменты данных имеют незначительны отличия

Затем аппаратура использует поле предела Limit, чтобы проверить, не выходит ли смещение за предел сегмента, и в этом случае также возникает системное прерывание. По логике, для предоставления размера сегмента в дескрипторе должно быть 32-разрядное поле, но доступны только 20 бит, поэтому используется другая схема. Если поле Gbit (Granularity — степень детализации) равно 0, в поле Limit содержится точный размер сегмента вплоть до 1 Мбайт. Если оно равно 1, то в поле Limit предоставляется размер сегмента в страницах, а не в байтах. При размере страниц, равном 4 Кбайт, 20 битов вполне достаточно для сегментов размером до 232 байт.

Предположим, что сегмент находится в памяти и смещение попало в нужный интервал, тогда система x86 прибавляет 32-разрядное поле Base (база) в дескрипторе к смещению, формируя то, что называется линейным адресом (рис. 4.14).

Рис

Рис. 4.14. Преобразование пары
«селектор — смещение» в линейный адрес

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

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

У каждой работающей программы есть страничный каталог, состоящий из 1024 32-разрядных записей. Он расположен по адресу, который указан в глобальном регистре. Каждая запись в каталоге указывает на таблицу страниц, также содержащую 1024 32-разрядных записи. Записи в таблицах страниц, в свою очередь, указывают на страничные блоки. Эта схема показана на рис. 4.15.

Рис

Рис. 4.15. Отображение линейного адреса на физический

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

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

Каждая таблица страниц включает в себя записи для 1024 страничных блоков размером по 4 Кбайт, таким образом, одна таблица страниц справляется с 4 Мбайт памяти. Сегмент, длина которого меньше 4 Мбайт, будет иметь страничный каталог с единственной записью — указателем на его единственную таблицу страниц. Следовательно, в случае короткого сегмента на поддержку таблиц страниц расходуется только две страницы вместо 1 млн., которые были бы нужны в одноуровневой таблице страниц.

Чтобы избежать повторных обращений к памяти, система x86 имеет небольшой буфер быстрого преобразования адреса (TLB), который напрямую отображает наиболее часто использующиеся комбинации Каталог — Страница на физический адрес страничного блока. Механизм, показанный на рис. 4.15, задействуется лишь при отсутствии текущей комбинации в буфере TLB, при этом сам буфер обновляется. Если отсутствие нужной информации в буфере TLB встречается довольно редко, система достигает неплохой производительности.

Предыдущий раздел Оглавление Следующий раздел