Перехід у захищений режим. Програма яка виводить на екран відомості про тип процесора і виводить вміст регістру флагів і іншу інформацію о системі. Завершення циклу чекання натиску клавіші. Масковані і немасковані переривання. Вихід до реального режиму.
Пояснення до змісту роботиВ даній розрахунково-графічній роботі розроблено програму, що реалізує захищений режим роботи мікропроцесора, обробку апаратних і програмних переривань, засвоєно основні принципи роботи мікропроцесора у захищеному режимі при використанні сегментної моделі памяті, порядок обробки переривань, структуру таблиць GDT та IDT.
Вывод
1. Індивідуальне завдання
Варіант 16
В захищеному режимі виконати наступні дії: I. Викликати необхідне згідно із індивідуальним завданням виключення
II. Обробити задане виключення двома засобами: а) прибравши причину виключення;
б) пропустивши команду, що визвала виключення.
III. Обробити задане зовнішнє переривання.
2. Пояснення до змісту роботи
Для виконання завдання необхідно виконати наступні дії: розробити дескриптори усіх необхідних сегментів памяті і сформувати з них глобальну дескрипторну таблицю GDT. за допомогою регістра GDTR задати базову адресу і розмір таблиці GDT;
розробити дескриптори усіх шлюзів, сформувати з них таблицю IDT. за допомогою регістра IDTR задати базову адресу і розмір таблиці IDT;
сформувати дані для повернення в реальний режим;
заборонити масковані і немасковані переривання;
перевести мікропроцесор у захищений режим;
виконати в захищеному режимі дії, задані індивідуальним завданням;
повернутися в реальний режим;
дозволити масковані і немасковані переривання.
Для розуміння принципів програмування роботи в захищеному режимі необхідно розуміти його особливості. Захищений режим має такі особливості роботи з перериваннями (порівнюючи з реальним режимом): 1) вводиться новий тип переривань - виключення;
2) замість дальніх адрес в таблиці переривань використовуються дескриптори шлюзів;
3) таблиця переривань може знаходитися в будь-якому місці памяті.
Виключення поділяються на три типи: - Помилка (trap);
- Пастка (fault);
- Аварія (abort).
Помилка - це виключення, що виникає в ситуації помилкових дій програми й припускається, що таку помилку можна виправити. Виконання програми продовжується починаючи із команди, при якій виникло виключення.
Пастка - це виключення, що виникає відразу після виконання команди. Виконання програми продовжується із наступної команди,що йде за командою на якій виникло виключення. На пастках строїться механізм відладки програм.
Аварія - це виключення, що не дозволяє продовжити виконання перерваної програми і сигналізує про серйозні порушення цілісності системи.
3. Опис програми
Для написання програми для виконання разрахункового завдання, скористались модулем PROT і програмою P_INT, що поставляються разом із індивідуальним завданням. В модулі PROT містяться основні необхідні константи і функції для створення власних таблиць GDT та IDT, для переходу в захищений режим, містяться також заглушки для всіх апаратних і програмних переривань. Програма P_INT містить перевизначення необхідних для роботи, або заданих за індивідуальним завданням переривань, в ній задається вміст таблиць GDT та IDT (в ній визначаються селектори заглушок, або необхідних переривань, на необхідних місцях), програма реалізує перехід в захищений режим, імітує виникнення програмного переривання, а також реалізує вічний цикл, до виникнення апаратного переривання. Після цього реалізується вихід до реального режиму, шляхом скидання мікропроцесору (не працює на нових моделях мікропроцесорів) або шляхом відновлення старої GDT та IDT, і повернення до реального режиму. Нами було додано необхідні по індивідуальному завданню апаратне і програмне переривання, і реалізовано виключну ситуацію для їх виникнення.4. Текст програми
{----Модуль содержит константы, типы переменных, переменные,----}
{------процедуры и функции для работы в защищенном режиме-------} unit prot;
interface uses crt;
const hex_tabl:array[0..15] of char="0123456789ABCDEF";
var gdt:array[0..15] of t_gdt; { Таблица GDT } idt:array[0..$32] of t_idt; { Таблица IDT } gdtr, { Содержимое GDTR } idtr, { Содержимое IDTR для работы в защищенном режиме } idtr_r { Содержимое IDTR для работы в реальном режиме }
:t_dtr;
ofs_ret, { Смещение и } sel_ret, { селектор точки возврата в реальный режим } ofs_ret_mov, { Смещение метки ret_mov: } cs_prot, { Селектор регистра CS в защищенном режиме } cs1, { Значение сегмента кода модуля PROT }
{ Переменные для хранения значений регистров: } real_ss, { SS, } real_es, { ES и } real_sp:word; { SP } scan, { Скан-код нажатия клавиши } cpu_type, { Номер типа микропроцессора } res, { Признак сброса МП } rm1, { Содержимое регистров маски 1-го } rm2, { и 2-го контроллеров прерывания } excep, { Номер исключения } acc_int, { Байт доступа прерывания } acc_trap, { Байт доступа ловушки } t:byte; { Признак разрядности МП: T=0 - 16; T=8 - 32 } function lin_adr(seg,off:word):longint;
(* db 2eh *) mov cs:[0],ax { Запись в сегмент кода } end;
pic(0); { Программирование ПКП для реального режима } end; {test_wr}
{-----------------Формирование TSS для 80286------------------} procedure init_tss_286 (var tss:t_tss_286; cs,ds,es, ofs_task,ofs_task_stack,flags:word);
begin tss.cs:=cs;
tss.ds:=ds;
tss.es:=es;
tss.ss:=ds;
tss.ip:=ofs_task;
tss.bp:=ofs_task_stack;
tss.sp:=ofs_task_stack;
tss.ldtr:=0;
tss.flags:=flags;
end;{init_tss_286}
{--------------Формирование TSS для 80386 и выше--------------} procedure init_tss_386(var tss:t_tss_386; cs,ds,es, ofs_task,ofs_task_stack,eflags:word);
begin tss.cs:=cs;
tss.ds:=ds;
tss.es:=es;
tss.ss:=ds;
tss.eip:=ofs_task;
tss.ebp:=ofs_task_stack;
tss.esp:=ofs_task_stack;
tss.ldtr:=0;
tss.eflags:=eflags;
tss.bit_t:=0;
tss.adr_bkvv:=108;
tss.BKVV:=0;
tss.byte_end:=$ff end;{init_tss_386}
{---------Определение типа микропроцессора (cpu_type)---------} procedure get_cpu_type(inf:byte;var cpu:byte);
var data_cach:array[1..4,1..4] of byte; { Данные о кэше МП } max_inp, { Max значение вх. параметра команды CPUID }
EBX_, { Брэнд ID и др. } feature, { Данные об особенностях МП (регістр EDX) }
ECX_:longint; { Данные об особенностях МП (регістр ECX) } desc_L2:word; { Дескриптор кэша L2 }
{ Серийный номер микропроцессора: } sn_1, { младшие 32 разряда, } sn_2, { средние 32 разряда, } sn_3:longint; { старшие 32 разряда } vend:array[1..12] of char;{ Название фирмы-изготовителя } brand_str:array[1..48] of char; { Брэнд-строка } typ, { Тип МП (0-2) } model, { Модель МП (4-6) } i,j, id_flag, { Флаг исполнения МП команды CPUID } cpu_type, { Возвращаемый номер типа МП (0, 2-6) } brand, { Брэнд ID }
CLFSH, { Длина строки кэша }
NMP, { Число логических процессоров в кристалле } par:byte; { Число параметров команды CPUID } unknown:boolean; { Признак нераспознавания типа МП } s:string;
begin unknown:=false;
id_flag:=0;
asm pushf { Сохранить FLAGS }
@8086: { Проверка МП i8086: }
{ биты 12-15 регистра FLAGS всегда установлены } pushf pop ax mov cx,ax and ax,0fffh push ax popf pushf pop ax and ax,0f000h cmp ax,0f000h mov cpu_type,0 { Микропроцессор: 8086 } jne @80286
@80286: { Проверка МП i80286: }
{ биты 12-15 регистра FLAGS в реальном режиме всегда сброшены } or cx,0f000h push cx popf pushf pop ax and ax,0f000h mov cpu_type,2 { Микропроцессор: 80286 } jnz @80386 jmp @end_cpuid
@80386: { Проверка МП i80386: }
{ флаг AC (бит 18) регистра EFLAGS не может быть установлен } db 66h { префикс разрядности: 32 разряда } pushf db 66h pop ax { Занести в EAX исходное значение EFLAGS } db 66h mov cx,ax { Сохранить исходное значение EFLAGS в ECX } db 66h,35h { Изменить командой XOR бит AC в EFLAGS } dd 040000h db 66h push ax { Сохранить новое значение EFLAGS в стеке } db 66h popf { Заменить текущее значение EFLAGS } db 66h pushf db 66h pop ax { Запомнить новое значение EFLAGS в EAX } db 66h xor ax,cx mov cpu_type,3 jz @end_cpuid { Если бит AC не меняется: } db 66h { микропроцессор: 80386 } push cx db 66h popf { Восстановить AC бит в EFLAGS }
@80486: { Проверка МП i486 и последующих моделей: }
{ установка/сброс ID флага (бит 21) в EFLAGS }
{ указывает на выполнимость команды CPUID на данном МП } mov cpu_type,4 { Микропроцессор: i486 } db 66h mov ax,cx { Получить исходное значение EFLAGS } db 66h,35h { Изменить командой XOR бит ID в EFLAGS } dd 200000h db 66h push ax { Сохранить новое значение в стеке } db 66h popf { Занести новое значение в EFLAGS } db 66h pushf { Записать его в стек } db 66h pop ax { Переписать в EAX } popf { Восстановить EFLAGS } db 66h xor ax,cx { Если бит ID не меняется: } je @end_cpuid { МП не поддерживает команду CPUID }
{ Выполнение команды CPUID для определения }
{ фирмы, семейства, модели микропроцессора } mov id_flag,1 { Установка флага }
{ выполнения МП команды CPUID } db 66h xor ax,ax { Параметр для CPUID: EAX=0 } db 0fh,0a2h { Команда CPUID } db 66h mov ss:[bp offset vend],bx { Из регистров EBX, } db 66h { EDX } mov ss:[bp offset vend 4],dx { и ECX } db 66h { в переменную vend } mov ss:[bp offset vend 8],cx { заносится имя фирмы } cmp al,1 { В AL - наибольшее значение параметра CPUID } jl @end_cpuid mov par,al db 66h xor ax,ax db 66h inc ax { Установка параметра CPUID =1 } db 0fh,0a2h { Команда CPUID: в AL - сигнатура МП } db 66h { В sn_3 - старшие 32 разряда } mov word ptr sn_3,ax { серийного номера МП } mov word ptr EBX_,bx { В EBX_- Brand ID и др. } db 66h mov word ptr ECX_,cx { В ЕСХ_- особенности МП } db 66h mov word ptr feature,dx { В EDX_- особенности МП } mov cx,ax and ax,0f0h db 0c1h,0e8h,4 { Сдвиг в AX на 4 разряда вправо } mov model, al { В AL - модель МП } mov ax,cx and ax,0f00h db 0c1h,0e8h,8 { Сдвиг в AX на 8 разрядов вправо } mov cpu_type, al { В AL - номер семейства МП } mov ax,cx and ax,3000h db 0c1h,0e8h,12 { Сдвиг в AX на 12 разрядов вправо } mov typ, al { В AL - номер типа МП } db 66h mov word ptr feature,dx { В feature - особенности МП } cmp par,1 jz @end_cpuid db 66h,0b8h { MOV EAX,2: установка параметра } dd 2 { команды CPUID =2 } db 0fh,0a2h { Команда CPUID } db 66h mov ss:[bp offset data_cach],ax { В регистрах EAX, } db 66h { EBX, ECX } mov ss:[bp offset data_cach 4],bx { и EDX - } db 66h { информация о } mov ss:[bp offset data_cach 8],cx { кэш-памяти МП, } db 66h { которая заносится в массив } mov ss:[bp offset data_cach 12],dx { data_cach }
@end_cpuid: end;
s:="";
clrscr;
if id_flag=0 then begin { Определение типа МП } case cpu_type of { без использования команды CPUID }
0:s:="i8086";
2:s:="i80286";
3:s:="i80386";
4:s:="i486";
end;
writeln(s);
end else begin brand:=EBX_; { Значение брэнд ID } for i:=1 to 4 do { Определение дескриптора } for j:=1 to 4 do { кэша второго уровня } if data_cach[i,4] and 128=0 then if (data_cach[i,j]=$41) or (data_cach[i,j]=$42) or (data_cach[i,j]=$43) or (data_cach[i,j]=$44) or (data_cach[i,j]=$45) then begin desc_L2:=data_cach[i,j];
break end;
case cpu_type of
4:case model of
0,1:s:="i486 DX";
2:s:="i486 SX";
3:s:="IDX2";
4:s:="i486 SL";
5:s:="ISX2";
7:s:="IDX2 WB";
8:if typ=0 then s:="IIDX4" else s:="IDX4 OVERDRIVE";
9:s:="AMD DX4";
14:s:="Am5x86 в режиме WT";
15:s:="Am5x86 в режиме WB";
else unknown:=true end;
5: if vend="GENUINEINTEL" then case model of
1:if typ=0 then s:="Pentium (60,66)" else s:="Pentium OVERDRIVE (60,66)";
2:if typ=0 then s:="Pentium (75..200)" else s:="Pentium OVERDRIVE (75..133)";
else begin write(" Дескриптор: ",hex(data_cach[i,j]));
s:="" end end;
writeln(" ",s);
end end end;
if (feature shr 18) and 10 then begin asm db 66h,0b8h { MOV EAX,3 } dd 3 { CPUID с параметром 3: определение } db 0fh,0a2h { серийного номера микропроцессора } db 66h { В sn_2 - средние 32 разряда } mov word ptr sn_2,dx { серийного номера МП } db 66h { В sn_1 - младшие 32 разряда } mov word ptr sn_1,cx { серийного номера МП } end;
procedure exc_03;assembler; { Обработчик исключения 3: } asm { по команде INT 3 } mov excep,3 int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
@1:db 9ah dw offset reset dw code_sel2 end;
procedure exc_04;assembler; { Обработчик исключения 4: } asm { по команде INTO при OF=1 } mov excep,4 int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
@1:db 9ah dw offset reset dw code_sel2 end;
procedure exc_05;assembler; { Обработчик исключения 5: } asm { выход за пределы диапазона } mov excep,5 { при выполнении команды BOUND } int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
@1:db 9ah dw offset reset dw code_sel2 end;
procedure exc_06;assembler; { Обработчик исключения 6: } asm { неверный код операции } mov excep,6 { или адресации } int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
@1:db 9ah dw offset reset dw code_sel2 end;
procedure exc_07;assembler; { Обработчик исключения 7: } asm { недоступно устройство FPU } mov excep,7 int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
procedure exc_12;assembler; { Обработчик исключения 12: } asm { ошибка доступа к сегменту стека } mov excep,12 int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
@1:db 9ah dw offset reset dw code_sel2 end;
procedure exc_13;assembler; { Обработчик исключения 13: } asm { нарушение общей защиты } mov excep,13 int 32h cmp cpu_type,2 jz @1 db 0ffh,2eh dw ofs_ret_mov
{----------поступающих на 1-й контроллер прерываний-----------} procedure PIC_1;assembler;
asm push ax mov al,$20 out $20,al { Сброс бита регистра ISR 1-го ПКП } pop ax cmp cpu_type,2 { Если 80286 - разрядность 16, } je @7 { иначе - 32 } db 66h
{----------поступающих на 2-й контроллер прерываний-----------} procedure PIC_2;assembler;
asm push ax mov al,$20 { Сброс бита регистра ISR } out $20,al { 1-го и } out $a0,al { и 2-го контроллеров прерываний } pop ax cmp cpu_type,2 je @8 db 66h
@8:iret end;
procedure keyb;assembler; { Обработчик прерываний } asm { от клавиатуры: } mov al,20h out 20h,al in al,60h { Чтение скан-кода нажатия/отжатия клавиши } test al,$80 jnz @k1 { Переход, если клавиша отжата } mov scan,al
@k1:cmp cpu_type,2 je @k2 db 66h
@k2:iret end;
procedure int_30h;assembler; { Обработчик программного } asm { прерывания 30h: } cmp ah,2 { AH - номер функции } jz @i2 { Al - номер подфункции } cmp ah,3 { BL - номер строки экрана } jz @i3 { BH - номер столбца экрана } cmp ah,4 { DL/DX/EDX - значение данных } jz @i4 { (байта/слова/двойного слова) } cmp ah,5 { CL - видеоатрибут } jz @i5 { SI - смещение строки символов }
{ Функция 1: установка маркера в заданную точку экрана } mov ax,bx xor bh,bh mov bl,ah xor ah,ah mov dl,80 mul dl add ax,bx shl ax,1 mov di,ax jmp @end
@i2: { Функция 2: вывод символа на экран } mov al,dl mov ah,cl stosw jmp @end
@i3: { Функция 3: вывод данных на экран в 16-ричной форме }
@2:push cx push cx shl cx,3 sub cx,2 add di,cx { di cx*8-2 } pop cx
@lp_1:push cx xor ah,8 mov cx,4
@lp_2:mov al,dl and al,01h db 66h shr dx,1 xlat stosw sub di,4 loop @lp_2 pop cx loop @lp_1 pop cx shl cx,3 add cx,2 { di cx*8 2 } add di,cx
@end: iret end;
{------------------Вывод номера исключения--------------------} procedure int_32h;assembler;
asm mov ah,1 { Функция 1: установка маркера на экране } mov bl,22 { с координатами - строка 22, } mov bh,1 { столбец 1 } int 30h mov ah,4 { Функция 4: вывод на экран } mov si, offset s2 { строки символов s2 } mov cl,1ah { видеоатрибут } int 30h mov ax,300h { Функция 3, подфункция 0: } mov dl,excep { вывод на экран номера исключения } mov cl,1ch { видеоатрибут } int 30h db 66h iret end;
end.
(*16. а) Исключение, вызванное запретом чтения из сегмента кода б) Разработать обработчик прерывания от системного таймера, который каждые 5 секунд меняет цвет бордюра.
I. Вызвать требуемое в индивидуальном задании исключение.
II. Обработать это исключение одним из двух способов: а) устранив причину исключения;
б) пропустив команду, вызвавшую исключение.
III. Обработать заданное внешнее прерывание.*) program p_intr;
{ Обработка прерываний в защищенном режиме } uses crt, prot; { Модуль PROT содержит константы, }
{ типы переменных, переменные, процедуры и функции }
{ для работы в защищенном режиме } label ret_r; { Точка возврата в реальный режим } const s:string="Обработка исключений и прерываний в защищенном режиме";
s1:string="CS SS DS ES CR0 EFLAGS: ";
s2:string="Обработано исключение ";
s3:string="Na 5 tik timera menyaem cvet BORDURA.";
s4:string="Press Esc to exit";
var cs_real, { Значение регистра CS в реальном режиме } err, { Код ошибки } lim1,lim2,count:word;
scan,i,al_,ah_,n_exc,row:byte;
sscan:byte;
eflags:longint;
quel,counter,color:byte;
dwd:word;
{--------------Разработка обработчиков исключений--------------} procedure out_exc;assembler; { Вывод номера исключения } asm mov ah,1 { Функция 1: установка маркера на экране } mov bl,22 { с координатами - строка 22, } mov bh,1 { столбец 1 } int 30h mov ah,4 { Функция 4: вывод на экран } mov si, offset s2 { строки символов s2 } mov cl,1eh int 30h mov ax,300h { Функция 3, подфункция 0: } mov dl,excep { вывод на экран номера исключения } mov cl,1ch int 30h mov dx,dwd ret end;
{-----Два варианта устранения зацикливания обработки отказа----} mov bl,1 { Вариант 1: устранение причины отказа } pusha
(* push bp { Вариант 2: изменение в стеке значения } mov bp,sp { счетчика команд IP на величину длины команды } inc word ptr [bp 2] pop bp *) mov excep,0 call out_exc; { Вывод сообщения об обработке исключения } popa cmp cpu_type,2 jz @2 db 66h
{ вызывается при отсутствии сегмента в памяти и выполняет }
{ коррекцию дескриптора сегмента - востанавливает бит P } asm mov excep,0bh cmp cpu_type,2 jz @1 db 66h
@1:pop bx { Чтение из стека кода ошибки } mov err,bx { и запись в переменную err } and bx,not 7 { Выделение смещения селектора } add bx,offset gdt 5 { Выбор поля байта доступа в GDT } push ax mov al, [bx] { Чтение байта доступа сегмента } or al,80h mov [bx],al { Установка бита P=1 в байте доступа } pop ax cmp cpu_type,2 jz @2 db 66h
@2:iret end;
procedure keyb;assembler; { Обработчик прерываний } asm { от клавиатуры: } mov al,20h out 20h,al { Сброс контроллера прерываний } in al,60h { Чтение скан-кода нажатия/отжатия клавиши } test al,80h jnz @1 { Переход, если клавиша отжата } mov scan,al
@1:cmp cpu_type,2 jz @3 db 66h
@3:iret end;
procedure ttim;assembler; { Обработчик прерываний } asm { от timer: } push ax mov al,$20 out $20,al { Сброс бита регистра ISR 1-го ПКП } pop ax inc counter cmp counter,5 jnz @99 mov counter,0 push dx push ax mov dx,3dah in al,dx mov dx,3c0h mov al,11h out dx,al inc color mov al,color out dx,al mov al,20h out dx,al pop dx pop ax
@99:cmp cpu_type,2 { Если 80286 - разрядность 16, } jz @l1 { иначе - 32 } db 66h
@l1:iret end;
begin clrscr;
{------Определение значения сегмента кода cs1 процедур,-----}
{------------------описанных в модуле PROT------------------} cs1:=Seg(int_30h);
excep:=$ff; { Отличное от FFH значение переменной excep }
{ означает номер возникшего при работе программы исключения } sscan:=0; { Клавиша не нажата } res:=0; { МП сброшен не был }
{-----------Определение типа микропроцессора----------------} get_cpu_type(0,cpu_type); { В cpu_type - номер типа МП } if cpu_type=2 then t:=0 { 16-разрядный МП } else t:=8; { 32-разрядный МП }
{ Формирование байта доступа прерывания: } acc_int:=present OR type_int OR t;
{ Формирование байта доступа ловушки: } acc_trap:=present OR type_trap OR t;