А..Ю. Physics Faculty, Electronic Devices & Systems, 7th
semester,2010 Dr. Mokhovikov Alexander YurievichДескрипторы и таблицы. Переключение задач: Начало.
Дескрипторы и таблицы. Переключение задач: Начало.
Основные положения защищенного режима
Основные положения защищенного режима
Основные положения защищенного режима
Процессор может обраться только к тем сегментам памяти, для которых имеются дескрипторы в таблицах.
Дескрипторы выбираются с помощью 16-битных селекторов, программно загружаемых в сегментные регистры.
Индекс совместно с индикатором таблицы TI позволяет выбрать дескриптор из локальной(TI =1) или глобальной(TI=0) таблицы дескрипторов.
Для неиспользуемых сегментных регистров предназначен нулевой селектор сегмента , формально адресующийся к самому первому элементу глобальной таблицы.
Попытка обращения к памяти по такому сегментному регистру вызовет исключение. Исключение возникает и при попытке загрузки нулевого селектора в регистре CS и SS. Поле RPL указывает требуемый уровень привилегий.
Основные положения защищенного режима
Как отмечалось выше, защищенный режим сохранил сегментную модель памяти (адрес ячейки памяти определяется суммой компонент: адрес начала сегмента и внутрисегментного смещения).
Но! в отличие от режима реального адреса, где адрес сегмента находился непосредственно в одном из сегментных регистров – алгоритм формирования физического адреса в защищенном режиме абсолютно иной.
Сегмент, в защищенном режиме, это не просто область памяти, ограниченная лишь максимально допустимым значением внутрисегментного смещения, как это было в реальном режиме, - это «объект», который имеет строго определенный размер,
не пересекается с другими сегментами (хотя один и тот же сегмент можно описать дважды)
и имеет ряд других атрибутов, по которым, в частности, происходит аппаратная защита памяти со стороны процессора.
Каждый сегмент имеет свой дескриптор (описатель сегмента).
Дескрипторы сегментов собираются в специализированных системных сегментах – дескрипторных таблицах.
Основные положения защищенного режима
Существует три типа дескрипторных таблиц – глобальная таблица дескрипторов (одна в системе); локальная таблица дескрипторов (своя для каждой задачи); таблица дескрипторов прерываний
Каждый дескриптор (элемент) таблицы описывает свой сегмент памяти.
Сегменты памяти не пересекаются!
Адрес начала каждой из таблиц (указатель на начало таблицы) хранится в специальных (программно доступных) регистрах процессора.
Указатели на таблицу глобальных дескрипторов (GDTR) и таблицу прерываний (IDTR) имеют размер 48 байт, 32 из которых указывают линейный адрес начала таблицы, а остальные 16 – ее размер (предел).
У регистра-указателя локальной дескрипторной таблицы (LDTR) программно доступно только 16-битное поле селектора (индекса для GDT), по которому из GDT автоматически загружаются программно недоступные и невидимые поля базового адреса и размера таблицы.
Регистр LDTR указывает на дескриптор в GDT, описывающий локальную дескрипторную таблицу для текущей задачи.
Основные положения защищенного режима
Команды загрузки регистров-указателей таблиц (GDTR, LDTR, IDTR) являются привилегированными (выполняются только на нулевом кольце привилегий
Глобальная таблица (GDT) содержит дескрипторы, доступные все задачам. Может содержать дескрипторы любых типов, кроме дескрипторов прерываний и ловушек
Локальная таблица (LDT) может быть собственной для каждой задачи и может содержать только дескрипторы сегментов, шлюзов задачи и вызовов. Сегмент недоступен задаче, если его дескриптора нет ни в LDT, ни в GDT.
Дескрипторные таблицы создаются и поддерживаются операционной системой.
Нулевой элемент этой таблицы процессором не используется.
Основные дескрипторы подразделяются на следующие категории:
Дескрипторы адресных пространств:
Сегмент кода
Сегмент данных
Сегмент состояния задачи
2. Дескрипторы системных объектов:
Шлюз вызова*
Шлюз задачи
Шлюз прерывания
Шлюз ловушки
Таблицы локальных дескрипторов
* - ограниченно совместим.
Дескрипторы и таблицы дескрипторов
Адрес сегмента – физический адрес начала сегмента (если нет страничного преобразования);
Размер - размер сегмента (Размер сегмента – 1);
Байт доступа – содержит информацию о защите сегмента;
D - бит разрядности выполняемых команд (для кодового сегмента):
0 – 16-разрядные;
1 – 32-разрядные
G - признак единицы измерения сегмента:
0 – в байтах;
1 – в страницах (по 4 Кб), при использовании страничной адресации памяти;
AVL - сегмент доступен для использования системным программным обеспечением (используются только ОС);
Дескрипторы и таблицы дескрипторов
Дескрипторы системных сегментов имеют следующий формат:
Системные сегменты предназначены для хранения локальных таблиц дескрипторов LDT и состояния задач TSS (Task State Segment)
Их дескрипторы определяют базовый адрес, лимит сегмента (1-64 Кбайт), права доступа (чтение, чтение/запись, только исполнение кода или исполнение/чтение) и присутствие сегмента в физической памяти.
В байте управления доступом у этих дескрипторов бит Р определяет действительность (Р=1) или недействительность (Р=0) содержимого сегмента.
Поле уровня привилегий DPL используется только в дескрипторах сегментов состояния задач (TSS). Поскольку обращение к дескрипторам LDT возможно только по привилегированным командам, поле DPL для дескрипторов локальных таблиц не используется
. Поле ТYPE (1-3, 9-В) определяет тип сегмента.
Общие поля-характеристики для обеих групп дескрипторов:
Дескрипторы и таблицы дескрипторов
1. Наличие в ОЗУ [P - бит присутствия]
2. Уровень привилегий [DPL - 2 бита уровня доступа]
3. Расширенный тип* [ETYPE - 5 бит расширенного типа]
* Расширенный тип введен для приведения всех типов дескрипторов разных групп к общему типу. Он учитывает значение поля S - системный бит.
Выделим общие поля-характеристики дескрипторов 1 группы:
1. Разрядность[D - бит разрядности, 16 бит/32 бита]
2. Гранулярность [G - бит дробности, 1 байт/4Кб]
3. Сегмент/системный объект [S - бит типа сегмент/объект]
4. Собственные нужды ОС[AVL - бит нужд ОС]
5. Базовый адрес [BASE - 32 бита базового адреса]
6. Предел сегмента [LIMIT - 20 бит размера сегмента]
Дескрипторы и таблицы дескрипторов
Выделим общие поля-характеристики дескрипторов 2 группы:
1. Смещение[OFFSET - 32 бита смещения]
2. Селектор [SELECTOR - 15 бит]
3. Константа [CONST - 3 бита = 000]
Дескрипторы и таблицы дескрипторов
Для 2 группы дескриптор типа A является ограниченно совместимым c другими дескрипторами этой группы из-за наличия поля COUNT - количество параметров 5 бит. В принципе, это поле в других сегментах можно выделить как резерв.
!
Дескрипторы и таблицы дескрипторов
Таким образом, выделим две структуры данных для класса дескрипторов:
«дескриптор пространства» - группа 1:
struct s_DSpace
{
word wLimit;
word wBase_I;
byte bBase_II;
byte bAttr_I;
byte bAttr_II;
byte bBase_III;
};
«дескриптор системных объектов» - группа 2:
struct s_DSysObj
{
word wOffset_I;
word wSelector;
byte bCount;
byte bAttr;
word wOffset_II;
};
«вспомогательное представление дескриптора» - группы 1 и 2:
struct s_DVector
{
dword dwVec_I;
dword dwVec_II;
};
Дескрипторы и таблицы дескрипторов
Соответственно, должны существовать два класса дескрипторов, производных от одного общего класса дескрипторов, включающего общие методы работы со всеми типами дескрипторов.
class c_Descriptor
{
private:
union
{
s_DSpace s_Space;
s_DSysObj s_SysObj;
s_DVector s_Vector;
} u_Vector;
public:
c_Descriptor(e_DPLevel e_Level, s_ExtType s_EType, e_SgmState e_State);
~c_Descriptor();
void Level_Set (e_DPLevel e_Level);
void EType_Set (s_ExtType s_EType);
void Addr16(void);
void Addr32(void);
void Present (void);
void UnPresent (void);
bool IsSgmRAM (void);
};
class c_DSpace : private c_Descriptor
{
public:
c_DSpace();
~c_DSpace ();
void DSpace_Set (void *vBase, s_SpcLimit s_Limit, s_SpcType s_Type);
void Base_Set (void *vBase);
void Limit_Set (s_SpcLimit s_Limit);
void Type_Set (s_SpcType s_Type);
};
Основная нагрузка для общего класса дескрипторов ляжет на создание дескриптора с заданным уровнем приоритета объекта, наличием в ОЗУ и расширенным типом, который описывается данным дескриптором и методами изменения этих параметров.
Дескрипторы и таблицы дескрипторов
Разберемся с дополнительными типами.
Рассмотрим тип s_SpcLimit - определяемый дескриптором размер сегмента:
Поскольку он неотделим от характеристики грануляции сегмента и его разрядности и никогда не превышает 20 байт, то есть смысл объединить их в структуру:
Значение типа уровня доступа находится в интервале 0..3, однако лучше всего будет сдвинуть его влево на 5 бит для удобства работы:
enum e_DPLevel
{
k_KLvl = 0,
k_DLvl = 1 << 5,
k_SLvl = 2 << 5,
k_ALvl = 3 << 5
};
Точно так же поступаем с типом e_SgmState, подменяющим флаг присутствия отождествляемого дескриптором объекта в оперативной памяти компьютера:
enum e_SgmState
{
k_Swap = 0,
k_RAM = 1 << 7
};
Дескрипторы и таблицы дескрипторов
Тип «дескриптора пространства» - это перечисление возможных типов сегментов, без учета бита ACCESSED. Так как установка этого бита - прерогатива процессора.
0. Пространство данных только для чтения с увеличением границы вверх
1. Пространства данных с возможностью записи с увеличением границы вверх
2. Пространство данных только для чтения с увеличением границы вниз
3. Пространство данных с возможностью записи с увеличением границы вниз
4. Пространство неподчиненного кода с запретом чтения
5. Пространство неподчиненного кода c возможностью чтения
6. Пространство подчиненного кода с запретом чтения
7. Пространство подчиненного кода c возможностью чтения
В этом случае преобразование e_SpcType -> s_SpcType будет выполняться сдвигом влево на один бит, с установкой бита 4,
S [Segment] = 1.
Необходимо отметить!, что дескрипторы, как элемент данных, имеют четкое местоположение в памяти - дескрипторные таблицы GDT, LDT, IDT. Потому создание дескриптора должно быть привязано по месту его «прописки». Обеспечить это можно обращением к дескриптору через метод выделения дескриптора в соответствующей ему таблице, инкапсулируемой классом. Создание дескриптора традиционным способом - оператором new, приведет лишь к созданию неработоспособной копии объекта.
Рассмотрим создание дескриптора в таблице GDT:
Дескрипторы и таблицы дескрипторов
c_Descriptor *pc_DExample = GDT.DAlloc();
Вызов метода DAlloc (Allocate Descriptor) произведет необходимые действия с таблицей GDT:
1.Изменение части LIMIT регистра GDTR на длину дескриптора.
2.При необходимости, выделение дополнительной памяти под таблицу дескрипторов
3. Возвращение указателя на работоспособный дескриптор.
Далее, необходимо использовать конструктор дескриптора.
Случай 2 может потребовать манипуляций со страницами памяти, так как хотелось бы избавиться от излишнего перемещения данных из области GDT в новое место при нехватке памяти в заранее выделенной под GDT (при работе еще 16 битного кода загрузчика) куче, кратной размеру страницы [4Kb = 4096 байта].
Дескрипторы и таблицы дескрипторов
Приступим к расширенному полю ETYPE.
Необходимо отметить!, что это достаточно синтетическое поле и его прямая задача объединить типы разных групп дескрипторов в одну, за счет выделения 5 бита - S (системный дескриптор).
Опять-таки, поле ETYPE является простейшим перечислением входящих комбинаций простых типов s_SpcType и s_SysType.
Рассмотрим системный набор дескрипторов s_SpcType:
1. [0001] Свободный TSS - 16 бит 9. [1001] Свободный TSS - 32 бит
2. [0010] Локальная таблица дескрипторов (LDT)
3. [0011] Занятый TSS - 16 бит 11. [1011] Занятый TSS - 32 бит
4. [0100] Шлюз вызова - 16 бит 12. [1100] Шлюз вызова - 32 бит
5. [0101] Шлюз задачи
6. [0110] Шлюз прерывания - 16 бит 14. [1110] Шлюз прерывания - 32 бит
7. [0111] Шлюз ловушки - 16 бит 15. [1111] Шлюз ловушки - 32 бит
Как видно из таблицы, системные дескрипторы за исключением 2, 5 определяются симметрично относительно 4-ого бита. Таким образом, можно свести системные объекты в перечисление:
Дескрипторы и таблицы дескрипторов
Дескрипторы первой и второй группы сходны в определении разрядности (16/32) отождествляемых с ними объектов. Поэтому в c_Descriptor присутствуют методы Addr16 и Addr32. Методы по биту S [Segment] могут различить тип дескриптора и установить, соответственно, либо бит 4 поля ETYPE (за исключением LDT и TaskGate типов), либо бит D/B поля dwVec_II.
void c_Descriptor :: Addr16(void)
{
register s_ExtType s_EType = (s_ExtType) u_Vector.s_SysObj.bAttr;
if (s_EType.IsSystem())
s_EType.u_ExtType.s_SysObj.Addr16();
else
((s_SpcLimit) u_Vector.s_Vector.dwVec_II).Addr16();
}
void c_Descriptor :: Addr32(void)
{
register s_ExtType s_EType = (s_ExtType) u_Vector.s_SysObj.bAttr;
if(s_EType.IsSystem ())
if((s_EType.u_ExtType.s_SysObj.bValue != k_LDT) &&
(s_EType.u_ExtType.s_SysObj.bValue != k_TaskGate))
s_EType.u_ExtType.s_SysObj.Addr32();
else
((s_SpcLimit) u_Vector.s_Vector.dwVec_II).Addr32();
}
Дескрипторы и таблицы дескрипторов
При создании же дескриптора конструктором c_Descriptor бит D/B или бит 4 поля ETYPE уже установлен в 1. Это означает, что все дескрипторы пространств и системных объектов в системе создаются 32 битными по умолчанию.
А для принудительного их перевода в 16 битный вид необходимо запросить метод дескриптора Addr16().
inline c_Descriptor :: c_Descriptor(e_DPLevel e_Level, s_ExtType s_EType, e_SgmState e_State)
{
u_Vector.s_Dspace.bAttr_I = e_Level | s_EType | e_State;
}
Объединение типов s_SpcType и s_SysType дает расширенный тип:
Дескрипторы и таблицы дескрипторов
Рассмотрим теперь путь исполнения, проделываемый в случае вызова одного из конструкторов c_DSpace или c_DSystem.
Процедура Expand_ROR разводит верхнее слово базового адреса пространства, так как оно должно выглядеть в дескрипторе и представляет собой специфический для Watcom asm макрос:
Дескрипторы и таблицы дескрипторов
extern Expand_ROR(dword dwBase);
#pragma aux Expand_ROR=\
"shr eax, 16"
"xchg ah, al"
"ror eax, 8"
parm [eax] \
value [eax] \
modify [eax];
Схема «эволюции» базового адреса с помощью макроса Expand_ROR
Таким образом, выделяются два вида владельцев дескрипторов: «системный объект» и «пространство». Они получают адрес дескриптора от объектов GDT, LDT, IDT, а затем осуществляют необходимые изменения в нем.
Дескрипторы и таблицы дескрипторов
Глобальная таблица дескрипторов начинает формироваться на самой ранней стадии загрузки ядра. Практически, ее содержимое (дескрипторы) сформировано еще на стадии компиляции исходного кода при помощи макрокоманд препроцессора С++ как массив константных значений типа s_DVector. В макрокоманде m_DATA_DESCRIPTOR используются все те же типы переменных, что и для класса c_DSpace:
#define k_4Kb 0x00800000 \\ Гранулярность сегмента = 4 кБ
#define k_1Bt 0x00000000 \\ Гранулярность сегмента = 1 Байт
#define k_D32 0x00400000 \\ Разрядность сегмента = 32 бита
#define k_D16 0x00000000 \\ Разрядность сегмента = 16 бит
#define m_DATA_DESCRIPTOR(dwLim, dwBAddr, e_State, e_Level, e_Type, dwGranulate, dwD)\
{\
(dwLimit & 0x0000FFFF) | (dwBAddr << 16),\
(dwBAddr & 0xFF000000) | ((dwBAddr & 0x00FF0000) >> 16) |\
((((dword)(e_State | e_Level | e_Type) << 8) | 0x00001000) & 0x0000FF00) |\
dwGranulate | dwD \
}
Сам массив GDT определяется обязательно с выравниванием на параграф следующим образом:
#pragma pack(16) \\ Установим выравнивание на параграф (= 16 байт)
s_DVector GDT[M] = {
…………………………………………………………………
…………………………………………………………………
};
#pragma pack(0) \\ Восстановим предыдущее значение выравнивания
Дескрипторы и таблицы дескрипторов
Содержимое массива определяется нуждами ядра на момент его перехода в 32-разрядный защищенный режим процессора (далее просто PM). Проанализируем нужды ядра на момент перехода его в PM:
1. Код ядра, лежащий в ОЗУ в 32 р-р сегменте кода, с грануляцией в 1 байт и уровнем привилегий k_KLvl. Протяженность данного сегмента определяется длиной оставшегося участка кода от места исполнения процессором команды, являющейся первой после перехода в PM и очистки конвейера процессора межсегментным, длинным переходом (FAR JMP) на эту команду. Соответственно базовый адрес сегмента также должен начинаться с этой же команды. Таким образом, становится возможным избавиться от 16 р-р кода первичного загрузчика, освобождая участок ОЗУ. Тип сегмента - k_ERCode.
2. Данные ядра, совпадающие по базовому адресу с сегментом кода ядра, 32 р-р, грануляция в 1 байт, с уровнем привилегий k_KLvl. Протяженность сегмента до конца доступного 32 р-р адресного пространства процессора. Это необходимо для того, чтобы смещение, рассчитанное компилятором заранее для данных (глобальные переменные) оставалось тем же, а также для размещения за границей сегмента кода ядра, "кучи" ядра максимальной длины, в которой динамически будут распределяться объекты ядра. Тип сегмента - k_RWDataUp
3. Стек ядра 32р-р, с грануляцией 1 байт, являющийся простым сегментом данных (с увеличением границы сегмента в сторону увеличения 32 р-р адреса). Протяженность сегмента стека выбрана таким образом, чтобы он заканчивался непосредственно перед сегментом кода ядра, начинаясь со смещения 0x00000000 (базовый адрес). Тип сегмента - k_RWDataUp. Уровень доступа k_KLvl.
4. Плоский, 32 р-р, 4Гб сегмент данных, охватывающий все доступное 32 р-р адресное пространство процессора со смещения 0x00000000. Тип сегмента - k_RWDataUp. Данный сегмент необходим для превентивного доступа ядра к любой части адресного пространства, как к данным, поэтому уровень привилегий плоского сегмента k_KLvl. Протяженность сегмента вынуждает использовать в его описание грануляцию k_4Kb, а при такой дробности сегмента предел будет составлять 0xFFFFF.
Дескрипторы и таблицы дескрипторов
Во время загрузки 16-битной части ядра происходит инициализация регистра GDTR процессора значением 32-битного адреса начала таблицы дескрипторов в памяти. Стандартными средствами C++ сделать это невозможно. Для этого используется макрос Watcom:
extern void LoadGDTR(TVirtualGDTR *ps_VGDTR);
#pragma aux LoadGDTR = \
"LGDT [eax]" \
parm [eax];
И структура данных TVirtualGDTR, являющаяся виртуальным содержимым GDTR регистра в памяти:
struct
{
word wLim;
dword dwGDT_Addr;
} TVirtualGDTR;
Используемые Интернет-ресурсы:
http://ru.wikipedia.org/wiki/Стек
http://sasm.narod.ru/docs/pm/pm_int/chap_2.htm
http://sasm.narod.ru/docs/pm/pm_int/chap_4.htm
http://web-protect.net/p442.htm
http://www.3os.ru/old/3os.ru/oven/work/kernel/docs/0x86_part01.html
Книга «Ассемблер. Учебник для ВУЗов», авторы Михаил Гук, Виктор Юров
Книга «Архитектура ЭВМ»,автор Мюллер
Книга «Процессоры Pentium4, Athlon и Duron», авторы Михаил Гук, Виктор Юров
Книга «Архитектура ЭВМ», автор Танненбаум
Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:
Email: Нажмите что бы посмотреть