Написание программы, переходящей процессор из реального режима в защищенный

Страницы работы

Фрагмент текста работы

Лабораторная работа №4

Защищённый режим

Цель: В защищённом режиме создать 2 задачи. Каждая задача выводит на экран мигающий символ. Управляя клавишами ‘1' , ‘ 2 ' останавливать или возобновлять мигание символа соответствующей задачи. Задачи выполняются в защищенном режиме.

Теоретические сведения:

В подавляющем большинстве программы, составленные для реального режима процессора, выполняются в однозадачном режиме, полностью монополизируя все ресурсы компьютера. Однако в реальной жизни человеку, работающему с компьютером требуется одновременный доступ к двум или большему числу программ. Мультизадачность позволяет не только задействовать все ресурсы современных персональных компьютеров, но и существенно повышает производительность труда. В защищенном режиме процессора i80x86 можно как раз и  реализовать эту мультизадачность.

Ход выполнения работы

Определяем селекторы как константы. У них все биты TI = 0 (выборка  дескрипторов производится из GDT), RPL = 00 - уровень привилегий -  нулевой.

Создаем GDT и описываем дескрипторы в ней. Нам понадобится создать 15 дескрипторов для кода, данных, стека , видеопамяти. Так же создаем дескрипторы для возврата в режим реальных адресов. После этого устанавливаем GDT, запретив перед этим прерывания.

Устанавливаем IDT для шлюзов исключений и аппаратных прерываний. Будем обрабатывать аппаратные прерывания только от таймера  и клавиатуры. Для остальных устанавливает заглушки. Для исключения деления на ноль создаем обработчик, который вывод на экран число обращений к нему.

Для перевода процессора из реального режима в защищённый можно использовать специальную команду LMSW, загружающую регистр состояния процессора (Mashine Status Word). Младший бит этого регистра указывает режим работы процессора. Значение, равное 0, соответствует реальному режиму работы, а значение 1 - защищённому.

Если установить младший бит регистра состояния процессора в 1, процессор переключится в защищённый режим:

mov     ax, 1

lmsw    ax

Для того, чтобы вернуть процессор из защищённого режима в реальный, необходимо выполнить аппаратный сброс (отключение) процессора. Это можно сделать следующим образом:

mov     ax, 0FEh        ; команда отключения

out     64h, ax

В защищенном режиме запускаем две задачи, которые выводят на экран строчки Task in Progress or Task Stop, показывая в каком состоянии они находятся. Для остановки, какой либо задачи использует семафоры. Таким образом при нажатии цифровой клавиши 1 или 2 происходит остановка или запуск соответствующего потока. При нажатии на клавишу 3 вызывается процедура деления на ноль. При нажатии на Esc происходит выход в реальный режим. Диспетчеризация осуществляется на основе выделения кванта времени при помощи генерируемого прерывания от timer.

Пример работы приложения:

Вывод: в лабораторной работе написана программа, переходящая процессор из реального режима в защищенный, запускает в этом режиме два потока, кроме того, программа обрабатывает прерывания от таймера и клавиатуры.

Литература

1.  В.И. Юров “Assembler” – СПб: Питер, 2002 – 624с.

2.  С.В. Зубков “Assembler” – ДМК “Пресс”, 1999 – 624с.

3.  А. Фролов, Г. Фролов Защищенный режим процессоров Intel 80286/80386/80486 Том 6, М.: Диалог-МИФИ, 1993, 234 стр.

4.  А.В. Гордеев А.Ю. Молчанов. Системное программное обеспечение. Санкт-Петербург. Питер. 2002  г. 740 с.


Приложение

Файл EXCEPT.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

void prg_abort(int err);

void div_abort();

// Номер текущей строки для вывода на экран

extern unsigned int y;

// Обработчики исключений

void  exception_0(void) { div_abort(); }

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, ++y);

cprintf(" Исключение %X, нажмите любую клавишу", err);

getch();

textcolor(WHITE);

textbackground(BLACK);

clrscr();

exit(0);

}

int num = 0;

void div_abort() {

num++;

vi_print(1,8,"Упсс. Деление на ноль", 0xc);

vi_print(1,9," Сколько раз можно нажимать эту клавишу", 0x7f);

vi_put_word(1,10,num,0x7f);

}

Файл INTPROC.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

// Заглушки для необрабатываемых

// аппаратных прерываний.

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

}

}

Файл KEYB.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

extern word key_code;

// Функция, ожидающая нажатия любой

// клавиши и возвращающая её скан-код

unsigned int kb_getch(void) {

asm int 30h

return(key_code);

}

Файл KEYBOARD.ASM


IDEAL

MODEL SMALL

RADIX  16

P386

include "tos.inc"

; -----------------------------------------; Модуль обслуживания клавиатуры

; -----------------------------------------PUBLIC _Keyb_int, _Int_30h_Entry, _key_code, _keyb_status

EXTRN  _beep:PROC

DATASEG

_key_flag      db     0

_key_code      dw     0

ext_scan       db     0

_keyb_status   dw     0

CODESEG

PROC   _Keyb_int      NEAR

cli

call   _beep

push   ax

mov    al, [ext_scan]

cmp    al, 0

jz     normal_scan1

cmp    al, 0e1h

jz     pause_key

in     al, 60h

cmp    al, 2ah

jz     intkeyb_exit_1

cmp    al, 0aah

jz     intkeyb_exit_1

mov    ah, [ext_scan]

call   Keyb_PutQ

mov    al, 0

mov    [ext_scan], al

jmp    intkeyb_exit

pause_key:

in     al, 60h

cmp    al, 0c5h

jz     pause_key1

cmp    al, 45h

jz     pause_key1

jmp    intkeyb_exit

pause_key1:

mov    ah, [ext_scan]

call   Keyb_PutQ

mov    al, 0

mov    [ext_scan], al

jmp    intkeyb_exit

normal_scan1:

in     al, 60h

cmp    al, 0feh

jz     intkeyb_exit

cmp    al, 0e1h

jz     ext_key

cmp    al, 0e0h

jnz    normal_scan

ext_key:

mov    [ext_scan], al

jmp    intkeyb_exit

intkeyb_exit_1:

mov    al, 0

mov    [ext_scan], al

jmp    intkeyb_exit

normal_scan:

mov    ah, 0

call   Keyb_PutQ

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

pop    ax

sti

iret

jmp    _Keyb_int

ENDP   _Keyb_int

PROC   Keyb_PutQ      NEAR

push   ax

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:

test   ax, 0080h

jnz    keyb_putq_exit

mov    [_key_code], ax

mov    al, 0ffh

mov    [_key_flag], al

keyb_putq_exit:

pop    ax

ret

ENDP   Keyb_PutQ

; Обработчик программного прерывания

; для ввода с клавиатуры. По своим функциям

; напоминает прерывание INT 16 реального

; режима.

PROC   _Int_30h_Entry NEAR

push   ax dx

; Ожидаем прерывание от клавиатуры

keyb_int_wait:

sti

nop

nop

cli

; Проверяем флаг, который устанавливается

; обработчиком аппаратного прерывания клавиатуры

mov    al, [_key_flag]

cmp    al, 0

jz     keyb_int_wait

; Сбрасываем флаг после прихода прерывания

mov    al, 0

mov    [_key_flag], al

sti

pop    dx ax

iret

ENDP   _Int_30h_Entry

END


Файл SCREEN.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

void vi_putch(unsigned int x, unsigned int y ,char c, char attr);

char hex_tabl[] = "0123456789ABCDEF";

// Вывод байта на экран, координаты (x,y),

// выводится шестнадцатеричное представление

// байта chr с экранными атрибутами attr.

void vi_put_byte(unsigned int x,

unsigned int y, unsigned char chr, char attr) {

unsigned char temp;

temp = hex_tabl[(chr & 0xf0) >> 4];

vi_putch(x, y, temp, attr);

temp = hex_tabl[chr & 0xf];

vi_putch(x+1, y, temp, attr);}

// Вывод слова на экран, координаты (x,y),

// выводится шестнадцатеричное представление

// слова chr с экранными атрибутами attr.

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);

}

// Вывод символа c на экран, координаты - (x,y),

// атрибут выводимого символа - attr

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;

}

// Вывод строки s на экран, координаты - (x,y),

// атрибут выводимой строки - 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"

" v1.0 for CPU 80x86 Вершинин Алексей 2004 г.", 0x30);

}

Файл SEMAPHOR.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

// Массив из пяти семафоров

word semaphore[7];

// Процедура сброса семафора.

// Параметр sem - номер сбрасываемого семафора

void sem_clear(int sem) {

asm cli

semaphore[sem] = 0;

asm sti

}

// Процедура установки семафора

// Параметр sem - номер устанавливаемого семафора

void sem_set(int sem) {

asm cli

semaphore[sem] = 1;

asm sti

}

// Ожидание установки семафора

// Параметр sem - номер ожидаемого семафора

void sem_wait(int sem) {

while(1) {

asm cli

if(semaphore[sem]) break; // проверяем семафор

asm sti // ожидаем установки семафора

asm nop

asm nop

}

asm sti

}

int sem_test(int sem) {

if (semaphore[sem]) return 1;

return 0;

}

Файл TASKS.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

word dispatcher(void);

// Номер текущей строки для вывода на экран

extern unsigned int y;

// Задача TASK_1

long delay_cnt1 = 0l;

void task2(void) {

while(1){

asm sti

if(delay_cnt1 > 150000l ) {

asm cli

if (!sem_test(2)) {

vi_print(60,3, " Task 1 In Progress", 0x4f);

}

else

{

sem_clear(2);

vi_print(60,3, " Task 1 Stop       ", 0x1f);

sem_wait(2);

sem_clear(2);

}

delay_cnt1 = 0l;

asm sti

}

delay_cnt1++;

}

}

word flipflop = 0;

long delay_cnt = 0l;

//Задача TASK_2

void flipflop_task(void) {

while(1){

asm sti

if(delay_cnt > 150000l ) {

asm cli

if (!sem_test(3)) {

vi_print(60,4, " Task 2 In Progress", 0x4f);

}

else

{

sem_clear(3);

vi_print(60,4, " Task 2 Stop       ", 0x1f);

sem_wait(3);

sem_clear(3);

}

delay_cnt=0l;

asm sti

}

delay_cnt++;

}

}

word keyb_code;

extern word keyb_status;

int error;

void keyb_task(void) {

// Эта задача вводит символы с клавиатуры.

// Работающая параллельно главная задача

// ожидает установку семафора. Как только

// семафор 0 окажется установлен, главная задача

// завершает свою работу и программа возвращает

// процессор в реальный режим, затем передаёт

// управление MS-DOS.

while(1){

keyb_code = kb_getch();

if (keyb_code == 0x0004) {

error =5;

error = error/0;

}

if (keyb_code == 0x0002) sem_set(2);

if (keyb_code == 0x0003) sem_set(3);

if ((keyb_code & 0x00ff) == 1) sem_set(0);

}

}

Файл TIMER.C

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#include <stdlib.h>

#include "tos.h"

// ------------------------------------------//     Модуль обслуживания таймера

// ------------------------------------------#define EOI 0x20

#define MASTER8259A 0x20

extern void beep(void);

extern void flipflop_task(void);

void Timer_int(void);

word dispatcher(void);

word   timer_cnt;

// -----------------------------------------// Обработчик аппаратного прерывания таймера

// -----------------------------------------void Timer_int(void) {

asm pop bp

// Выдаём в контроллер команду конца

// прерывания

asm mov al,EOI

asm out MASTER8259A,al

// Переключаемся на следующую задачу,

// селектор TSS которой получаем от

// диспетчера задач dispatcher()

jump_to_task(dispatcher());

asm iret

}

// -------------------------------------// Диспетчер задач

// -------------------------------------// Массив селекторов, указывающих на TSS

// задач, участвующих в параллельной работе,

// т.е. диспетчеризуемых задач

word task_list[] = {

MAIN_TASK_SELECTOR,

FLIP_TASK_SELECTOR,

KEYBIN_TASK_SELECTOR,

TASK_2_SELECTOR

};

word current_task = 0; // текущая задача

word max_task = 3;     // количество задач - 1

// Используем простейший алгоритм диспетчеризации // выполняем последовательное переключение на все

// задачи, селекторы TSS которых находятся

// в массиве task_list[].

word dispatcher(void) {

if (current_task < max_task) current_task++;

else current_task = 0;

return(task_list[current_task]);

}

Файл 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(unsigned long gdt_ptr, unsigned int gdt_size,

word cseg, word dseg, word sseg);

word           load_task_register(word tss_selector);

void           real_mode(void);

void           jump_to_task(word tss_selector);

void           load_idtr(unsigned long idt_ptr, word idt_size);

void           Keyb_int(void);

void           Timer_int(void);

void           Int_30h_Entry(void);

extern word kb_getch(void);

void           enable_interrupt(void);

void           task2(void);

void           flipflop_task(void);

void           keyb_task(void);

void           init_tss(tss *t, word cs, word ds, word ss,

unsigned char *sp, func_ptr ip);

void           init_gdt_descriptor(descriptor *descr, unsigned long base,

word limit, unsigned char type);

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);

// -------------------------------------// Глобальная таблица дескрипторов GDT

// -------------------------------------descriptor     gdt[11];

// -------------------------------------// Дескрипторная таблица прерываний IDT

// -------------------------------------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

Похожие материалы

Информация о работе

Тип:
Отчеты по лабораторным работам
Размер файла:
1 Mb
Скачали:
0