Міністерство освіти Республіки Білорусь Білоруський Державний p>
Університет Інформатики і радіоелектроніки p>
Кафедра ЕОМ p>
Пояснювальна записка до курсового проекту по курсу p>
"СПO ЕОМ", на тему: p>
"DOS-extender для компілятора Borland C + + 3.1, захищений режим процесора 80286, організація багатозадачного роботи процесора" p>
Виконав: студент групи 500501 p >
Балахонов Е.В. p>
Мінськ 2000 p>
Зміст. p>
1. Вступ. 2
1.1 Рівні програмної підтримки захищеного режиму. 2 p>
1.1.1 Інтерфейс BIOS. 2 p>
1.1.2 інтерфейс драйвера HIMEM.SYS. 2 p>
1.1.3 інтерфейс EMS/VCPI. 3 p >
1.1.4 інтерфейс DPMI. 3 p>
1.1.5 розширювачі DOS (DOS-екстендера). 3
1.2 Поточний стан справ у світі DOS-extender-ів. 4
2. Обгрунтування вибору засобів. 4
3. Реалізація роботи програми в захищеному режимі процесора 80286. 5
3.1 Адресація захищеного режиму процесора 80286. 5
3.2 Перехід в захищений режим процесора 80286 8
3.3 Повернення до реального режиму процесора. 10
3.4 Обробка переривань в захищеному режимі. 11
3.5 Реалізація мультизадачності. 13 p>
3.5.1 Контекст завдання. 14 p>
3.5.2 Перемикання завдань. 15 p>
3.5.3 Поділ ресурсів. 16 p>
3.5.4 Завдання. 16
4. Повні вихідні тексти програми. 17
4.1 Файл TOS.INC. Визначення констант і структур для модулів, складених на мові асемблера. 17
4.2 Файл TOS.H. Визначення констант і структур для модулів, складених на мові Сі. 18
4.3 Файл TOS.H. Основний файл програми. 19
4.4 Файл TASKS.C. Має функції завдань. 24
4.5 Файл SEMAPHOR.C. Містить процедури для роботи з семафора. 26
4.6 Файл TIMER.C. Процедури для роботи з таймером і диспетчер завдань. 27
4.7 Файл EXCEPT.C. Обробка винятків. 28
4.8 Файл INTPROC.C. Заглушки для апаратних переривань. 29
4.9 Файл KEYB.C. Введення символу з клавіатури. 30
4.10 Файл KEYBOARD.ASM. Процедури для роботи з клавіатурою. 30
4.11 Файли SCREEN.H і SCREEN.C - модуль для роботи з відеоадаптером. 34 p>
4.11.1 SCREEN.H 34 p>
4.11.2 SCREEN.C 34
4.12 Файл TOSSYST.ASM. Процедури для ініціалізації, переходу в захищений режим і повернення в реальний режим, для завантаження регістру TR і перемикання завдань. 36
5. Висновки. 41
6. Література. 41 p>
1. Введення. P>
Операційна система MS DOS, не дивлячись на своє моральне старіння,все ще досить часто знаходить застосування на парку старих ПК, а значить, всеще існує необхідність створення програм для неї. p>
На жаль, написання програм в реальному режимі процесорівархітектури Intel x86 ускладнене відсутністю можливості використовувати впрограмі оперативну пам'ять обсягом понад горезвісних 640 кілобайт, ареально понад 500-620 кілобайт. Це обмеження на жаль переслідує MS
DOS і аналогічні їй ОС інших виробників, починаючи з того моменту, якгаряче улюблений в навколокомп'ютерні колах Білл Гейтс заявив, що 640кілобайт достатньо для всіх можливих завдань ПК. Подолання бар'єра 640кілобайт в нових версіях MS DOS ускладнювалося необхідністю сумісності зстарими програмами, які життєво необхідно було підтримувати.
Програмування захищеного режиму процесора і розширеної пам'ятівимагало від програмістів чималих знань архітектури процесорів Intelі досить трудомісткого програмування. p>
1.1 Рівні програмної підтримки захищеного режиму. P>
Інженерна думка не стоїть на місці, особливо в такій галузі, якпрограмування. Завдання програмної підтримки захищеного режиму тапідтримки роботи з розширеною пам'яттю отримала не одне, а відразу кількарішень. Цими рішеннями стали так звані рівні програмної підтримкизахищеного режиму та підтримки роботи з розширеною пам'яттю: p>
. інтерфейс BIOS; p>
. інтерфейс драйвера HIMEM.SYS; p>
. інтерфейс EMS/VCPI; p>
. інтерфейс DPMI; p>
. розширювачі DOS (DOS-екстендера). p>
1.1.1 Інтерфейс BIOS. p>
Інтерфейсом найнижчого рівня є інтерфейс BIOS,що надається програмами у вигляді декількох функцій переривання BIOS
INT 15h. Інтерфейс BIOS дозволяє програмі перевести процесор зреального режиму в захищений, переслати блок пам'яті із стандартної пам'ятів розширену або з розширеною в стандартну. Цим всі його можливості таобмежуються. Інтерфейс BIOS використовується для старту мультизадачностіопераційних систем захищеного режиму (таких, як OS/2) або в старихпрограмах, що працюють з розширеною пам'яттю в захищеному режимі (наприклад,
СУБД ORACLE версії 5.1). P>
1.1.2 інтерфейс драйвера HIMEM.SYS. P>
За допомогою функцій, що надаються цим драйвером, програма можевиконувати різні дії з блоками розширеної пам'яті, а такожкерувати адресної лінією A20. Основна відмінність між способом роботи зрозширеною пам'яттю драйвера HIMEM.SYS і інтерфейсом переривання BIOS
INT 15h полягає в тому, що перший виконує виділення програмі івнутрішній облік блоків розширеної пам'яті, а другий розглядає всюрозширену пам'ять як один безперервний ділянку. Однак драйвер HIMEM.SYSне відкриває для програм доступ до захищеного режиму. Він повністюпрацює в реальному режимі, а для звернення до розширеної пам'яті використовуєабо недокументовані машинну команду LOADALL (якщо використовуєтьсяпроцесор 80286), або можливості процесора 80386, який дозволяєадресувати розширену пам'ять у реальному режимі (при відповіднійініціалізації системних регістрів і таблиць). p>
1.1.3 інтерфейс EMS/VCPI. p>
Використовуючи трансляцію сторінок, деякі драйвери пам'яті (наприклад,
EMM386 або QEMM) можуть емулювати присутність додаткової пам'яті,використовуючи розширену пам'ять. При цьому стандартний набір функцій управліннядодатковою пам'яттю, реалізований у рамках переривання INT 67h, доповненийще декількома функціями для роботи в захищеному режимі процесора. Цінові функції реалізують інтерфейс віртуальної керуючої програми VCPI
(Virtual Control Programm Interface). Вони дозволяють встановлюватизахищений і віртуальний режими роботи процесора, працювати з розширеноюпам'яттю на рівні сторінок і встановлювати спеціальні налагоджувальний регістрипроцесора i80386. Інтерфейс VCPI полегшує використання механізмутрансляції сторінок, звільняючи програміста від необхідності працювати зсистемними регістрами процесора. p>
1.1.4 інтерфейс DPMI. p>
Інтерфейс DPMI (DOS Protected Mode Interface - інтерфейс захищеногорежиму для DOS) реалізується модулем, що називається сервером DPMI. Цейінтерфейс доступний для тих програм, які працюють на віртуальній машині
WINDOWS або OS/2 версії 2.0 (пізніше ми обговоримо деякі деталі, пов'язані звикористанням інтерфейсу DPMI в WINDOWS). Інтерфейс DPMI надаєповний набір функцій для створення однозадачних програм, що працюють взахищеному режимі. У цьому інтерфейсі є функції для перемикання зреального режиму в захищений і назад, для роботи з локальною таблицеюдескрипторів LDT, для роботи з розширеною і стандартною пам'яттю на рівністорінок, для роботи з переривань (у тому числі для виклику перериваньреального режиму із захищеного режиму), для роботи з налагоджувальнийрегістрами процесора i80386. Це найбільш розвинений інтерфейс з усіхрозглянутих раніше. p>
1.1.5 розширювачі DOS (DOS-екстендера). p>
Останній, найвищий рівень програмної підтримки захищеногорежиму - розширювачі DOS або DOS-екстендера (DOS-extender). Вонипоставляються, як правило, разом із засобами розробки програм
(трансляторами) у вигляді бібліотек і компонуються разом зі створюваноюпрограмою в єдиний завантажувальний модуль. DOS-екстендера значнополегшують використання захищеного режиму та розширеної пам'яті впрограмах, призначених для запуску з середовища MS-DOS. Програми,складені з використанням DOS-екстендера, зовні дуже схожі назвичайні програми MS-DOS, проте вони отримують управління, коли процесорвже знаходиться в захищеному режимі. До що формується за допомогою DOS-екстендеразавантажувальному модулю додаються процедури, необхідні для ініціалізаціїзахищеного режиму. Ці процедури першими отримують управління і виконуютьпочаткову ініціалізацію таблиць GDT, LDT, IDT, містять обробникипереривань і виключень, систему управління віртуальною пам'яттю і т.д. p>
1.2 Поточний стан справ у світі DOS-extender-ів. p>
Ще кілька років тому цілі фірми заробляли собі на існуваннястворенням різних модифікацій DOS extender-ів. Наприклад доситьвідомий externder фірми Phar Lap. Після переходу більшостікористувачів у середу Win32 необхідність у DOS extender-ах різкоскоротилася і більшість таких фірм, не зумівши зорієнтуватися вумовах, що змінилися, припинили своє існування. p>
Багато фірм, які розробляли компілятори для DOS, включали в постачаннясвоїх середовищ програмування DOS-extender-и власної розробки. Такимприкладом може служити фірма Borland (нині підрозділ фірми Corel) з її
Borland Pascal, Borland C + + і розширювачем DOS RTM. P>
У даний момент доступні декілька DOS-extender-ів з вільноїліцензії, які можуть використовуватися ким завгодно для будь-яких цілей. І цезрозуміло, грошей на них зараз не заробиш. p>
Приклади таких програм: p>
- ZRDX by Sergey Belyakov (http://www.zrdx.da.ru) p> < p> Маленький і функціональний DOS-extender для Watcom C + + і 32-х бітових виконуваних файлів формату OS/2 LE. Використовується в комерційних програмах, таких як антивірус AVP для DOS32. P>
- WDOSX by Michael Tippach (http://www.wuschel.demon.co.uk) p>
Найбільш вразили мене DOS -extender. Список підтримуваних функцій просто вражає. Підтримує всі поширені середовища програмування: Visual C + + 4 і пізніше, Borland C + + 4 і пізніше, p>
Delphi 2 і пізніше. При бажанні ніхто не забороняє використовувати p>
Assembler. P>
2. Обгрунтування вибору коштів. P>
DOS-екстендера звичайно поставляються в комплекті з трансляторами,редакторами зв'язків, відладчиком і бібліотеками стандартних функцій
(наприклад, бібліотеками для транслятора мови Сі). Код DOS-extenderлінкуются або вже до готового виконуваного файлу спеціальною програмою
(найчастіше), або лінковка повністю проходить за допомогою програми-лінкера,спеціально розробленого для даного компілятора. p>
На даний момент науці відомі всього одна DOS-extender для Borland
C + + 3.1. Це програма фірми Phar Lap, яка не має власної назви.
Фірми, на жаль, давно вже немає, як і вихідних текстів цього DOS -extender-а. У нього входив власна програма - лінкер і набірспеціальних бібліотек функцій спеціально для Borland C + + 3.1, якій іпроводилася остаточна збірка EXE-файлу. p>
Написання власної середовища розробки, на зразок програм-лінкер івласних трансляторів мови Асемблера явно виходить за межі даногокурсового проекту. Тому зупинимося на розробці набору функцій,дозволяють: p>
- реалізувати захищений режим процесора 80286, p>
- адресувати до 16 Мб пам'яті, p>
- обробляти переривання реального режиму DOS p>
- реалізуємо набір засобів для створення паралельно що виконуються потоків в середовищі DOS. p>
Після розробки необхідних коштів, напишемо програму-приклад з їхвикористанням. Власне це вийде не просто програма, а якийсьпрототип багатозадачного операційної системи. p>
Отже, згідно із завданням буду користуватися наступними засобамирозробки: p>
- Borland C + + 3.1 p>
- Borland Turbo Assembler з поставки Borland C + + 3.1 p>
3. Реалізація роботи програми в захищеному режимі процесора 80286. P>
3.1 Адресація захищеного режиму процесора 80286. P>
Логічний адреса в захищеному режимі (іноді використовується термін
"віртуальний адреса") складається з двох 16-розрядних компонент - селектора ізміщення. Селектор записується в ті ж сегментні регістри, що ісегментний адреса в реальному режимі. Проте перетворення логічногоадреси у фізичний виконується не простим додаванням зі зрушенням, а придопомогою спеціальних таблиць перетворення адрес. p>
У першому наближенні можна вважати, що для процесора i80286 селекторє індексом в таблиці, що містить базові 24-розрядні фізичніадреси сегментів. У процесі перетворення логічного адреси у фізичнийпроцесор додає до базового 24-розрядному адресою 16-розрядне зміщення,тобто другого компоненту логічного адреси (Мал. 1). p>
Така схема формування фізичної адреси дозволяє безпосередньоадресувати 16 мегабайт пам'яті за допомогою 16-розрядних компонент логічногоадреси. p>
Таблиць дескрипторів в системі звичайно є присутнім від однієї докількох десятків. Але завжди існує так звана таблиця GDT
(Global Descriptor Table), в якій зазвичай зберігається опис сегментівсамої операційної системи захищеного режиму 80286. Таблиці LDT (Local
Descriptor Table) створюються на кожен новий запускається процес вопераційній системі, і в них зберігається опис сегментів тільки однієїокремої завдання. p>
Таблиця дескрипторів - це просто таблиця перетворення адрес,містить базові 24-розрядні фізичні адреси сегментів і деякуіншу інформацію. Тобто кожен елемент таблиці дескрипторів (дескриптор)містить 24-розрядний базова адреса сегменту та іншу інформацію,описує сегмент. p>
Процесор 80286 має спеціальний 5-байтним регістр захищеного режиму
GDTR, в якому старші 3 байти містять 24-розрядний фізичну адресутаблиці GDT, молодші два байти - довжину таблиці GDT, зменшену на 1. p>
p>
Рис. 1. Схема перетворення логічного адреси у фізичний у захищеному режимі процесора 80286. P>
Перед переходом в захищений режим програма повинна створити воперативної пам'яті таблицю GDT і завантажити регістр GDTR за допомогоюспеціальної команди LGDT. p>
Кожен елемент таблиці дескрипторів мають такий вигляд: p>
p>
Загальна його довжина складає 8 байт, в яких розташовані наступніполя: p>
. поле базової адреси довжиною 24 біта містить фізична адреса сегмента, описуваного даними дескриптором; p>
. поле межі містить розмір сегмента в байтах, зменшений на одиницю; p>
. поле доступу описує тип сегмента (сегмент коду, сегмент даних тощо); p>
. зарезервоване поле довжиною 16 біт для процесора i80286 повинно містити нулі, це поле використовується процесорами i80386 і i80486 p>
(там, зокрема, зберігається старший байт 32-розрядного базової адреси сегмента). p>
Поле доступу, що займає в дескриптор один байт (байт доступу) служитьдля класифікації дескрипторів. На рис. 2 приведені формати поля доступудля трьох типів дескрипторів - дескрипторів сегментів коду, сегментів данихі системних.
p>
Рис. 2. Формати поля доступу дескриптора. P>
Поле доступу дескриптора сегментів коду містить бітове поле R,зване бітом дозволу читання сегмента. Якщо цей біт встановлений в 1,програма може зчитувати вміст сегменту коду. В іншому випадкупроцесор може тільки виконувати цей код. p>
Біти P і A призначені для організації віртуальної пам'яті. Їхпризначення буде описано в розділі, присвяченому віртуальної пам'яті. Заразвідзначимо, що біт P називається бітом присутності сегменту в пам'яті. Для тихсегментів, які знаходяться у фізичній пам'яті (ми будемо мати справу восновному з такими сегментами) цей біт повинен бути встановлений в 1. p>
Будь-яка спроба програми звернутися до сегменту пам'яті, в дескрипторякого біт P встановлено в 0, призведе до переривання. p>
Біт A називається бітом звернення до сегмента і для всіх наших програмповинен бути встановлений у 0. p>
Поле доступу дескриптора сегмента даних має бітові поля W і D.
Поле W називається бітом дозволу запису в сегмент. Якщо цей бітвстановлений в 1, разом з читанням можлива і запис в даний сегмент. УІнакше при спробі читання виконання програми буде перервано. p>
Поле D задає напрямок розширення сегмента. Звичайний сегмент данихрозширюється в область старших адрес (розширення вгору). Якщо ж усегменті розташований стек, розширення відбувається у зворотному напрямку - вобласть молодших адрес (розширення вниз). Для сегментів, в якихорганізуються стеки, необхідно встановлювати поле D рівним 1. p>
Розглянемо, як таблиця дескрипторів буде виглядати на мовіпрограмування C. (Надалі де це тільки можливо будемо застосовуватимову С, а Асемблер - тільки там, де це необхідно .): p>
typedef struct descriptor
(Word limit;// Межа (розмір сегмента в байтах) word base_lo;// Базовий адресу сегменту (молодше слово) unsigned char base_hi;// Базовий адресу сегменту (старший байт) unsigned char type_dpl;// Поле доступу дескриптора unsigned reserved;// Зарезервовані 16 біт
) Descriptor; p>
Дана структура описана у файлі tos.h. p>
ініціалізацію примірника такої структури можна зробити за допомогоюфункції, подібної функції init_gdt_descriptor, описаної у файлі tos.c: p>
void init_gdt_descriptor (descriptor * descr, unsigned long base, word limit, unsigned char type)
(
// Молодше слово базової адреси descr-> base_lo = (word) base; p>
// Старший байт базової адреси descr-> base_hi = (unsigned char) (base>> 16);
// Поле доступу дескриптора descr-> type_dpl = type; p>
// Межа descr-> limit = limit; p>
// зарезервоване поле, має бути < br>// скинуто в 0 завжди (для процесорів 286) descr-> reserved = 0;
) p>
Наприклад, запис у третій за рахунком елемент GDT інформації про сегментданих з сегментним адресою _DS і межею 0xffff буде виглядітьеть так: p>
init_gdt_descriptor (& gdt [2], MK_LIN_ADDR (_DS, 0), 0xffffL, p>
TYPE_DATA_DESCR | SEG_PRESENT_BIT |
SEG_WRITABLE); p>
Макрос MK_LIN_ADDR визначений у файлі tos.h і служить для перетворенняадреси реального режиму формату сегмент: зміщення у фізичну адресу: p>
# define MK_LIN_ADDR (seg, off) (((unsigned long) (seg)) ss = ds; t-> ip = (word) ip;// покажчик команд t-> sp = (word) sp;// зсув стека t-> bp = (word) sp;
) p>
// ---------------------------------------- ---------< br>//Функція ініціалізації дескриптора в таблиці GDT
//------------------------------------------------ - p>
void init_gdt_descriptor (descriptor * descr, unsigned long base, word limit, unsigned char type)
(
// Молодше слово базової адреси descr-> base_lo = (word) base; p>
// Старший байт базової адреси descr-> base_hi = (unsigned char) (base>> 16);
// Поле доступу дескриптора descr-> type_dpl = type; p>
// Межа descr-> limit = limit; p>
// зарезервоване поле, має бути < br>// скинуто в 0 завжди (для процесорів 286) descr-> reserved = 0;
) p>
// ---------------------------------------- -------< br>//Ініціалізація всіх таблиць і вхід
//В захищений режим
//-----------------------------------------------
void Init_And_Protected_Mode_Entry (void)
(Union REGS r; p>
// Ініціалізіруем таблицю GDT, елементи з 1 по 5 p>
init_gdt_descriptor (& gdt [1], MK_LIN_ADDR (_CS, 0), p>
0xffffL, TYPE_CODE_DESCR | SEG_PRESENT_BIT |
SEG_READABLE); p>
init_gdt_descriptor (& gdt [2], MK_LIN_ADDR (_DS, 0), p>
0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT |
SEG_WRITABLE); p>
init_gdt_descriptor (& gdt [3],
MK_LIN_ADDR (_DS, & task_1_tss), p>
(unsigned long) TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT); p >
init_gdt_descriptor (& gdt [4], p>
MK_LIN_ADDR (_DS, & task_2_tss), p>
(unsigned long) TSS_SIZE-1, TYPE_TSS_DESCR |
SEG_PRESENT_BIT); p>
init_gdt_descriptor (& gdt [5], p>
MK_LIN_ADDR (_DS, & main_tss), p>
(unsigned long) TSS_SIZE-1, TYPE_TSS_DESCR |
SEG_PRESENT_BIT); p>
// Ініціалізіруем TSS для задач TASK_1, TASK_2 p>
init_tss (& task_1_tss, CODE_SELECTOR, DATA_SELECTOR, task_1_stack + sizeof (task_1_stack), task1); p>
init_tss (& task_2_tss, CODE_SELECTOR, DATA_SELECTOR, task_2_stack + sizeof (task_2_stack), task2); p>
// Ініціалізіруем елемент 6 таблиці GDT -
// дескриптор для сегменту відеопам'яті p>
// Визначаємо відеорежим rhah = 15; int86 (0x10, & r, & r); p>
// Ініціалізація для монохромного режиму if (rhal == MONO_MODE) init_gdt_descriptor (& gdt [6], MONO_VID_MEM,
3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);
// Ініціалізація для кольорового режиму else if (rhal == BW_80_MODE | | rhal == COLOR_80_MODE) init_gdt_descriptor (& gdt [6], COLOR_VID_MEM,
3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); else
(printf ( "nІзвініте, цей режим відео неприпустимий."); exit (-1);
) p>
// Ініціалізація елементів 7 і 8 таблиці GDT init_gdt_descriptor (& gdt [7], p>
MK_LIN_ADDR (_DS, & idt), p>
(unsigned long) IDT_SIZE-1, p>
TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); p>
init_gdt_descriptor (& gdt [8], p>
MK_LIN_ADDR (_DS, & keyb_task_tss), p>
(unsigned long) TSS_SIZE-1 , p>
TYPE_TSS_DESCR | SEG_PRESENT_BIT); p>
// Ініціалізація TSS для завдання KEYB_TASK init_tss (& keyb_task_tss, CODE_SELECTOR, DATA_SELECTOR, keyb_task_stack + sizeof (keyb_task_stack), keyb_task); p> < p>// Ініціалізація елемента 9 таблиці GDT init_gdt_descriptor (& gdt [9], p>
MK_LIN_ADDR (_DS, & keyb_tss), p>
(unsigned long) TSS_SIZE-1, p> < p> TYPE_TSS_DESCR | SEG_PRESENT_BIT); p>
// Ініціалізація TSS для завдання KEYB обробки введення з клавіатури init_tss (& keyb_tss, CODE_SELECTOR, DATA_SELECTOR, keyb_stack + sizeof (keyb_stack), Keyb_int); p>
// Ініціалізація елемента 10 таблиці GDT init_gdt_descriptor (& gdt [10], p>
MK_LIN_ADDR (_DS, & flipflop_tss), p>
(unsigned long) TSS_SIZE-1, p>
TYPE_TSS_DESCR | SEG_PRESENT_BIT); p>
// Ініціалізація TSS для завдання FLIP_TASK init_tss (& flipflop_tss, CODE_SELECTOR, DATA_SELECTOR, flipflop_stack + sizeof (flipflop_stack), flipflop_task); p>
// Завантаження регістра IDTR load_idtr (MK_LIN_ADDR (_DS, & idt), IDT_SIZE); p>
// Вхід в захищений режим protected_mode (MK_LIN_ADDR (_DS, & gdt), sizeof (gdt), p>
CODE_SELECTOR, DATA_SELECTOR);
) p>
4.4 Файл TASKS.C. Має функції завдань. P>
# include
# include
# include
# include
# include
# include "tos.h"
# include "screen.h" p>
word dispatcher (void); p>
// Номер поточного рядка для виводу на екранextern unsigned int y; p>
// Завдання TASK_1void task1 (void)
(While (1)
(vi_print (0, y + +, "Запущена завдання TASK_1," p>
"повернення управління головної задачі", 0x70); jump_to_task (MAIN_TASK_SELECTOR); p>
// Після повторного запуску цього завдання
// знову входимо в цикл.
)
) p>
// Завдання TASK_2long delay_cnt1 = 0l;word flipflop1 = 0;void task2 (void)
(Char Buf [B_SIZE + 1];// Буфер виведення завдання 2 static TLabel Label1; static TLabel Label2; p>
memset (Buf, '', B_SIZE);
Buf [B_SIZE] = 0; p>
Label1.Pos = 0;
Label1.Dir = 1; p>
Buf [Label1.Pos] ='/'; p>
Label2.Pos = B_SIZE;
Label2.Dir = 0;
Buf [Label2.Pos] =''; p>
vi_print (30, 15, "Працює завдання 2:", 0x7f); p>
while (1)
(
// Періодично виводимо на екран движки,
// щоразу перемикаючи
// семафор номер 1. Цей семафор однозначно
// відповідає виведеної на екран рядку. asm sti if (delay_cnt1> 150000l)
(asm cli p>
StepLabel (& Label1, & Label2, Buf); p>
if (flipflop1) p>
(vi_print (5, 16, Buf, 0x1f); sem_clear (1); p>
) else p>
(vi_print (5, 16, Buf, 0x1f); sem_set (1); p>
) flipflop1 ^ = 1; delay_cnt1 = 0l; asm sti
) delay_cnt1 + +;
)
) p>
word flipflop = 0;long delay_cnt = 0l; p>
// Це завдання також періодично виводить на екран
//З меншим періодом. Крім того, це завдання
//Працює тільки тоді, коли встановлено
//Семафор номер 1.void flipflop_task (void)
(Char Buf [B_SIZE + 1];// Буфер виведення завдання 2 static TLabel Label1; static TLabel Label2; p>
memset (Buf, '', B_SIZE);
Buf [B_SIZE] = 0; p>
Label1.Pos = 0;
Label1.Dir = 1;
Buf [Label1.Pos] ='/'; p>
Label2.Pos = B_SIZE; < br> Label2.Dir = 0;
Buf [Label2.Pos] =''; p>
vi_print (30, 12, "Працює завдання 0:", 0x7f); p>
while (1)
(asm sti if (delay_cnt> 20000l)
(sem_wait (1);// очікуємо встановлення світлофора asm cli p>
StepLabel (& Label1, & Label2, Buf); vi_print (5, 13, Buf, 0x1f); flipflop ^ = 1; delay_cnt = 0l; asm sti
) delay_cnt + +;
)
) p>
word keyb_code; p>
extern word keyb_status; p>
// Це завдання вводить символи з клавіатури
//І відображає скан-коди натиснутих клавіш
//І стан перемикаючих клавіш на екрані.
//Якщо натискається клавіша ESC, завдання
//Встановлює семафор номер 0.
//Яка працює паралельно головне завдання
//Очікує встановлення цього семафора. Як тільки
//Семафор 0 виявиться встановлено, головне завдання
//Завершує свою роботу і програма повертає
//Процесор до реального режиму, потім передає
//Керування MS-DOS.void keyb_task (void)
(Vi_print (32, 20, "Key code: ....", 0x20); vi_print (32, 21, "Key status: ....", 0x20); while (1)
(keyb_code = kb_getch (); vi_put_word (45, 20, keyb_code, 0x4f); vi_put_word (45, 21, keyb_status, 0x4f); if ((keyb_code & 0x00ff) == 1) sem_set (0);
)
) p>
4.5 Файл SEMAPHOR.C. Містить процедури для роботи з семафора. P>
# include
# include
# include
# include
# include "tos.h" p>
// Масив з п'яти семафорів p>
word semaphore [5]; p>
// Процедура скидання семафора.
//Параметр sem - номер скидається семафораvoid sem_clear (int sem)
(Asm cli semaphore [sem] = 0; asm sti
) p>
// Процедура установки семафора
//Параметр sem - номер встановлюваного семафораvoid sem_set (int sem)
(Asm cli semaphore [sem] = 1; asm sti
) p>
// Очікування установки семафора
//Параметр sem - номер очікуваного семафораvoid sem_wait (int sem)
(While (1)
(asm cli
// перевіряємо семафор if (semaphore [sem]) break; p>
asm sti// очікуємо встановлення світлофора asm nop asm nop
) asm sti
) p>
4.6 Файл TIMER.C. Процедури для роботи з таймером і диспетчер завдань. P>
Cодержит обробник апаратного переривання таймера, якийперіодично видає звуковий сигнал і ініціює роботу диспетчера завдань.
Диспетчер завдань циклічно перебирає селектори TSS завдань, що беруть участь впроцесі поділу часу, повертаючи селектор того завдання, яка повиннастати активною. У самому кінці обробки апаратного переривання таймеравідбувається перемикання саме на цю задачу. p>
# include
# include
# include
# include
# include "tos.h" p>
// ---------------------------------- ---------< br>//Модуль обслуговування таймера
//------------------------------------------- P> < p> # define EOI 0x20
# define MASTER8259A 0x20 p>
extern void beep (void);extern void flipflop_task (void);void Timer_int (void);word dispatcher (void); p>
word timer_cnt; p>
// ------------------------- -----------------< br>//Оброблювач апаратного переривання таймера
//------------------------------------------ P>
void Timer_int (void)
(Asm pop bp p>
// Періодично видаємо звуковий сигнал p>
timer_cnt + = 1; if ((timer_cnt & 0xf) == 0xf)
(beep ();
) p>
// Видаємо в контролер команду кінця
// переривання asm mov al, EOI asm out MASTER8259A, al p>
// Перемикаємося на наступне завдання,
// селектор TSS якої отримуємо від
// диспетчера завдань dispatcher () p>
jump_to_task (dispatcher ()); asm iret
) p>
// --------------------------------------< br >//Диспетчер завдань
//-------------------------------------- P>
// Масив селектор, що вказують на TSS
//Завдань, які беруть участь у паралельній роботі,
//Тобто діспетчерізуемих завдань p>
word task_list [] =
(
MAIN_TASK_SELECTOR,
FLIP_TASK_SELECTOR,
KEYBIN_TASK_SELECTOR,
TASK_2_SELECTOR
); p>
word current_task = 0;// поточна завданняword max_task = 3;// кількість завдань - 1 p>
// Використовуємо найпростіший алгоритм диспетчеризації -
//Виконуємо послідовне перемикання на всі
//Завдання, селектори TSS яких знаходяться
//В масиві task_list []. p>
word dispatcher (void)
(If (current_task ) p>
4.7 Файл EXCEPT.C. Обробка винятків. P>
# include
# include
# include
# include
# include "tos.h" p>
void prg_abort (int err); p>
// Номер поточного рядка для виводу на екран p>
extern unsigned int y;
// Обробники винятків p>
void exception_0 (void) (prg_abort (0);)void exception_1 (void) (prg_abort (1);)void exception_2 (void) (prg_abort (2);)void exception_3 (void) (prg_abort (3);)void exception_4 (void) (prg_abort (4);)void exception_5 (void) (prg_abort (5);)void exception_6 (void) (prg_abort (6);)void exception_7 (void) (prg_abort (7);)void exception_8 (void) (prg_abort (8);)void exception_9 (void) (prg_abort (9);)void exception_A (void) (prg_abort (0xA);)void exception_B (void) (prg_abort (0xB);)void exception_C (void) (prg_abort (0xC);)void exception_D (void) (prg_abort (0xD);)void exception_E (void) (prg_abort (0xE);)void exception_F (void) (prg_abort (0xF);)void exception_10 (void) (prg_abort (0x10);)void exception_11 (void) (prg_abort (0x11);)void exception_12 (void) (prg_abort (0x12);)void exception_13 (void) (prg_abort (0x13);)void exception_14 (void) (prg_abort (0x14);)void exception_15 (void) (prg_abort (0x15);)void exception_16 (void) (prg_abort (0x16);)void exception_17 (void) (prg_abort (0x17);)void exception_18 (void) (prg_abort (0x18);)void exception_19 (void) (prg_abort (0x19);)void exception_1A (void) (prg_abort (0x1A);)void exception_1B (void) (prg_abort (0x1B);)void exception_1C (void) (prg_abort (0x1C);)void exception_1D (void) (prg_abort (0x1D);)void exception_1E (void) (prg_abort (0x1E);)void exception_1F (void) (prg_abort (0x1F);) p>
// ----------------------------- -
//Аварійний вихід з програми
//------------------------------ P>
void prg_abort (int err)
(Vi_print (1, y + +, "ERROR! ---> Сталося виключення", 0xc); p>
real_mode ();// Повертаємося до реального режиму p>
// В реальному режимі виводимо повідомлення про виключення p>
gotoxy (1, + + y); cprintf ( "Виключення% X, натисніть будь-яку клавішу", err); getch (); p>
textcolor ( WHITE); textbackground (BLACK); clrscr (); exit (0);
) p>
4.8 Файл INTPROC.C. Заглушки для апаратних переривань. P>
# include
# include
# include
# include
# include "tos.h" p>
// Заглушки для необроблюваних
//Апаратних переривань. P>
void iret0 (void)
(//Перший контролер переривань asm (push ax mov al, EOI out MASTER8259A, al pop ax pop bp iret
)
) p>
// ---------------------------------------- -------------------< br>//Другий контролер перериваньvoid iret1 (void)
(Asm (push ax mov al, EOI out MASTER8259A, al out SLAVE8259A, al pop ax pop bp iret
)
) p>
4.9 Файл KEYB.C. Введення символу з клавіатури. P>
# include
# include
# include
# include
# include "tos.h" p>
extern word key_code; p>
// Функція, яка очікує натискання будь-якої
//Клавіші і повертає її скан-код p>
unsigned int kb_getch (void)
(Asm int 30h return (key_code);
) p>
4.10 Файл KEYBOARD.ASM. Процедури для роботи з клавіатурою. P>
IDEAL p>
MODEL SMALL
RADIX 16 p>
P286include "tos.inc" p>
; ------------------------------------ ------< br>; Модуль обслуговування клавіатури
; ------------------------------------------ P>
PUBLIC _Keyb_int, _Int_30h_Entry, _key_code, _keyb_status
EXTRN _beep: PROC
DATASEG p>
_key_flag db 0 p>
_key_code dw 0 ext_scan db 0 p>
_keyb_status dw 0 p>
CODESEG p>
PROC _Keyb_int NEAR cli p>
call _beep p>
push ax mov al, [ext_scan] cmp al, 0 jz normal_scan1 cmp al, 0e1h jz pause_key p>
in al, 60h p>
cmp al, 2ah jz intkeyb_exit_1 cmp al, 0aah jz intkeyb_exit_1 p>
mov ah, [ext_scan] call Keyb_PutQ p>
mov al, 0 mov [ext_scan], al jmp intkeyb_exit p>
pause_key: p>
in al, 60h cmp al, 0c5h jz pause_key1 cmp al, 45h jz pause_key1 p>
jmp intkeyb_exit p>
pause_key1: mov ah, [ext_scan] call Keyb_PutQ p>
mov al, 0 mov [ext_scan], al jmp intkeyb_exit p>
normal_scan1: in al, 60h cmp al, 0feh jz intkeyb_exit cmp al, 0e1h jz ext_key cmp al, 0e0h jnz normal_scan p>
ext_key: mov [ext_scan], al jmp intkeyb_exit p>
intkeyb_exit_1: mov al, 0 mov [ext_scan], al jmp intkeyb_exit p>
normal_scan: mov ah, 0 call Keyb_PutQ p>
intkeyb_exit: in al, 61h mov ah, al or al, 80h out 61h, al xchg ah, al out 61h, al mov al, EOI out MASTER8259A, al p>
pop ax sti iret jmp _Keyb_int
ENDP _Keyb_int p>
PROC Keyb_PutQ NEAR p>
push ax p>
cmp ax, 002ah; L_SHIFT down jnz @ @ kb1 mov ax, [_keyb_status] or ax, L_SHIFT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb1: cmp ax, 00aah; L_SHIFT up jnz @ @ kb2 mov ax, [_keyb_status] and ax, NL_SHIFT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb2: cmp ax, 0036h; R_SHIFT down jnz @ @ kb3 mov ax, [_keyb_status] or ax, R_SHIFT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb3: cmp ax, 00b6h; R_SHIFT up jnz @ @ kb4 mov ax, [_keyb_status] and ax, NR_SHIFT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb4: cmp ax, 001dh; L_CTRL down jnz @ @ kb5 mov ax, [_keyb_status] or ax, L_CTRL mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb5: cmp ax, 009dh; L_CTRL up jnz @ @ kb6 mov ax, [_keyb_status] and ax, NL_CTRL mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb6: cmp ax, 0e01dh; R_CTRL down jnz @ @ kb7 mov ax, [_keyb_status] or ax, R_CTRL mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb7: cmp ax, 0e09dh; R_CTRL up jnz @ @ kb8 mov ax, [_keyb_status] and ax, NR_CTRL mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb8: cmp ax, 0038h; L_ALT down jnz @ @ kb9 mov ax, [_keyb_status] or ax, L_ALT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb9: cmp ax, 00b8h; L_ALT up jnz @ @ kb10 mov ax, [_keyb_status] and ax, NL_ALT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb10: cmp ax, 0e038h; R_ALT down jnz @ @ kb11 mov ax, [_keyb_status] or ax, R_ALT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb11: cmp ax, 0e0b8h; R_ALT up jnz @ @ kb12 mov ax, [_keyb_status] and ax, NR_ALT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb12: cmp ax, 003ah; CAPS_LOCK up jnz @ @ kb13 mov ax, [_keyb_status] xor ax, CAPS_LOCK mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb13: cmp ax, 00bah; CAPS_LOCK down jnz @ @ kb14 jmp keyb_putq_exit
@ @ kb14: cmp ax, 0046h; SCR_LOCK up jnz @ @ kb15 mov ax, [_keyb_status] xor ax, SCR_LOCK mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb15: cmp ax, 00c6h; SCR_LOCK down jnz @ @ kb16 jmp keyb_putq_exit
@ @ kb16: cmp ax, 0045h; NUM_LOCK up jnz @ @ kb17 mov ax, [_keyb_status] xor ax, NUM_LOCK mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb17: cmp ax, 00c5h; NUM_LOCK down jnz @ @ kb18 jmp keyb_putq_exit
@ @ kb18: cmp ax, 0e052h; INSERT up jnz @ @ kb19 mov ax, [_keyb_status] xor ax, INSERT mov [_keyb_status], ax jmp keyb_putq_exit
@ @ kb19: cmp ax, 0e0d2h; INSERT down jnz @ @ kb20 jmp keyb_putq_exit
@ @ kb20: p>
test ax, 0080h jnz keyb_putq_exit p>
mov [_key_code], ax p>
mov al, 0ffh mov [_key_flag], alkeyb_putq_exit: pop ax ret
ENDP Keyb_PutQ p>
; Оброблювач програмного переривання
; Для введення з клавіатури. За своїми функціями
; Нагадує переривання INT 16 реального
; Режиму. P>
PROC _Int_30h_Entry NEAR push ax dx p>
; Очікуємо переривання від клавіатури p>
keyb_int_wait: sti nop nop cli p>
; Перевіряємо прапор, який встановлюється
; Обробником апаратного переривання клавіатури p>
mov al, [_key_flag] cmp al, 0 jz keyb_int_wait p>
; скидаємо прапор після приходу переривання p>
mov al, 0 mov [ _key_flag], al sti pop dx ax iret
ENDP _Int_30h_Entry p>
END p>
4.11 Файли SCREEN.H і SCREEN.C - модуль для роботи з відеоадаптером. P>
4.11.1 SCREEN.H p>
# ifndef SCREEN_H
# define SCREEN_H p>
// Кордони переміщення бігунків
# define B_SIZE 70 p>
// Структура, що описує бігунокtypedef struct _TLabel
(Char Pos;// Позиція бігунка char Dir;// Напрямок руху
) TLabel; p>
extern void StepLabel (TLabel * Label1, TLabel * Label2, char * Buf); p>
# endif p>
4.11.2 SCREEN.C
# include
# include
# include
# include
# include "tos.h"
# include "screen.h" p>
void vi_putch (unsigned int x, unsigned int y, char c, char attr); p>
char hex_tabl [] = "0123456789ABCDEF"; p>
// Висновок байти на екран, координати (x, y),
//Виводиться шістнадцяткове подання
//Байти chr з екранними атрибутами attr. P>
void vi_put_byte (unsigned int x, unsigned int y, unsigned char chr, char attr)
(Unsigned char temp; p>
temp = hex_tabl [(chr & 0xf0)>> 4]; vi_putch (x, y, temp, attr); p>
temp = hex_tabl [chr & 0xf]; vi_putch (x 1, y, temp, attr);
) p>
// Висновок слова на екран, координати (x, y),
//Виводиться шістнадцяткове подання
//Слова chr з екранними атрибутами attr. P>
void vi_put_word (unsigned int x, unsigned int y, word chr, char attr)
(Vi_put_byte (x, y, (chr & 0xff00)>> 8, attr); vi_put_byte (x 2, y, chr & 0xff, attr);
) p>
// Вивід символу c на екран, координати - (x, y),
//Атрибут виведеного символу - attr p>
void vi_putch (unsigned int x, unsigned int y, char c, char attr)
(Register unsigned int offset; char far * vid_ptr; p>
offset = (y * 160) + (x * 2); vid_ptr = MK_FP (VID_MEM_SELECTOR, offset);
* vid_ptr + + = c; * vid_ptr = attr;
) p>
// Висновок рядка s на екран, координати - (x, y),
//Атрибут що виводиться рядки - attr p>
void vi_print (unsigned int x, unsigned int y, char * s, char attr)
(While (* s) vi_putch (x + +, y, * s + +, attr);
) p>
// Висновок стоки повідомлення про запуск програмиvoid vi_hello_msg (void)
(Vi_print (0, 0, p>
"Threads for DOS," p>
"Version 0.1/i286, Copyright (c) 2000 Eugeny Balahonov",
0x30);
) p>
// Висновок рядка, що біжитьvoid StepLabel (TLabel * Label1, TLabel * Label2, char * Buf)
(
// Стираємо символи міток
Buf [Label1-> Pos] = '';
Buf [Label2-> Pos] = ''; p>
// Якщо рухаємося наліво if (Label1-> Dir == 0)
(
// Якщо не дійшли до крайньої лівої позиції if (Label1-> Pos> 0)
( p>
Label1-> Pos - -; p>
Buf [Label1-> Pos] ='';
) else
( p>
Label1-> Dir = 1; p>
Buf [Label1-> Pos] ='/';< br>)
)
// Якщо рухаємося направо else
(
// Якщо не дійшли до крайньої правої позиції if (Label1-> Pos ( p> Label1-> Pos ++; p>
Buf [Label1-> Pos] ='/';< br>) else
( p>
Label1-> Dir = 0; p>
Buf [Label1-> Pos] ='';
)
) p>
// Якщо рухаємося наліво if (Label2-> Dir == 0)
(
// Якщо не дійшли до крайньої лівої позиції if (Label2-> Pos> 0)
( p>
Label2-> Pos --; p>
Buf [Label2-> Pos] ='';
) else
( p>
Label2-> Dir = 1; p>
Buf [Label2-> Pos] ='/';< br>)
)
// Якщо рухаємося направо else
(
// Якщо не дійшли до крайньої правої позиції if (Label2 - > Pos ( p> Label2-> Pos ++; p>
Buf [Label2-> Pos] ='/';< br>) else
(
Label2-> Dir = 0; p>
Buf [Label2-> Pos] ='';
)
)
) p>
4.12 Файл TOSSYST.ASM. Процедури для ініціалізації, переходу в захищенийрежим і повернення в реальний режим, для завантаження регістру TR і перемиканнязавдань. p>
IDEAL p>
MODEL SMALL p>
RADIX 16 p>
P286 p>
DATASEG p>
include "tos.inc" p>
PUBLIC _beep p>
; Область пам'яті для ініціалізації IDTR p>
idtr idtr_struc p>
; Область пам'яті для ініціалізації GDTR p>
gdt_ptr dw (8 * 15) -1; розмір GDT, 15 елементів gdt_ptr2 dw? gdt_ptr4 dw? p>
; Область пам'яті для запису селектора завдання,
; На яку буде відбуватися перемикання p>
new_task dw 00h new_select dw 00h p>
; Область пам'яті для зберігання регістрів,
; Використовується для повернення в реальний режим p>
real_ss dw? real_sp dw? real_es dw? p>
protect_sel dw? p>
init_tss dw? p>
CODESEG p>
PUBLIC _real_mode, _protected_mode, _jump_to_task p>
PUBLIC _load_task_register, _load_idtr, _enable_interrupt p>
; ----------------------------------- --------------------------------< br>; Процедура для перемикання в захищений режим.
; Прототип для виклику:
; Void protected_mode (unsigned long gdt_ptr, unsigned int gdt_size,
; Unsigned int cseg, unsigned int dseg)
; ------------------------------------------------- ------------------ p>
PROC _protected_mode NEAR push bp mov bp, sp p>
; Параметр gdt_ptr p>
mov ax, [bp +4]; мл. слово адреси GDT mov dx, [bp +6]; ст. слово адреси GDT p>
mov [gdt_ptr4], dx; запам'ятовуємо адреса GDT mov [gdt_ptr2], ax p>
; Параметр gdt_size p>
mov ax, [bp +8 ]; отримуємо розмір GDT mov [gdt_ptr], ax; і запам'ятовуємо його p>
; Параметри cseg і dseg p>
mov ax, [bp +10 d]; отримуємо селектор сегменту коду mov dx, [bp +12 d]; отримуємо селектор сегменту даних mov [cs: p_mode_select], ax; запам'ятовуємо для команди mov [protect_sel], dx; переходу far jmp p>
; Підготовка до повернення в реальний режим p>
push ds; готуємо адреса повернення mov ax, 40h; із захищеного режиму mov ds, ax mov [WORD 67h], OFFSET shutdown_return mov [WORD 69h], cs pop ds p>
; Забороняємо і маскуючи все переривання p>
cli in al, INT_MASK_PORT and al, 0ffh out INT_MASK_PORT, al p>
; Записуємо код повернення в CMOS-пам'ять p>
mov al, 8f out CMOS_PORT, al jmp delay1delay1: mov al, 5 out CMOS_PORT 1, al p>
call enable_a20; відкриваємо лінію A20 p>
mov [real_ss], ss; запам'ятовуємо регістри SS і ES mov [real_es], es p>
; Перепрограмміруем контролер переривань
; Для роботи в захищеному режимі p>
mov dx, MASTER8259A mov ah, 20 call set_int_ctrlr mov dx, SLAVE8259A mov ah, 28 call set_int_ctrlr p>
; Завантажуємо регістри IDTR і GDTR p>
lidt [FWORD idtr] lgdt [QWORD gdt_ptr] p>
mov ax, 0001h; перемикаємо процесор lmsw ax; в захищений режим p>
; jmp far flush db 0eah dw OFFSET flushp_mode_select dw? p>
LABEL flush FAR p>
mov dx, [protect_sel] mov ss, dx mov ds, dx mov es, dx p>
; Обнуляємо вміст регістру LDTR p>
mov ax, 0 lldt ax p>
pop bp ret
ENDP _protected_mode p>
; ---------------------------------------- ------------< br>; Повернення до реального режиму.
; Прототип для виклику
; Void real_mode ();
; ---------------------------------------------------- p>
PROC _real_mode NEAR p>
; Скидання процесора p>
cli mov [real_sp], sp mov al, SHUT_DOWN out STATUS_PORT, al p>
rmode_wait: hlt jmp rmode_wait p> < p> LABEL shutdown_return FAR p>
; Повернулися до реального режиму p>
mov ax, DGROUP mov ds, ax p>
assume ds: DGROUP p>
mov ss, [real_ss] mov sp, [real_sp] p>
in al, INT_MASK_PORT and al, 0 out INT_MASK_PORT, al p>
call disable_a20 p>
mov ax, DGROUP mov ds, ax mov ss, ax mov es, ax p>
mov ax, 000dh out CMOS_PORT, al sti p>
ret
ENDP _real_mode p>
; ---------------------------------------- ---------------< br>; Завантаження регістра TR.
; Прототип для виклику:
; Void load_task_register (unsigned int tss_selector);
; ------------------------------------------------- ------ p>
PROC _load_task_register NEAR push bp mov bp, sp ltr [bp +4]; селектор для поточного завдання pop bp ret
ENDP _load_task_register p>
; ---------------------------------------- ---------------< br>; Переключення на завдання.
; Прототип для виклику:
; Void jump_to_task (unsigned int tss_selector);
; ------------------------------------------------- ------ p>
PROC _jump_to_task NEAR push bp mov bp, sp mov ax, [bp +4]; отримуємо селектор p>
; нового завдання mov [new_select], ax; запам'ятовуємо його p>
jmp [DWORD new_task]; перемикаємося на p>
; нове завдання pop bp ret
ENDP _jump_to_task p>
; ------------------------------< br>; Відкриваємо лінію A20
; ------------------------------ P>
PROC enable_a20 NEAR push ax mov al, A20_PORT out STATUS_PORT, al mov al, A20_ON out KBD_PORT_A, al pop ax ret
ENDP enable_a20 p>
; ------------------------------< br>; Закриваємо лінію A20
; ------------------------------ P>
PROC disable_a20 NEAR push ax mov al, A20_PORT out STATUS_PORT, al mov al, A20_OFF out KBD_PORT_A, al pop ax ret
ENDP disable_a20 p>
; ---------------------------------------- -------------------< br>; Готуємо структуру для завантаження регістра IDTR
; Прототип для виклику функції:
; Void load_idtr (unsigned long idt_ptr, word idt_size);
; ------------------------------------------------- ---------- p>
PROC _load_idtr NEAR push bp p>
mov bp, sp mov ax, [bp +4]; мл. слово адреси IDT mov dx, [bp +6]; ст. слово адреси IDT mov bx, OFFSET idtr p>
; Запам'ятовуємо адреса IDTR в структурі p>
mov [(idtr_struc bx). idt_low], ax mov [(idtr_struc bx). idt_hi], dl p>
; Отримуємо межа IDT і запам'ятовуємо його в структурі p>
mov ax, [bp +8] mov [(idtr_struc bx). idt_len], ax p>
pop bp ret
ENDP _load_idtr p>
; ----------------------------------< br>; Встановлення контролера переривань
; ---------------------------------- P>
PROC set_int_ctrlr NEAR p>
mov al, 11 out dx, al jmp SHORT $ +2 mov al, ah inc dx out dx, al jmp SHORT $ +2 mov al, 4 out dx, al jmp SHORT $ + 2 mov al, 1 out dx, al jmp SHORT $ +2 mov al, 0ffh out dx, al dec dx ret
ENDP set_int_ctrlr p>
; --------------------------< br>; Видача звукового сигналу
; -------------------------- P>
PROC _beep NEAR p>
push ax bx cx p>
in al, KBD_PORT_B push ax mov cx, 80 p>
beep0: p>
push cx and al, 11111100b out KBD_PORT_B, al mov cx, 60 p> < p>idle1: p>
loop idle1 or al, 00000010b out KBD_PORT_B, al mov cx, 60 p>
idle2: p>
loop idle2 pop cx loop beep0 p> < p> pop ax out KBD_PORT_B, al p>
pop cx bx ax ret p>
ENDP _beep p>
; ------------- ------------------< br>; Затримка виконання програми
; ------------------------------- P>
PROC _pause NEAR p>
push cx mov cx, 10 p>
ploop0: p>
push cx xor cx, cx p>
ploop1: p>
loop ploop1 pop cx loop ploop0
pop cx ret p>
ENDP _pause p>
; -----------------------< br>; Размаскірованіе переривань
; ----------------------- P>
PROC _enable_interrupt NEAR p>
in al, INT_MASK_PORT and al, 0fch out INT_MASK_PORT, al sti ret
ENDP _enable_interrupt p>
end p>
5. Висновки. P>
Процесори сімейства Intel x86 реалізують необхідні кошти дляорганізації мультизадачності ОС з розподілом адресного простору івіртуальної пам'яті. p>
У процесі написання даного курсового проекту мною були вивченаорганізація роботи захищеного режиму процесорів 80286, адресація нимипонад 1 Мб пам'яті, робота з переривань в захищеному режимі процесора,організація мультизадачності операційних систем. p>
6. Література. P>
1. «Захищений режим процесорів Intel 80286/80386/80486» © Олександр p>
Фролов, Григорій Фролов Том 6, М.: Диалог-МИФИ, 1993, 234 стор p>
2. «MS-DOS для програміста» ©