немогу скомпилить найденный в книге проект...

Тема в разделе "WASM.BEGINNERS", создана пользователем Q_sam, 17 янв 2009.

  1. Q_sam

    Q_sam New Member

    Публикаций:
    0
    Регистрация:
    10 янв 2009
    Сообщения:
    21
    Нашел в книге Фролова "Защищенный режим процессоров Intel 80286/80386/80486" реализацию многозадачности под дос. есть исходники даже...а скомпилить их немогу...=).....там часть на си часть на асме...кому не сложно дайте инструкцию что куда втыкать.....Заранее спасибо.
    прикпелеплена папка с исходниками
    _______________________________________________________________________________________________________
    Вот собственно сам код:
    Код (Text):
    1. Эта программа состоит из нескольких модулей, составленных на языках ассемблера и Си.
    2.  
    3. Первые два файла предназначены для определения используемых констант и структур данных.
    4. Листинг 4. Определение констант и структур для модулей,
    5.                 составленных на языке ассемблера.
    6.  
    7. Файл tos.inc
    8. -----------------------------------------------------------
    9.  
    10. CMOS_PORT               equ     70h
    11. PORT_6845               equ     63h
    12. COLOR_PORT      equ     3d4h
    13. MONO_PORT               equ     3b4h
    14. STATUS_PORT     equ     64h
    15. SHUT_DOWN               equ     0feh
    16. INT_MASK_PORT   equ     21h
    17. VIRTUAL_MODE    equ     0001
    18. A20_PORT                equ     0d1h
    19. A20_ON          equ     0dfh
    20. A20_OFF         equ     0ddh
    21. EOI                     equ     20h
    22. MASTER8259A     equ     20h
    23. SLAVE8259A      equ     0a0h
    24. KBD_PORT_A      equ     60h
    25. KBD_PORT_B      equ     61h
    26.  
    27. L_SHIFT         equ     0000000000000001b
    28. NL_SHIFT                equ     1111111111111110b
    29. R_SHIFT         equ     0000000000000010b
    30. NR_SHIFT                equ     1111111111111101b
    31.  
    32. L_CTRL          equ     0000000000000100b
    33. NL_CTRL         equ     1111111111111011b
    34. R_CTRL          equ     0000000000001000b
    35. NR_CTRL         equ     1111111111110111b
    36.  
    37. L_ALT           equ     0000000000010000b
    38. NL_ALT          equ     1111111111101111b
    39. R_ALT           equ     0000000000100000b
    40. NR_ALT          equ     1111111111011111b
    41.  
    42. CAPS_LOCK               equ     0000000001000000b
    43. SCR_LOCK                equ     0000000010000000b
    44. NUM_LOCK                equ     0000000100000000b
    45. INSERT          equ     0000001000000000b
    46.  
    47.  
    48. STRUC   idtr_struc
    49.         idt_len dw      0
    50.         idt_low dw      0
    51.         idt_hi  db      0
    52.         rsrv    db      0
    53. ENDS            idtr_struc
    54.  
    55. Листинг 5. Определение констант и структур для модулей,
    56.                 составленных на языке Си.
    57.  
    58. Файл tos.h
    59. -----------------------------------------------------------
    60.  
    61. #define word unsigned int
    62.  
    63. // Селекторы, определённые в GDT
    64.  
    65. #define CODE_SELECTOR        0x08 // сегмент кода
    66. #define DATA_SELECTOR        0x10 // сегмент данных
    67.  
    68. #define TASK_1_SELECTOR            0x18 // задача TASK_1
    69. #define TASK_2_SELECTOR            0x20 // задача TASK_2
    70. #define MAIN_TASK_SELECTOR      0x28 // главная задача
    71.  
    72. #define VID_MEM_SELECTOR          0x30 // сегмент видеопамяти
    73. #define IDT_SELECTOR            0x38 // талица IDT
    74.  
    75. #define KEYBIN_TASK_SELECTOR    0x40 // задача ввода с клавиатуры
    76. #define KEYB_TASK_SELECTOR       0x48 // задача обработки
    77.                                                   // клавиатурного прерывания
    78. #define FLIP_TASK_SELECTOR       0x50 // задача FLIP_TASK
    79.  
    80. // Байт доступа
    81.  
    82. typedef struct {
    83.          unsigned accessed   : 1;
    84.          unsigned read_write : 1;
    85.          unsigned conf_exp   : 1;
    86.          unsigned code       : 1;
    87.          unsigned xsystem    : 1;
    88.          unsigned dpl         : 2;
    89.          unsigned present    : 1;
    90.          } ACCESS;
    91.  
    92. // Структура дескриптора
    93.  
    94. typedef struct descriptor {
    95.         word limit;
    96.         word base_lo;
    97.         unsigned char base_hi;
    98.         unsigned char type_dpl;
    99.         unsigned reserved;
    100. } descriptor;
    101.  
    102. // Структура вентиля вызова, задачи, прерывания,
    103. // исключения
    104.  
    105. typedef struct gate {
    106.         word offset;
    107.         word selector;
    108.         unsigned char count;
    109.         unsigned char type_dpl;
    110.         word reserved;
    111. } gate;
    112.  
    113. // Структура сегмента состояния задачи TSS
    114.  
    115. typedef struct tss {
    116.         word link;      // поле обратной связи
    117.  
    118.         word sp0;               // указатель стека кольца 0
    119.         word ss0;
    120.         word sp1;               // указатель стека кольца 1
    121.         word ss1;
    122.         word sp2;               // указатель стека кольца 1
    123.         word ss2;
    124.  
    125.         word ip;                // регистры процессора
    126.         word flags;
    127.         word ax;
    128.         word cx;
    129.         word dx;
    130.         word bx;
    131.         word sp;
    132.         word bp;
    133.         word si;
    134.         word di;
    135.         word es;
    136.         word cs;
    137.         word ss;
    138.         word ds;
    139.         word ldtr;
    140. } tss;
    141.  
    142. // Размеры сегментов и структур
    143.  
    144. #define TSS_SIZE            (sizeof(tss))
    145. #define DESCRIPTOR_SIZE     (sizeof(descriptor))
    146. #define GATE_SIZE           (sizeof(gate))
    147. #define IDT_SIZE            (sizeof(idt))
    148.  
    149. // Физические адреса видеопамяти для цветного
    150. // и монохромного видеоадаптеров
    151.  
    152. #define COLOR_VID_MEM       0xb8000L
    153. #define MONO_VID_MEM        0xb0000L
    154.  
    155. // Видеоржеимы
    156.  
    157. #define MONO_MODE           0x07 // монохромный
    158. #define BW_80_MODE          0x02 // монохромный, 80 символов
    159. #define COLOR_80_MODE       0x03 // цветной, 80 символов
    160.  
    161. // Значения для поля доступа
    162.  
    163. #define TYPE_CODE_DESCR     0x18
    164. #define TYPE_DATA_DESCR     0x10
    165. #define TYPE_TSS_DESCR      0x01
    166. #define TYPE_CALL_GATE      0x04
    167. #define TYPE_TASK_GATE      0x85
    168. #define TYPE_INTERRUPT_GATE 0x86
    169. #define TYPE_TRAP_GATE      0x87
    170.  
    171. #define SEG_WRITABLE        0x02
    172. #define SEG_READABLE        0x02
    173. #define SEG_PRESENT_BIT     0x80
    174.  
    175. // Константы для обработки аппаратных
    176. // прерываний
    177.  
    178. #define EOI                             0x20
    179. #define MASTER8259A             0x20
    180. #define SLAVE8259A                      0xa0
    181.  
    182. // Макро для формирования физического
    183. // адреса из компонент сегменоного адреса
    184. // и смещения
    185.  
    186. #define MK_LIN_ADDR(seg,off) (((unsigned long)(seg))<<4)+(word)(off)
    187.  
    188. // Тип указателя на функцию типа void без параметров
    189.  
    190. typedef void (func_ptr)(void);
    191.  
    192.  
    193.  
    194.  
    195.  
    196. Файл tos.c (листинг 6) содержит основную программу, которая инициализирует процессор для работы в защищённом режиме и запускает все задачи. С помощью функции с названием Init_And_Protected_Mode_Entry() мы попадаем в защищённый режим и выводим сообщение на экран о том, что в главной задаче установлен защищённый режим. Регистр TR загружается селектором главной задачи при помощи функции load_task_register().
    197.  
    198. Сразу после этого программа переключается на выполнение задачи TASK_1. Эта задача просто выводит сообщение о своём запуске на экран и возвращает управление главной задаче. Цель этой процедуры - продемонстрировать процесс переключения задач с помощью команды JMP.
    199.  
    200. После возврата в главную задачу программа размаскирует прерывания от клавиатуры и таймера. Как только начинают поступать и обрабатываться прерывания таймера, оживают остальные задачи, определённые при инициализации системы.
    201.  
    202. Начиная с этого момента главная задача разделяет процессорное время наравне с остальными задачами. Что же она делает?
    203.  
    204. Главная задача сбрасывает семафор с номером 0, вслед за чем ожидает его установку. Этот семафор устанавливается задачей, которая занимается вводом символов с клавиатуры и выводит на экран скан-коды клавиш, а также состояние переключающих клавиш. Как только окажется нажатой клавиша ESC, задача ввода символов с клавиатуры устанавливает семафор 0, что и приводит к завершению работы главной задачи.
    205.  
    206. Перед тем, как завершить работу, главная задача устанавливает реальный режим работы процессора, стирает экран и возвращает управление операционной системе.
    207. Листинг 6. Программа мультизадачного монитора.
    208.  
    209. Файл tos.c
    210. -----------------------------------------------------------
    211.  
    212.  
    213. #include <stdio.h>
    214. #include <stdlib.h>
    215. #include <dos.h>
    216. #include <conio.h>
    217. #include "tos.h"
    218.  
    219. // --------------------------------
    220. // Определения вызываемых функций
    221. // --------------------------------
    222.  
    223. void Init_And_Protected_Mode_Entry(void);
    224.  
    225. void protected_mode(unsigned long gdt_ptr, unsigned int gdt_size,
    226.                 word cseg, word dseg);
    227.  
    228. word load_task_register(word tss_selector);
    229. void real_mode(void);
    230. void jump_to_task(word tss_selector);
    231. void load_idtr(unsigned long idt_ptr, word idt_size);
    232. void Keyb_int(void);
    233. void    Timer_int(void);
    234. void Int_30h_Entry(void);
    235.  
    236. extern  word kb_getch(void);
    237. void            enable_interrupt(void);
    238.  
    239. void    task1(void);
    240. void    task2(void);
    241. void            flipflop_task(void);
    242. void     keyb_task(void);
    243.  
    244. void init_tss(tss *t, word cs, word ds,
    245.                         unsigned char *sp, func_ptr ip);
    246.  
    247. void init_gdt_descriptor(descriptor *descr, unsigned long base,
    248.                         word limit, unsigned char type);
    249.  
    250. void  exception_0(void); //{ prg_abort(0); }
    251. void  exception_1(void); //{ prg_abort(1); }
    252. void  exception_2(void); //{ prg_abort(2); }
    253. void  exception_3(void); //{ prg_abort(3); }
    254. void  exception_4(void); //{ prg_abort(4); }
    255. void  exception_5(void); //{ prg_abort(5); }
    256. void  exception_6(void); //{ prg_abort(6); }
    257. void  exception_7(void); //{ prg_abort(7); }
    258. void  exception_8(void); //{ prg_abort(8); }
    259. void  exception_9(void); //{ prg_abort(9); }
    260. void  exception_A(void); //{ prg_abort(0xA); }
    261. void  exception_B(void); //{ prg_abort(0xB); }
    262. void  exception_C(void); //{ prg_abort(0xC); }
    263. void  exception_D(void); //{ prg_abort(0xD); }
    264. void  exception_E(void); //{ prg_abort(0xE); }
    265. void  exception_F(void); //{ prg_abort(0xF); }
    266. void  exception_10(void); //{ prg_abort(0x10); }
    267. void  exception_11(void); //{ prg_abort(0x11); }
    268. void  exception_12(void); //{ prg_abort(0x12); }
    269. void  exception_13(void); //{ prg_abort(0x13); }
    270. void  exception_14(void); //{ prg_abort(0x14); }
    271. void  exception_15(void); //{ prg_abort(0x15); }
    272. void  exception_16(void); //{ prg_abort(0x16); }
    273. void  exception_17(void); //{ prg_abort(0x17); }
    274. void  exception_18(void); //{ prg_abort(0x18); }
    275. void  exception_19(void); //{ prg_abort(0x19); }
    276. void  exception_1A(void); //{ prg_abort(0x1A); }
    277. void  exception_1B(void); //{ prg_abort(0x1B); }
    278. void  exception_1C(void); //{ prg_abort(0x1C); }
    279. void  exception_1D(void); //{ prg_abort(0x1D); }
    280. void  exception_1E(void); //{ prg_abort(0x1E); }
    281. void  exception_1F(void); //{ prg_abort(0x1F); }
    282.  
    283. void iret0(void);
    284. void iret1(void);
    285.  
    286. // --------------------------------------
    287. // Глобальная таблица дескрипторов GDT
    288. // --------------------------------------
    289.  
    290. descriptor      gdt[11];
    291.  
    292. // --------------------------------------
    293. // Дескрипторная таблица прерываний IDT
    294. // --------------------------------------
    295.  
    296. gate            idt[] = {
    297.  
    298. // Обработчики исключений
    299.  
    300.  { (word)&exception_0, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 0
    301.  { (word)&exception_1, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1
    302.  { (word)&exception_2, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 2
    303.  { (word)&exception_3, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 3
    304.  { (word)&exception_4, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 4
    305.  { (word)&exception_5, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 5
    306.  { (word)&exception_6, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 6
    307.  { (word)&exception_7, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 7
    308.  { (word)&exception_8, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 8
    309.  { (word)&exception_9, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 9
    310.  { (word)&exception_A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // A
    311.  { (word)&exception_B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // B
    312.  { (word)&exception_C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // C
    313.  { (word)&exception_D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // D
    314.  { (word)&exception_E, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // E
    315.  { (word)&exception_F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // F
    316.  { (word)&exception_10, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 10
    317.  { (word)&exception_11, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 11
    318.  { (word)&exception_12, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 12
    319.  { (word)&exception_13, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 13
    320.  { (word)&exception_14, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 14
    321.  { (word)&exception_15, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 15
    322.  { (word)&exception_16, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 16
    323.  { (word)&exception_17, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 17
    324.  { (word)&exception_18, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 18
    325.  { (word)&exception_19, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 19
    326.  { (word)&exception_1A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1A
    327.  { (word)&exception_1B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1B
    328.  { (word)&exception_1C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1C
    329.  { (word)&exception_1D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1D
    330.  { (word)&exception_1E, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1E
    331.  { (word)&exception_1F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1F
    332.  
    333. // Обработчик прерываний таймера
    334.  
    335.  { (word)&Timer_int, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 20
    336.  
    337. // Вентиль задачи, запускающейся по прерыванию от клавиатуры
    338.  
    339.  { 0, KEYB_TASK_SELECTOR, 0, TYPE_TASK_GATE, 0 }, // 21
    340.  
    341. // Заглушки для остальных аппаратных прерываний
    342.  
    343.  { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 22
    344.  { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 23
    345.  { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 24
    346.  { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 25
    347.  { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 26
    348.  { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 27
    349.  
    350.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 28
    351.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 29
    352.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2A
    353.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2B
    354.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2C
    355.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2D
    356.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2E
    357.  { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2F
    358.  
    359. // Обработчик для программного прерывания, которое
    360. // используется для ввода с клавиатуры
    361.  
    362.  { (word)&Int_30h_Entry, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 },  // 30
    363.  
    364. // Вентиль задачи FLIP_TASK
    365.  
    366.  { 0, FLIP_TASK_SELECTOR, 0, TYPE_TASK_GATE, 0 } // 31
    367.  
    368. };
    369.  
    370. // -------------------------------------------
    371. // Сегменты TSS для различных задач
    372. // -------------------------------------------
    373.  
    374. tss main_tss;           // TSS главной задачи
    375. tss task_1_tss; // TSS задачи TASK_1
    376. tss task_2_tss;     // TSS задачи TASK_2
    377. tss keyb_task_tss;  // TSS задач обслуживания
    378. tss keyb_tss;           //              клавиатуры
    379. tss flipflop_tss;       // TSS задачи FLIP_TASK
    380.  
    381. // -------------------------------------------
    382. // Стеки для задач
    383. // -------------------------------------------
    384.  
    385. unsigned char task_1_stack[1024];
    386. unsigned char task_2_stack[1024];
    387. unsigned char keyb_task_stack[1024];
    388. unsigned char keyb_stack[1024];
    389. unsigned char flipflop_stack[1024];
    390.  
    391. word y=0;       // номер текущей строки для вывода на экран
    392.  
    393.  
    394.  
    395. // -------------------------------------------
    396. // Начало программы
    397. // -------------------------------------------
    398.  
    399. void main(void) {
    400.  
    401. // Стираем экран
    402.  
    403.         textcolor(BLACK); textbackground(LIGHTGRAY); clrscr();
    404.  
    405. // Входим в защищённый режим
    406.  
    407.         Init_And_Protected_Mode_Entry();
    408.  
    409. // Выводим сообщение
    410.  
    411.         vi_hello_msg();
    412.         y=3;
    413.         vi_print(0, y++,
    414.          " Установлен защищённый режим в главной задаче", 0x7f);
    415.  
    416. // Загружаем регистр TR селектором главной задачи
    417. // т.е. задачи main()
    418.  
    419.         load_task_register(MAIN_TASK_SELECTOR);
    420.  
    421. // Переключаемся на задачу TASK_1
    422.  
    423.         jump_to_task(TASK_1_SELECTOR);
    424.  
    425. // После возврата в главную задачу выдаём сообщение
    426.  
    427.         vi_print(0, y++ ," Вернулись в главную задачу", 0x7f);
    428.         y++;
    429.  
    430. // Запускаем планировщик задач
    431.  
    432.         vi_print(0, y++ ," Запущен планировщик задач", 0x70);
    433.         enable_interrupt(); // разрешаем прерывание таймера
    434.  
    435. // Ожидаем установки семафора с номером 0. После того,
    436. // как этот семафор окажется установлен, возвращаемся
    437. // в реальный режим.
    438.  
    439. // Семафор 0 устанавливается задачей, обрабатывающей ввод с
    440. // клавиатуры, которая работает независимо от
    441. // главной задаче.
    442.  
    443.         vi_print(0, y++ ," Для возврата в реальный режим нажмите ESC", 0x70);
    444.  
    445.         sem_clear(0); // сброс семафора 0
    446.         sem_wait(0);  // ожидание установки семафора 0
    447.  
    448. // Возврат в реальный режим, стирание экрана и
    449. // передача управления MS-DOS
    450.  
    451.         real_mode();
    452.         textcolor(WHITE); textbackground(BLACK); clrscr();
    453. }
    454.  
    455. // -----------------------------------
    456. // Функция инициализации сегмента TSS
    457. // -----------------------------------
    458.  
    459. void init_tss(tss *t, word cs, word ds,
    460.         unsigned char *sp, func_ptr ip) {
    461.  
    462.         t->cs = cs;          // селектор сегмента кода
    463.         t->ds = ds;          // поля ds, es, ss устанавливаем
    464.         t->es = ds;          // на сегмент данных
    465.         t->ss = ds;
    466.         t->ip = (word)ip;    // указатель команд
    467.         t->sp = (word)sp;    // смещение стека
    468.         t->bp = (word)sp;
    469. }
    470.  
    471. // -------------------------------------------------
    472. // Функция инициализации дескриптора в таблице GDT
    473. // -------------------------------------------------
    474.  
    475. void init_gdt_descriptor(descriptor *descr,
    476.                 unsigned long base, word limit,
    477.                 unsigned char type) {
    478.  
    479. // Младшее слово базового адреса
    480.         descr->base_lo  = (word)base;
    481.  
    482. // Старший байт базового адреса
    483.         descr->base_hi  = (unsigned char)(base >> 16);
    484.  
    485. // Поле доступа дескриптора
    486.         descr->type_dpl = type;
    487.  
    488. // Предел
    489.         descr->limit    = limit;
    490.  
    491. // Зарезервированное поле, должно быть
    492. // сброшено в 0
    493.         descr->reserved = 0;
    494. }
    495.  
    496. // -----------------------------------------------
    497. // Инициализация всех таблиц и вход
    498. // в защищённый режим
    499. // -----------------------------------------------
    500.  
    501. void Init_And_Protected_Mode_Entry(void) {
    502.  
    503.         union REGS r;
    504.  
    505. // Инициализируем таблицу GDT, элементы с 1 по 5
    506.  
    507.         init_gdt_descriptor(&gdt[1], MK_LIN_ADDR(_CS, 0),
    508.          0xffffL, TYPE_CODE_DESCR | SEG_PRESENT_BIT | SEG_READABLE);
    509.  
    510.         init_gdt_descriptor(&gdt[2], MK_LIN_ADDR(_DS, 0),
    511.          0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);
    512.  
    513.         init_gdt_descriptor(&gdt[3],
    514.          MK_LIN_ADDR(_DS, &task_1_tss),
    515.          (unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);
    516.  
    517.         init_gdt_descriptor(&gdt[4],
    518.          MK_LIN_ADDR(_DS, &task_2_tss),
    519.          (unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);
    520.  
    521.         init_gdt_descriptor(&gdt[5],
    522.          MK_LIN_ADDR(_DS, &main_tss),
    523.          (unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);
    524.  
    525.  
    526. // Инициализируем TSS для задач TASK_1, TASK_2
    527.  
    528.         init_tss(&task_1_tss, CODE_SELECTOR, DATA_SELECTOR, task_1_stack+
    529.                 sizeof(task_1_stack), task1);
    530.  
    531.         init_tss(&task_2_tss, CODE_SELECTOR, DATA_SELECTOR, task_2_stack+
    532.                 sizeof(task_2_stack), task2);
    533.  
    534. // Инициализируем элемент 6 таблицы GDT -
    535. // дескриптор для сегмента видеопамяти
    536.  
    537. // Определяем видеорежим
    538.         r.h.ah=15;
    539.         int86(0x10,&r,&r);
    540.  
    541. // Инициализация для монохромного режима
    542.  
    543.         if(r.h.al==MONO_MODE)
    544.           init_gdt_descriptor(&gdt[6], MONO_VID_MEM,
    545.           3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);
    546.  
    547. // Инициализация для цветного режима
    548.  
    549.         else if(r.h.al == BW_80_MODE || r.h.al == COLOR_80_MODE)
    550.           init_gdt_descriptor(&gdt[6], COLOR_VID_MEM,
    551.           3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);
    552.         else {
    553.                 printf("\nИзвините, этот видеорежим недопустим.");
    554.                 exit(-1);
    555.         }
    556.  
    557. // Инициализация элементов 7 и 8 таблицы GDT
    558.  
    559.         init_gdt_descriptor(&gdt[7],
    560.                 MK_LIN_ADDR(_DS, &idt),
    561.                 (unsigned long)IDT_SIZE-1,
    562.                 TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);
    563.  
    564.         init_gdt_descriptor(&gdt[8],
    565.                 MK_LIN_ADDR(_DS, &keyb_task_tss),
    566.                 (unsigned long)TSS_SIZE-1,
    567.                 TYPE_TSS_DESCR | SEG_PRESENT_BIT);
    568.  
    569. // Инициализация TSS для задачи KEYB_TASK
    570.  
    571.         init_tss(&keyb_task_tss, CODE_SELECTOR, DATA_SELECTOR,
    572.                 keyb_task_stack + sizeof(keyb_task_stack), keyb_task);
    573.  
    574. // Инициализация элемента 9 таблицы GDT
    575.  
    576.         init_gdt_descriptor(&gdt[9],
    577.                 MK_LIN_ADDR(_DS, &keyb_tss),
    578.                 (unsigned long)TSS_SIZE-1,
    579.                 TYPE_TSS_DESCR | SEG_PRESENT_BIT);
    580.  
    581. // Инициализация TSS для задачи KEYB обработки ввода с клавиатуры
    582.  
    583.         init_tss(&keyb_tss, CODE_SELECTOR, DATA_SELECTOR,
    584.                 keyb_stack + sizeof(keyb_stack), Keyb_int);
    585.  
    586.  
    587. // Инициализация элемента 10 таблицы GDT
    588.  
    589.         init_gdt_descriptor(&gdt[10],
    590.                 MK_LIN_ADDR(_DS, &flipflop_tss),
    591.                 (unsigned long)TSS_SIZE-1,
    592.                 TYPE_TSS_DESCR | SEG_PRESENT_BIT);
    593.  
    594. // Инициализация TSS для задачи FLIP_TASK
    595.  
    596.         init_tss(&flipflop_tss, CODE_SELECTOR, DATA_SELECTOR,
    597.                 flipflop_stack + sizeof(flipflop_stack), flipflop_task);
    598.  
    599. // Загрузка регистра IDTR
    600.  
    601.         load_idtr(MK_LIN_ADDR(_DS, &idt), IDT_SIZE);
    602.  
    603. // Вход в защищённый режим
    604.  
    605.         protected_mode(MK_LIN_ADDR(_DS, &gdt), sizeof(gdt),
    606.                         CODE_SELECTOR, DATA_SELECTOR);
    607. }
    608.  
    609.  
    610.  
    611.  
    612.  
    613. Файл tasks.c содержит тексты программ, которые будут работать в режиме разделения времени (кроме задачи TASK_1, эта задача запускается только один раз).
    614.  
    615. Задача TASK_1 (процедура task1) выдаёт сообщение о своём запуске и передаёт управление главной задаче.
    616.  
    617. Задача TASK_2 (процедура task2) попеременно выводит на экран строки "FLIP" и "FLOP", переключая попутно семафор с номером 1.
    618.  
    619. Задача FLIP_TASK (процедура flipflop_task) также попеременно выводит на экран строки "FLIP" и "FLOP", но только тогда, когда семафор с номером 1 установлен. Таким образом, задача TASK_2 управляет работой задачи FLIP_TASK.
    620.  
    621. Задача KEYB_TASK (процедура keyb_task) вводит символы с клавиатуры и выводит скан-коды нажатых клавиш, а также состояние переключающих клавиш. Как только оказывается нажатой клавиша ESC, задача устанавливает семафор с номером 0, что приводит к завершению работы главной задачи (ожидающей установки этого семафора).
    622. Листинг 7. Задачи, которые будут работать параллельно.
    623.  
    624. Файл tasks.c
    625. -----------------------------------------------------------
    626.  
    627. #include <stdio.h>
    628. #include <dos.h>
    629. #include <conio.h>
    630. #include <stdlib.h>
    631. #include "tos.h"
    632.  
    633. word dispatcher(void);
    634.  
    635. // Номер текущей строки для вывода на экран
    636.  
    637. extern unsigned int y;
    638.  
    639. // Задача TASK_1
    640.  
    641. void task1(void) {
    642.         while(1){
    643.                 vi_print(0,y++," Запущена задача TASK_1, "
    644.                                         "переходим к главной задаче", 0x70);
    645.                 jump_to_task(MAIN_TASK_SELECTOR);
    646.  
    647. // После повторного запуска этой задачи
    648. // снова входим в цикл.
    649.  
    650.         }
    651. }
    652.  
    653. // Задача TASK_2
    654.  
    655. word flipflop1 = 0;
    656. long delay_cnt1 = 0l;
    657.  
    658. void task2(void) {
    659.         while(1){
    660.  
    661. // Периодически выводим на экран строки
    662. // FLIP/FLOP, каждый раз переключая
    663. // семафор номер 1. Этот семафор однозначно
    664. // соответствует выведенной на экран строке.
    665.  
    666.                 asm sti
    667.                 if(delay_cnt1 > 150000l ) {
    668.                         asm cli
    669.                         if(flipflop1)   {
    670.                                 vi_print(73,3," FLIP ", 0x4f);
    671.                                 sem_clear(1);
    672.                         }
    673.                         else  {
    674.                                 vi_print(73,3," FLOP ", 0x1f);
    675.                                 sem_set(1);
    676.                         }
    677.                         flipflop1 ^= 1;
    678.                         delay_cnt1 = 0l;
    679.                         asm sti
    680.                 }
    681.                 delay_cnt1++;
    682.         }
    683. }
    684.  
    685. word flipflop = 0;
    686. long delay_cnt = 0l;
    687.  
    688. void flipflop_task(void) {
    689.  
    690. // Эта задача также периодически выводит на экран
    691. // строки FLIP/FLOP, но выводит строкой выше и
    692. // с меньшим периодом. Кроме того, эта задача
    693. // работает только тогда, когда установлен
    694. // семафор номер 1.
    695.  
    696.         while(1){
    697.                 asm sti
    698.                 if(delay_cnt > 20000l ) {
    699.                         sem_wait(1); // ожидаем установки семафора
    700.                         asm cli
    701.                         if(flipflop)    vi_print(73,2," FLIP ", 0x20);
    702.                         else            vi_print(73,2," FLOP ", 0x20);
    703.                         flipflop ^= 1;
    704.                         delay_cnt = 0l;
    705.                         asm sti
    706.                 }
    707.                 delay_cnt++;
    708.         }
    709. }
    710.  
    711. word keyb_code;
    712.  
    713. extern word keyb_status;
    714.  
    715. void keyb_task(void) {
    716.  
    717. // Эта задача вводит символы с клавиатуры
    718. // и отображает скан-коды нажатых клавиш
    719. // и состояние переключающих клавиш на экране.
    720. // Если нажимается клавиша ESC, задача
    721. // устанавливает семафор номер 0.
    722. // Работающая параллельно главная задача
    723. // ожидает установку этого семафора. Как только
    724. // семафор 0 окажется установлен, главная задача
    725. // завершает свою работу и программа возвращает
    726. // процессор в реальный режим, затем передаёт
    727. // управление MS-DOS.
    728.  
    729.  
    730.         vi_print(60, 5, " Key code:   .... ", 0x20);
    731.         vi_print(60, 6, " Key status: .... ", 0x20);
    732.         while(1){
    733.                 keyb_code = kb_getch();
    734.                 vi_put_word(73, 5, keyb_code, 0x4f);
    735.                 vi_put_word(73, 6, keyb_status, 0x4f);
    736.                 if((keyb_code & 0x00ff) == 1) sem_set(0);
    737.         }
    738. }
    739.  
    740.  
    741.  
    742.  
    743.  
    744. Файл semaphor.c содержит исходные тексты процедур сброса семафора, установки семафора и ожидания семафора.
    745.  
    746. В массиве semaphore[5] определено пять семафоров. Разумеется, что когда вы будете экспериментировать с программой, вы можете изменить количество доступных семафоров.
    747. Листинг 8. Процедуры для работы с семафорами.
    748.  
    749. Файл semaphor.c
    750. -----------------------------------------------------------
    751.  
    752. #include <stdio.h>
    753. #include <dos.h>
    754. #include <conio.h>
    755. #include <stdlib.h>
    756. #include "tos.h"
    757.  
    758. // Массив из пяти семафоров
    759.  
    760. word semaphore[5];
    761.  
    762. // Процедура сброса семафора.
    763. // Параметр sem - номер сбрасываемого семафора
    764.  
    765. void sem_clear(int sem) {
    766.         asm cli
    767.         semaphore[sem] = 0;
    768.         asm sti
    769. }
    770.  
    771. // Процедура установки семафора
    772. // Параметр sem - номер устанавливаемого семафора
    773.  
    774. void sem_set(int sem) {
    775.         asm cli
    776.         semaphore[sem] = 1;
    777.         asm sti
    778. }
    779.  
    780. // Ожидание установки семафора
    781. // Параметр sem - номер ожидаемого семафора
    782.  
    783. void sem_wait(int sem) {
    784.         while(1) {
    785.                 asm cli
    786.                 if(semaphore[sem]) break; // проверяем семафор
    787.  
    788.                 asm sti // ожидаем установки семафора
    789.                 asm nop
    790.                 asm nop
    791.         }
    792.         asm sti
    793. }
    794.  
    795.  
    796.  
    797.  
    798.  
    799. Файл timer.c содержит обработчик аппаратного прерывания таймера, который периодически выдаёт звуковой сигнал и инициирует работу диспетчера задач. Диспетчер задач циклически перебирает селекторы TSS задач, участвующих в процессе разделения времени, возвращая селектор той задачи, которая должна стать активной. В самом конце обработки аппаратного прерывания таймера происходит переключение именно на эту задачу.
    800. Листинг 9. Процедуры для работы с таймером и
    801.                 диспетчер задач.
    802.  
    803. Файл timer.c
    804. -----------------------------------------------------------
    805.  
    806.  
    807. #include <stdio.h>
    808. #include <dos.h>
    809. #include <conio.h>
    810. #include <stdlib.h>
    811. #include "tos.h"
    812.  
    813. // -------------------------------------------
    814. //      Модуль обслуживания таймера
    815. // -------------------------------------------
    816.  
    817. #define EOI 0x20
    818. #define MASTER8259A 0x20
    819.  
    820. extern void beep(void);
    821. extern void flipflop_task(void);
    822. void Timer_int(void);
    823. word dispatcher(void);
    824.  
    825. word    timer_cnt;
    826.  
    827. // ------------------------------------------
    828. // Обработчик аппаратного прерывания таймера
    829. // ------------------------------------------
    830.  
    831. void Timer_int(void) {
    832.  
    833.         asm pop bp
    834.  
    835. // Периодически выдаём звуковой сигнал
    836.  
    837.         timer_cnt += 1;
    838.         if((timer_cnt & 0xf) == 0xf) {
    839.                 beep();
    840.         }
    841.  
    842. // Выдаём в контроллер команду конца
    843. // прерывания
    844.  
    845.         asm mov al,EOI
    846.         asm out MASTER8259A,al
    847.  
    848. // Переключаемся на следующую задачу,
    849. // селектор TSS которой получаем от
    850. // диспетчера задач dispatcher()
    851.  
    852.         jump_to_task(dispatcher());
    853.         asm iret
    854. }
    855.  
    856. // --------------------------------------
    857. // Диспетчер задач
    858. // --------------------------------------
    859.  
    860. // Массив селекторов, указывающих на TSS
    861. // задач, участвующих в параллельной работе,
    862. // т.е. диспетчеризуемых задач
    863.  
    864. word task_list[] = {
    865.         MAIN_TASK_SELECTOR,
    866.         FLIP_TASK_SELECTOR,
    867.         KEYBIN_TASK_SELECTOR,
    868.         TASK_2_SELECTOR
    869. };
    870.  
    871. word current_task = 0; // текущая задача
    872. word max_task = 3;     // количество задач - 1
    873.  
    874. // Используем простейший алгоритм диспетчеризации -
    875. // выполняем последовательное переключение на все
    876. // задачи, селекторы TSS которых находятся
    877. // в массиве task_list[].
    878.  
    879. word dispatcher(void) {
    880.  
    881.         if(current_task < max_task) current_task++;
    882.         else current_task = 0;
    883.         return(task_list[current_task]);
    884. }
    885.  
    886.  
    887.  
    888.  
    889.  
    890. Для сокращения объёма и без того сложной программы мы не стали делать функционально полную обработку исключений, ограничившись простым аварийным завершением работы программы с выдачей номера исключения.
    891.  
    892. Исходные тексты обработчиков исключений находятся в файле except.c.
    893. Листинг 10. Обработка исключений.
    894.  
    895. Файл except.c
    896. -----------------------------------------------------------
    897.  
    898. #include <stdio.h>
    899. #include <dos.h>
    900. #include <conio.h>
    901. #include <stdlib.h>
    902. #include "tos.h"
    903.  
    904. void prg_abort(int err);
    905.  
    906. // Номер текущей строки для вывода на экран
    907.  
    908. extern unsigned int y;
    909.  
    910. // Обработчики исключений
    911.  
    912. void  exception_0(void) { prg_abort(0); }
    913. void  exception_1(void) { prg_abort(1); }
    914. void  exception_2(void) { prg_abort(2); }
    915. void  exception_3(void) { prg_abort(3); }
    916. void  exception_4(void) { prg_abort(4); }
    917. void  exception_5(void) { prg_abort(5); }
    918. void  exception_6(void) { prg_abort(6); }
    919. void  exception_7(void) { prg_abort(7); }
    920. void  exception_8(void) { prg_abort(8); }
    921. void  exception_9(void) { prg_abort(9); }
    922. void  exception_A(void) { prg_abort(0xA); }
    923. void  exception_B(void) { prg_abort(0xB); }
    924. void  exception_C(void) { prg_abort(0xC); }
    925. void  exception_D(void) { prg_abort(0xD); }
    926. void  exception_E(void) { prg_abort(0xE); }
    927. void  exception_F(void) { prg_abort(0xF); }
    928. void  exception_10(void) { prg_abort(0x10); }
    929. void  exception_11(void) { prg_abort(0x11); }
    930. void  exception_12(void) { prg_abort(0x12); }
    931. void  exception_13(void) { prg_abort(0x13); }
    932. void  exception_14(void) { prg_abort(0x14); }
    933. void  exception_15(void) { prg_abort(0x15); }
    934. void  exception_16(void) { prg_abort(0x16); }
    935. void  exception_17(void) { prg_abort(0x17); }
    936. void  exception_18(void) { prg_abort(0x18); }
    937. void  exception_19(void) { prg_abort(0x19); }
    938. void  exception_1A(void) { prg_abort(0x1A); }
    939. void  exception_1B(void) { prg_abort(0x1B); }
    940. void  exception_1C(void) { prg_abort(0x1C); }
    941. void  exception_1D(void) { prg_abort(0x1D); }
    942. void  exception_1E(void) { prg_abort(0x1E); }
    943. void  exception_1F(void) { prg_abort(0x1F); }
    944.  
    945. // ------------------------------
    946. // Аварийный выход из программы
    947. // ------------------------------
    948.  
    949. void prg_abort(int err) {
    950.  
    951.         vi_print(1,y++,"!!! ---> Произошло исключение", 0xc);
    952.  
    953.         real_mode(); // Возвращаемся в реальный режим
    954.  
    955. // В реальном режиме выводим сообщение об исключении
    956.  
    957.         gotoxy(1, ++y);
    958.         cprintf(" Исключение %X, нажмите любую клавишу", err);
    959.         getch();
    960.  
    961.         textcolor(WHITE);
    962.         textbackground(BLACK);
    963.         clrscr();
    964.         exit(0);
    965.  
    966. }
    967.  
    968.  
    969.  
    970.  
    971.  
    972. В файле intproc.c расположены заглушки для тех аппаратных прерываний, обработка которых сводится к простой посылке кода конца прерывания в соответствующий контроллер прерывания.
    973. Листинг 11. Заглушки для аппаратных прерываний.
    974.  
    975. Файл intproc.c
    976. -----------------------------------------------------------
    977.  
    978.  
    979. #include <stdio.h>
    980. #include <dos.h>
    981. #include <conio.h>
    982. #include <stdlib.h>
    983. #include "tos.h"
    984.  
    985. // Заглушки для необрабатываемых
    986. // аппаратных прерываний.
    987.  
    988. void iret0(void) {     // первый контроллер прерываний
    989.         asm {
    990.                 push    ax
    991.                 mov     al,EOI
    992.                 out     MASTER8259A,al
    993.                 pop     ax
    994.                 pop bp
    995.                 iret
    996.         }
    997. }
    998.  
    999. void iret1(void) {     // второй контроллер прерываний
    1000.         asm {
    1001.                 push    ax
    1002.                 mov     al,EOI
    1003.                 out     MASTER8259A,al
    1004.                 out     SLAVE8259A,al
    1005.                 pop     ax
    1006.                 pop bp
    1007.                 iret
    1008.         }
    1009. }
    1010.  
    1011.  
    1012.  
    1013.  
    1014.  
    1015. Файл keyb.c содержит простой интерфейс для вызова программного прерывания int 30h, обеспечивающего ввод с клавиатуры.
    1016. Листинг 12. Ввод символа с клавиатуры.
    1017.  
    1018. Файл keyb.c
    1019. -----------------------------------------------------------
    1020.  
    1021.  
    1022. #include <stdio.h>
    1023. #include <dos.h>
    1024. #include <conio.h>
    1025. #include <stdlib.h>
    1026. #include "tos.h"
    1027.  
    1028. extern word key_code;
    1029.  
    1030. // Функция, ожидающая нажатия любой
    1031. // клавиши и возвращающая её скан-код
    1032.  
    1033. unsigned int kb_getch(void) {
    1034.         asm int 30h
    1035.         return(key_code);
    1036. }
    1037.  
    1038.  
    1039.  
    1040.  
    1041.  
    1042. Обработчик аппаратного прерывания клавиатуры мы взяли практически без изменений из программы, представленной в предыдущей главе. Исходные тексты находятся в файле keyboard.asm.
    1043. Листинг 13. Процедуры для работы с клавиатурой.
    1044.  
    1045. Файл keyboard.asm
    1046. -----------------------------------------------------------
    1047.  
    1048. IDEAL
    1049.  
    1050. MODEL SMALL
    1051. RADIX   16
    1052.  
    1053. P286
    1054. include "tos.inc"
    1055.  
    1056. ; ------------------------------------------
    1057. ; Модуль обслуживания клавиатуры
    1058. ; ------------------------------------------
    1059.  
    1060. PUBLIC  _Keyb_int, _Int_30h_Entry, _key_code, _keyb_status
    1061. EXTRN   _beep:PROC
    1062. DATASEG
    1063.  
    1064.         _key_flag       db      0
    1065.         _key_code       dw      0
    1066.         ext_scan        db      0
    1067.         _keyb_status    dw      0
    1068.  
    1069. CODESEG
    1070.  
    1071. PROC    _Keyb_int        NEAR
    1072.         cli
    1073.  
    1074.         call    _beep
    1075.  
    1076.         push    ax
    1077.         mov     al, [ext_scan]
    1078.         cmp     al, 0
    1079.         jz      normal_scan1
    1080.         cmp     al, 0e1h
    1081.         jz      pause_key
    1082.  
    1083.         in      al, 60h
    1084.         cmp     al, 2ah
    1085.         jz      intkeyb_exit_1
    1086.         cmp     al, 0aah
    1087.         jz      intkeyb_exit_1
    1088.  
    1089.         mov     ah, [ext_scan]
    1090.         call    Keyb_PutQ
    1091.  
    1092.         mov     al, 0
    1093.         mov     [ext_scan], al
    1094.         jmp     intkeyb_exit
    1095.  
    1096. pause_key:
    1097.  
    1098.         in      al, 60h
    1099.         cmp     al, 0c5h
    1100.         jz      pause_key1
    1101.         cmp     al, 45h
    1102.         jz      pause_key1
    1103.  
    1104.         jmp     intkeyb_exit
    1105.  
    1106. pause_key1:
    1107.         mov     ah, [ext_scan]
    1108.         call    Keyb_PutQ
    1109.  
    1110.         mov     al, 0
    1111.         mov     [ext_scan], al
    1112.         jmp     intkeyb_exit
    1113.  
    1114.  
    1115. normal_scan1:
    1116.         in      al, 60h
    1117.         cmp     al, 0feh
    1118.         jz      intkeyb_exit
    1119.         cmp     al, 0e1h
    1120.         jz      ext_key
    1121.         cmp     al, 0e0h
    1122.         jnz     normal_scan
    1123.  
    1124. ext_key:
    1125.         mov     [ext_scan], al
    1126.         jmp     intkeyb_exit
    1127.  
    1128.  
    1129. intkeyb_exit_1:
    1130.         mov     al, 0
    1131.         mov     [ext_scan], al
    1132.         jmp     intkeyb_exit
    1133.  
    1134. normal_scan:
    1135.         mov     ah, 0
    1136.         call    Keyb_PutQ
    1137.  
    1138. intkeyb_exit:
    1139.         in      al, 61h
    1140.         mov     ah, al
    1141.         or      al, 80h
    1142.         out     61h, al
    1143.         xchg    ah, al
    1144.         out     61h, al
    1145.         mov     al,EOI
    1146.         out     MASTER8259A,al
    1147.  
    1148.         pop     ax
    1149.         sti
    1150.         iret
    1151.         jmp     _Keyb_int
    1152. ENDP    _Keyb_int
    1153.  
    1154.  
    1155. PROC    Keyb_PutQ       NEAR
    1156.  
    1157.         push    ax
    1158.  
    1159.         cmp     ax, 002ah       ; L_SHIFT down
    1160.         jnz     @@kb1
    1161.         mov     ax, [_keyb_status]
    1162.         or      ax, L_SHIFT
    1163.         mov     [_keyb_status], ax
    1164.         jmp     keyb_putq_exit
    1165. @@kb1:
    1166.         cmp     ax, 00aah       ; L_SHIFT up
    1167.         jnz     @@kb2
    1168.         mov     ax, [_keyb_status]
    1169.         and     ax, NL_SHIFT
    1170.         mov     [_keyb_status], ax
    1171.         jmp     keyb_putq_exit
    1172. @@kb2:
    1173.         cmp     ax, 0036h       ; R_SHIFT down
    1174.         jnz     @@kb3
    1175.         mov     ax, [_keyb_status]
    1176.         or      ax, R_SHIFT
    1177.         mov     [_keyb_status], ax
    1178.         jmp     keyb_putq_exit
    1179. @@kb3:
    1180.         cmp     ax, 00b6h       ; R_SHIFT up
    1181.         jnz     @@kb4
    1182.         mov     ax, [_keyb_status]
    1183.         and     ax, NR_SHIFT
    1184.         mov     [_keyb_status], ax
    1185.         jmp     keyb_putq_exit
    1186. @@kb4:
    1187.         cmp     ax, 001dh       ; L_CTRL down
    1188.         jnz     @@kb5
    1189.         mov     ax, [_keyb_status]
    1190.         or      ax, L_CTRL
    1191.         mov     [_keyb_status], ax
    1192.         jmp     keyb_putq_exit
    1193. @@kb5:
    1194.         cmp     ax, 009dh       ; L_CTRL up
    1195.         jnz     @@kb6
    1196.         mov     ax, [_keyb_status]
    1197.         and     ax, NL_CTRL
    1198.         mov     [_keyb_status], ax
    1199.         jmp     keyb_putq_exit
    1200. @@kb6:
    1201.         cmp     ax, 0e01dh      ; R_CTRL down
    1202.         jnz     @@kb7
    1203.         mov     ax, [_keyb_status]
    1204.         or      ax, R_CTRL
    1205.         mov     [_keyb_status], ax
    1206.         jmp     keyb_putq_exit
    1207. @@kb7:
    1208.         cmp     ax, 0e09dh      ; R_CTRL up
    1209.         jnz     @@kb8
    1210.         mov     ax, [_keyb_status]
    1211.         and     ax, NR_CTRL
    1212.         mov     [_keyb_status], ax
    1213.         jmp     keyb_putq_exit
    1214. @@kb8:
    1215.         cmp     ax, 0038h       ; L_ALT down
    1216.         jnz     @@kb9
    1217.         mov     ax, [_keyb_status]
    1218.         or      ax, L_ALT
    1219.         mov     [_keyb_status], ax
    1220.         jmp     keyb_putq_exit
    1221. @@kb9:
    1222.         cmp     ax, 00b8h       ; L_ALT up
    1223.         jnz     @@kb10
    1224.         mov     ax, [_keyb_status]
    1225.         and     ax, NL_ALT
    1226.         mov     [_keyb_status], ax
    1227.         jmp     keyb_putq_exit
    1228. @@kb10:
    1229.         cmp     ax, 0e038h      ; R_ALT down
    1230.         jnz     @@kb11
    1231.         mov     ax, [_keyb_status]
    1232.         or      ax, R_ALT
    1233.         mov     [_keyb_status], ax
    1234.         jmp     keyb_putq_exit
    1235. @@kb11:
    1236.         cmp     ax, 0e0b8h      ; R_ALT up
    1237.         jnz     @@kb12
    1238.         mov     ax, [_keyb_status]
    1239.         and     ax, NR_ALT
    1240.         mov     [_keyb_status], ax
    1241.         jmp     keyb_putq_exit
    1242. @@kb12:
    1243.         cmp     ax, 003ah       ; CAPS_LOCK up
    1244.         jnz     @@kb13
    1245.         mov     ax, [_keyb_status]
    1246.         xor     ax, CAPS_LOCK
    1247.         mov     [_keyb_status], ax
    1248.         jmp     keyb_putq_exit
    1249. @@kb13:
    1250.         cmp     ax, 00bah       ; CAPS_LOCK down
    1251.         jnz     @@kb14
    1252.         jmp     keyb_putq_exit
    1253. @@kb14:
    1254.         cmp     ax, 0046h       ; SCR_LOCK up
    1255.         jnz     @@kb15
    1256.         mov     ax, [_keyb_status]
    1257.         xor     ax, SCR_LOCK
    1258.         mov     [_keyb_status], ax
    1259.         jmp     keyb_putq_exit
    1260. @@kb15:
    1261.         cmp     ax, 00c6h       ; SCR_LOCK down
    1262.         jnz     @@kb16
    1263.         jmp     keyb_putq_exit
    1264. @@kb16:
    1265.         cmp     ax, 0045h       ; NUM_LOCK up
    1266.         jnz     @@kb17
    1267.         mov     ax, [_keyb_status]
    1268.         xor     ax, NUM_LOCK
    1269.         mov     [_keyb_status], ax
    1270.         jmp     keyb_putq_exit
    1271. @@kb17:
    1272.         cmp     ax, 00c5h       ; NUM_LOCK down
    1273.         jnz     @@kb18
    1274.         jmp     keyb_putq_exit
    1275. @@kb18:
    1276.         cmp     ax, 0e052h      ; INSERT up
    1277.         jnz     @@kb19
    1278.         mov     ax, [_keyb_status]
    1279.         xor     ax, INSERT
    1280.         mov     [_keyb_status], ax
    1281.         jmp     keyb_putq_exit
    1282. @@kb19:
    1283.         cmp     ax, 0e0d2h      ; INSERT down
    1284.         jnz     @@kb20
    1285.         jmp     keyb_putq_exit
    1286. @@kb20:
    1287.  
    1288.         test    ax, 0080h
    1289.         jnz     keyb_putq_exit
    1290.  
    1291.         mov     [_key_code], ax
    1292.  
    1293.         mov     al, 0ffh
    1294.         mov     [_key_flag], al
    1295. keyb_putq_exit:
    1296.         pop     ax
    1297.         ret
    1298. ENDP    Keyb_PutQ
    1299.  
    1300. ; Обработчик программного прерывания
    1301. ; для ввода с клавиатуры. По своим функциям
    1302. ; напоминает прерывание INT 16 реального
    1303. ; режима.
    1304.  
    1305.  
    1306. PROC    _Int_30h_Entry   NEAR
    1307.         push   ax dx
    1308.  
    1309. ; Ожидаем прерывание от клавиатуры
    1310.  
    1311. keyb_int_wait:
    1312.         sti
    1313.         nop
    1314.         nop
    1315.         cli
    1316.  
    1317. ; Проверяем флаг, который устанавливается
    1318. ; обработчиком аппаратного прерывания клавиатуры
    1319.  
    1320.         mov     al, [_key_flag]
    1321.         cmp     al, 0
    1322.         jz      keyb_int_wait
    1323.  
    1324. ; Сбрасываем флаг после прихода прерывания
    1325.  
    1326.         mov     al, 0
    1327.         mov     [_key_flag], al
    1328.         sti
    1329.         pop     dx ax
    1330.         iret
    1331. ENDP   _Int_30h_Entry
    1332.  
    1333. END
    1334.  
    1335.  
    1336.  
    1337.  
    1338.  
    1339. Файл screen.c содержит процедуры, необходимые для вывода информации на экран дисплея. Работа этих процедур основана на непосредственной записи данных в видеопамять.
    1340. Листинг 14. Процедуры для работы с видеоадаптером.
    1341.  
    1342. Файл screen.c
    1343. -----------------------------------------------------------
    1344.  
    1345. #include <stdio.h>
    1346. #include <dos.h>
    1347. #include <conio.h>
    1348. #include <stdlib.h>
    1349. #include "tos.h"
    1350.  
    1351. void vi_putch(unsigned int x, unsigned int y ,char c, char attr);
    1352.  
    1353. char hex_tabl[] = "0123456789ABCDEF";
    1354.  
    1355. // Вывод байта на экран, координаты (x,y),
    1356. // выводится шестнадцатеричное представление
    1357. // байта chr с экранными атрибутами attr.
    1358.  
    1359. void vi_put_byte(unsigned int x,
    1360.                 unsigned int y, unsigned char chr, char attr) {
    1361.         unsigned char temp;
    1362.  
    1363.         temp = hex_tabl[(chr & 0xf0) >> 4];
    1364.         vi_putch(x, y, temp, attr);
    1365.  
    1366.         temp = hex_tabl[chr & 0xf];
    1367.         vi_putch(x+1, y, temp, attr);
    1368. }
    1369. // Вывод слова на экран, координаты (x,y),
    1370. // выводится шестнадцатеричное представление
    1371. // слова chr с экранными атрибутами attr.
    1372.  
    1373. void vi_put_word(unsigned int x,
    1374.         unsigned int y, word chr, char attr) {
    1375.  
    1376.         vi_put_byte(x, y, (chr & 0xff00) >> 8, attr);
    1377.         vi_put_byte(x+2, y, chr & 0xff, attr);
    1378.  
    1379. }
    1380.  
    1381. // Вывод символа c на экран, координаты - (x,y),
    1382. // атрибут выводимого символа - attr
    1383.  
    1384. void vi_putch(unsigned int x,
    1385.         unsigned int y ,char c, char attr) {
    1386.  
    1387.         register unsigned int offset;
    1388.         char far *vid_ptr;
    1389.  
    1390.         offset=(y*160) + (x*2);
    1391.         vid_ptr=MK_FP(VID_MEM_SELECTOR, offset);
    1392.         *vid_ptr++=c; *vid_ptr=attr;
    1393. }
    1394.  
    1395. // Вывод строки s на экран, координаты - (x,y),
    1396. // атрибут выводимой строки - attr
    1397.  
    1398. void vi_print(unsigned int x,
    1399.         unsigned int y, char *s, char attr) {
    1400.         while(*s) vi_putch(x++, y, *s++, attr);
    1401. }
    1402.  
    1403. // Вывод стоки сообщения о запуске программы
    1404.  
    1405. void vi_hello_msg(void) {
    1406.  
    1407.         vi_print(0, 0,
    1408.                 " Protected mode monitor *TINY/OS*, "
    1409.                 "v.1.2 for CPU 80286  ¦ © Frolov A.V., 1992 ", 0x30);
    1410.  
    1411. }
    1412.  
    1413.  
    1414.  
    1415.  
    1416.  
    1417. Последний файл - tossyst.asm - содержит уже знакомые вам процедуры для входа в защищённый режим и возврата обратно в реальный режим. Обратите внимание на процедуры _load_task_register и _jump_to_task, выполняющие загрузку регистра задачи TR и переключение на другую задачу соответственно.
    1418. Листинг 15. Процедуры для инициализации, перехода в
    1419.                 защищённый режим и возврата в реальный режим,
    1420.                 для загрузки регистра TR и переключения задач.
    1421.  
    1422. Файл tossyst.asm
    1423. -----------------------------------------------------------
    1424.  
    1425. IDEAL
    1426. MODEL SMALL
    1427. RADIX   16
    1428. P286
    1429.  
    1430.         DATASEG
    1431.  
    1432.         include "tos.inc"
    1433.  
    1434.         PUBLIC  _beep
    1435.  
    1436. ; Область памяти для инициализации IDTR
    1437.  
    1438.         idtr                    idtr_struc <,,,0>
    1439.  
    1440. ; Область памяти для инициализации GDTR
    1441.  
    1442.         gdt_ptr         dw  (8*15)-1  ; размер GDT, 15 элементов
    1443.         gdt_ptr2                dw  ?
    1444.         gdt_ptr4                dw  ?
    1445.  
    1446. ; Область памяти для записи селектора задачи,
    1447. ; на которую будет происходить переключение
    1448.  
    1449.         new_task                dw  00h
    1450.         new_select       dw  00h
    1451.  
    1452. ; Область памяти для хранения регистров,
    1453. ; используется для возврата в реальный режим
    1454.  
    1455.         real_ss         dw      ?
    1456.         real_sp         dw      ?
    1457.         real_es         dw      ?
    1458.  
    1459.         protect_sel     dw      ?
    1460.  
    1461.         init_tss                dw      ?
    1462.  
    1463. CODESEG
    1464.  
    1465.         PUBLIC  _real_mode,_protected_mode,_jump_to_task
    1466.         PUBLIC  _load_task_register, _load_idtr, _enable_interrupt
    1467.  
    1468. ; -------------------------------------------------------------------
    1469. ; Процедура для переключения в защищённый режим.
    1470. ; Прототип для вызова:
    1471. ;  void protected_mode(unsigned long gdt_ptr, unsigned int gdt_size,
    1472. ;                unsigned int cseg, unsigned int dseg)
    1473. ; -------------------------------------------------------------------
    1474.  
    1475. PROC _protected_mode NEAR
    1476.                 push    bp
    1477.                 mov     bp,sp
    1478.  
    1479. ; Параметр gdt_ptr
    1480.  
    1481.                 mov     ax,[bp+4]           ; мл. слово адреса GDT
    1482.                 mov     dx,[bp+6]                   ; ст. слово адреса GDT
    1483.  
    1484.                 mov     [gdt_ptr4], dx      ; запоминаем адрес GDT
    1485.                 mov     [gdt_ptr2], ax
    1486.  
    1487. ; Параметр gdt_size
    1488.  
    1489.                 mov     ax,[bp+8]                   ; получаем размер GDT
    1490.                 mov     [gdt_ptr], ax       ; и запоминаем его
    1491.  
    1492. ; Параметры cseg и dseg
    1493.  
    1494.                 mov     ax,[bp+10d]         ; получаем селектор сегмента кода
    1495.                 mov     dx,[bp+12d]         ; получаем селектор сегмента данных
    1496.                 mov     [cs:p_mode_select], ax      ; запоминаем для команды
    1497.                 mov        [protect_sel], dx          ; перехода far jmp
    1498.  
    1499. ; Подготовка к возврату в реальный режим
    1500.  
    1501.                 push            ds                              ; готовим адрес возврата
    1502.                 mov             ax,40h                  ; из защищённого режима
    1503.                 mov             ds,ax
    1504.                 mov             [WORD 67h],OFFSET shutdown_return
    1505.                 mov             [WORD 69h],cs
    1506.                 pop             ds
    1507.  
    1508. ; Запрещаем и маскируем все прерывания
    1509.  
    1510.                 cli
    1511.                 in              al, INT_MASK_PORT
    1512.                 and             al, 0ffh
    1513.                 out             INT_MASK_PORT, al
    1514.  
    1515. ; Записываем код возврата в CMOS-память
    1516.  
    1517.                 mov             al,8f
    1518.                 out             CMOS_PORT,al
    1519.                 jmp             delay1
    1520. delay1:
    1521.                 mov             al,5
    1522.                 out             CMOS_PORT+1,al
    1523.  
    1524.                 call    enable_a20              ; открываем линию A20
    1525.  
    1526.                 mov             [real_ss],ss    ; запоминаем регистры SS и ES
    1527.                 mov             [real_es],es
    1528.  
    1529. ; Перепрограммируем контроллер прерываний
    1530. ; для работы в защищённом режиме
    1531.  
    1532.                 mov             dx,MASTER8259A
    1533.                 mov             ah,20
    1534.                 call            set_int_ctrlr
    1535.                 mov             dx,SLAVE8259A
    1536.                 mov             ah,28
    1537.                 call            set_int_ctrlr
    1538.  
    1539. ; Загружаем регистры IDTR и GDTR
    1540.  
    1541.                 lidt            [FWORD idtr]
    1542.                 lgdt       [QWORD gdt_ptr]
    1543.  
    1544.                 mov             ax, 0001h       ; переключаем процессор
    1545.                 lmsw            ax              ; в защищённый режим
    1546.  
    1547. ;               jmp     far flush
    1548.                 db      0eah
    1549.                 dw      OFFSET flush
    1550. p_mode_select   dw      ?
    1551.  
    1552. LABEL   flush   FAR
    1553.  
    1554.                 mov      dx, [protect_sel]
    1555.                 mov         ss, dx
    1556.                 mov         ds, dx
    1557.                 mov         es, dx
    1558.  
    1559. ; Обнуляем содержимое регистра LDTR
    1560.  
    1561.                 mov             ax, 0
    1562.                 lldt            ax
    1563.  
    1564.                 pop         bp
    1565.                 ret
    1566. ENDP _protected_mode
    1567.  
    1568. ; ----------------------------------------------------
    1569. ; Возврат в реальный режим.
    1570. ; Прототип для вызова
    1571. ;   void real_mode();
    1572. ; ----------------------------------------------------
    1573.  
    1574. PROC _real_mode   NEAR
    1575.  
    1576. ; Сброс процессора
    1577.  
    1578.                 cli
    1579.                 mov             [real_sp], sp
    1580.                 mov             al, SHUT_DOWN
    1581.                 out             STATUS_PORT, al
    1582.  
    1583. rmode_wait:
    1584.                 hlt
    1585.                 jmp             rmode_wait
    1586.  
    1587. LABEL   shutdown_return FAR
    1588.  
    1589. ; Вернулись в реальный режим
    1590.  
    1591.                 mov             ax, DGROUP
    1592.                 mov             ds, ax
    1593.  
    1594. assume  ds:DGROUP
    1595.  
    1596.                 mov     ss,[real_ss]
    1597.                 mov     sp,[real_sp]
    1598.  
    1599.                 in      al, INT_MASK_PORT
    1600.                 and     al, 0
    1601.                 out     INT_MASK_PORT, al
    1602.  
    1603.                 call    disable_a20
    1604.  
    1605.                 mov     ax, DGROUP
    1606.                 mov     ds, ax
    1607.                 mov     ss, ax
    1608.                 mov     es, ax
    1609.  
    1610.                 mov     ax,000dh
    1611.                 out     CMOS_PORT,al
    1612.                 sti
    1613.  
    1614.                 ret
    1615. ENDP _real_mode
    1616.  
    1617. ; -------------------------------------------------------
    1618. ; Загрузка регистра TR.
    1619. ; Прототип для вызова:
    1620. ;   void load_task_register(unsigned int tss_selector);
    1621. ; -------------------------------------------------------
    1622.  
    1623. PROC _load_task_register  NEAR
    1624.                 push    bp
    1625.                 mov     bp,sp
    1626.                 ltr       [bp+4] ; селектор для текущей задачи
    1627.                 pop     bp
    1628.                 ret
    1629. ENDP _load_task_register
    1630.  
    1631. ; -------------------------------------------------------
    1632. ; Переключение на задачу.
    1633. ; Прототип для вызова:
    1634. ;   void jump_to_task(unsigned int tss_selector);
    1635. ; -------------------------------------------------------
    1636.  
    1637. PROC _jump_to_task   NEAR
    1638.                 push    bp
    1639.                 mov     bp,sp
    1640.                 mov     ax,[bp+4]        ; получаем селектор
    1641.                                                         ; новой задачи
    1642.                 mov     [new_select],ax  ; запоминаем его
    1643.  
    1644.                 jmp     [DWORD new_task] ; переключаемся на
    1645.                                                         ; новую задачу
    1646.                 pop     bp
    1647.                 ret
    1648. ENDP _jump_to_task
    1649.  
    1650. ; ------------------------------
    1651. ; Открываем линию A20
    1652. ; ------------------------------
    1653.  
    1654. PROC    enable_a20      NEAR
    1655.         push    ax
    1656.         mov     al, A20_PORT
    1657.         out     STATUS_PORT, al
    1658.         mov     al, A20_ON
    1659.         out     KBD_PORT_A, al
    1660.         pop     ax
    1661.         ret
    1662. ENDP    enable_a20
    1663.  
    1664. ; ------------------------------
    1665. ; Закрываем линию A20
    1666. ; ------------------------------
    1667.  
    1668. PROC    disable_a20     NEAR
    1669.         push    ax
    1670.         mov     al, A20_PORT
    1671.         out     STATUS_PORT, al
    1672.         mov     al ,A20_OFF
    1673.         out     KBD_PORT_A, al
    1674.         pop     ax
    1675.         ret
    1676. ENDP    disable_a20
    1677.  
    1678. ; -----------------------------------------------------------
    1679. ; Готовим структуру для загрузки регистра IDTR
    1680. ; Прототип для вызова функции:
    1681. ; void load_idtr(unsigned long idt_ptr, word idt_size);
    1682. ; -----------------------------------------------------------
    1683.  
    1684. PROC _load_idtr NEAR
    1685.                 push    bp
    1686.  
    1687.                 mov    bp,sp
    1688.                 mov    ax,[bp+4] ; мл. слово адреса IDT
    1689.                 mov    dx,[bp+6] ; ст. слово адреса IDT
    1690.                 mov       bx, OFFSET idtr
    1691.  
    1692. ; Запоминаем адрес IDTR в структуре
    1693.  
    1694.                 mov         [(idtr_struc bx).idt_low], ax
    1695.                 mov         [(idtr_struc bx).idt_hi], dl
    1696.  
    1697. ; Получаем предел IDT и запоминаем его в структуре
    1698.  
    1699.                 mov             ax, [bp+8]
    1700.                 mov        [(idtr_struc bx).idt_len], ax
    1701.  
    1702.                 pop         bp
    1703.                 ret
    1704. ENDP _load_idtr
    1705.  
    1706. ; ----------------------------------
    1707. ; Установка контроллера прерываний
    1708. ; ----------------------------------
    1709.  
    1710. PROC    set_int_ctrlr   NEAR
    1711.  
    1712.         mov     al, 11
    1713.         out     dx, al
    1714.         jmp     SHORT $+2
    1715.         mov     al, ah
    1716.         inc     dx
    1717.         out     dx, al
    1718.         jmp     SHORT $+2
    1719.         mov     al, 4
    1720.         out     dx, al
    1721.         jmp     SHORT $+2
    1722.         mov     al, 1
    1723.         out     dx, al
    1724.         jmp     SHORT $+2
    1725.         mov     al, 0ffh
    1726.         out     dx, al
    1727.         dec     dx
    1728.         ret
    1729. ENDP    set_int_ctrlr
    1730.  
    1731. ; --------------------------
    1732. ; Выдача звукового сигнала
    1733. ; --------------------------
    1734.  
    1735. PROC    _beep   NEAR
    1736.  
    1737.         push    ax bx cx
    1738.  
    1739.         in      al,KBD_PORT_B
    1740.         push    ax
    1741.         mov     cx,80
    1742.  
    1743. beep0:
    1744.  
    1745.         push    cx
    1746.         and     al,11111100b
    1747.         out     KBD_PORT_B,al
    1748.         mov     cx,60
    1749.  
    1750. idle1:
    1751.  
    1752.         loop    idle1
    1753.         or      al,00000010b
    1754.         out     KBD_PORT_B,al
    1755.         mov     cx,60
    1756.  
    1757. idle2:
    1758.  
    1759.         loop    idle2
    1760.         pop     cx
    1761.         loop    beep0
    1762.  
    1763.         pop     ax
    1764.         out     KBD_PORT_B,al
    1765.  
    1766.         pop     cx bx ax
    1767.         ret
    1768.  
    1769. ENDP    _beep
    1770.  
    1771. ; -------------------------------
    1772. ; Задержка выполнения программы
    1773. ; -------------------------------
    1774.  
    1775. PROC    _pause          NEAR
    1776.  
    1777.         push    cx
    1778.         mov     cx,10
    1779.  
    1780. ploop0:
    1781.  
    1782.         push    cx
    1783.         xor     cx,cx
    1784.  
    1785. ploop1:
    1786.  
    1787.         loop    ploop1
    1788.         pop     cx
    1789.         loop    ploop0
    1790.  
    1791.         pop     cx
    1792.         ret
    1793.  
    1794. ENDP    _pause
    1795.  
    1796. ; -----------------------
    1797. ; Размаскирование прерываний
    1798. ; -----------------------
    1799.  
    1800. PROC    _enable_interrupt NEAR
    1801.  
    1802.                 in              al, INT_MASK_PORT
    1803.                 and             al, 0fch
    1804.                 out             INT_MASK_PORT, al
    1805.  
    1806.                 sti
    1807.                 ret
    1808. ENDP    _enable_interrupt
    1809.  
    1810.         end
     
  2. Q_sam

    Q_sam New Member

    Публикаций:
    0
    Регистрация:
    10 янв 2009
    Сообщения:
    21
    как я понял все сишные файлы нужно компилить в broland 3,11 . тоесть добавить их в один проект и получиться объектный файл,после чего скомпилить ассембрерныый код, например в MASM и уже Linkакуть полученные объектные файлы...? так? сейчас скачаю borland с 3.11 попробую)))))
     
  3. Q_sam

    Q_sam New Member

    Публикаций:
    0
    Регистрация:
    10 янв 2009
    Сообщения:
    21
    оказалось все проще протого!!!!!
    всем спасибо !!

    :dntknw:
     
  4. Clear_Energy

    Clear_Energy Алексей

    Публикаций:
    0
    Регистрация:
    3 ноя 2008
    Сообщения:
    375
    Куда мне, млять, со своим процессором до великих!!!

    З.Ы.
    Еб&сь оно конём