Аппаратное обеспечение персонального компьютера© Александр Фролов, Григорий ФроловТом 33, М.: Диалог-МИФИ, 1997, 304 стр. Определение типа центрального процессораВ некоторых случаях эффективность работы программы можно заметно повысить, если использовать команды новых моделей процессоров 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:
Слово сигнатуры состоит из отдельных полей, назначение которых будет описано ниже. Биты 12 и 13 определяют тип процессора:
Заметим, что многопроцессорные системы могут быть построены не только на базе процессоров типа Dual, но и на обычных процессорах. Ниже мы привели таблицу, с помощью которой по содержимому трех полей слова сигнатуры (тип процессора, код семейства и код модели) можно распознать процессор:
Что же касается кода модификации модели (stepping), то он определяет изменения в процессоре. Вы найдете описания этих кодов для процессора Pentium в руководстве Pentium Processor Specification Update, который можно приобрести в фирме Intel. Приведем описание битов, возвращаемых командой CPUID в регистре EDX. Напомним, что это слово состоит из отдельных флагов, характеризующих возможности процессора (feature flags).
Еще одно применение для команды 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 <stdio.h> #include <conio.h> #include <stdlib.h> #include <memory.h> 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; } |