Я один, но это не значит что я одинок.. Виктор Цой За двумя зайцами погонишься – ни одного не поймаешь Пословица
Первая глава-преамбула, подготавливающая почву для темы «Защита: передача управления».
Задача главы предельно проста: объяснить, как правильно создать одну задачу (task) и как проинициализировать регистр задачи (Task Register, TR). В данный момент механизм задач интересен нам не сам по себе, а только как некоторая инфраструктура, которую процессор использует при передаче управления между сегментами кода с различными уровнями привилегий.
Заданий к главе нет.
Сегмент состояния задачи (task state segment, TSS) содержит «состояние задачи» – некоторые специфичные для задачи данные, определяющие её поведение. Грубо и упрощённо, можно разбить эти данные на две части:
Минимальный размер TSS – 104 байта, именно столько занимает стандартная структура, содержащая все обязательные данные. Поскольку в течение этой главы мы не будем делать с задачами ничего интересного, структура и содержимое TSS пока не имеют значения, то есть он может состоять из 104-х байт абсолютно произвольного содержания. Для простоты, пусть будут нули.
Выглядит это так:
tss_seg db 104 dup(0) |
Естественно, сегмент не может существовать без дескриптора. Дескриптор сегмента состояния задачи (task state segment descriptor) должен находиться в GDT, его формат таков:
Положение | Название | Краткое описание |
---|---|---|
Два младших байта (нулевой и первый) | Segment Limit (part 1) | Младшие 16 бит поля Segment Limit. |
Второй, третий, четвёртый байты | Base Address (part 1) | Младшие три байта поля Base Address. |
0-й – 3-й биты пятого байта | Type | Дескриптору сегмента состояния задачи соответствует 1001 (на самом деле, тут немного интереснее, более подробно в настоящей главе про многозадачность). |
4-й бит пятого байта | S | Это системный дескриптор, поэтому 0. |
5-й – 6-й биты пятого байта | DPL | Пока 0, подробнее в главе про многозадачность. |
7-й бит пятого байта | P | Устанавливайте в 1, подробнее в приложении. |
0-й – 3-й биты шестого байта | Segment Limit (part 2) | Старшие 4 бита поля Segment Limit. |
4-й – 6-й биты шестого байта | ?? | Устанавливайте в 0. |
7-й бит шестого байта | G | Granularity. Флаг гранулярности. Теоретически, вам может потребоваться сегмент состояния задачи, превышающий 1 мегабайт, но в рамках курса этого не произойдёт. |
Седьмой байт | Base Address (part 2) | Старший байт поля Base Address. |
На картинке это выглядит так:
В качестве примера – дескриптор сегмента состояния задачи, размер сегмента 104 байта, базовый адрес 01020304h:
db 103 ; Segment Limit db 0 db 4 ; base address db 3 db 2 db 10001001b ; 1, DPL – 00, S - 0, 1001 db 0 ; G - 0, 000, Limit - 0 db 1 ; base address |
Или так:
; Дескриптор сегмента состояния задачи, 104 байта, базовый адрес 01020304h segment_descriptor <103, 0304h, 2h, 10001001b, 0, 1h> |
Для того, чтобы корректно инициализировать механизм управления задачами, нужно выполнить три действия:
Инструкция ltr относится к привилегированным и имеет следующий формат:
ltr selector |
Где selector это 16-ти разрядный регистр или переменная типа dw.
Замечательный пример, сложностью и объёмом возвращающий нас примерно ко второй главе. Коротенькая инициализация, две инструкции, ради которых всё это затевалось, возврат в реальный режим. Всегда бы так!
; task.asm ; Программа, инициализирующая TR .model tiny .code .386p org 100h ;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Структуры ; ;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Сегментный дескриптор segment_descriptor struct limit_low dw 0 ; Младшие два байта поля Segment limit base_low dw 0 ; Младшие два байта поля Base Address base_high0 db 0 ; Второй байт поля Base Address type_and_permit db 0 ; Флаги flags db 0 ; Ещё одни флаги base_high1 db 0 ; Старший байт поля Base Address segment_descriptor ends ; Регистр, описывающий таблицу дескриптров table_register struct limit dw 0 ; Table Limit base dd 0 ; Linear Base Address table_register ends ;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Код ; ;;;;;;;;;;;;;;;;;;;;;;;;;; start: ; Подготавливаем DS push cs pop ds ; Получаем адрес начала сегмента TSS call cs_to_eax add eax, offset tss_seg ; Записываем его в дескриптор mov word ptr tss_dsc.base_low, ax shr eax, 16 mov byte ptr tss_dsc.base_high0, al ; Запрещаем прерывания call disable_interrupts ; Инициалиируем GDT call initialize_gdt ; Переключаем режим call set_PE ; загрузить селектор дескриптора TSS в TR mov ax, 8 ltr ax call clear_PE call enable_interrupts ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Данные ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Глобальная таблица дескрипторов GDT label byte ; Нулевой дескриптор segment_descriptor <> ; Дескриптор TSS, 104 байта, базовый адрес 0 tss_dsc segment_descriptor <103, 0, 0, 10001001b, 0, 0> ; Данные для загрузки в GDTR gdtr table_register <$ - GDT - 1, 0> ; Сегмент TSS. Можно было его вообще не объявлять и оставить ; базовый адрес 0, всё равно бы сработало. Но в будущем пригодится. tss_seg db 104 dup(0) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Служебные функции ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Инициализирует GDT initialize_gdt: ; Вычисляем линейный адрес начала массива дескрипторов call cs_to_eax add eax, offset GDT ; Записываем его в структуру mov dword ptr gdtr.base, eax ; Загружаем GDTR lgdt fword ptr gdtr ret ; Запрещает маскируемые и немаскируемые прерывания disable_interrupts: cli ; запретить прерывания in al, 70h ; индексный порт CMOS or al, 80h ; установка бита 7 в нем запрещает NMI out 70h, al ret ; Разрешает маскируемые и немаскируемые прерывания enable_interrupts: in al, 70h ; индексный порт CMOS and al, 7Fh ; сброс бита 7 отменяет блокирование NMI out 70h, al sti ; разрешить прерывания ret ; Устанавливает флаг PE set_PE: mov eax, cr0 ; прочитать регистр CR0 or al, 1 ; установить бит PE, mov cr0, eax ; с этого момента мы в защищенном режиме ret ; Сбрасывает флаг PE clear_PE: mov eax, cr0 ; прочитать CR0 and al, 0FEh ; сбросить бит PE mov cr0, eax ; с этого момента мы в реальном режиме ret ; Вычисляет линейный адрес начала сегмента кода cs_to_eax: mov eax, 0 mov ax, cs shl eax, 4 ret end start |