Дескрипторные таблицы

advertisement
Дескрипторные таблицы
В системах на базе Рх86 допускается создание практически любого
числа сегментов и описывающих их дескрипторов. Область памяти,
предназначенная для хранения 8-байтных дескрипторов, называется
дескрипторной таблицей. Порядок размещения дескрипторов в таблице
не играет роли, а максимальное число дескрипторов составляет 8192 ( т.
е. максимальный размер дескрипторной таблицы равен 64Кбайт. В
процессоре предусмотрено использование дескрипторных таблиц трех
типов (Рис. . Выбор таблицы, в которую при создании сегмента
помещается его дескриптор, зависит от назначения сегмента.
Глобальная дескрипторная таблица (GDT)
является главной
общесистемной таблицей дескрипторов. Все программы (задачи),
выполняющиеся в системе, могут использовать её для обращения к
сегментам памяти (т.е. GDT разделяют («коллективно используют») все
задачи. Для локализации таблицы в памяти и предназначен регистр
GDTR, в котором находятся 32-битное поле линейного базового адреса
таблицы и 16-битное поле предела с байтной грануляцией. Значение
предела L связано с числом N дескрипторов в таблице простым
соотношением L=8 * N – 1.
Дескрипторная таблица прерываний (IDT) является также
общесистемной и содержит дескрипторы специальных системных
объектов, называемых шлюзами (gate), которые определяют точки входа
процедур обработки прерываний и особых случаев. Иначе говоря,
таблица
IDT служит заменой таблицы векторов прерываний в
реальном режиме. Для локализации таблицы в памяти и предназначен
регистр IDTR, формат которого аналогичен формату регистра GDTR.
Для перевода процессора из реального (R) режима в защищённый (P)
необходимо создать таблицы GDTR
и IDTR
и соответственно
инициализировать регистры GDTR и IDTR.
Локальная дескрипторная таблица (LDT).
В мультизадачной системе для каждой задачи в дополнение к
таблице GDT можно построить свою локальную дескрипторную
таблицу. Она определяет сегменты, доступные только этой конкретной
задаче. Для локализации таблицы LDT предназначен регистр LDTR,
который содержит только селектор, указывающий в таблице GDT
нужный дескриптор и атрибуты таблицы LDT, которые становятся
доступны процессору.
В процессоре с регистром LDTR ассоциируется так называемый
«теневой регистр», в котором и хранится дескриптор текущей задачи.
При переключении с одной задачи на другую для замены используемой
локальной дескрипторной таблицы достаточно загрузить в регистр
LDTR селектор новой таблицы LDT , а процессор автоматически
загрузит дескриптор новой LDT в теневой регистр.
ОП
Дескриптор N
…. . . . .
+
47
Дескриптор 1
0
Базовый адрес
Предел
Дескриптор 0
Регистр GDTR
Дескриптор M
+
47
…. . . . .
Дескриптор 1
0
Предел
G
D
T
I
D
T
Дескриптор 0
Базовый адрес
Регистр IDTR
Дескриптор K
.. . . . . . . .
+
15
0
Предел
LDTR
47
Дескриптор 1
Дескриптор 0
Базовый адрес
0
Рис. 1 Дескрипторные таблицы и системные регистры
L
D
T
Селектор сегментов
В защищенном режиме, также как и реальном, для доступа к
сегментам используются сегментные регистры, однако в защищенном
режиме содержимое сегментного регистра, называемое селектором,
интерпретируется иначе. Селектор косвенно через дескрипторную
таблицу определяет сегмент памяти. Новый формат селектора сегмента
следующий:
15
2 1 0
TI RPL
Index (индекс)
Двухбитное поле запрашиваемого уровня привилегий RPL
используется для контроля привилегий в механизме защиты процессора.
Бит индикатора TI показывает из какой дескрипторной таблицы
выбирается дескриптор: если TI = 0, обращение производится к
глобальной дескрипторной таблице GDT, а при TI = 1 – к локальной
дескрипторной таблице LDT.
Старшие 13 бит селектора, образующие поле индекса Index,
определяют нужный дескриптор в дескрипторной таблице.
Процесс формирования линейного адреса памяти с помощью
селектора и эффективного адреса показан на рис. 1.
15
0
Index
31
0
Эффективный адрес
0
63
0
63
GDT
Права
LDT
База
Права
Предел
База
Предел
0
31
Базовый адрес сегмента
+
31
0
Линейный адрес
Рис. 1 Формирование линейного адреса памяти
Так как дескриптор содержит 8 байт, поле индекса дополняется в
процессоре тремя младшими нулями (умножается на 8). Значение
селектора с полем Index = 0 и TI = 0 допустимо, но первый элемент
таблицы GDT зарезервирован процессором и должен содержать нули.
Такой селектор (Index = 0, TI = 0 и поле RPL произвольно) называется
пустым селектором (null selector) или нуль- селектором, а
соответствующий дескриптор – пустым дескриптором. Следовательно,
пустые селекторы 0000Н – 0003Н не описывают никаких полезных
сегментов. Пустой селектор разрешается загружать в сегментный
регистр (кроме CS и SS), но любая попытка использовать его в
формировании адреса вызывает особый случай.
Рассмотрим процесс выполнения команды
MOV EAX, [EBX][ESI + 8h]
В это команде нет префикса замены сегмента, поэтому она
обращается к текущему сегменту данных, селектор которого находится в
регистре DS. Пусть в регистре DS содержится двоичное значение
00000000001010ххB. Бит TI = 0, следовательно, дескриптор сегмента
находится в таблице GDT и имеет номер 5. Выполнение команды
включает в себя следующее:
1. Образовать эффективный адрес ЕА = (ЕВХ) + (ESI) + 8 h
2. Выбрать пятый дескриптор из таблицы GDT. Для этого следует
обратиться к полю базы регистра GDTR, прибавить к нему Index
*8 из регистра DS и считать в процессор дескриптор по
полученному адресу.
3. Просуммировать базовый адрес сегмента из дескриптора и
эффективный адрес. В результате получится линейный
(физический) адрес операнда.
4. Обратиться по линейному адресу к памяти и передать двойное
слово в регистр ЕАХ.
Описанные выше операции обращения к сегменту данных, требуют
считывания из памяти 8-ми байтного дескриптора из таблицы GDT.
(Отметим, что при обращении к сегменту через таблицу LDT,
потребовалось бы дополнительное считывание из памяти дескриптора
этой таблицы из таблицы GDT). Если производить все эти операции при
каждом обращении к памяти (в том числе и при выборке каждой
команды), производительность процессора будет невысокой. Чтобы не
допустить этого в процессоре применяется кэширование (caching)
дескрипторов.
Кэширование опирается на тот факт, что обращение к памяти
производится гораздо чаще, чем изменение сегментов и переключения
задач. Поэтому целесообразно ускорить обращение к памяти за счёт
замедления загрузки сегментных регистров. Компромиссное решение
заключается в ассоциировании с каждым сегментным регистром (а
также с регистрами LDTR и TR) «теневого» (shadow) регистра или кэшрегистра (рис.2). Такие кэш-регистры невидимы и явно недоступны
программам. Когда программа загружает селектор в сегментный
регистр, процессор автоматически считывает («кэширует») нужный
дескриптор в соответствующий теневой регистр. Поскольку теперь
дескриптор находится внутри процессора, для получения линейного
адреса памяти потребуется сформировать эффективный адрес и
просуммировать его с базовым адресом сегмента из нужного теневого
регистра.
Сегментные
регистры
15
0
Регистры дескрипторов
64
0
CS
SS
DS
ES
FS
GS
Рис. 2 Теневые регистры дескрипторов сегментов
Если программа редко модифицирует сегментные регистры, то в
защищенном Р - режиме она будет выполняться примерно с такой же
скоростью, как и в R – режиме.
Загрузка и просмотр селекторов
Процессор до загрузки селектора и кэширования дескриптора
осуществляет несколько контрольных проверок. Некоторые из них
связаны с контролем уровня привилегий в механизме защиты памяти, а
остальные предотвращают загрузку бессмысленных селекторов.
Процессор проверяет, что поле Index селектора находится в пределах
таблицы, определяемой битом TI селектора сегмента. Именно в связи с
этим пределы дескрипторных таблиц хранятся вместе с их базовыми
адресами. При загрузке селектора в сегментный регистр данных (DS, ES,
FS, GS) тип дескриптора должен разрешать считывание из сегмента (
сегменты с разрешенными операциями выполнения/считывания
допустимы). В случае регистра SS в сегменте стека должны быть
разрешены операции считывания и записи. При загрузке регистра CS
сегмент должен быть обязательно исполняемым. Загрузка сегментного
регистра и кэширование выбираемого селектором дескриптора
осуществляется только при Р=1. В тех случаях, когда хотя бы одна
проверка даёт отрицательный результат, формируется особый случай и
загрузка селектора не производится.
Для работы с сегментными регистрами доступны обычные
команды MOV, PUSH и POP, а также специальные команды загрузки
LDS, LES, LFS, LGS и LSS.
При редактировании связей (компоновке) символическим адресам
назначаются действительные (относительные) адреса памяти. Но
окончательную
привязку
адресов
осуществляет
загрузчик.
Манипуляции селекторами, дескрипторами и дескрипторными
таблицами предоставлены разработчикам операционных систем и
системным программистам.
Для анализа селекторов предусмотрено несколько команд:
LAR reg16/reg32, reg16/mem16
; загрузка в регистр-получатель
права доступа селектора, адресуемого вторым операндом. Т.е.
возвращает байт прав доступа AR и биты G, D, X и U (расширение прав)
из соответствующего селектору дескриптора сегмента. Анализируя
соответствующие биты, можно определить, доступен ли данный сегмент
программе, не нарушая защиты памяти;
LSL reg16/reg32, reg16/mem16
; по адресу первого операнда
загружается предел сегмента, который определяет селектор, адресуемый
вторым операндом. Если бит гранулярности G = 1 ( т.е. сегмент имеет
страничную гранулярность), предел расширяется до 4Гб и регистрприёмник д.б. 32-х разрядным;
VERR
reg16/mem16
; операнд задаёт селектор проверяемого
сегмента и устанавливает бит ZF = 1, если программа может загрузить
адресуемый селектор в сегментный регистр данных DS, ES, FS или GS, а
также считывать из сегмента без нарушения защиты;
VERW reg16/mem16
; операнд задаёт селектор проверяемого
сегмента и устанавливает бит ZF = 1, если программа может загрузить
адресуемый селектор в сегментный регистр данных DS, ES, FS или GS, а
также записывать в сегмент без нарушения защиты.
Обе последние команды не контролируют бит Р в дескрипторе
(присутствие сегмента в памяти).
Download