Защищенный режим процессоров Intel 80286 80386 80486

         

Пример использования интерфейса BIOS


Наш пример демонстрирует использование функции 89h прерывания INT 15h для установки защищённого режима работы процессора. Программа устанавливает защищённый режим, выдаёт первое сообщение и через некоторое время, выдав второе сообещние, возвращается в реальный режим. После того, как будет нажата любая клавиша, работа программы будет завершена.

Обратите внимание на то, как в файле tos.c подготавливается таблица GDT. Адрес подготовленной таблицы передаётся функции protected_mode(), которая передаёт его функции 89h прерывания INT 15h. Вызов этой функции выполняется в файле tossyst.asm. Листинг 16. Определение констант и структур данных Файл tos.h ----------------------------------------------------------- #define word unsigned int // Селекторы, определённые в GDT #define GDT_SELECTOR 0x08 // 1 - селктор для GDT #define IDT_SELECTOR 0x10 // 2 - селектор для IDT #define DATA_SELECTOR 0x18 // 3 - селектор для DS #define VID_MEM_SELECTOR 0x20 // 4 - селектор для ES, // будет использован для адресации видеопамяти #define SS_SELECTOR 0x28 // 5 - селектор для SS #define CODE_SELECTOR 0x30 // 6 - селектор для CS #define BIOS_SELECTOR 0x38 // 7 - селектор для адресации // области данных BIOS #define COLOR_VID_MEM 0xb8000L #define MONO_VID_MEM 0xb0000L #define MONO_MODE 0x07 #define BW_80_MODE 0x02 #define COLOR_80_MODE 0x03 typedef struct descriptor { word limit; word base_lo; unsigned char base_hi; unsigned char type_dpl; unsigned reserved; } descriptor; typedef struct gate { word offset; word selector; unsigned char count; unsigned char type_dpl; word reserved; } gate; #define DESCRIPTOR_SIZE (sizeof(descriptor)) #define GATE_SIZE (sizeof(gate)) #define IDT_SIZE (sizeof(idt)) #define TYPE_CODE_DESCR 0x18 #define TYPE_DATA_DESCR 0x10 #define TYPE_INTERRUPT_GATE 0x86 #define TYPE_TRAP_GATE 0x87 #define SEG_WRITABLE 0x02 #define SEG_READABLE 0x02 #define SEG_EXPAND_DOWN 0x04 #define SEG_ACCESSED 0x01 #define SEG_PRESENT_BIT 0x80 #define EOI 0x20 #define MASTER8259A 0x20 #define SLAVE8259A 0xA0


#define MK_LIN_ADDR(seg,off) (((unsigned long)(seg))<<4)+(word)(off) Листинг 17.
Главная программа Файл tos.c ----------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <dos.h> #include <conio.h> #include "tos.h" void Init_And_Protected_Mode_Entry(void); void protected_mode(descriptor far *gdt_ptr); void real_mode(void); void init_gdt_descriptor(descriptor *descr, unsigned long base, word limit, unsigned char type); void vi_print(unsigned int x, unsigned int y, char *s, char attr); void vi_hello_msg(void); 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); } void iret0(void); void iret1(void); descriptor gdt[8]; gate idt[] = { { (word)&exception_0, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 0 { (word)&exception_1, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1 { (word)&exception_2, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 2 { (word)&exception_3, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 3 { (word)&exception_4, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 4 { (word)&exception_5, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 5 { (word)&exception_6, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 6 { (word)&exception_7, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 7 { (word)&exception_8, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 8 { (word)&exception_9, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 9 { (word)&exception_A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // A { (word)&exception_B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // B { (word)&exception_C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // C { (word)&exception_D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // D { (word)&exception_E, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // E { (word)&exception_F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // F { (word)&exception_10, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 10 { (word)&exception_11, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 11 { (word)&exception_12, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 12 { (word)&exception_13, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 13 { (word)&exception_14, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 14 { (word)&exception_15, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 15 { (word)&exception_16, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 16 { (word)&exception_17, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 17 { (word)&exception_18, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 18 { (word)&exception_19, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 19 { (word)&exception_1A, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1A { (word)&exception_1B, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1B { (word)&exception_1C, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1C { (word)&exception_1D, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1D { (word)&exception_1E, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1E { (word)&exception_1F, CODE_SELECTOR, 0, TYPE_TRAP_GATE, 0 }, // 1F { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 20 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 21 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 22 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 23 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 24 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 25 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 26 { (word)&iret0, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 27 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 28 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 29 { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2A { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2B { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2C { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2D { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 }, // 2E { (word)&iret1, CODE_SELECTOR, 0, TYPE_INTERRUPT_GATE, 0 } // 2F }; word y=0; void main(void) { textcolor(BLACK); textbackground(LIGHTGRAY); clrscr(); Init_And_Protected_Mode_Entry(); enable_interrupt(); vi_hello_msg(); y=3; vi_print(0, y++, " Вошли в защищённый режим", 0x7f); pause(); vi_print(0, y++, " Для возврата в реальный режим нажмите любую клавишу", 0x7f); real_mode(); getch(); textcolor(WHITE); textbackground(BLACK); clrscr(); } void init_gdt_descriptor(descriptor *descr, unsigned long base, word limit, unsigned char type) { descr->base_lo = (word)base; descr->base_hi = (unsigned char)(base >> 16); descr->type_dpl = type; descr->limit = limit; descr->reserved = 0; } void Init_And_Protected_Mode_Entry(void) { union REGS r; word crt_mode; extern word gv1_; // Дескриптор, описывающий таблицу GDT init_gdt_descriptor(&gdt[1], MK_LIN_ADDR(_DS, &gdt), sizeof(gdt)-1, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); // Дескриптор, описывающий таблицу IDT init_gdt_descriptor(&gdt[2], MK_LIN_ADDR(_DS, &idt), (unsigned long)IDT_SIZE-1, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); // Дескриптор сегмента данных init_gdt_descriptor(&gdt[3], MK_LIN_ADDR(_DS, 0), 0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); // Определяем текущий видеорежим r.h.ah=15; int86(0x10,&r,&r); crt_mode = r.h.al; // Инициализация дескриптора для видеопамяти // монохромного видеоадаптера if(crt_mode == MONO_MODE) init_gdt_descriptor(&gdt[4], MONO_VID_MEM, 3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); // Инициализация дескриптора для видеопамяти // цветного видеоадаптера else if(crt_mode == BW_80_MODE || crt_mode == COLOR_80_MODE) init_gdt_descriptor(&gdt[4], COLOR_VID_MEM, 3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); else { printf("\nИзвините, этот видеорежим недопустим."); exit(-1); } // Дескриптор для сегмента стека init_gdt_descriptor(&gdt[5], MK_LIN_ADDR(_DS, 0), 0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); // Дескриптор для сегмента кода init_gdt_descriptor(&gdt[6], MK_LIN_ADDR(_CS, 0), 0xffffL, TYPE_CODE_DESCR | SEG_PRESENT_BIT | SEG_READABLE); // Входим в защищённый режим // В качестве параметра передаём адрес подготовленной // таблицы GDT protected_mode(gdt); } void prg_abort(int err); 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); } void prg_abort(int err) { vi_print(1,y++,"---> Произошло исключение", 0xc); real_mode(); gotoxy(1,24); cprintf("Исключение %X, нажмите любую клавишу", err); getch(); textcolor(WHITE); textbackground(BLACK); clrscr(); exit(0); } void iret0(void) { asm { push ax mov al,EOI out MASTER8259A,al pop ax pop bp iret } } void iret1(void) { asm { push ax mov al,EOI out MASTER8259A,al out SLAVE8259A,al pop ax pop bp iret } } void vi_putch(unsigned int x, unsigned int y ,char c, char attr) { register unsigned int offset; char far *vid_ptr; offset=(y*160) + (x*2); vid_ptr=MK_FP(VID_MEM_SELECTOR, offset); *vid_ptr++=c; *vid_ptr=attr; } void vi_print(unsigned int x, unsigned int y, char *s, char attr) { while(*s) vi_putch(x++, y, *s++, attr); } void vi_hello_msg(void) { vi_print(0, 0, " Protected mode monitor *TINY/OS*, " "v.1.11 for CPU 80286 ¦ © Frolov A.V., 1992 ", 0x30); } Листинг 18.


Функции для перехода в защищённый режим и возврата в реальный режим. Файл tossyst.asm ----------------------------------------------------------- IDEAL MODEL SMALL RADIX 16 P286 DATASEG CMOS_PORT EQU 70 PORT_6845 EQU 63h COLOR_PORT EQU 03d4h MONO_PORT EQU 03b4h STATUS_PORT EQU 64h SHUT_DOWN EQU 0feh INT_MASK_PORT EQU 21h VIRTUAL_MODE EQU 0001 A20_PORT EQU 0d1 A20_ON EQU 0df A20_OFF EQU 0ddh EOI EQU 20 MASTER8259A EQU 20 SLAVE8259A EQU 0a0h KBD_PORT_A EQU 60h KBD_PORT_B EQU 61h gdt_off dw ? gdt_seg dw ? real_ss dw ? real_sp dw ? real_es dw ? CODESEG PUBLIC _real_mode, _protected_mode PUBLIC _enable_interrupt PUBLIC _pause PROC _protected_mode NEAR push bp mov bp,sp mov ax,[bp+4] mov dx,[bp+6] mov [gdt_seg], dx mov [gdt_off], ax push ds mov ax,40 mov ds,ax mov [WORD 67],OFFSET shutdown_return mov [WORD 69],cs pop ds cli in al, INT_MASK_PORT and al, 0ffh out INT_MASK_PORT, al mov al,8f out CMOS_PORT,al jmp delay1 delay1: mov al,5 out CMOS_PORT+1,al mov [real_ss],ss mov [real_es],es ; Загружаем регистры ES:SI адресом GDT, полученным ; как параметр функции protected_mode() mov es, [gdt_seg] mov si, [gdt_off] ; Подготавливаем номера прерываний IRQ0 и IRQ8 ; для перепрограммирования контроллеров прерываний. mov bx, 2028h ; Устанавливаем защищённый режим работы mov ax, 8900h int 15h jnc pok ; Если произошла ошибка, мы остались в реальном режиме, ; завершаем работу программы. mov ah, 4ch int 21h ; Установлен защищённый режим работы процессора ! pok: pop bp ret ENDP _protected_mode PROC _real_mode NEAR mov [real_sp], sp mov al, SHUT_DOWN out STATUS_PORT, al waitr1: hlt jmp waitr1 LABEL shutdown_return FAR mov ax, DGROUP mov ds, ax assume ds:DGROUP cli mov ss,[real_ss] mov sp,[real_sp] in al, INT_MASK_PORT and al, 0 out INT_MASK_PORT, al mov ax, DGROUP mov ds, ax mov ss, ax mov es, ax mov ax,000dh out CMOS_PORT,al sti ret ENDP _real_mode PROC _pause NEAR push cx mov cx,10 ploop0: push cx xor cx,cx ploop1: loop ploop1 pop cx loop ploop0 pop cx ret ENDP _pause PROC _enable_interrupt NEAR sti in al, INT_MASK_PORT and al, 0fch out INT_MASK_PORT, al ret ENDP _enable_interrupt end

Содержание раздела