Заказать дизайн упаковки - pазработка дизаи на упаковки заказать svoemnenie.com.
В защищенном режиме схема вычисления линейного адреса аналогична схеме реального режима в том отношении, что линейный адрес, как и в реальном режиме, получается сложением базового адреса сегмента и значения offset (см. рисунок ниже).
Разница состоит в следующем:
1) Базовый адрес каждого из шести сегментов хранится в не видимом программисту (теневом) "продолжении" соответствующего сегментного регистра и имеет длину 32 бита (4 байта). Теневая часть сегментного регистра имеет длину 8 байтов (64 бита).
2) Логический адрес (offset), как для кода, так и для данных, — имеет длину 32 бита (4 байта).
3) Диапазон значений линейных адресов определяется длиной линейного адреса, которая также составляет 32 бита. Таким образом, базовый адрес задает положение начала сегмента, которое может располагаться в любом месте диапазона линейных адресов.
4) Длина сегмента в защищенном режиме не фиксирована, а задается 20-битовым полем Limit (предел), которое вместе с базовым адресом находится в теневой части сегментного регистра. Длина сегмента может иметь величину от 1 байта до 4 Гбайтов.
5) При выполнении команды процессор сравнивает значение offset с длиной сегмента. Если величина offset превышает размер сегмента (т.е. программа пытается обратиться за границу сегмента), выполнение данной команды останавливается и генерируется прерывание по исключительной ситуации.
6) Если предел не превышен, то вычисляется линейный адрес, и выполнение команды продолжается (и завершается).
Кроме базового адреса (32 бита) и длины сегмента (20 битов), в теневой части каждого сегментного регистра хранится еще ряд характеристик (атрибутов) данного сегмента. Они, в совокупности с базовым адресом и длиной, образуют дескриптор (описатель) сегмента.
Для работы одной программы необходимо определить хотя бы четыре сегмента:
•сегмент кода cs,
•сегмент стека ss,
•два сегмента данных ds и es.
Однако защищенный режим процессоров х86 предназначен для многозадачной работы, когда в памяти ЭВМ одновременно находятся и попеременно (во времени) выполняются несколько программ. Дескрипторы сегментов программ формируются операционной системой в специальных системных структурах данных (дескрипторных таблицах) при подготовке программы к выполнению. Дескрипторные таблицы постоянно хранятся в ОЗУ.
При загрузке ОС вначале работают программы реального режима, котрые создают дескрипторные таблицы и определяют дескрипторы для компонентов ОС, после чего процессор переводится в защищенный режим.
При последующей работе ОС для каждой загружаемой программы определяет несколько сегментов, для каждого сегмента заводит дескриптор и задает для сегмента длину и атрибуты. В ходе попеременной работы нескольких программ часть этих сегментов (или даже все) оказываются загруженными в ОЗУ. Для всех сегментов, загруженных в ОЗУ, операционная система определяет и записывает в дескриптор базовый адрес в линейном адресном пространстве.
Каждая задача, выполняемая на компьютере, может иметь собственную локальную дескрипторную таблицу (Local Descriptor Table, LDT), содержащую описания сегментов (а также и других объектов), доступных только этой задаче. Кроме того, имеется одна глобальная дескрипторная таблица (Global Descriptor Table, GDT), которая содержит описания сегментов, потенциально доступных любой задаче. Каждый из шести сегментных регистров содержит двоичное слово, называемое селектором сегмента (детали см. далее). Селектор сегмента однозначно задает дескриптор сегмента, который используется процессором в данный момент.
Схема трансляции адреса с использованием GDT приведена на рисунке ниже.
Схема трансляции адреса с использованием LDT приведена ниже.
Рассмотрим форматы отдельных элементов. Формат селектора сегмента представлен на рисунке ниже.
Поле INDEX указывает номер дескриптора в таблице дескрипторов. Таблица дескрипторов также представляет собой сегмент размером до 64 Кбайт и может содержать до 8192 элементов.
Поле TI (Table Indicator) выбирает одну из двух дескрипторных таблиц: глобальную GDT или локальную LDT. Каждой задаче могут быть доступны две дескрипторные таблицы, а общее максимальное количество сегментов составляет 16384. (Следует помнить, что часть дескрипторов всегда занята под служебные нужды, сами дескрипторные таблицы тоже представляют собой сегменты, нулевой дескриптор в таблице не допускается использовать, и т.п.)
Двухбитовое поле RPL указывает запрошенный программой уровень привилегий (см. далее) и используется при защите памяти.
Рассмотрим подробнее формат дескриптора сегмента (см. рисунок ниже).
32-битовое поле базового адреса используется при вычислении линейного адреса в соответствии с вышеприведенной схемой.
20-битовое поле предела (Segment Limit) содержит размер сегмента. В зависимости от значения бита G (Granularity), этот размер может быть указан в байтах (при G=0 — максимальный размер сегмента 1Мбайт), либо в 4К-страницах (при G=1 — максимальный размер сегмента 212220 = 4Гбайт). Таким образом, размер сегмента может быть задан в пределах от 1 байта до 4 Гбайт (в отличие от реального режима, где размер сегмента равен 216 байт и фиксирован).
Однобитовый признак размера операнда D/B задает размер операнда по умолчанию, используемого командой при обращении к данному сегменту.
Двухбитовое поле уровень привилегий сегмента DPL (Descriptor Privilege Level) используется механизмом защиты памяти.
Бит присутствия P (Segment Present). Бит присутствия может быть установлен либо сброшен программно, аппаратно только анализируется его состояние. Нулевое значение этого бита при обращении к сегменту вызывает прерывание по исключительной ситуации. Этот бит может быть использован разработчиком операционной системы для "маркировки" сегментов, загруженных в данный момент в физическую память. Этот бит, в частности, может быть использован для органиации виртуальной памяти на уровне замены сегментов.
Бит S равен 0 в дескрипторах сегментов, содержащих код или данные и равен 1 для системных дескрипторов (описывающих сегменты, содержащие дескрипторные таблицы, а также еще ряда других, которые будут рассмотрены позже).
Поле TYPE в дескрипторах системных сегментов обозначает один из 12 возможных типов, а в дескрипторах сегментов кода или данных на этом месте содержатся дополнительные битовые поля, которые будут далее рассмотрены.
Байт, включающий поля P, DPL, S, TYPE носит название байт доступа. Бит 21 старшего слова дескриптора имеет предопределенное значение 0, а бит AVL может использоваться системным ПО как флаг общего назначения.
При рассмотрении механизма формирования линейного адреса при трансляции сегмента возникают следующие вопросы:
1) Откуда берутся дескрипторные таблицы и конкретные значения полей в дескрипторах?
2) Базовые адреса сегментов хранятся в дескрипторах, находящихся в дескрипторной таблице в основной памяти. Если в ходе трансляции сегментов при выполнении каждой команды требуется (возможно неоднократно) обращаться за значениями базовых адресов в основную память, команды в защищенном режиме должны выполняться гораздо медленнее, нежели в реальном. Так ли это?
Ответим на эти вопросы.
Дескрипторные таблицы создаются и заполняются при инициализации операционной среды компонентами операционной системы. Это означает, что, если в реальном режиме процессор способен немедленно после включения выбирать (fetch) и выполнять команды, то для того, чтобы выполнить хотя бы одну команду в защищенном режиме, должна быть создана хотя бы одна дескрипторная таблица (GDT), содержащая хотя бы один дескриптор, описывающий сегмент с кодом программы, а, если в программе содержатся команды обращения к памяти, то требуется наличие еще одного дескриптора, описывающего сегмент данных.
Для ускорения процедуры трансляции сегментов, как уже было отмечено, дескрипторы сегментов, селекторы которых загружены в сегментные регистры, скопированы в невидимые "теневые" 8-байтовые "продолжения" сегментных регистров. Именно из теневых частей (быстро !) извлекается значение базового адреса при трансляции сегмента (см. рисунок ниже).
Когда происходит загрузка дескриптора в теневой регистр? Это происходит при выполнении команд, изменяющих содержимое "обычных" сегментных регистров (команды mov seg_reg, reg; lds; les; lfs, lgs, lss, jmp far, call far, int n,…). При выполнении подобных команд в защищенном режиме, процессор не только помещает новое значение (селектор сегмента) в видимую часть сегментного регистра, но и загружает из соответствующей дескрипторной таблицы восьмибайтовый дескриптор в теневую часть сегментного регистра. Вследствие этого команды, изменяющие содержимое сегментных регистров в защищенном режиме выполняются значительно дольше, чем в реальном.
Как процессор находит дескриптор? Для этого ему надо знать адрес начала (базовый адрес) дескрипторной таблицы и расположение в ней нужного дескриптора (смещение). Индекс дескриптора содержится в селекторе, загружаемом в сегментный регистр. Для хранения базовых адресов дескрипторных таблиц в архитектуру процессоров 386+ было введено несколько новых регистров GDTR, LDTR, IDTR, TR (см. рисунок ниже). Рассмотрим их назначение.
Глобальная дескрипторная таблица хранится в отдельном сегменте памяти. 32-битовый базовый адрес этого сегмента и его 16-битовая длина хранятся в регистре GDTR (Global Descriptor Table Register). Таким образом, максимальная длина таблицы составляет 64 Кбайт, в ней может максимально содержаться 8192 дескриптора.
Локальные дескрипторные таблицы могут создаваться индивидуально для каждой задач. Каждая локальная дескрипторная таблица также хранится в отдельном сегменте, который описывается дескриптором, хранимым в GDT. При запуске данной задачи ее локальная дескрипторная таблица активизируется путем записи селектора ее дескриптора в 16-битовый регистр LDTR (Local Descriptor Table Register). При этом автоматически загружается теневая часть этого регистра, куда переносятся из GDT базовый адрес LDT и ее предел, а также битовые поля атрибутов сегмента.
Регистр IDTR (Interrupt Descriptor Table Register) хранит базовый адрес и длину сегмента, содержащего таблицу дескрипторов прерываний. Дескриптор прерывания выполняет в защищенном режиме те же функции, что вектор прерывания в реальном режиме.
Наконец, регистр задачи TR (Task Register) содержит селектор сегмента задачи TSS (Task State Segment). Его назначение рассматривается в разделе, посвященном поддержке многозадачности.
Рассмотрим более подробно схему обращения к памяти в защищенном режиме.
1) После получения команды на запуск программы операционная система загружает в память первый сегмент кода программы, заполняет в соответствующем дескрипторе поля базы и предела, устанавливает в 1 бит присутствия, а затем передает управление на первую команду программы. При этом перезагружается новым значением селектора сегментный регистр cs. Используя поле index этого селектора, процессор находит в дескрипторной таблице дескриптор соответствующего сегмента кода и переносит его в теневую часть регистра cs.
2) Положение объекта (команды или элемента данных) в памяти задается парой значений seg:offset. Значение seg — селектор сегмента — находится в сегментном регистре. Значение offset для выборки команды берется из счетчика команд, а для элемента данных аппаратно вычисляется процессором в соотвествии с используемым способом адресации. При обращении к памяти, процессор вычисляет линейный адрес. Для этого он складывает значение базового адреса сегмента (из теневой части сегментного регистра) со значением offset и производит обращение к памяти.
3) Если при выполнении команды оказывается, что сегмент, индекс которого используется в команде, отстутствует в памяти (процессор "узнает" об этом, проверяя значение бита присутствия), происходит прерывание по исключительной ситуации. Управление передается операционной системе, и она переносит недостающий сегмент в память с диска, заполняет поля базы и предела в дескрипторе, устанавливает в 1 бит присутствия, а затем (возвратом из прерывания) возвращает управление на ту же команду. Теперь эта команда может выполниться до конца.
4) При выполнении каждой команды аппаратура процессора проверяет выполнение ряда условий (наличие сегмента в памяти — одно из этих условий). Если условие не выполняется, то выполнение команды прекращается и происходит прерывание по исключительной ситуации — это общий принцип срабатывания механизмов защиты.
Сегментный механизм можно использовать для организации виртуальной памяти. Однако это оказалось очень неудобным, так как обычно сегменты имеют разный размер и располагаются в памяти с произвольного адреса. При свопинге (замене) сегментов пространство памяти вследствие этого фрагментируется и, тем самым, расходуется нерационально. Сегментный механизм появился в семействе х86, начиная с модели i80286. Однако работоспособной ОС с виртуальной памятью на базе этого процессора, которая стала бы сколько-нибудь популярной, так и не было разработано. В процессорах 386+ в дополнение к сегментному механизму был разработан страничный механизм трансляции адресов (см далее).
Задаче могут быть доступны две дескрипторные таблицы: GDT и LDT, каждая из которых может содержать до 8192 (213) дескрипторов сегментов. Каждый сегмент может иметь размер до 4 Гбайт (232 байт). Таким образом, ограничение сверху на размер логического адресного пространства составляет 2+213+232=246 байт.
Естественно, такой объем еще весьма долго не сможет целиком поместиться в физической памяти компьютера (для процессоров х86 ее размер ограничен величиной 232 байт). Однако при наличии виртуальной памяти ограничение размера физической памяти лишь замедлит выполнение очень большой программы (за счет потерь на обмен сегментов между памятью и диском).