ПРОЦЕССОР INTEL В
ЗАЩИЩЕННОМ РЕЖИМЕ
Выпуск
№3
FAQ выпуска №2:
-
Я не вижу никакой картинки с дескриптором! Что делать?
Дело в том, что сама картинка находится здесь: http://brokensword.narod.ru/descriptor.gif,
при просмотре второго выпуска рассылки ты должен находится в онлайне и дождаться, пока она полностью загрузится. Потом
сохрани ее целиком, как ты обычно это делаешь со страницами, содержащими картинки.
У кого НЕТ интернета, а только почта – пишите на brokensword@ukr.net я его вам вышлю по мылу (весит 5 килобайт)
__________________________________________________
Рассылка постепенно набирает обороты! Я по прежнему жду не
дождусь писем с вопросами… Вариантов здесь может быть только два: или вам все
сходу понятно, или вообще ничего не понятно… Второй
вариант как то не особо впечатляет на дальнейшее продолжение. Хотя, пока
слишком мало материала, и спрашивать, по сути, не о чем.
Таблица дескрипторов
Итак,
к чему мы пришли: оказывается, сегменты не раскиданы по памяти как попало и
непонятно где, теперь мы с уверенностью можем сказать
где какой из сегментов начинается, где заканчивается, что это за сегмент (код,
данные или стек), вся эта информация хранится в ДЕСКРИПТОРЕ. Казалось бы, чего
нам не хватает для полного счастья? Все же вроде ясно и понятно и не о чем
здесь больше говорить! Однако, есть еще кое что… Один
вопрос, который уже должен был загореться в твоем подсознании… ГДЕ ЖЕ НАХОДИТСЯ
САМ ДЕСКРИПТОР ???!!! :)
Находиться
он может в трех местах:
- Глобальная таблица дескрипторов (GDT - Global Descriptor Table)
- Локальная таблица дескрипторов (LDT - Local Descriptor Table)
- Таблица дескрипторов прерываний (IDT – Interrupt Descriptor Table)
Эти
таблицы находятся в оперативной памяти (там же, где и собственно сами программы),
а не в процессоре, жестком диске или куда еще могут завести тебя фантазии… Поэтому, очевидно, что строить ТАБЛИЦЫ ДЕСКРИПТОРОВ
придется «руками», нам самим. И вообще, с этого момента пора привыкать – в
защищенном режиме ВСЕ НУЖНО СТРОИТЬ САМОМУ. В этом и
заключается сила! :)
Несколько
слов по поводу первых двух таблиц (на третьей (IDT) мы остановимся в главе посвященной
прерываниям в защищенном режиме).
Глобальная
таблица дескрипторов (GDT):
ЗАПОМНИ:
КАЖДАЯ ОС ДОЛЖНА ИМЕТЬ ОДНУ ТАБЛИЦУ GDT!!! Без нее – никуда! Ей (таблицей) могут
пользоваться ВСЕ (!) программы и задачи системы. Что значит «пользоваться
таблицей дескрипторов»? Это значит, хранить в ней СВОЙ
дескриптор.
Таблица
GDT –
сама по себе НЕ СЕГМЕНТ! Это структура данных в линейном адресном пространстве
(в памяти). НАЧАЛО таблицы GDT
храниться В РЕГИСТРЕ GDTR! Регистр GDTR – это самый обыкновенный регистр, такой же
обыкновенный, как EAX, EIP, ES, только вот его функция заключается не в
хранении каких-то промежуточных данных, а в хранении фиксированного числа –
НАЧАЛА ТАБЛИЦЫ GDT.
Называние регистра GDTR
запомнить очень легко: GDT – это таблица, R – регистр. Не
правда ли, пока все просто? )
Да,
кстати, не упусти важный момент: мы должны сделать все так, чтобы начало
таблицы GDT в
памяти было кратно 8. Это связано с архитектурой и так проц
быстрее соображает при обращении к таблице.
GDTR:
32-битный
линейный базовый адрес |
16-битный
лимит таблицы |
Вот
он, регистр GDTR.
Весит 48 бит. Как видишь, он содержит не только адрес начала таблицы GDT в памяти, а еще и ее лимит. Лимит таблицы –
16-битное значение, показывает величину таблицы в байтах + 1. (т.е. все как и в случае с лимитом сегмента: если лимит таблицы в GDTR равен 0, то на самом деле это означает что
реально (в памяти) лимит равен одному байту).
Как
ты уже знаешь, сегментный дескриптор ВСЕГДА занимает 8 байт (2 двойных слова). Если уже забыл – посмотри на картинку из 2
выпуска. Следовательно, лимит таблицы дескрипторов – величина, равная 8N-1 байт. Но и N – тоже не резиновая величина. Скоро узнаешь каков предел этого самого N (т.е. сколько всего дескрипторов может
содержать таблица)
Первый
дескриптор в GDT не
используется и называется «нулевой дескриптор» (null descriptor). При обращении к памяти
через этот дескриптор возникает уже знакомая нам «рука правосудия» с #GP, и все опять вынуждены
пасть ниц :)
Поэтому
первый дескриптор в GDT – РУКАМИ
НЕ ТРОГАТЬ!
Загрузить/считать
значение регистра GDTR можно командами LGDT/SGDT. По умолчанию (т.е. после нажатия на кнопку Reset или включения компа)
база GDT
равна нулю, а лимит – FFFFh, т.е. фактически по умолчанию выделено
максимум места, под FFFFh/8 = 8191 дескрипторов (ну минус один,
учитывая null
descriptor).
Локальная
таблица дескрипторов (LDT):
В
отличии от GDT совершенно не ОБЯЗАНА присутствовать вообще.
И в то же самое время, ПО ЖЕЛАНИЮ, их можно развести великое множество (GDT ДОЛЖНА БЫТЬ только одна). Каждая задача
может иметь свою собственную LDT, в
то же время несколько задач могут использовать одну LDT на всех.
LDT – это СЕГМНЕТ! (GDT – структура данных). Это принципиально!
И вот почему: т.к. LDT – это сегмент, то значит у нее тоже есть свой
дескриптор! И где бы вы думали? Да все в той же GDT!!! Да да, звучит
несколько странновато – у таблицы дескрипторов есть свой дескриптор!! Но, то ли еще будет! :)
Так же, как и у GDT у LDT
тоже есть свой регистр – LDTR. В отличии от GDTR этот регистр, помимо инфы про базу и лимит LDT, содержит еще одно поле – сегментный селектор.
Пока что не вникай, просто запомни слово – СЕЛЕКТОР.
LDTR:
Сегм. Селектор (16 бит) |
32-битный линейный базовый адрес |
16-битный лимит сегмента |
Инструкции LLDT и SLDT позволяют писать/читать регистр LDTR. Точно так же, при reset-е значение базы в LDTR падает в ноль, а лимит – в FFFFh
Ну и напоследок - ВНИМАНИЕ! КОНКУРС!!! )
Перед тобой пример структуры, которая являет собой таблицу GDT (вместо ИКС-ов значения, которые мы еще не рассматривали, поэтому
не смотри на них); Тебе предстоит найти РЕАЛЬНЫЕ ЗНАЧЕНИЯ базы и лимита для
каждого из описуемых семи сегментов (именно линейные
адреса в памяти). Для одного из них дана подсказка в комментарии. Победителей
ожидают ценные призы, а того, кто первым пришлет ответ – КВАРТИРА В МОСКВЕ! Поторопитесь!!!
Чтобы было проще – открой картинку с дескриптором и смотри одним глазом на
нее, другим - на значения. Да, и помни: смотреть картинку нужно «задом-наперед» (т.е. сначала младшие байты, потом старшие):
GDT:
; нулевой дескриптор (ОБЯЗАТЕЛЬНО ДОЛЖЕН ПРИСУТСВОВАТЬ, НО
РУКАМИ НЕ ТРОГАТЬ!)
0. db 8 dup (0)
; Сегмент с базой в 0 и
лимитом в 1235h (не забывай про +1 к
лимиту!)
; Линейный адрес базы = 0, линейный адрес лимита = 0 + 1235h = 1235h
1. Descr_code db
34h,12h,00h,00h,00h,XXh,0X000000b,00h
2. Descr_data db
0C8h,0Dh,36h,12h,00h,XXh,0X100000b,00h
3. Descr_stack db
0FFh,00h,00h,20h,00h,XXh,1X000000b,00h
4. Descr_code2 db
0DEh,0BCh,01h,20h,10h,XXh,0X001010b,00h
5. Descr_data2 db
00h,00h,00h,00h,00h,XXh,0X000000b,10h
6. Descr_stack2 db
01h,00h,10h,00h,00h,XXh,0X000001b,10h
7. Descr_LDT db 04h,00h,00h,00h,00h,XXh,1X000000b,20h
GDT_limit = $-GDT
GDTR dw GDT_limit-1
dd ?
Дополнительные задания:
1. Найди ошибку! Один из дескрипторов содержит ОШИБКУ!
2. Покажи, как правильно нужно загрузить регистр GDTR.
Ответы присылать сюда: brokensword@ukr.net в таком виде
1. Линейный адрес базы = 0
Линейный адрес лимита =
1235h
2. . . .
Слово «линейный адрес» можешь опустить :)
Ариведерчи