Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Orgevm_Ekzamen.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
998.59 Кб
Скачать

Описание сегментного механизма

Вначале рассмотрим еще раз (более подробно) формат сегментного регистра (рис. 50).

Тринадцать старших разрядов видимой части занимает селектор, адресующий дескриптор в одной из двух дескрипторных таблиц. В какой именно таблице находится этот дескриптор определяет бит TI. Если он равен 0 адресуется GDT, при TI=1 адресуется LDT. В теневой части МП хранит копию этого дескриптора.

Поле RPL задает «запрашиваемый уровень привилегий». Существуют три структуры, свя-занные с понятием уровня привилегий:

  • DPL. Это два бита в дескрипторе, задающие уровень привилегий сегмента;

  • CPL. Это два младших бита видимой части сегментного регистра cs, то есть это текущий уровень привилегий, на котором выполняется текущая программа (задача);

  • RPL. Это два младших бита слова (селектора), загружаемого в видимую часть любого сег-ментного регистра при смене сегмента.

При смене сегмента данных МП проверяет права доступа к новому сегменту, реализуя проверку неравенства:

DPL >= max { CPL, RPL }.

Если это условие не выполняется доступ к новому сегменту данных предоставлен не будет, а будет прерывание. При смене сегмента кода проводится более жесткая проверка:

DPL = max { CPL, RPL }.

Из всего сказанного выше можно сделать следующие выводы. Мы можем перейти к новому сег-менту данных, уровень привилегий которого равен нашему CPL или ниже его (по смыслу ниже, а по величине больше!) путем непосредственного обращения к дескриптору этого сегмента. Перейти же к более привилегированному (чем текущий CPL) сегменту данных не удастся, поскольку шлюзов для сегментов данных не существует. Для сегментов кода ситуация иная. Мы можем перейти к сегменту кода с таким же уровне привилегий (совпадающим с нашим CPL) обратившись к его дескриптору или перейти к более привилегированному сегменту кода через шлюз. Но мы не можем перейти к менее привилегированному сегменту кода, даже если он помечен как согласованный. Кроме того существу-ет правило, согласно которому текущий DPL стека должен равняться CPL. То есть уровень привиле-гий стека должен быть таким же как уровень привилегий текущей программы ( сегменты данных мо-гут быть менее привилегированными). За соблюдением этого правила следит сам МП, автоматически меняя стек при изменении уровня CPL на более высокий. Как он это делает будет показано в даль-нейшем.

Поле RPL иногда используется для понижения текущего уровня привилегий. Если мы хотим, чтобы RPL ни на что не влияло, надо брать RPL = 0. Например, RPL может использоваться в сле-дующей ситуации. Пусть у нас имеется привилегированная подпрограмма (нулевого уровня), к кото-рой мы можем обратиться с пользовательского (третьего) уровня через известный нам шлюз. Пусть эта подпрограмма записывает информацию в заказанную нами область памяти. Параметром, переда-ваемым в эту подпрограмму, является селектор дескриптора сегмента данных, в который мы запра-шиваем запись. Поскольку этот селектор формируем мы сами перед обращением к подпрограмме, у нас может возникнуть соблазн «обмануть» систему. Для этого мы записываем в этот селектор RPL = 0 и «просим» подпрограмму записать информацию в какой-нибудь системный сегмент (сегмент данных нулевого уровня). Если не предпринимать никаких мер, эта попытка будет успешной , так как под-программа имеет CPL = 0 и наше RPL = 0. Процессор отследить такие ситуации не может, они для него слишком сложные. Однако эту ситуацию может отследить сама подпрограмма. Для этого, полу-чив селектор, она определяет CPL задачи, которая ее вызвала. Сделать это ей нетрудно, поскольку в ее стеке лежит адрес возврата в исходную программу. Определив, что вызов был с третьего уровня, подпрограмма меняет RPL в переданном ей селекторе с нуля на тройку, понижая тем самым собст-венный уровень привилегий. В результате мы не сможем обратится к заказанному сегменту данных, если его уровень привилегий выше трех.

Далее рассмотрим работу сегментного механизма при обращении в текущем сегменте, допус-тим на примере выполнения команды mov [bx+2] ,al .

  • МП вычисляет Аэф. Для нашей команды Аэф = (bx)+2.

  • МП проверяет не выводит ли полученный Аэф за заданные границы сегмента. Размер сег-мента МП ( для рассматриваемой команды) возьмет из теневой части сегментного регист-ра ds.

  • МП проверяет соответствие выполняемой команды заданным атрибутам сегмента. Атри-буты он также возьмет из теневой части ds. Для рассматриваемой команды будет произве-дена проверка «разрешен ли сегмент для записи».

  • Если обе проверки прошли успешно МП формирует физический адрес по формуле Аф = начальный адрес сегмента + Аэф. Начальный адрес сегмента он также возьмет из те-невой части ds.

  • Если какая-то из проверок была неудачной МП генерирует соответствующее прерывание.

Рассмотрим далее работу сегментного механизма при смене сегмента. Чтобы перейти к новому сегменту (сменить сегмент) надо загрузить новый селектор в видимую часть соответствующе-го сегментного регистра. Для регистра cs здесь можно использовать команды jmp far, call far и дру-гие, а для остальных сегментных регистров - mov sr , r 16 ; pop sr и ряд других.

МП берет загружаемый селектор и по биту TI определяет на какую дескрипторную таблицу он ссылается. Затем МП проверяет не выводит ли этот селектор за заданные (в gdtr или ldtr) размеры таблицы. Если не выводит, МП обращается в таблицу и находит там адресуемый дескриптор. Произ-водится ряд проверок (в частности проверяются права доступа) и, если все они прошли удачно, в те-невую часть сегментного регистра ( в который команда загружает селектор !) копируется найденный дескриптор, а в видимую часть этого регистра из команды загружается селектор.

Рассмотрим примерную последовательность действий МП при выполнении команды pop ds. Эта команда выталкивает из стека в видимую часть ds новый селектор и следовательно должна (если все проверки пройдут успешно) привести к смене сегмента данных. Однако сначала МП еще должен найти в стеке этот селектор. Поэтому вначале выполнения этой команды идет обращение в текущем сегменте стека.

  • МП вычисляет Аэф = (sp).

  • Проверяет не выводит ли этот адрес за заданные границы стека. Размер стека он берет из теневой части ss.

  • Если проверка прошла удачно МП берет из теневой части ss начальный адрес сегмента стека и формирует Аф = начальный адрес + Аэф. По этому адресу из ОП считывается слово, представляющее из себя (по смыслу команды) новый селектор. Только с этого момента действительно начинается смена сегмента.

  • По биту TI определяется дескрипторная таблица.

  • Проверяется не выводит ли селектор за заданные размеры таблицы.

  • В таблице отыскивается адресуемый дескриптор.

  • Проверяется находится ли сегмент в ОП (по информации в дескрипторе).

  • Проверяются права доступа.

  • Проверяется отмечен ли адресуемый дескриптор как дескриптор сегмента данных (по-скольку в команде указан ds !) или как сегмент кода, разрешенный для чтения.

  • Если все проверки прошли успешно в теневую часть ds загружается копия найденного де-скриптора и далее мы работаем с новым сегментом данных.

Далее приведем требования к сегментам, загружаемым в различные сегментные регистры про-цессора:

  • В cs можно загружать только дескрипторы сегментов кода. Отметим здесь, что запись в ко-довый сегмент всегда запрещена.

  • В ds, es, fs и gs можно загружать дескрипторы сегментов данных и дескрипторы сегментов кода, но последние должны обязательно быть разрешены для чтения (что это за сегмент данных из которого нельзя даже прочитать информацию).

  • Наиболее жесткими являются требования для регистра ss. В этот регистр можно загружать только дескрипторы сегментов данных, обязательно разрешенные для записи, у которых dpl = cpl и биты G и D в дескрипторе ( смотри формат дескриптора ) равны между собой.

При любом нарушении вышеперечисленных условий будет прерывание.

Сегментный механизм в защищенном режиме выключить нельзя, но его можно подавить. Для этого надо обеспечить загрузку в теневые части всех сегментных регистров дескрипторов, описы-вающих один и тот же сегмент. Обычно берется сегмент с начальным адресом 00000000h, имеющий размер 4 Гбайта и уровень привилегий 0 или 3. После этого содержимое сегментных регистров не меняется. Таким образом мы все время работаем в одном сегменте, в котором у нас располагаются и программа, и стек и данные. К тому же, так как начальный адрес этого сегмента равен нулю, адрес, поставленный программистом в команде будет сразу физическим адресом и при этом адресуемый объем памяти равен 4 Гбайта ! Это, очевидно, весьма удобно. Такая безсегментная память называется линейной (или плоской – flat) памятью. Однако такой способ организации памяти имеет и существенные недостатки: теряются механизм защиты и многозадачность. Страничный механизм при такой организации использовать можно. При этом появляется механизм защиты на уровне страниц. В минимальном случае при организации линейной памяти достаточно иметь GDT, содержащую два дескриптора (один кода, а другой данных).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]