Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЭВУ 2 семестр / Презентации ЭВУ в пдф / метода моховикова

.pdf
Скачиваний:
36
Добавлен:
31.05.2015
Размер:
4.4 Mб
Скачать

word wSelector;

byte bCount;

byte bAttr;

word wOffset_II;

};

«вспомогательное представление дескриптора» – группы 1 и 2

(рис. 46):

Рис. 46. Вспомогательное представление дескриптора обеих групп

struct s_DVector

{

dword dwVec_I; dword dwVec_II; };

Соответственно, должны существовать два класса дескрипторов, произ-

водных от одного общего класса дескрипторов, включающего общие методы работы со всеми типами дескрипторов. Описать это можно, используя язык высокого уровня C++.

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);

111

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 байт, то есть смысл объединить их в структуру (рис. 47):

112

Рис. 47. Работа со структурой при формировании размера сегмента

Значение типа уровня доступа находится в интервале 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

};

Тип «дескриптора пространства» – это перечисление возможных типов сегментов (рис. 48), без учета бита ACCESSED, так как установка этого бита

прерогатива процессора.

0.Пространство данных только для чтения с увеличением границы

вверх.

1.Пространство данных с возможностью записи с увеличением границы

вверх.

2.Пространство данных только для чтения с увеличением границы вниз.

3.Пространство данных с возможностью записи с увеличением границы

вниз.

4.Пространство неподчиненного кода с запретом чтения.

5.Пространство неподчиненного кода c возможностью чтения.

6.Пространство подчиненного кода с запретом чтения.

113

7. Пространство подчиненного кода c возможностью чтения.

Рис. 48. Тип дескриптора пространства

В этом случае преобразование 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 на длину дескриптора.

114

2. При необходимости, выделение дополнительной памяти под табли-

цу дескрипторов.

3. Возвращение указателя на работоспособный дескриптор.

Далее, необходимо использовать конструктор дескриптора. Случай 2

может потребовать манипуляций со страницами памяти, так как хотелось бы избавиться от излишнего перемещения данных из области GDT в новое ме-

сто при нехватке памяти в заранее выделенном под GDT (при работе еще 16-

битного кода загрузчика) пространстве, кратном размеру страницы [4 Kb = 4

096 байт].

Приступим к расширенному полю ETYPE. Необходимо отметить, что это достаточно синтетическое поле, и его прямая задача объединить – типы разных групп дескрипторов в одну, за счет выделения 5-го бита – S (систем-

ный дескриптор). Опять-таки, поле ETYPE является простейшим перечисле-

нием входящих комбинаций простых типов s_SpcType и s_SysType.

Рассмотрим системный набор дескрипторов s_SpcType (табл. 4):

Таблица 4

Системный набор

 

1. [0001] Свободный

TSS

- 16

бит

 

9. [1001] Свободный TSS - 32 бита

2.

[0010] Локальная таблица дескрипто-

 

 

 

ров

 

 

 

 

 

(LDT)

11.

[1011] Занятый TSS - 32

бита

3.

[0011]

Занятый TSS

 

-

16

бит

12.

[1100] Шлюз вызова - 32

бита

4.

[0100]

Шлюз

вызова

 

-

16

бит

 

 

 

5.

[0101]

Шлюз

 

 

задачи

14.

[1110] Шлюз прерывания - 32 бита

6.

[0110]

Шлюз

прерывания

 

- 16

бит

15.

[1111] Шлюз ловушки - 32 бита

 

7.

[0111] Шлюз ловушки - 16

бит

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Как видно из табл. 4, системные дескрипторы за исключением 2, 5 опре-

деляются симметрично относительно 4-го бита (рис. 49). Таким образом,

можно свести системные объекты в перечисление:

115

Рис. 49. Структура распределения битов в типе дескриптора системных объектов

Дескрипторы первой и второй группы сходны в определении разрядно-

сти (16/32) отождествляемых с ними объектов. Поэтому в c_Descriptor при-

сутствуют методы Addr16 и Addr32. Методы по биту S [Segment] могут раз-

личить тип дескриптора и установить, соответственно, либо бит 4 поля

ETYPE (за исключением LDT и TaskGate типов), либо бит D/B поля dwVec_II.

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 дает расширенный тип (рис.

50):

116

Рис. 50. Структура типов

Рассмотрим теперь путь исполнения, проделываемый в случае вызова одного из конструкторов c_DSpace или c_DSystem (рис. 51).

Процедура 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

осуществляется так, как показано на рис. 52.

Таким образом, выделяются два вида владельцев дескрипторов: «сис-

темный объект» и «пространство». Они получают адрес дескриптора от объ-

ектов GDT, LDT, IDT, а затем осуществляют необходимые изменения в нем.

Рассмотрим типы таблиц в ракурсе их описания через аппарат ООП.

117

Рис. 51. Вызов конструктора

Глобальная таблица дескрипторов начинает формироваться на самой ранней стадии загрузки ядра. Практически ее содержимое (дескрипторы)

сформировано еще на стадии компиляции исходного кода при помощи мак-

рокоманд препроцессора С++ как массив константных значений типа s_DVector.

Рис. 52. Эволюция базового адреса

В макрокоманде m_DATA_DESCRIPTOR используются все те же типы переменных, что и для класса c_DSpace:

#define k_4Kb 0x00800000 \\ Гранулярность сегмента = 4 кБ

118

#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 байт и уровнем привилегий ядра. Протяженность данного сег-

мента определяется длиной оставшегося участка кода от места испол-

нения процессором команды, являющейся первой после перехода в PM

и очистки конвейера процессора межсегментным, длинным переходом

(FAR JMP) на эту команду. Соответственно базовый адрес сегмента также должен начинаться с этой же команды. Таким образом, стано-

119

вится возможным избавиться от 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);

120