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