Поиск по базе сайта:
Лабораторна робота №1 тема: Дескриптори І таблиці глобальних дескрипторів icon

Лабораторна робота №1 тема: Дескриптори І таблиці глобальних дескрипторів




Скачати 159.78 Kb.
НазваЛабораторна робота №1 тема: Дескриптори І таблиці глобальних дескрипторів
Дата конвертації25.10.2014
Розмір159.78 Kb.
ТипЛабораторна робота


Лабораторна робота №1

ТЕМА: Дескриптори і таблиці глобальних дескрипторів.

МЕТА: Навчитись програмно описувати дескриптори у таблиці глобальних дескрипторів та завантажувати в регістр процесора GDTR, інформацію про таблицю глобальних дескрипторів.

Короткі теоретичні відомості

При вмиканні процесора в ньому автоматично встановлюється режим реальної адреси. Перехід у захищений режим здійснюється програмно шляхом виконання відповідної послідовності команд. Оскільки багато деталей функціонування процесора в реальному і захищеному режимах істотно відрізняються, програми, призначені для захищеного режиму, повинні бути написані особливим чином. Реальний і захищений режими є несумісними.

Розглянемо програму, яка переключає процесор у захищений режим.
.386P ;Дозвiл трансляцiї привiлейованих команд

;Структура для опису дескрипторiв сегментiв

descr struc

limit dw 0 ;Межа (бiти 0..15)

base_l dw 0 ;База, бiти 0..15

base_m db 0 ;База, бiти 16..23

attr_1 db 0 ;Байт атрибутiв 1

attr_2 db 0 ;Межа (бiти 16..19) i атрибути 2

base_h db 0 ;База, бiти 24..31

descr ends
;Сегмент даних

data segment use16 ;16-розрядна програма
;^ Таблиця глобальних дескрипторiв GDT

gdt_null descr <0,0,0,0,0,0> ;Селектор 0 - обов'язковий

;нульовий дескриптор

gdt_data descr ;Селектор 8,сегмент даних

gdt_code descr ;Селектор 16,сегмент команд

gdt_stack descr <255,0,0,92h,0,0> ;Селектор 24, сегмент стеку

gdt_size=$-gdt_null ;Розмiр GDT

pdescr dq 0 ;Псевдодескриптор для lgdt

real_sp dw 0 ;Змiнна для збереження SP

mes db 27, '[31;42m Повернулися в реальний режим! ',27,'[0m$'

data_size=$-gdt_null ;Розмiр сегменту даних

data ends ;Кiнець сегменту даних
;Сегмент команд

text segment 'code' use16 ;16-розрядна програма

assume CS:text, DS:data

main proc

mov AX, data ;Iнiцiалiзацiя DS

mov DS, AX ;у реальному режимi

;Знайдемо 32-бiтову лiнiйну адресу сегменту даних

mov DL,0

shld DX,AX,4

shl AX,4

mov BX,offset gdt_data

mov [BX]. base_l,AX

mov [BX]. base_m,DL

;Знайдемо 32-бiтову лiнiйну адресу сегменту команд

mov AX, CS

mov DL,0

shld DX,AX,4

shl AX,4

mov BX,offset gdt_code

mov [BX]. base_l,AX

mov [BX]. base_m,DL

;Знайдемо 32-бiтову лiнiйну адресу сегменту стеку

mov AX,SS

mov DL,0

shld DX,AX,4

shl AX,4

mov BX,offset gdt_stack

mov [BX]. base_l,AX

mov [BX]. base_m,DL

;^ Пiдготуємо дескриптор i завантажимо регiстр GDTR

mov BX,offset gdt_data ;Адреса GDT

mov AX,[BX].base_l;Одержимо та занесемо у pdescr

mov word ptr pdescr+2, AX ;базу, бiти 0..15

mov DL,[BX]. base_m;Одержимо i занесемо у pdescr

mov byte ptr pdescr+4, DL ;базу, бiти 16..23

mov word ptr pdescr, gdt_size-1 ;Межа GDT

lgdt pdescr ;Завантажимо регiстр GDTR

;Пiдготуємося до повернення в реальний режим

mov AX, 40h ;Налаштуємо ES на область

mov ES,AX ;даних BIOS

mov word ptr ES:[67h],offset return;Зсув точки повернення

mov ES:[69h],CS ;Сегмент точки повернення

;Пiдготуємося до переходу в захищений режим

cli ;Заборона апаратних переривань

mov AL,0Fh ;Вибiрка байту стану вiдключення

out 70h,AL ;Порт КМОП-мiкросхеми

mov AL, 0Ah ;Установка режиму вiдновлення

out 71h,AL ;пiсля скидання процесора

;Перехід в захищений режим

smsw AX ;Одержимо слово стану комп’ютера

or AX,1 ;Встановимо бiт PE

lmsw AX ;Запишемо слово стану

;^ Процесор працює в захищеному режимi

mov CX,1000 ; Кількість ітерацій циклу

m1: mov BX,AX

loop m1 ;Цикл

;Повернемося в реальний режим

mov real_sp,SP ;Збережемо SP

mov AL,0FEh ;Команда скидання процесора

out 64h,AL ;у порт 64h

hlt ;Зупиняемо процесор до кiнця скидання

;Процесор працює в реальному режимi

;Вiдновимо операцiйне середовище реального режиму

return: mov AX,data ;Вiдновимо адресуємість даних

mov DS,AX

mov SP,real_sp ;Вiдновимо адресуємість стеку

mov AX,stk

mov SS,AX

sti ;Дозволимо апаратнi переривання

;Виконуємо перевiрку функцiй DOS пiсля повернення в ;реальний режим

mov AH, 09h ;Функцiя виведення на екран рядка

mov DX, offset mes ;Адреса рядка

int 21h

mov AX, 4C00h ;Завершимо програму звичайним чином

int 21h

main endp ;Кiнець головної процедури

code_size=$-main ;Розмiр сегменту команд

text ends ;Кiнець сегменту команд
stk segment stack 'stack' ;Початок сегменту стеку

db 256 dup ('^')

stk ends ;Кiнець сегменту стеку

end main ;Кiнець програми
Програма починається з опису структури дескриптора сегменту. На відміну від реального режиму, у якому сегменти визначаються їхніми базовими адресами, що задаються програмістом у явній формі, у захищеному режимі для кожного сегменту програми повинен бути визначений дескриптор – 8-байтове поле, в якому у визначеному форматі записуються базова адреса сегменту, його довжина і деякі інші характеристики (рисунок 1).

Байти 7

6

5

4

3

2

1

0

База 31..24

Атрибути 2

Атрибути 1

























База сегменту 23..0

Межa сегменту 15..0

























Base_h

attr_2

Attr_1

Base_m

base_h

Limit



















^ Рисунок 1– Дескриптор сегменту


Біт 15

3

2

1

0

Індекс дескриптора

TI

RPL

^ Рисунок 2 – Селектор дескриптора
Тепер для звертання до необхідного сегменту програміст заносить у сегментний регістр не сегментну адресу, а так званий селектор (рисунок 2), до складу якого входить номер (індекс) відповідного сегменту дескриптора. Процесор за цим номером знаходить потрібний дескриптор, витягає з нього базову адресу сегменту, збільшує її на зазначене в конкретній команді зміщення (відносну адресу), формує адресу чарунки пам'яті. Індекс дескриптора (0, 1, 2 і т.д.) записується в селектор починаючи з біту 3, що еквівалентно множенню його на 8. Таким чином, можна вважати, що селектори послідовних дескрипторів являють собою числа 0, 8, 16, 24 і т.д. Інші поля селектора, що для нашого випадку приймають значення 0, будуть описані пізніше.

Структура descr є шаблоном для дескрипторів сегментів, що полегшує їхнє формування. Розглянемо вміст дескриптора. Межa (limit) сегменту являє собою номер останнього байту сегменту. Так, для сегменту розміром 375 байтів межа дорівнює 374. Поле межі складається з 20 бітів і розбите на дві частини. З рисунку 1 видно, що молодші 16 бітів межі займають байти 0 і 1 дескриптора, а старші 4 біти входять до байту атрибутів_2, займаючи в ньому біти 0...3. Виходить, що розмір сегменту обмежений розміром 1 Мбайт. Насправді це не так. Межа може вказуватися або в байтах (і тоді, дійсно, максимальний розмір сегменту дорівнює 1 Мбайт), або в блоках по 4 Кбайти (і тоді розмір сегменту може досягати 4 Гбайт). Одиниці, в яких задається межа, визначаються старшим бітом байту атрибутів_2, який називається бітом дробовості. Якщо він дорівнює 0, межа вказується в байтах; якщо 1 - у блоках по 4 Кбайти.

База сегменту (32 біти) визначає початкову лінійну адресу сегменту в адресному просторі процесора.

Поле бази, як і поле межі, розбито на 2 частини: біти 0...23 займають байти 2, 3 і 4 дескриптора, а біти 24...31 - байт 7. Для зручності програмного звертання в структурі descr база описується трьома полями: молодшим словом (base_l) і двома байтами: середнім (base_m) і старшим (base_h).

У байті атрибутів_1 задається низка характеристик сегменту. У прикладі використовуються сегменти двох типів: сегмент команд, для якого байт attr_l повинний мати значення 98h, і сегмент даних (або стеку) із кодом 92h.

Сегмент даних data оголошений із типом використання use16 (так само буде оголошений і сегмент команд). Він повідомляє, що в даному сегменті будуть використовуватися 16-бітові адреси. Якби ми готували нашу програму для роботи під керуванням операційної системи захищеного режиму, що реалізує всі можливості мікропроцесора, тип використання був би use32. Проте наша програма буде працювати під керуванням DOS, яка працює в реальному режимі з 16-бітовими адресами й операндами.

Сегмент даних починається з опису найважливішої системної структури - таблиці глобальних дескрипторів. Як вже відзначалося вище, звертання до сегментів у захищеному режимі можливо тільки через дескриптори цих сегментів. Таким чином, у таблиці дескрипторів повинно бути описано стільки дескрипторів, скільки сегментів використовує програма. У нашому випадку до таблиці включені, крім обов'язкового нульового дескриптора, що завжди займає перше місце в таблиці, чотири дескриптори для сегментів даних, команд, стеку і додаткового сегменту даних, який ми накладемо на відеобуфер, щоб забезпечити можливість виведення в нього символів. Порядок дескрипторів у таблиці (крім нульового) не має значення.

Крім єдиної таблиці глобальних дескрипторів, що позначається GDT (Global Descriptor Table), у пам'яті може знаходитися багато таблиць локальних дескрипторів (LDT - Local Descriptor Table). Різниця між ними полягає в тому, що сегменти, які описуються глобальними дескрипторами, доступні всім задачам, виконуваним процесором, а до сегментів, що описуються локальними дескрипторами, може звертатися тільки та задача, у якій ці дескриптори описані. Оскільки ми маємо справу з однозадачним режимом, локальна таблиця нам не потрібна.

^ У дескрипторі gdt_data, що описує сегмент даних програми, заповнюється поле межі сегменту (фактичне значення розміру сегменту data_size буде обчислено транслятором), а також байт атрибутів_1. Код 92h вказує на те, що це сегмент даних із дозволом запису і читання. Базу сегменту, тобто фізичну адресу його початку, прийдеться обчислити програмно і занести в дескриптор вже на етапі виконання.

^ Дескриптор gdt_code сегменту команд заповнюється таким же чином. Код атрибута 98h вказує, що це виконуємий сегмент, до якого заборонене звертання з метою читання або запису. Таким чином, сегменти команд у захищеному режимі не можна модифікувати по ходу виконання програми.

^ Дескриптор gdt_stack сегменту стеку має, як і будь-який сегмент даних, код атрибуту 92h, що дозволяє його читання і запис, і явно задану межу 255 байт, що відповідає розміру стеку. Базова адреса сегменту стеку так само буде обчислена на етапі виконання програми.

Перед переходом у захищений режим процесору треба повідомити фізичну адресу таблиці глобальних дескрипторів і її розмір (точніше, межу). Розмір GDT визначається на етапі трансляції. А також треба завершити формування дескрипторів сегментів програми, у яких залишилися незаповненими базові адреси сегментів. Базові (32-бітові) адреси визначаються шляхом множення значень сегментних адрес на 16. Для цього ми зсуваємо значення в AX на 4 біти ліворуч, заносячи 4 старші біти у DL. Командами

mov BX,offset gdt_data

mov [BX]. base_l,AX

mov [BX]. base_m,DL

вміст АХ відправляється в поле base_l дескриптора gdt_data, а вміст DL - у поле base_m.

Аналогічно обчислюються 32-бітові адреси сегментів команд і стеку, що поміщаються в дескриптори gdt_code і gdt_stack.

Наступний етап підготовки до переходу в захищений режим - завантаження в регістр процесора GDTR (Global Descriptor Table Register, регістр таблиці глобальних дескрипторів) інформації про таблицю глобальних дескрипторів. Ця інформація містить у собі лінійну базову адресу таблиці і її межі і розміщується в 6 байтах поля даних, який називається псевдодескриптором. Для завантаження GDTR передбачена спеціальна привілейована команда Lgdt (load global descriptor table, завантаження таблиці глобальних дескрипторів), що потребує в якості операнда ім’я псевдодескриптора. Формат псевдодескриптора наведений на рисунку 3.



5

4

3

2

1

0



















Лінійна базова адреса

Межа



















^ Рисунок 3 – Формат псевдодескриптора

У принципі, ми вже можемо перейти в захищений режим, проте в захищеному режимі заборонені будь-які звертання до функцій DOS або BIOS. Причина цього цілком очевидна - і DOS, і BIOS є програмами реального режиму, у яких широко використовується сегментна адресація реального режиму. У захищеному ж режимі в сегментні регістри завантажуються не сегментні адреси, а селектори. Крім того, звертання до функцій DOS і BIOS здійснюється за допомогою команд int, а в захищеному режимі ці команди призведуть до цілком інших результатів. Таким чином, програму, що працює в захищеному режимі, не можна завершити засобами DOS. Спочатку її треба повернути в реальний режим.

Повернення в реальний режим можна здійснити скиданням процесора. Дії процесора після скидання визначаються однією з чарунок КМОП-мікросхеми - байтом стану відключення, що розташовується за адресою Fh. Зокрема, якщо в цьому байті записаний код Ah, після скидання керування негайно передається за адресою, що витягається з двослівної чарунки 40h:67h, розташованої в області даних BIOS. Таким чином, для підготування повернення в реальний режим ми повинні в чарунку 40h:67h записати адресу повернення, а в байт Fh КМОП-мікросхеми занести код Ah. У рядках

mov AX, 40h

mov ES,AX

mov word ptr ES:[67h], offset return

mov ES:[69h],CS

заносимо повну адресу точки повернення return за адресою 0h:67h.

Ще одна важлива операція, яку необхідно виконати перед переходом у захищений режим, полягає в забороні всіх апаратних переривань. Справа в тому, що в захищеному режимі процесор виконує процедуру переривання не так, як у реальному. При надходженні сигналу переривання процесор не звертається до таблиці векторів переривань у першому кілобайті пам'яті, як у реальному режимі, а витягає адресу програми обробки переривання з таблиці дескрипторів переривань, побудованої схоже з таблицею глобальних дескрипторів і розташованій в програмі користувача (або в операційній системі). У прикладі такої таблиці немає, і на час роботи програми переривання прийдеться заборонити. Заборона всіх апаратних переривань здійснюється командою cli.

У рядках

mov AL,0Fh

out 70h,AL

mov AL, 0Ah

out 71h,AL

у порт 70h заноситься код 0Fh, що вибирає для запису байт Fh КМОП-мікросхеми, а потім у порт даних 71h посилається код 0Ah, що визначає режим відновлення (перехід за адресою, яка вибирається з області даних BIOS).

Перехід у захищений режим здійснюється встановленням біту 0 слова стану машини. Оскільки інші біти цього слова нам не відомі, спочатку ми читаємо в регістр АХ слово стану машини, потім встановлюємо в ньому біт 0 і, нарешті, записуємо модифіковане слово стану назад у процесор. Всі наступні команди виконуються вже в захищеному режимі.

Хоча захищений режим встановлений, проте налагодження системи ще не закінчені. Дійсно, в усіх сегментних регістрах, які використовуються у програмі зберігаються не селектори дескрипторів сегментів, а базові сегментні адреси, що не мають сенсу в захищеному режимі. Звідси можна зробити висновок, що після переходу в захищений режим програма не повинна працювати, тому що в регістрі CS поки ще немає селектора сегменту команд, і процесор не може звертатися до цього сегменту. У дійсності це не зовсім так.

У процесорі для кожного із сегментних регістрів є так званий тіньовий регістр дескриптора, що має формат дескриптора (рисунок 4). Тіньові регістри недоступні програмісту; вони автоматично завантажуються процесором із таблиці дескрипторів щоразу, коли процесор завантажує відповідний сегментний регістр. Таким чином, у захищеному режимі програміст має справу із селекторами, тобто номерами дескрипторів, а процесор - із самими дескрипторами, що зберігаються в тіньових регістрах. Саме вміст тіньового регістра (у першу чергу, лінійна адреса сегменту) визначає область пам'яті, до якої звертається процесор при виконанні конкретної команди.
Сегментні регістри Тіньові регістри

CS

Селектор




База

Межа

Атрибути

SS

Селектор




База

Межа

Атрибути

DS

Селектор




База

Межа

Атрибути

ES

Селектор




База

Межа

Атрибути

FS

Селектор




База

Межа

Атрибути

GS

Селектор




База

Межа

Атрибути

^ Рисунок 4. Сегментні та тіньові регістри

У реальному режимі тіньові регістри заповнюються не з таблиці дескрипторів, а безпосередньо самим процесором. Зокрема, процесор заповнює поле бази кожного тіньового регістра лінійною базовою адресою сегменту, отриманим шляхом множення на 16 вмісту сегментного регістра, як це і потрібно в реальному режимі. Тому після переходу в захищений режим у тіньових регістрах знаходяться правильні лінійні базові адреси, і програма буде виконуватися правильно, хоча з погляду правил адресації захищеного режиму вміст сегментних регістрів позбавлений сенсу.

Проте після переходу в захищений режим насамперед варто завантажити у сегментні регістри (і, зокрема, у регістр CS) селектори відповідних сегментів. Це дозволить процесору правильно заповнити всі поля тіньових регістрів із таблиці дескрипторів. Доки ця операція не виконана, деякі поля тіньових регістрів (зокрема, межі сегментів) можуть містити невірну інформацію.

Завантажити селектори в сегментні регістри DS, SS і ES не завдає клопоту. Але як завантажити селектор у регістр CS? Для цього можна скористатися штучно сконструйованою командою дальнього переходу, яка призводить до зміни вмісту IP і CS. Рядки

db 0EAh ;Код команди far jmp

dw offset continue ;Зсув

dw 16 ;Селектор сегменту команд

демонструють цю методику. У реальному режимі ми помістили б у друге слово адреси сегментну адресу сегменту команд, у захищеному ж ми записуємо в нього селектор цього сегменту (число 16).

Команда дальнього переходу, крім завантаження в CS селектора, виконує ще одну функцію - вона очищує чергу команд у блоці передвиборки команд процесора. Як відомо, у сучасних процесорах із метою підвищення швидкості виконання програми використовується конвейєрна обробка команд програми. Одночасно з виконанням поточної (першої) команди здійснюється вибірка операндів наступної (другої), дешифрування третьої і вибірка з пам'яті четвертої команди. Таким чином, у момент переходу в захищений режим уже можуть бути розшифровані декілька таких команд і обрані з пам'яті їхні операнди. Проте ці дії виконувалися, очевидно, по правилах реального, а не захищеного режиму, що може призвести до порушень у роботі програми. Команда переходу очищує чергу передвиборки, примушуючи процесор заповнити її наново вже в захищеному режимі.

Як вже відзначалося вище, для того, щоб не зруйнувати працездатність DOS, процесор варто повернути в реальний режим, після чого можна буде завершити програму звичайним чином. Перейти в реальний режим можна різними засобами; у цьому прикладі скидання процесора виконується засиланням команди FEh у порт 64h контролера клавіатури. Ця команда збуджує сигнал на одному з виводів контролера клавіатури, що насамкінець призводить до появи сигналу скидання на виводі RESET мікропроцесора. Перед виконанням скидання поточний вміст SP зберігається в чарунці real_sp, щоб після переходу в реальний режим можна було відновити стан стеку.

Після скидання процесор працює в реальному режимі, причому керування передається програмам BIOS. BIOS аналізує вміст байту стану відключення (Fh) КМОП-мікросхеми і, оскільки ми записали туди код 0Ah, здійснює передачу керування за адресою, що зберігається в чарунці 40h:67h області даних BIOS. У нашому випадку перехід здійснюється на помітку return.

Команда hlt (halt, останов) дозволяє організувати чекання скидання процесора, що виконується не миттєво.

Передача керування на мітку return здійснюється програмами BIOS, які звичайно ж використовують регістри процесора. Зокрема, регістри SS:SP і DS вказують на поля даних BIOS, і їх варто ініціювати заново.

Для відновлення працездатності системи варто дозволити переривання, після чого програма може працювати вже в реальному режимі. У розглянутому прикладі для перевірки працездатності системи на екран виводиться деякий текст за допомогою функції DOS 09h. Для наочності в нього включені Esc-послідовності зміни кольору символів, тому програму варто виконувати при встановленому драйвері ANSI.SYS.

Програма завершується звичайним чином функцією DOS 4Ch. Нормальне завершення програми і перехід у DOS теж якоюсь мірою свідчить про її правильність.
ЗАВДАННЯ

Розробити та відлагодити програму, яка:

  • описує таблицю глобальних дескрипторів;

  • описує дескриптори сегменту даних, сегменту команд, сегменту стеку програми;

  • ініціалізує дескриптори, завантажує в регістр процесора GDTR дані про таблицю глобальних дескрипторів та переводить ЦП у захищений режим;

  • виконує 10N ітерацій циклу, де N – порядковий номер студента у списку журнала, та повертає процесор у реальний режим.


^
ПИТАННЯ ДЛЯ САМОКОНТРОЛЮ




  1. Які можливості архітектури МП реалізуються при переході в захищений режим?

  2. Що таке дескриптор сегменту?

  3. Яку інформацію зберігає дескриптор сегменту?

  4. Як формується лінійна адреса в захищеному режимі?

  5. Що таке таблиця глобальних дескрипторів?

  6. Чи можна модифікувати сегменти команд в захищеному режимі під час виконання програми?

  7. Що таке регістр таблиці глобальних дескрипторів?

  8. Які таблиці треба підготувати для виходу в захищений режим?

  9. У який спосіб можна повернутися з захищеного режиму до реального?

  10. Яке призначення тіньових регістрів? Чи доступні вони програмісту?





Схожі:




База даних захищена авторським правом ©lib.exdat.com
При копіюванні матеріалу обов'язкове зазначення активного посилання відкритою для індексації.
звернутися до адміністрації