Процессор Intel в защищенном режиме #2 — Архив WASM.RU

Все статьи

Процессор Intel в защищенном режиме #2 — Архив WASM.RU

В предыдущем выпуске ты в самом первом приближении ознакомился с видами организации памяти в защищенном режиме. Напомню, что существует всего 2 вида: сегментная (segment) и страничная (paging) модели. Также я обещал в этом выпуске более подробно остановиться на страничной организации. На самом деле еще рановато… Давай лучше до конца разберемся с сегментной организацией, потом будет намного проще разобраться со страничной…

Итак, что мы имеем: программа (вернее, программы) загружены в оперативную память, каждая программа владеет группой сегментов (данные, код, стек). Теперь возникает вопрос: откуда же процессор знает, где какой сегмент? Где начало сегмента? И где его конец? И что это за сегмент: данных? кода? А может быть, стека? Или, может быть, всего разом? Ответить на этот вопрос может только одна структура данных: ДЕСКРИПТОР. Повторите это слово про себя несколько раз, запомните его. Напишите на бумажке 10 раз :). ДЕСКРИПТОР – это структура, ОПИСЫВАЮЩАЯ сегмент. Если человек – это сегмент, то паспорт – это его дескриптор. У каждого человека он свой собственный. И разница лишь в том, что человеку паспорт (дескриптор) выдается с 16 лет (на Украине), а у сегмента он с момента рождения.

Сегментный дескриптор

Вот он, наш красавец! Посмотри на него повнимательнее, включи зрительную память на максимум… Я его вообще около получаса вымалевывал, и вот какой он получился ненаглядный!

Теперь распишу во всех пикантных подробностях значения полей дескриптора (хочется тебе или нет, но без этого, к сожалению, НИКУДА дальше не уедешь, придется тебе их всех запомнить):

(Смотри одним глазом на фиолетовые слова, другим – ищи их на картинке :) )

Адрес базы: адрес нулевого байта описываемого сегмента в 4 Гб линейном адресном пространстве (т.е. адрес, с которого начинается сегмент). Процессор собирает в кучу три поля зеленого цвета :) и образует единый 32-х битный адрес. Почему так убого? Потому что вообще говоря, процессор Интел представляет собой штопанно-перелатанного уродца (достаточно взглянуть на дескриптор). И этому есть несколько причин. Единственное, что могу добавить – это не самое ужасное. Что еще хотелось бы отметить по поводу адреса базы сегмента – желательно он должен быть кратен 16 (так проц при обращении к описываемому сегменту и формировании адреса будет быстрее соображать).

Лимит сегмента: определяет размер сегмента. Опять же, проц собирает в кучу поля красного цвета, и формирует конечный, 20- битовый адрес. Реальный лимит сегмента зависит от бита гранулярности (G-granularity);
- если бит гранулярности сброшен (0), то 20-битное значение и будет тем самым лимитом сегмента
- если бит гранулярности установлен (1), то всё 20-битное значение автоматически увеличивается в 1000h раз, т.е. если при G=0 мы измеряем размер в байтах, то при G=1 – в 4Кб единицах, (см. мультфильм «48 попугаев»).

Например, если G=1 и поле «Лимит сегмента» = 0000Fh (15 байт), то реальный лимит (читай – размер) данного сегмента равен 0Fh*1000h=0F000h (около 61 тысячи байт!).

Следует отметить, что если поле «Лимит сегмента» содержит значение равное 0, то это значит, что описуемый сегмент имеет размер в 1 байт (а не ноль!) при G=0, и размер в 4Кб при G=1. Т.е. сегмент никак не может иметь нулевую длину, минимум – 1 байт, максимум – 0хFFFFFh * 4Кб = 4 Гб.

Есть еще один бит, от которого зависит смысловое значение этого поля. Бит направления роста сегмента (B-big));
- если этот бит сброшен (0), то разрешены все смещения от 0 до лимита
- если установлен (1) – то все, кроме от 0 до лимита Но этот бит B несколько затуманивает понятие лимита, поэтому пока не бери в голову :)

В противном случае (если мы попытаемся обратится за пределы лимита) – возникнет исключение главной защиты (#GP) – страшная вещь! Вообще говоря, лимиты для этой цели и придуманы – отслеживать обращения в недоступные адресные пространства.

Еще один момент, который нигде в документации явно не указан. Лимит сегмента отсчитывается ОТ БАЗЫ СЕГМЕНТА, а не от нуля !!! Это совсем не ОЧЕВИДНО! (по крайней мере, я долго заблуждался…)

Тип:
Определяет тип сегмента (или шлюза, что такое шлюз – узнаете потом), определяет права доступа к сегменту и направление роста сегмента (помните бит B). Значение этого поля зависит от значения поля «Тип дескриптора» (S-descriptor type). Значение этого поля различно для разных типов сегментов (кода, данных и системного)

S (descriptor type) – флаг «тип дескриптора»:
Означает только одно: если сброшен (0), то описуемый сегмент – системный, если установлен (1) – это сегмент данных или кода. Подробности – в след. выпуске. И вообще привыкай: если что то непонятно – узнаешь об этом в следующем выпуске 100%. Или если не можешь спокойно спать – пиши мне (см. мыло винзу).

DPL (descriptor privilege level) – уровень привилегий дескриптора:
Определяет уровень привилегий сегмента. Т.к. это поле – двухразрядное, то соответственно может принимать только четыре различных значения (от 0 до 3). Самый крутой – нулевой уровень привилегий (ядро ОС). Это поле нужно для контроля за доступом к сегменту. Во всех подробностях распишу его назначение в последующих главах рассылки. Пока забудь о нем.

P (segment present flag) – флаг присутствия сегмента:
Если установлен, значит сегмент присутствует непосредственно в памяти; если сброшен – сами догадайтесь. Зачем оно нада: все видели и трогали мастдай, все знают что такое своп-файл. Вообщем, этот флаг предназначен для организации работы при использовании страничной адресации (дело в том, что когда в сегментный регистр грузят селектор на дескриптор, в котором сброшен этот бит – возникает исключение #NP (segment-not- present exeption)), поэтому, если отлавливать это самое #NP можно вовремя подгрузить новую страницу в ОП из файла подкачки. Страничная адресация ждет нас впереди!

G (Granularity) – флаг «гранулярности»:
См. «Лимит сегмента». Еще раз повторю - этот флаг влияет на лимит сегмента: если сброшен – лимит измеряется в байтах, если установлен – в 4 Кб единицах. Еще что запомни раз и навсегда: на адрес базы этот флаг НИКАКИМ БОКОМ НЕ ВЛИЯЕТ! Только на лимит! База ВСЕГДА измеряется в байтах! Clear? )

AVL (Available and reserved bits) – зарезервировано:
Это два битика (21-20 во втором двойном слове). Они вообще не стоят того, чтобы на них заострять внимание, но все же может кому и пригодиться: битик 20 может использоваться как угодно по вашему усмотрению :), битик 21 ВСЕГДА ДОЛЖЕН БЫТЬ РАВЕН НУЛЮ! ИНАЧЕ ГОВРОЯ - РУКАМИ НЕ ТРОГАТЬ!

Остался последний битик. Двадцать второй. D/B. Довольно мутный. Зависит от типа сегмента (в зависимости от этого он называется либо D, либо B). Учитывая то, что про него уже было сказано при описании лимита сегмента, следует отметить еще вот что:

Определяет разрядность сегмента. Если установлен – значит сегмент 32-х разрядный, если сброшен – 16-ти. Это общий случай. Теперь частные:

- Сегмент кода. Для сегмента кода данный флаг называется D и устанавливает длину по умолчанию для эффективных адресов и операндов в сегменте. Если установлен – то в сегменте допустимы 32-х битные адреса и 32-х битные ИЛИ 8-ми битные операнды; Если сброшен – 16-битные адреса и 16-битные ИЛИ 8-ми битные операнды. Но никто не мешает нам использовать префикс 66h (для изменения разрядности операндов) и префикс 67h (для изменения разрядности адресов).

- Сегмент стека. Для сегмента стека данный флаг называется B (big) флаг и устанавливает длину УКАЗАТЕЛЯ СТЕКА (регистр ESP) для команд push, pop и call. Если установлен – используется 32-х разрядный указатель стека (т.е. регистр ESP использован по максимуму), если сброшен – то используется только 16 бит (регистр SP, уже без буковки E).

Вот и все на сегодня. Кстати, если ты что то упустил или недопонял – ОБЯЗАТЕЛЬНО пиши на brokensword@ukr.net! Я об этом просил еще в первом выпуске и пришло аж ни одного письма! Ну, надеюсь, это потому, что все было ясно, как никогда ).

2002-2013 (c) wasm.ru