Глава 10. Использование LDT.
В этой главе и в примере, приведенном в конце, показано, как используются локальные дескрипторные таблицы в задачах.
В качестве базового примера используются предыдущий - те же три задачи, переключаются через FAR CALL из основной задачи и программа прекращает работу по нажатию Esc. Обработчики исключений и прерываний также не реализованы отдельными задачами - пример предназначен для демонстрации использования LDT.
Для реализации мультизадачности нужно выполнить те же три действия:
1. | Подготовить все необходимые дескрипторы. |
2. | Установить контексты всех задач в их сегментах TSS. |
3. | Запустить мультизадачность и обеспечить переключение задач. |
В каждом из них будут некоторые изменения, по сравнению с предыдущим примером.
В примере используются следующие дескрипторы:
TSS_area - описывает алиасный сегмент данных, отображённый на сегменты состояния всех задач.
| LDT_area - описывает алиасный сегмент данных, отображённый на локальные дескрипторные таблицы всех задач.
| Task_Stack - сегмент данных, используемый как стек для всех задач. Каждой задаче будет выделена область в этом сегменте.
| Main_TSS, TSS_2 и TSS_3 - дескрипторы TSS всех трёх задач.
| LDT_2 и LDT_3 - дескрипторы LDT задач 2 и 3 (задача Main не использует LDT).
| |
Вот так выглядит код инициализации дескрипторов. Этот код выполняется до перехода в защищённый режим.
; Устанавливаем сегмент TSS_area размером 4Кб для описаний TSS. mov bx,offset GDT + TSS_area mov eax,cr3 add eax,3 * 4096 mov ebp,eax ; Временно сохраняем этот адрес. mov edx,4096 mov cx,92h call set_descriptor ; TSS_area ; Устанавливаем сегмент LDT_area размером 4Кб для описаний LDT. mov bx,offset GDT + LDT_area mov eax,cr3 add eax,4 * 4096 mov edx,4095 mov cx,92h call set_descriptor ; LDT_area ; Устанавливаем сегмент Task_stack размером 4Кб для всех стеков задач. mov eax,cr3 add eax,5 * 4096 mov edx,4095 mov cx,92h call set_descriptor ; Task_stack ; Устанавливаем дескрипторы трёх TSS: mov bx,offset GDT + Main_TSS mov eax,ebp mov edx,67h mov cx,10001001b call set_descriptor ; Main_TSS add eax,104 call set_descriptor ; TSS_2 add eax,104 call set_descriptor ; TSS_3 ; Устанавливаем дескрипторы двух LDT: mov bx,offset GDT + LDT_2 mov eax,cr3 add eax,4 * 4096 + 64 mov edx,65 mov cx,10000010b call set_descriptor ; LDT_2 add eax,64 call set_descriptor ; LDT_3
Процедура установки TSS немного усложнилась. Теперь в ней добавилось следующее:
Значение поля IOPL берётся из образа EFLAGS для задачи, переданного в регистре ECX. Это поле используется для построения селекторов и определяет уровень привилегий задачи.
| Если задача использует LDT (т.е. регистр BP при вызове процедуры содержит 0), то задача будет использовать локальные селекторы с установленным битом TI и полем RPL, равным значению поля IOPL.
| Конструируется LDT задачи размером 64 байта (т.е. для 8 дескрипторов) и в ней определяются три дескриптора - кода, стека и данных. Содержимое дескрипторов кода и стека копируется из соответствующих дескрипторов в GDT, а для стека используется копия дескриптора Task_Stack. На самом деле для задач нужно создавать новые, уникальные дескрипторы, но в данном примере акцент делается на использовании дескрипторов LDT, а не их создании.
| |
Перед вызовом этой процедуры регистр EBP должен содержать для создаваемой задачи:
в старшей половине - указатель в LDT_area на начало описания LDT,
| в младшей половине - селектор дескриптора LDT.
| |
set_TSS proc near ; Создаёт 32-разрядный TSS минимального размера (104 байта - предел 67h). ; DI = указатель на TSS внетри сегмента TSS_area ; Параметры новой задачи: ; EAX = CR3 ; EBX = EIP ; ECX = EFLAGS ; EDX = ESP ; EBP = LDT_description & LDT_sel push eax push bx push di push es push eax push ecx push di mov ax,TSS_area mov es,ax xor eax,eax mov cx,26 cld rep stosd ; Очистка TSS перед заполнением. pop di pop ecx pop eax mov es:[ di + 28 ],eax ; Записали CR3 mov es:[ di + 32 ],ebx ; EIP mov es:[ di + 36 ],ecx ; EFLAGS mov es:[ di + 56 ],edx ; ESP mov es:[ di + 96 ],bp ; LDT mov eax,ecx ; EAX = ECX = EFLAGS shr eax,12 and al,11b ; AL = IOPL mov dl,al ; Временно сохраняем значение IOPL в DL. cmp bp,0 je stss_1 or al,100b ; TI = 1 - селектор выбирает дескрипторы из LDT. stss_1: add al,8 mov es:[ di + 76 ],al ; CS add al,8 mov es:[ di + 80 ],al ; SS add al,8 mov es:[ di + 84 ],al ; DS cmp bp,0 je stss_2 ; Установка LDT задачи размером 64 байта (т.е. на 8 дескрипторов). mov ax,LDT_area mov es,ax shr ebp,16 sub bp,offset LDT_area mov di,bp ; ES:DI = указатель на LDT задачи xor eax,eax mov cx,16 push di rep stosd ; Очищаем 64 байта LDT. pop di add di,8 ; Пропускаем 0-й дескриптор. ; Записываем дескриптор сегмента кода (1-й дескриптор в этой LDT). Т.к. ; код задачи находится в том же сегменте, что и основной код программы, то ; мы просто создадим в LDT копию 1-го дескриптора (доступного по селектору ; Code_selector). lea bx,GDT add bx,Code_selector mov eax,[ bx ] stosd mov eax,[ bx + 4 ] stosd ; Память, предназначенная для стека описывается для всех задач одним ; сегментом - Task_Stack. Его и будет использовать задача в регистре SS: lea bx,GDT add bx,Task_Stack mov eax,[ bx ] stosd mov eax,[ bx + 4 ] stosd ; Создаём копию дескриптора данных: lea bx,GDT add bx,Data_Selector mov eax,[ bx ] stosd mov eax,[ bx + 4 ] stosd stss_2: pop es pop di pop bx pop eax ret endp
Установка мультизадачности также усложняется, потому что теперь для каждой задачи нужно указывать больше параметров:
; Установка мультизадачности xor di,di ; Это будет первая задача. mov eax,cr3 lea ebx,first_task_entry_point ; EIP задачи. mov ecx,10b ; EFLAGS задачи. mov edx,256 - 4 ; ESP 1-й задачи. mov bp,0 ; LDT у 1-й задачи нет. call set_TSS add di,104 ; Это будет вторая задача. lea ebx,second_task_entry_point ; EIP задачи. mov edx,512 - 4 ; ESP 2-й задачи. mov bp,offset LDT_area + 64 shl ebp,16 mov bp,LDT_2 ; LDT 2-й задачи. call set_TSS add di,104 ; Это будет третья задача. lea ebx,third_task_entry_point ; EIP задачи. mov edx,768 - 4 ; ESP 3-й задачи. mov bp,offset LDT_area + 128 shl ebp,16 mov bp,LDT_2 ; LDT 3-й задачи. call set_TSS
Вот и всё. Полностью пример - файлы examp_10.asm, examp_10.com, pmode_10.lib и init.lib, - доступен в архиве examp_10.zip (19'843 байт).
Следующая глава | Оглавление | Вопросы? Замечания? Пишите: sasm@narod.ru |
Copyright © Александр Семенко. |