Определение типа центрального процессора
В некоторых случаях эффективность работы программы можно заметно повысить, если использовать команды новых моделей процессоров Pentium, такие как, например, команды MMX. На сервере Intel с адресом http://www.intel.com вы найдете исчерпывающую информацию о том, как распознать различные модели процессоров, созданных этой фирмой. В нашей книге мы рассмотрим упрощенную методику, которая, тем не менее, может быть использована в большинстве случаев.
Модели Intel 8086/8088
Способ распознавания процессоров Intel 8086/8088 основан на том факте, что биты 12-15 регистра FLAGS всегда установлены в единицу.
Прежде всего программа записывает текущее содержимое регистра FLAGS в регистр AX. Для этого используется стек:
pushf
pop ax
Первоначальное содержимое регистра FLAGS сохраняется в регистре CX:
mov cx, ax
Далее программа пытается записать нулевые значения в биты 12-15 регистра FLAGS:
and ax, 0fffh
push ax
popf
Теперь нужно проверить, изменилось ли содержимое указанных битов регистра FLAGS. Для этого новое содержимое регистра FLAGS записывается через стек в регистр AX, а затем, после наложения маски 0f000h, сравнивается со значением 0f000h:
pushf
pop ax
and ax, 0f000h
cmp ax, 0f000h
je is_8086
Если биты 12-15 остались установленными в единичное значение, программа работает на процессоре Intel 8086/8088, если нет – в компьютере установлена более старшая модель процессора.
Модель Intel 80286
В процессоре Intel 80286, когда он работает в реальном режиме адресации, биты 12-15 регистра FLAGS всегда сброшены в нуль, что можно использовать для обнаружения этой модели процессора.
Следующий фрагмент кода пытается записать в эти биты единичное значение:
mov ax, 0f000h
push ax
popf
Затем новое содержимое регистра FLAGS переписывается в регистр AX:
pushf
pop ax
Если содержимое битов 12-15 равно нулю, программа работает на процессоре Intel 80286:
and ax, 0f000h
jz is_80286
В противном случае необходимо продолжить проверку модели процессора.
Модель Intel 80386
Для того чтобы отличить процессор Intel 80386 от процессоров старших моделей, можно попробовать установить в регистре EFLAGS бит 18. Этот бит был впервые определен в процессоре Intel 80486 для сигнализации ошибки выравнивания. Его невозможно установить в процессоре Intel 80386.
В процессе проверки программа вначале получает исходное содержимое регистра EFLAGS, записывая его в регистры EAX и ECX:
pushfd
pop eax
mov ecx, eax
Далее программа инвертирует значение бита 18 и записывает полученный результат в регистр EFLAGS:
xor eax, 40000h
push eax
popfd
На последнем шаге идентификации новое содержимое регистра EFLAGS извлекается и сравнивается со старым:
pushfd
pop eax
xor eax, ecx
jz is_80386
Если бит 18 не изменил своего значения, мы имеем дело с процессором Intel 80386.
Модель Intel 80486
Отличительная особенность процессора Intel 80486 – невозможность изменения состояния бита 21 регистра EFLAGS. Этот бит используется процессорами Intel Pentium и более старшими моделями процессоров Intel для определения возможности вызова команды идентификации процессора CPUID, о которой мы скоро расскажем.
Фрагмент кода, который нужно использовать для обнаружения процессора Intel 80486, аналогичен фрагменту для процессора Intel 80386. Отличие заключается в том, что вместо бита 18 проверяется бит 21:
pushfd
pop eax
mov ecx, eax
xor eax, 200000h
push eax
popfd
pushfd
pop eax
xor eax, ecx
je is_80486
Если же выяснилось, что содержимое бита 21 регистра EFLAGS можно изменять, дальнейшую идентификацию модели процессора следует выполнять с использованием команды CPUID, к описанию которой мы и переходим.
Команда CPUID
В новых процессорах фирмы Intel появилась команда CPUID, специально предназначенная для определения модели процессора. В своей программе, составленной на языке ассемблера, вы можете определить эту команду следующим образом:
CPU_ID MACRO
db 0fh
db 0a2h
ENDM
Как работает команда CPUID?
Перед вызовом этой команды необходимо загрузить в регистр EAX значение, которое определяет выполняемые действия. В первый раз вы должны вызвать команду CPUID, загрузив предварительно в регистр EAX нулевое значение:
mov eax, 00h
CPU_ID
Команда вернет в регистре EAX максимальное значение, которое можно передавать команде CPUID для определения выполняемых действий. Кроме того, в регистрах EBX, ECX и EDX будут находиться байты текстовой строки описания фирмы-изготовителя процессора. Для процессоров Intel это будет строка GenuineIntel.
Следующая последовательность команд перепишет эти байты в буфер _vendor_id_msg в формате, пригодном для вывода на консоль средствами BIOS:
_vendor_id_msg db "............", 0dh, 0ah, "$"
. . .
mov dword ptr _vendor_id_msg, ebx
mov dword ptr _vendor_id_msg[+4], edx
mov dword ptr _vendor_id_msg[+8], ecx
Для определения модели процессора следует вызвать команду CPUID, загрузив предварительно в регистр EAX значение 1:
mov eax, 1
CPU_ID
При этом в регистр EAX будет загружено слово сигнатуры, по которому можно определить модель процессора, а в регистр EDX – слово, состоящее из отдельных флагов, характеризующих возможности процессора (feature flags). Регистры EBX и ECX зарезервированы для моделей процессоров, которые будут разработаны в будущем.
Ниже приведен фрагмент кода, в котором слово сигнатуры и слово возможностей записываются в переменные _cpu_signature и _features_edx для дальнейшего анализа:
_cpu_signature dd 0
_features_edx dd 0
. . .
mov _cpu_signature, eax
mov _features_edx, edx
Рассмотрим формат слова сигнатуры, возвращаемое командой CPUID в регистре EAX:
Биты
|
Описание
|
0-3
|
Код модификации модели (stepping)
|
4-7
|
Код модели
|
8-11
|
Код семейства моделей
|
12-13
|
Тип процессора
|
14-31
|
Зарезервировано
|
Слово сигнатуры состоит из отдельных полей, назначение которых будет описано ниже.
Биты 12 и 13 определяют тип процессора:
Значение битов 12 и 13
|
Тип процессора
|
00
|
Процессор, изготовленный производителем OEM
|
01
|
Процессор OverDrive
|
10
|
Процессор типа Dual, который можно использовать в двухпроцессорных системах
|
11
|
Зарезервировано
|
Заметим, что многопроцессорные системы могут быть построены не только на базе процессоров типа Dual, но и на обычных процессорах.
Ниже мы привели таблицу, с помощью которой по содержимому трех полей слова сигнатуры (тип процессора, код семейства и код модели) можно распознать процессор:
Тип процессора
|
Код семейства
|
Код модели
|
Описание процессора
|
00
|
0100
|
0100
|
Intel 486 SL
|
00
|
0100
|
0111
|
Intel DX2
|
00
|
0100
|
1000
|
Intel DX4
|
00, 01
|
0100
|
1000
|
Intel DX4 OverDrive
|
00
|
0101
|
0001
|
Pentium 60, 66;
Pentium OverDrive для процессоров Pentium 60, 66
|
00
|
0101
|
0010
|
Pentium 75, 90, 100, 120, 133, 150, 166, 200
|
01
|
0101
|
0010
|
Pentium OverDrive для процессоров Pentium 75, 90, 100, 120, 133
|
01
|
0101
|
0011
|
Pentium OverDrive для систем на базе процессора Intel 486
|
00
|
0101
|
0100
|
Pentium 166, 200 с командами MMX
|
01
|
0101
|
0100
|
Зарезервировано. Будет использоваться процессорами Pentium OverDrive для процессоров Pentium 75, 90, 100, 120, 133
|
00
|
0110
|
0001
|
Pentium Pro
|
00
|
0110
|
0011
|
Pentium II
|
00
|
0110
|
0101
|
Зарезервировано для новых процессоров P6
|
01
|
0110
|
0011
|
Зарезервировано для процессоров Pentium OverDrive для процессоров Pentium Pro
|
Что же касается кода модификации модели (stepping), то он определяет изменения в процессоре. Вы найдете описания этих кодов для процессора Pentium в руководстве Pentium Processor Specification Update, который можно приобрести в фирме Intel.
Приведем описание битов, возвращаемых командой CPUID в регистре EDX. Напомним, что это слово состоит из отдельных флагов, характеризующих возможности процессора (feature flags).
Бит
|
Описание
|
0
|
На кристалле процессора имеется арифметический сопроцессор, совместимый по командам с сопроцессором Intel 387
|
1
|
Процессор может работать в режиме виртуального процессора 8086
|
2
|
Процессор может работать с прерываниями ввода/вывода, а также с битом DE регистра CR4
|
3
|
Возможно использование страниц памяти размером 4 Мбайт
|
4
|
В процессоре есть команда RDTSC, которая может работать с битом TSD регистра CR4
|
5
|
Набор регистров процессора, специфический для модели, доступен с помощью команд RDMSR, WRMSR
|
6
|
Возможна физическая адресация памяти с использованием шины с шириной, большей чем 32 разряда
|
7
|
В процессоре реализовано исключение Machine Check (исключение с номером 18). Возможно использование бита MCE регистра CR4
|
8
|
В процессоре реализована команда сравнения и обмена 8 байт данных CMPXCHG8
|
9
|
В процессоре есть локальный APIC
|
10
|
Зарезервировано
|
11
|
В процессоре реализованы команды быстрого вызова системы SYSENTER и SYSEXIT
|
12
|
В процессоре есть регистры Memory Type Range
|
13
|
Доступен глобальный бит в PDE и PTE, а также бит PGE в регистре CR4
|
14
|
Применена архитектура Machine Check Architecture
|
15
|
В процессоре реализованы команды условного перемещения данных CMOVCC и (при установленном бите 0) FCMOVCC и FCOMI
|
16-22
|
Зарезервировано
|
23
|
Применена технология MMX
|
24-31
|
Зарезервировано
|
Еще одно применение для команды CPUID – определение характеристик кэша, установленного в процессоре. Для этого перед вызовом команды CPUID в регистр EAX необходимо загрузить значение 2. Подробное изучение этой возможности выходит за рамки нашей книги. При необходимости вы узнать все подробности о команде CPUID на сервере Intel в сети Internet по указанному нами ранее адресу.
Программа CPUINFO
Программа CPUINFO определяет модель и характеристики процессора, пользуясь только что описанной нами методикой. Полученная информация выводится на консоль в следующем виде (для процессора Pentium Pro):
*CPU Information*, (C) A. Frolov, 1997
CPU model: 5
Vendor ID: GenuineIntel
CPU Signature 00000619
CPU Feature EDX 0000F9FF
CPU type: 0
CPU family: 6
CPU model: 1
CPU stepping: 9
FPU detected
В листинге 1.4 вы найдете исходный текст модуля, составленного на языке ассемблера. В этом модуле определены все функции, необходимые для распознавания процессора и получения его характеристик.
Листинг 1.4. Файл cpuinfo\askcpu.asm
; =====================================================
; Get CPU information
;
; (C) A. Frolov, 1997
;
; E-mail: frolov@glas.apc.org
; WWW: http://www.glasnet.ru/~frolov
; or
; http://www.dials.ccas.ru/frolov
; =====================================================
.model small
CPU_ID MACRO
db 0fh
db 0a2h
ENDM
.stack 100h
.data
public _vendor_id_msg
public _cpu_model
public _cpu_signature
public _features_ecx
public _features_edx
public _features_ebx
public _get_cpu_model
_vendor_id_msg db "............", 0dh, 0ah, "$"
_cpu_model db 0
_cpu_signature dd 0
_features_ecx dd 0
_features_edx dd 0
_features_ebx dd 0
.code
; ============================================
; _get_cpu_model
; ============================================
.8086
_get_cpu_model proc
call cpu_8086
cmp ax, 0
jz try_80286
mov _cpu_model, 0
jmp end_of_detect
try_80286:
call cpu_80286
cmp ax, 0
jz try_80386
mov _cpu_model, 2
jmp end_of_detect
try_80386:
call cpu_80386
cmp ax, 0
jz try_80486
mov _cpu_model, 3
jmp end_of_detect
try_80486:
call cpu_80486
cmp ax, 0
jz Pent_CPU
mov _cpu_model, 4
jmp end_of_detect
Pent_CPU:
mov _cpu_model, 5
.386
pusha
mov eax, 00h
CPU_ID
mov dword ptr _vendor_id_msg, ebx
mov dword ptr _vendor_id_msg[+4], edx
mov dword ptr _vendor_id_msg[+8], ecx
cmp eax, 1
jl end_of_detect
mov eax, 1
CPU_ID
mov _cpu_signature, eax
mov _features_ebx, ebx
mov _features_edx, edx
mov _features_ecx, ecx
popa
end_of_detect:
.8086
ret
_get_cpu_model endp
; ============================================
; cpu_8086
; ============================================
cpu_8086 proc
pushf
pop ax
mov cx, ax
and ax, 0fffh
push ax
popf
pushf
pop ax
and ax, 0f000h
cmp ax, 0f000h
je is_8086
mov ax, 0
ret
is_8086:
mov ax, 1
ret
cpu_8086 endp
; ============================================
; cpu_80286
; ============================================
.286
cpu_80286 proc
mov ax, 0f000h
push ax
popf
pushf
pop ax
and ax, 0f000h
jz is_80286
mov ax, 0
ret
is_80286:
mov ax, 1
ret
cpu_80286 endp
; ============================================
; cpu_80386
; ============================================
.386
cpu_80386 proc
pushfd
pop eax
mov ecx, eax
xor eax, 40000h
push eax
popfd
pushfd
pop eax
xor eax, ecx
jz is_80386
mov ax, 0
ret
is_80386:
push ecx
popfd
mov ax, 1
ret
cpu_80386 endp
; ============================================
; cpu_80486
; ============================================
cpu_80486 proc
pushfd
pop eax
mov ecx, eax
xor eax, 200000h
push eax
popfd
pushfd
pop eax
xor eax, ecx
je is_80486
mov ax, 0
ret
is_80486:
mov ax, 1
ret
cpu_80486 endp
end
Данный файл был оттранслирован при помощи пакетного файла, представленного в листинге 1.5.
Листинг 1.5. Файл cpuinfo\mk.bat
masm /Zi askcpu.asm,,,,
Главный файл программы приведен в листинге 1.6.
Листинг 1.6. Файл cpuinfo\cpuinfo.c
// =====================================================
// Определение типа процессора
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
// =====================================================
#include
#include
#include
#include
extern void GET_CPU_MODEL(void);
extern char VENDOR_ID_MSG[12];
extern char CPU_MODEL;
extern long CPU_SIGNATURE;
extern long FEATURES_ECX;
extern long FEATURES_EDX;
extern long FEATURES_EBX;
int main(void)
{
char buf[128];
printf("*CPU Information*, (C) A. Frolov, 1997\n\n");
GET_CPU_MODEL();
printf("CPU model: %d\n", (unsigned)CPU_MODEL);
if(CPU_MODEL >= 5)
{
memcpy(buf, VENDOR_ID_MSG, 12);
buf[12] = 0;
printf("Vendor ID: %s\n\n", buf);
printf("CPU Signature %08.8X\n", CPU_SIGNATURE);
printf("CPU Feature EDX %08.8X\n\n", FEATURES_EDX);
printf("CPU type: %d\n",
(CPU_SIGNATURE & 0x3000) >> 12);
printf("CPU family: %d\n",
(CPU_SIGNATURE & 0xF00) >> 8);
printf("CPU model: %d\n",
(CPU_SIGNATURE & 0xF0) >> 4);
printf("CPU stepping: %d\n\n", CPU_SIGNATURE & 0xF);
if(FEATURES_EDX & 0x1)
printf("FPU detected\n");
if(FEATURES_EDX & 0x800000)
printf("MMX supported\n");
}
getch();
return 0;
}
|