Как отмечалось выше, защищенный режим сохранил сегментную модель памяти
(адрес ячейки памяти определяется суммой компонент: адрес начала сегмента и
внутрисегментного смещения). Но в отличие от режима реального адреса, где адрес
сегмента находился непосредственно в одном из сегментных регистров – алгоритм
формирования физического адреса в защищенном режиме абсолютно иной. Сегмент, в
защищенном режиме, это не просто область памяти, ограниченная лишь максимально
допустимым значением внутрисегментного смещения, как это было в реальном
режиме, - это «объект», который имеет строго определенный размер, не
пересекается с другими сегментами (хотя один и тот же сегмент можно описать
дважды) и имеет ряд других атрибутов, по которым, в частности, происходит
аппаратная защита памяти со стороны процессора. Каждый сегмент имеет свой дескриптор
(описатель сегмента). Дескрипторы
сегментов собираются в специализированных системных сегментах – дескрипторных
таблицах.
Существует три типа дескрипторных таблиц – глобальная таблица
дескрипторов (одна в системе); локальная таблица дескрипторов (своя
для каждой задачи); таблица дескрипторов прерываний (см. главу 4). Каждый дескриптор (элемент) таблицы
описывает свой сегмент памяти. Сегменты памяти не пересекаются! Размер
таблиц находится в пределах 8 байт – 64 Кбайт, что соответствует числу
элементов в таблице от 1 до 8192.
Адрес начала каждой из таблиц (указатель на начало таблицы) хранится в
специальных (программно доступных) регистрах процессора. Указатели на таблицу
глобальных дескрипторов (GDTR) и таблицу прерываний (IDTR) имеют размер 48 байт, 32 из которых указывают линейный адрес начала
таблицы, а остальные 16 – ее размер (предел).
У регистра-указателя локальной дескрипторной таблицы (LDTR) программно доступно только 16-битное поле селектора (индекса для GDT), по которому из GDT автоматически загружаются
программно недоступные и невидимые поля базового адреса и размера таблицы.
Регистр LDTR указывает на дескриптор в GDT, описывающий локальную
дескрипторную таблицу для текущей задачи.
Команды загрузки регистров-указателей таблиц (GDTR, LDTR, IDTR) являются привилегированными (выполняются только на нулевом кольце
привилегий (см. главу 3)).
Глобальная таблица (GDT) содержит дескрипторы, доступные все задачам.
Может содержать дескрипторы любых типов, кроме дескрипторов прерываний и
ловушек (см. главу 4). Нулевой элемент этой
таблицы процессором не используется.
Локальная таблица (LDT) может быть собственной для
каждой задачи и может содержать только дескрипторы сегментов, шлюзов задачи и
вызовов. Сегмент недоступен задаче, если его дескриптора нет ни в LDT, ни в GDT.
Дескрипторные таблицы создаются и поддерживаются операционной системой.
Дескрипторы сегментов кода и данных имеют следующий формат:
Адрес сегмента – физический адрес начала сегмента (если нет страничного
преобразования);
Размер - размер сегмента (Размер сегмента – 1);
Байт доступа – содержит информацию о защите сегмента;
D - бит разрядности выполняемых команд (для
кодового сегмента):
0 –
16-разрядные;
1 – 32-разрядные
G - признак единицы измерения сегмента:
0 – в байтах;
1 – в страницах (по 4 Кб), при использовании страничной
адресации памяти;
AVL -
сегмент доступен для использования системным программным обеспечением
(используются только ОС);
Дескрипторы системных
сегментов имеют следующий формат:
Системные сегменты предназначены для хранения
локальных таблиц дескрипторов LDT и состояния задач TSS (Task
State Segment) (см. главу 5). Их дескрипторы
определяют базовый адрес, лимит сегмента (1-64 Кбайт), права доступа (чтение,
чтение/запись, только исполнение кода или исполнение/чтение) и присутствие
сегмента в физической памяти. В байте управления доступом у этих дескрипторов
бит Р определяет действительность (Р=1) или недействительность (Р=0)
содержимого сегмента. Поле уровня привилегий DPL используется только в
дескрипторах сегментов состояния задач (TSS). Поскольку обращение к
дескрипторам LDT возможно только по
привилегированным командам, поле DPL для дескрипторов локальных таблиц
не используется. Поле ТYPE (1-3, 9-В) определяет тип
сегмента:
· 0, 8 - недопустимые значения;
· 1 - доступный сегмент состояния задачи 80286 (Available TSS-286);
· 2 - таблица локальных дескрипторов (LDT);
· 3 - занятый сегмент состояния задачи 80286 (Busy TSS-286);
· 9 - доступный сегмент состояния задачи 386+ (Available TSS-386);
· А - не определено (зарезервировано);
· B - занятый сегмент состояния
задачи 386+ (Busy TSS-386).
Дескрипторы шлюзов имеют следующий формат:
В байте управления доступом
у этих дескрипторов бит Р определяет действительность (Р=1) или
недействительность (Р=0) содержимого сегмента. Поле DPL задает уровень
привилегий. Поле TYPE определяет тип шлюза:
· 4 - шлюз вызова 80286 (Call Gate);
· 5 - шлюз задачи 80286 (Task Gate);
· 6 - шлюз прерывания 80286 (Interrupt Gate);
· 7 - шлюз ловушки 80286 (Trap Gate);
· C - шлюз вызова 386+ (Call Gate);
· D - шлюз задачи 386+ (Task Gate);
· Е - шлюз прерывания 386+ (Interrupt Gate);
· F - шлюз ловушки 386+ (Trap Gate).
Поле «Word Count» используется
только в шлюзах вызовов и определяет число слов из стека вызывающего процесса,
автоматически копируемых в стек вызываемой процедуры. Для сегментов 80286
слова 16-битные, для 386+ - 32-битные.
Слово «Селектор» для
шлюзов вызова, прерываний и ловушек задает селектор целевого сегмента кода, а
для шлюзов задачи - селектор целевого TSS.
Слово «Смещение» задает
смещение (адрес) точки входа в целевом сегменте.
При использовании шлюзов
может возникнуть исключение #GP, которое означает, что селектор указывает на
некорректный тип дескриптора. При попытке использования недействительного
шлюза (Р=0) возникает исключение #NР. (Подробнее о шлюзах см. главу 4, и главу 5).
Сегментные регистры в защищенном режиме играют роль селекторов
(индексов дескрипторов в дескрипторных таблицах).
Формат селектора следующий:
I - номер (индекс)
дескриптора в таблице (0¸213-1);
TI – тип дескрипторной таблицы: 0 -
GDT; 1 - LDT;
RPL – номер запрашиваемого
уровня привилегий;
Рассмотрим пример обращения процессора к памяти в сегмент (данных),
описанный в глобальной дескрипторной таблице (GDT) – т.е. бит “TI” в селекторе сегмента равен нулю.
Старшие 13 байт селектора являются смещением искомого
дескриптора от начала дескрипторной таблицы. Младшие байты играют роль
атрибутов (см. выше), и при адресации внутри таблицы интерпретируются как нули
– за счет чего происходит адресация таблицы по полю “i” с точностью до восьмибайтного слова, или (что в данном
случае одно и тоже) до дескриптора. Адрес сегмента, прочитанный из дескриптора,
складывается с внутрисегментным смещением и при отсутствии страничного
преобразования адреса (см. ниже) выставляется на адресную
шину.
Если бит “TI” в селекторе сегмента равен “1”, то происходит
выборка сегмента из локальной дескрипторной таблицы. В этом случае регистр LDTR должен содержать селектор этой таблицы (индекс) – локальная
дескрипторная таблица описывается дескриптором глобальной таблицы. Сам же
селектор (в котором “TI”=1) определяет
дескриптор сегмента памяти, описанного в локальной дескрипторной таблице. В
регистре LDTR бит “TI” всегда нулевой – т.к. дескриптор-описатель локальной
таблицы может находиться только в GDT.
Страничное управление (Paging) является средством
организации виртуальной памяти с подкачкой страниц по запросу (Demand-Paged Virtual Memory). В
отличие от сегментации, которая организует программы и данные в модули различного
размера, страничная организация оперирует с памятью, как с набором страниц
одинакового размера. В момент обращения страница может присутствовать в
физической оперативной памяти, а может быть выгруженной на внешнюю (дисковую)
память. При обращении к выгруженной странице памяти процессор вырабатывает
исключение #PF — отказ
страницы, а программный обработчик исключения (часть ОС) получит
необходимую информацию для свопинга — «подкачки» отсутствующей страницы
с диска. Страницы не имеют прямой связи с логической структурой данных или
программ. В то время как селекторы можно рассматривать как логические имена
модулей кодов и данных, страницы представляют части этих модулей. Учитывая
обычное свойство локальности (близкого расположения требуемых ячеек памяти)
кода и ссылок на данные, в оперативной памяти в каждый момент времени следует
хранить только небольшие области сегментов, необходимые активным задачам. Эту
возможность (а следовательно, и увеличение допустимого числа одновременно выполняемых
задач при ограниченном объеме оперативной памяти) как раз и обеспечивает
страничное управление памятью. В первых 32-разрядных процессорах (начиная с i80386) размер страницы
составлял 4 Кбайт. Начиная с Pentium, появилась возможность увеличения размера страницы до
4 Мбайт, одновременно с использованием страниц размером 4 Кбайт. В Р6 имеется
возможность расширения физического адреса до 36 бит (64 Гбайт), при котором
могут использоваться страницы размером 4 Кбайт и 2 Мбайт.
Базовый механизм
страничного управления использует двухуровневую табличную трансляцию линейного
адреса в физический.
Механизм имеет три части: каталог страниц
(Page Directory), таблицы
страниц (Page Table) и собственно
страницы (Page
Frame). Механизм включается установкой бита PG=1 в регистре CRO.
Регистр CR2
хранит линейный адрес отказа (Page Fault Linear Address) —
адрес памяти, по которому был обнаружен последний отказ страницы. Регистр CR3
хранит физический адрес каталога страниц (Page Directory Physical Base Address).
Его младшие 12 бит всегда нулевые (каталог выравнивается по границе страницы).
Каталог страниц,
размером 4 Кбайт содержит 1024 32-битных строки РDЕ (Page Directory Entry).
Каждая строка (см. ниже рис. а) содержит 20 старших бит адреса таблицы
следующего уровня (младшие биты этого адреса всегда нулевые) и признаки
(атрибуты) этой таблицы. Индексом поиска в каталоге страниц являются 10 старших
бит линейного адреса (А22-А31).
а — строка
каталога; б — строка таблицы
Каждая таблица страниц также имеет 1024
строки РТЕ (Page Table Entry)
аналогичного формата (рис. б), но эти строки содержат базовый физический адрес
(Page Frame Address) и
атрибуты самих страниц. Индексом поиска в таблице являются биты А12-А21
линейного адреса. Физический адрес получается из адреса страницы,
взятого из таблицы, и младших 12 бит линейного адреса. Строки каталога и таблиц
имеют следующие биты атрибутов:
• Р (Present) —
бит присутствия. Р=1 означает возможность использования данной строки для
трансляции адреса. Бит присутствия вхождений в таблицы, используемые текущим
исполняемым кодом, должен быть установлен. Программный код не должен его
изменять «на ходу». Если Р=0, то все остальные биты доступны операционной
системе и могут использоваться для получения информации о местонахождении
данной страницы.
• A (Accessed) — признак доступа, который
устанавливается перед любым чтением или записью по адресу, в преобразовании
которого участвует данная строка.
• D (Dirty) — признак, который устанавливается перед операцией
записи по адресу, в преобразовании которого участвует данная строка. Таким
образом, помечается использованная — «грязная» страница, которую в случае
замещения необходимо выгрузить на диск.
Биты Р, А, D модифицируются
процессором аппаратно в заблокированных шинных циклах. При их программной
модификации в многопроцессорных системах должен использоваться префикс LOCK,
гарантирующий сохранение целостности данных.
Поле OS Reserved
программно используется по усмотрению ОС и может хранить, например, информацию
о «возрасте» страницы, необходимую для реализации замещения по алгоритму LRU (Least Recently Used —
наиболее долго не использовавшаяся страница замещается первой).
Бит PWT (Page Write Through)
определяет политику записи при кэшировании, а бит PCD (Page Cache Disable)
запрещает кэширование памяти для обслуживаемых страниц или таблиц
(используются на процессорах i486+).
Бит PS (Page Size) задает размер
страницы (только в РОЕ). При PS=0 страница имеет размер 4 Кбайт, PS=1 используется в
расширениях РАЕ и PSE.
Бит G (Global), появившийся в Р6,
определяет глобальность страницы. Он анализируется только в строке, указывающей
на страницу физической памяти (в РТЕ для страниц в 4 Кбайт, в PDE — для страниц 2 Мбайт или 4
Мбайт). Этот бит, управляемый только программно, позволяет пометить страницы
глобального использования (например, ядра ОС). При установленном бите PGE в регистре
CR4 строки
с указателями на глобальные таблицы не будут аннулироваться в TLB при загрузке CR3 или
переключении задач, что снижает издержки обслуживания виртуальной памяти.