Защищенный режим ia-32
В архитектуре IA-32, защищенный режим (Protected Mode), является основным режимом работы процессора. Иногда этот режим называют защищенным режимом виртуальной адресации (Protected Virtual Address Mode).
$.1. Основные понятия защищенного режима
Защищенный режим предназначен для обеспечения независимости выполнения нескольких задач, что подразумевает защиту ресурсов одной задачи от возможного воздействия другой (под задачами подразумеваются как приложения, так и задачи операционной системы).
Основным защищаемым ресурсом является память, в которой хранятся коды, данные и различные системные таблицы (например, таблица прерываний). Естественно, что нужно защищать и совместно используемое аппаратное обеспечение, обращение к которому обычно происходит через операции ввода/вывода и прерывания. В защищенном режиме процессор аппаратно реализует многие функции защиты, необходимые для построения супервизора многозадачной ОС, в том числе механизм виртуальной памяти.
Защита памяти основана на двух независимых механизмах – сегментации и страничном обмене (paging). Защита других ресурсов основана на иерархической системе привилегий, привилегированных и чувствительных инструкциях, а также на использовании карты разрешения ввода-вывода (I/O Permission Bitmap) и карты перенаправления прерываний (Interrupt Redirection Bitmap).
В защищенном режиме, любое обращение к памяти обязательно состоит из двух частей – селектора сегмента и внутрисегментного относительного адреса (смещения). Из этих исходных данных аппаратно формируется линейный адрес, а также проверяются права доступа к сегменту и адресу внутри сегмента. Примерная схема этого процесса дана на рис. $1.
Логический адрес |
|
|||||||||||||
|
|
|||||||||||||
15 |
0 |
|
31/15 |
0 |
|
|||||||||
Селектор сегмента |
|
Относительный адрес |
|
|||||||||||
|
|
|
|
|
|
Выбранный сегмент |
|
|||||||
|
|
|
|
|
|
Предел сегмента |
|
|||||||
Дескриптор |
сегмента |
|
|
|
|
|
||||||||
|
|
|
|
|
|
. . . |
|
|||||||
Правила доступа и права доступа |
|
|
|
|
|
|||||||||
|
|
|
Линейный |
Выбираемый операнд (инструкция) |
|
|||||||||
Базовый адрес |
|
+ |
адрес |
|
||||||||||
|
|
|
|
|||||||||||
Граница сегмента |
|
|
|
. . . |
|
|||||||||
|
|
|
|
|||||||||||
|
|
|
|
|
Начало сегмента |
|
||||||||
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
||||||||
Рис.$1. Формирование линейного адреса
Сегмент – это блок пространства памяти определенного назначения. К элементам сегмента возможно обращение с помощью различных инструкций процессора, использующих разные режимы адресации для формирования адреса в пределах сегмента. Максимальный размер сегмента – 4GB. Сегменты памяти выделяются задачам операционной системой. В защищенном режиме прикладная программа может использовать только разрешенные для нее сегменты памяти, выбирая их с помощью селекторов из предварительно сформированных таблиц дескрипторов сегментов.
Процессор может обращаться только к тем сегментам памяти, для которых имеются дескрипторы в таблицах. Дескрипторы выбираются с помощью 16-битных селекторов. Селектор может появиться в сегментном регистре только с помощью привилегированной инструкции загрузки селектора. Эта инструкция загружает как сам сегментный регистр, так и его теневую часть. Попытка обращения к несуществующему сегменту вызовет исключение. Формат селектора приведен на рис. $2.
15 |
3 |
2 |
1 |
0 |
INDEX |
TI |
RPL |
||
Рис.$2. Формат селектора
Индекс совместно с индикатором таблицы TI позволяет выбрать дескриптор из локальной (TI=1) или глобальной (TI=0) таблицы дескрипторов. Для неиспользуемых сегментных регистров предназначен нулевой селектор сегмента, формально адресующийся к самому первому элементу глобальной таблицы. Попытка обращения к памяти по такому сегментному регистру вызовет исключение. Исключение возникнет и при попытке загрузки нулевого селектора в регистр CS или SS. Поле RPL указывает требуемый уровень привилегий (см. ниже).
Дескрипторы представляет собой 8-байтные структуры данных, используемые для определения свойств программных элементов (сегментов, шлюзов и таблиц). Дескриптор определяет положение элемента в памяти (Base Address), размер занимаемой элементом области (Limit), его назначение и характеристики защиты. Все дескрипторы хранятся в таблицах, обращение к которым поддерживается процессором аппаратно.
Защита памяти с помощью сегментации принципиально запрещает:
адресоваться к элементам, выходящим за границу сегмента;
использовать сегменты не по назначению (например, пытаться трактовать область данных как коды инструкций);
нарушать права доступа (пытаться модифицировать сегмент, предназначенный только для чтения, обращаться к сегменту, не имея достаточных привилегий и т.п.);
Кроме того, не имея достаточных привилегий, нельзя изменить содержимое таблиц дескрипторов (то есть параметры сегментов). Но если привилегии есть, то можно обойти все запреты, изменяя содержимое таблиц дескрипторов.
В защищенном режиме есть встроенные средства переключения задач. Состояние каждой задачи (значение всех связанных с ней регистров процессора) может быть сохранено в специальном сегменте состояния задачи TSS (где также хранятся и другие параметры этой задачи). На этот сегмент указывает селектор в регистре задачи TR. При переключении задач достаточно загрузить новый селектор в регистр задачи, и состояние текущей задачи автоматически сохранится в ее TSS, а в процессор загрузится состояние новой (возможно, ранее прерванной) задачи и начнется (либо продолжится) ее выполнение.
Четырехуровневая иерархическая система привилегий предназначена для управления использованием привилегированных инструкций и доступом к дескрипторам. Как уже упоминалось, уровни привилегий нумеруются от 0 до 3, нулевой уровень соответствует максимальным (неограниченным) возможностям доступа и отводится для ядра операционной системы. Уровень 3 имеет самые ограниченные права и обычно предоставляется прикладным задачам. Сервисы, предоставляемые задачам, могут находиться на разных уровнях защиты. Передача управления между задачами контролируется шлюзами (Gate), называемыми также вентилями, проверяющими правила использования уровней привилегий. Через шлюзы задачи могут получить доступ только к разрешенным им сервисам других сегментов.
Уровни привилегий относятся к дескрипторам, селекторам и задачам. Кроме того, в регистре флагов имеется поле привилегий ввода/вывода, с помощью которого обеспечивается управление доступом к инструкциям ввода/вывода и управлению флагом прерываний.
Дескрипторы и привилегии являются основой системы защиты: дескрипторы определяют структуры программных элементов (без которых эти элементы невозможно использовать), а привилегии определяют возможность доступа к дескрипторам и выполнения привилегированных инструкций. Любое нарушение защиты приводит к возникновению специальных исключений, обрабатываемых ядром операционной системы.
$.2. Дескрипторы и таблицы
Существуют три типа таблиц дескрипторов – локальная таблица дескрипторов LDT (Local Descriptor Table), глобальная таблица дескрипторов GDT (Global Descriptor Table) и таблица дескрипторов прерываний IDT (Interrupt Descriptor Table). Размеры таблиц могут находиться в пределах от 8 байт до 64К-байт, что соответствует числу элементов в таблице от 1 до 8К.
С каждой из этих таблиц связан соответствующий регистр процессора. Регистры GDTR и IDTR имеют программно-доступное 16-битное поле лимита, задающее размер таблицы, и 32-битное поле базового адреса, определяющее положение таблицы в пространстве линейных адресов памяти. У регистра LDTR программно доступно только 16-битное поле селектора, по которому из GDT автоматически загружаются программно-недоступные и невидимые поля базового адреса и границы. Схема выборки дескрипторов показана на рис. $3.
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||
Селектор сегмента (CS…GS) |
Дескриптор сегмента теневая часть регистра (CS…GS) |
|||||||||||||||||||||||||||||||||||||
15 |
3 |
2 |
1 |
0 |
||||||||||||||||||||||||||||||||||
INDEX |
TI |
DPL |
Атрибуты сегмента |
Граница сегмента |
Базовый адрес сегмента |
|||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||
|
|
|
|
G |
(TI=0) |
|
|
|
|
L DT |
(TI=1) |
|
||||||||||||||||||||||||||
|
|
|
|
|
Граница GDT |
|
|
|
|
Граница LDT |
|
|||||||||||||||||||||||||||
|
|
|
|
|
. . . |
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
. . . |
|
||||||||||||||||||||||||||||
|
|
|
+ |
|
|
Дескриптор сегмента |
|
|
|
|
|
|
||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||
|
|
|
|
|
. . . |
+ |
|
|
|
Дескриптор |
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
сегмента |
|
||||||||||||||||||||||||||||
|
|
|
+ |
|
Дескриптор LDT |
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||
|
|
|
|
|
. . . |
|
|
|
|
. . . |
|
|||||||||||||||||||||||||||
15 |
0 |
31 |
16 |
|
|
|
|
|
|
|
||||||||||||||||||||||||||||
Граница GDT |
Базовый адрес GDT |
|
Начало GDT |
|
|
|
|
Начало LDT |
|
|||||||||||||||||||||||||||||
|
|
|
|
|
|
|
||||||||||||||||||||||||||||||||
Регистр GDTR |
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||
|
Регистр LDTR |
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||
|
15 |
3 |
2 |
1 |
0 |
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
||||||||||||||||||||||||||||||||
|
INDEX |
0 |
DPL |
Атрибуты LDT |
Граница LDT |
Базовый адрес LDT |
|
|||||||||||||||||||||||||||||||
|
Селектор LDT |
теневая часть регистра LDTR |
|
|||||||||||||||||||||||||||||||||||
Рис. $3. Схема выборки дескрипторов из таблиц GDT и LDT.
Инструкции загрузки регистров таблиц LGDT, LIDT и LLDT являются привилегированными (выполняются только на уровне привилегий 0). Инструкции LGDT и LIDT загружают из памяти 6-байтное поле, содержащее базовый адрес и лимит локальной таблицы. Инструкция LLDT загружает только селектор, ссылающийся на дескриптор, содержащий базовый адрес и границу локальной таблицы дескрипторов.
Глобальная таблица (GDT) содержит дескрипторы, доступные всем задачам. Она может содержать дескрипторы любых типов, кроме дескрипторов прерываний и ловушек. Нулевой элемент этой таблицы процессором не используется. Локальная таблица (LDT) может быть собственной для каждой задачи и содержит только дескрипторы сегментов, шлюзы задач и вызовов. Сегмент недоступен задаче, если его дескриптора нет в текущий момент ни в GDT, ни в LDT.
Выбор таблицы (локальная или глобальная) определяется по значению бита TI селектора, а положение (номер) дескриптора задается 13-битным полем INDEX селектора. При ссылке на дескриптор, выходящий за лимит таблицы, возникает исключение #GP.
Таблица дескрипторов прерываний, используемая в защищенном режиме, может содержать описания до 256 прерываний. Таблица может содержать только шлюзы задач, прерываний и ловушек. Базовый адрес и лимит таблицы загружается привилегированной инструкцией LIDT (аналогично LGDT). Размер IDT должен быть не менее 256 байт, чтобы в нее поместились все зарезервированные прерывания процессора. Ссылка на элементы IDT происходит по инструкциям INT, аппаратным прерываниям и исключениям процессора. При возникновении прерывания или исключения, дескриптор которого выходит за лимит таблицы, вырабатывается исключение #DF.
В общем виде формат дескриптора представлен на рис. $4, где 32-разрядный базовый адрес сегмента (база ВА[31:0]) и 20-разрядная граница сегмента (L[19:0]) размещены по частям в различных байтах дескриптора.
Граница сегмента L указывает максимальное допустимое значение относительного адреса, которое может использоваться при обращении к сегменту. Величина (L+1) определяет размер сегмента в байтах или страницах. Обращение к ячейке памяти, находящейся за границей данного сегмента, вызывает исключение типа #GP.
Помимо базового адреса и границы сегмента дескрипторы задают ряд других важных его атрибутов, состав которых зависит от вида сегмента. Отдельные биты байта 6 дескриптора определяют следующие атрибуты сегмента.
Байт 7 |
Байт 6 |
Байт 5 |
Байт 4 |
||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||
31 |
24 |
23 |
22 |
21 |
20 |
19 |
16 |
15 |
14 |
13 |
12 |
11 |
8 |
7 |
|
|
0 |
||||||||||||
BA[31:24] |
G |
D/B |
0 |
Avail |
Граница L[19:16] |
P |
DPL |
S |
TYPE |
Базовый адрес BA[23:16] |
|||||||||||||||||||
Базовый адрес BA[15:0] |
Граница сегмента L[15:0] |
||||||||||||||||||||||||||||
31 |
16 |
15 |
0 |
||||||||||||||||||||||||||
|
|
|
|
|
|
||||||||||||||||||||||||
Байты 3,2 |
Байты 1,0 |
||||||||||||||||||||||||||||
Рис. $4. Общий формат дескриптора
Бит дробности G (Granularity) указывает, в каких единицах задан размер сегмента: в байтах при G=0 или страницах объемом по 4KB при G=1.
Таким образом, сегмент может иметь размер до 220 =1М-байт при G=0 или до 232 =4Г-байт при G=1.
Бит разрядности по умолчанию D/B. Для сегментов инструкций он определяет разрядность формируемого относительного адреса и выбираемого операнда: если D/B=0, то 16/8-разрядные, если D/B=1, то 32/8-разрядные. Если производится обращение к сегменту стека (при выполнении инструкций типа PUSH, POP, CALL, RET), то при D/B=0 используется регистр SP и 16-разрядные данные, а при D/B=1 – регистр ESP и 32-разрядные данные. Для расширяемых вниз сегментов данных (сегменты со стековой адресацией) бит D/B определяет их верхнюю границу: M=FFFFh при D/B=0, либо М=FFFFFFFFh при D/B=1. Для системных дескрипторов этот бит должен иметь нулевое значение.
Бит 5 в байте 6 всегда должен иметь нулевое значение, а бит 4 (Available) может принимать значение, устанавливаемое пользователем или операционной системой.
Байт 5 дескриптора определяет права доступа к выбираемому сегменту. В зависимости от вида сегмента байт доступа имеет различные форматы (рис. $5), хотя назначение ряда полей (битов) остается одинаковым. Одинаковое назначение имеют следующие биты и поля.
Бит присутствия P (Present) определяет наличие соответствующего сегмента в памяти. Если P=0 (сегмент отсутствует), то данный дескриптор не используется для формирования адресов, т.е. соответствующие байты дескриптора не загружаются в регистры, хранящие базовый адрес и размер сегмента. Поэтому содержимое этих байтов может быть установлено произвольно. Если в регистр сегмента поступает селектор дескриптора, имеющего P=0, то процессор переходит к обработке соответствующего исключения #NP (“отсутствие сегмента”). Когда P=0, исполнительная или операционная система может использовать все байты дескриптора (кроме байта 5) по своему усмотрению, например, для хранения информации о том, где хранится отсутствующий сегмент.
Примечание. Программное обеспечение управления памятью может использовать этот флаг для управления сегментами, которые в данное время реально присутствуют в физической памяти.
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
а) |
P |
DPL |
S=1 |
1 |
C |
R |
A |
|
|
|
|
|
|
|
|
|
|
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
б) |
P |
DPL |
S=1 |
0 |
E |
W |
A |
|
|
|
|
|
|
|
|
|
|
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
в) |
P |
DPL |
S=0 |
TYPE |
||||
Рис. $5. Формат байта доступа для дескрипторов сегментов программ (а), данных (б) и системных дескрипторов (в)
Поле DPL (Descriptor Privilege Level) указывает уровень защиты сегмента (уровень привилегий дескриптора). В зависимости от соотношения значений DPL и RPL, задаваемого в младших битах селектора (рис.$2), разрешается или запрещается обращение к данному сегменту. Таким образом, обеспечивается требуемый уровень защиты сегмента.
Системный бит S (System) определяет вид выбираемого сегмента. При S=1 дескриптор обеспечивает обращение к сегментам программ (кодов) или данных (включая стек). Системные дескрипторы, имеющие значение S=0, служат для обращения к таблицам LDT, сегментам состояния задачи TSS или шлюзам для входа в другие задачи или программы, включая программы обслуживания исключений и прерываний.
Форматы байта доступа для дескрипторов сегментов программ и данных (рис. $5, а, б) отличаются значениями бита 3, который имеет значение “1” для сегментов программ и “0” для сегментов данных.
Бит обращения A (Accessed) устанавливается в единицу при обращении к сегменту, т.е. при загрузке соответствующего селектора в сегментный регистр. Этот бит периодически проверяется операционной системой, реализующей виртуальную память, которая таким образом выявляет невостребованные сегменты, имеющие A=0. Сегменты, долгое время остающиеся невостребованными, выводятся из оперативной памяти на магнитный диск, освобождая место для других сегментов.
Назначение битов 1 и 2 байта доступа зависит от типа сегмента.
Бит разрешения считывания R (readable). Разрешает при R=1 производить считывание содержимого сегмента программ. При R=0 допускается только выборка содержимого этого сегмента для выполнения через регистр CS. Попытка считывания сегмента в этом случае вызовет исключение типа #GP. Отметим, что прерывание этого типа возникает также при попытке записи в сегмент программ независимо от значения бита R. Таким образом, запись в сегмент программ запрещена. Если возникает необходимость внести изменение в этот сегмент, то можно создать сегмент данных с разрешением записи (W=1), занимающий то же адресное пространство, что и модифицируемый сегмент программ. После внесения изменений в созданный сегмент данных можно обратиться к нему как к сегменту программ, загрузив селектор этого сегмента в регистр CS.
Бит подчиненности C (Conforming) определяет дополнительные правила обращения, которые обеспечивают защиту сегментов программ. При C=0 обращение к данному сегменту разрешается только программам, имеющим уровень привилегии CPL (значение поля RPL в регистре CS) такой же, как значение поля DPL в дескрипторе сегмента; при C=1 допускается обращение к данному сегменту программ, имеющих CPLDPL.
Бит разрешения записи W (Writeable). Разрешает (при W=1) или запрещает (при W=0) изменение содержимого сегмента данных. При W=0 разрешается только считывание данных, а при попытке записи реализуется исключение типа #GP.
Бит направления расширения E (Expand) определяет направление расширения сегмента данных. При Е=0 (расширение вверх) данные в сегменте размещаются от базового адреса ВА, задающего нижний предел сегмента до верхнего предела, определяемого суммой базового адреса и границы сегмента: (BA+L). Т.е. сегмент размещается вниз от границы – в направлении уменьшения адресов. При Е=1 (расширение вниз) данные располагаются, начиная с адреса (BA+L+1), определяющего нижний предел сегмента, до верхнего предела, задаваемого адресом (ВА+М). Верхний предел сегмента в этом случае равен базовому адресу, увеличенному на M=FFFFh (размер сегмента до 64KB) или на M=FFFFFFFFh (размер сегмента до 4 Гбайт) в зависимости от значения бита разрядности D/B в байте 6 дескриптора. Размер сегмента будет равен (M-L), и его максимальное значение достигается, когда заданная граница L=0. Отметим, что для сегментов с расширением вниз значения битов дробности и разрядности должны быть равными: G=D/B.
Таким образом, при расширении вверх (Е=0) относительный адрес выбираемой ячейки должен быть меньше или равен границе сегмента, при расширении вниз (Е=1) относительный адрес должен быть больше границы сегмента.
Формат байта доступа для системных дескрипторов (S=0) приведен на рис. $5,в. Поле TYPE определяет тип системного дескриптора в соответствии с табл. $.1.
Таблица $.1.

DT