Смекни!
smekni.com

Робота в захищеному режимі мікропроцесора (стр. 2 из 5)

idtr_r.base:=0; { базовый адрес таблицы векторов }

end;{init_idtr_r}

{-------------Формирование данных для возврата----------------}

{-------------в реальлный режим после сброса МП---------------}

procedure save_ret_real;

begin

{-------------Сохранение значений регистров маски-------------}

{-------------1-го и 2-го контроллеров прерываний-------------}

rm1:=port[$21];

rm2:=port[$a1];

{---------Занесение в ячейки 40h:67h и 40h:69h адреса---------}

{------(смещение и сегмент) точки возврата в реальный режим---}

{-------------------после сброса МП---------------------------}

memw[$40:$67]:=ofs;

memw[$40:$69]:=seg;

{--------Занесение в ячейку КМОП памяти с адресом 0Fh---------}

{-----------байта состояния отключения (byte_shut).-----------}

{-------Значение Ah этого байта обеспечивает при сбросе МП----}

{---------переход по адресу в ячейках 40h:67h и 40h:69h;------}

{----код 5 помимо этого осуществляет также инициализацию------}

{----------------контроллеров прерываний----------------------}

port[$70]:=$0f;

port[$71]:=byte_shut;

end;{save_ret_real}

{----------------Запрет аппаратных прерываний-----------------}

procedure not_int;

begin

asm cli end; { маскируемых }

port[$70]:=$80; { и немаскируемых }

end; {not_int}

{---------------Разрешение аппаратных прерываний--------------}

procedure en_int;

begin

asm sti end; { маскируемых }

port[$70]:=$d; { и немаскируемых }

mem[$40:$17]:=0 { Сброс состояния клавиш-переключателей }

end; {en_int}

{------------------Установка режима "Unreal"------------------}

procedure set_unr(base,limit:longint;kseg,byte_6h:byte);

begin

{ Формирование таблицы GDT: }

init_gdt(0,0,0,0,0); { нуль-дескриптор }

init_gdt(1,limit,base,$92,$80); { дескриптор сегмента }

init_gdtr; { Создание данных и загрузка регистра GDTR }

not_int;{ Запрет маскируемых и немаскируемых прерываний }

asm { Переход в защищенный режим: }

db $0f,$20,0c0h { MOV EAX,CR0 }

db 66h,0dh { OR EAX,1 }

dd 1h

db $0f,22h,0c0h { MOV CR0,EAX }

{ Загрузка селектора заданного сегмента (kseg): }

mov ax,8

cmp kseg,0

jnz @3

db 8eh,0c0h { MOV ES,AX }

jmp @k

@3: cmp kseg,3

db 8eh,0d8h { MOV DS,AX }

jmp @k

@4: cmp kseg,4

jnz @5

db 8eh,0e0h { MOV FS,AX }

jmp @k

@5:db 8eh,0e8h { MOV GS,AX }

{ Возврат в реальный режим: }

@k:db 0fh,20h,0c0h { MOV EAX,CR0 }

db 66h,25h { AND EAX,FFFFFFFEh }

dd 0fffffffeh

db 0fh,22h,0c0h { MOV CR0,EAX }

end;

en_int

end;

{------------Программирование ведущего и ведомого-------------}

{-------------контроллеров прерываний для работы-------------}

{------в реальном (mode=0) и защищенном (mode=1) режимах------}

procedure pic(mode:byte);

var k1,k2:byte;

begin

if mode=0 then begin

k1:=8; k2:=$70

end else begin

k1:=$20; k2:=$28

end;

port[$20]:=$11; { 1-й ПКП: ICW1 }

port[$21]:=k1; { 1-й ПКП: ICW2 }

port[$21]:=4; { 1-й ПКП: ICW3 }

port[$21]:=1; { 1-й ПКП: ICW4 }

port[$a0]:=$11; { 2-й ПКП: ICW1 }

port[$a1]:=k2; { 2-й ПКП: ICW2 }

port[$a1]:=2; { 2-й ПКП: ICW3 }

port[$a1]:=1; { 2-й ПКП: ICW4 }

end;{pic}

{----------Сохранение значений сегментных регистров-----------}

procedure save_sreg;

begin

memw[0:4*$60]:=Dseg; { DS, }

real_ss:=Sseg; { SS и }

asm mov real_es,es end { ES }

end;{save_sreg}

{-------------Возврат в реальный режим по команде-------------}

{--------контроллера клавиатуры, выполняющей сброс МП---------}

procedure reset;assembler;

asm

mov res,1 { Установка признака сброса МП }

mov al,0feh { Команда сброса }

out 64h,al { микропроцессора }

@wait_res: { Ожидание во время сброса МП }

hlt

jmp @wait_res

db 0cbh { Межсегментный возврат }

end; {reset}

{---Проверка сохранения запрета записи в сегмент кода после---}

{------возврата МП из защищенного режима по команде MOV:------}

{-----если запрет сохранен - вырабатывается прерывание 13,----}

{-----обработчик которого (процедура reset) сбрасывает МП-----}

procedure test_wr;

begin

Meml[0:13*4]:=Longint(@reset); { Занесение адреса }

{ обработчика прерывания 13 - процедуры reset }

{ в область векторов }

asm

(* db 2eh { CS: }*)

mov ax,cs:[0]

(* 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, { Данные об особенностях МП (регiстр EDX) }

ECX_:longint; { Данные об особенностях МП (регiстр 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 { В EСX_- особенности МП }

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

3:s:='Pentium OverDrive для 486';

4:if typ=0 then s:='Pentium MMX (166,200)'

else s:='Pentium MMX OverDrive (75..133)';

end else if vend='AuthenticAMD' then

case model of

0:s:='AMD-K-PR75,90,100';

1:s:='AMD-K-PR120,133';

2:s:='AMD-K-PR120,166';

end;

6: case model of

1:s:='Pentium Pro';

3:if typ=0 then s:='Pentium II модель 3'

else s:='Pentium II OverDrive';

5:case desc_L2 of

$41:s:='Celeron модель 5';

$43:s:='Pentium II модель 5';

$44:s:='Pentium II Xeon модель 5';

end;

6:s:='Celeron модель 6';

7:case desc_L2 of

$43: s:='Pentium III модель 7';

$44,$45:s:='Pentium III Xeon модель 7';

end;

8:case brand of

1:s:='Celeron модель 8';

2:s:='Pentium III модель 8';

3: if sn_3=$6B1 then s:='Celeron модель 8'

else s:='Pentium III Xeon модель 8';

4: s:='Pentium III модель 8';

6: s:='Мобильный Pentium III-M модель 8';

7: s:='Мобильный Celeron модель 8';

end;

$A:s:='Pentium III Xeon модель A';

$B:s:='Pentium III Xeon модель B';

else unknown:=true

end;

$F:case model of

0: begin

s:='0.18-микронный ';

case brand of

8: s:=s+'Pentium 4';

9: s:=s+'Pentium 4';

$B: s:=s+'Xeon';

end;

end;

1: begin

s:='0.18-микронный ';

case brand of

8: s :=s+'Pentium 4';