1 Определение конфигурации компьютераЕсли ваша программа работает с устройствами компьютера на низком уровне или использует какие-либо аппаратные особенности периферии, она должна «уметь» определять конфигурацию аппаратных средств. В настоящее время выпускается много различных моделей персональных компьютеров и серверных платформ с процессором Intel, совместимых или не очень с оригинальным компьютером IBM PC/AT. В компьютере могут быть установлены процессоры различных моделей и различные версии BIOS. Что же касается номенклатуры периферийных устройств, таких как сетевые контроллеры, видеоадаптеры, сетевые и звуковые адаптеры, то она практически безгранична. Для наиболее распространенных моделей персональных компьютеров конфигурация аппаратных средств задается установкой перемычек на системной плате (motherboard) и платах контроллеров периферийных устройств, а также записывается в область данных BIOS и в энергонезависимую память CMOS специальной программой BIOS Setup. В следующем разделе мы рассмотрим средства BIOS, позволяющие определить конфигурацию компьютера. Об энергонезависимой памяти CMOS мы расскажем позже. Определение конфигурации с помощью BIOSВо время инициализации системы BIOS опрашивает порты, к которым подключены перемычки, и определяет содержимое ячеек памяти CMOS, содержащие информацию о конфигурации компьютера. Результат записывается в область данных BIOS, откуда программа может его извлечь с помощью прерываний BIOS. Сведения о наличии основных устройств компьютера записывается в область данных BIOS с адресом 0000:0410 размером в двухбайтовое слово - слово конфигурации. С помощью прерывания INT 11h программа может получить в регистре AX слово конфигурации из указанной выше области данных BIOS.
Наличие НМДСейчас уже трудно найти компьютер, в котором не было бы жесткого диска (разве лишь вам встретится бездисковая рабочая станция для локальной сети или сетевой компьютер для Internet). Тем не менее, анализируя нулевой бит слова конфигурации, полученного в регистре AX от прерывания INT 11h, вы можете определить, оборудован ли данный компьютер жестким диском. Если этот бит установлен в единицу, то оборудован, если нет – жесткий диск отсутствует. Наличие арифметического сопроцессораДо появления процессора i486 арифметический сопроцессор, значительно ускоряющий вычисления с плавающей точкой, был необязательным устройством. На системной плате компьютера для него предусматривалось отдельное гнездо. Процессор i486 выпускался в двух модификациях – с встроенным арифметическим сопроцессором и без сопроцессора. В современных компьютерах на базе процессора Pentium арифметический сопроцессор присутствует всегда и находится в корпусе центрального процессора. Анализируя бит с номером 1 в значении, полученном в регистре AX от прерывания INT 11h, вы можете определить факт наличия в системе арифметического сопроцессора. Если сопроцессор установлен, программа может использовать его для выполнения вычислений. Каким именно образом - вы узнаете из главы нашей книги, посвященной этому устройству. Начальный режим работы видеоадаптераБиты с номерами 4 и 5 слова конфигурации содержат номер начального режима видеоадаптера. В современных компьютерах применяется, как правило, режим с номером 10b - цветной, 80 текстовых строк по 25 символов в каждой строке. Количество установленных НГМДПоле размером два бита с номерами 6 и 7 содержит количество накопителей НГМД, установленных в системе, минус единица. То есть, если в компьютере установлен один НГМД, в этом поле записано нулевое значение, если два – значение 1 и так далее. Современные модели компьютеров обычно оборудуют одним накопителем НГМД, предназначенным для чтения дискет размером 3,5 дюйма. Что же касается дискет размером 5,25 дюйма, то они уже ушли в прошлое. Наличие контроллера прямого доступа DMAКонтроллер прямого доступа DMA применяется для непосредственной передачи данных из периферийных устройств в оперативную память компьютера, минуя центральный процессор. Этот контроллер есть во всех современных компьютерах, поэтому бит с номером 8 обычно установлен в единицу. Количество асинхронных последовательных адаптеровВ поле, образованное битами 9, 10 и 11, хранится количество асинхронных последовательных адаптеров, установленных в системе и обнаруженных BIOS в процессе инициализации. Игровой адаптерЕсли установлен бит с номером 12, к компьютеру подключен игровой адаптер, предназанченный для джойстика. Последовательный порт компьютера PCjrМаловероятно, что вам попадется в руки антикварный образец компьютера PCjr, но, тем не менее, установленный 13 бит слова конфигурации означает, что этот компьютер оборудован последовательным портом. Количество параллельных адаптеровВ поле, образованное битами с номерами 14 и 15, записывается количество параллельных адаптеров, обнаруженных на этапе инициализации. Размер оперативной памятиВ компьютере имеются различные виды оперативной памяти. В первых компьютерах применялся так называемый реальный режим работы процессора, не позволявший адресовать более 1 Мбайт памяти. Начальная область адресов от 0 до 640 Кбайт использовалась для оперативной памяти, а область от 640 Кбайт до 1 Мбайт – для памяти и регистров периферийных устройств, таких как видеоадаптеры и дисковые контроллеры. Раньше оперативная память была очень дорогая, поэтому далеко не в каждом компьютере было установлен максимально возможный объем – 1 Мбайт. Можно было встретить компьютеры с объемом оперативной памяти, например, 512 Кбайт. Программы в те времена, конечно, тоже были не очень требовательны к объему памяти. С появлением операционных систем Microsoft Windows и IBM OS/2 требования к объему памяти, установленной в компьютере, резко возросли. Компания Intel выпустила процессор i80286, способный адресовать в защищенном режиме до 16 Мбайт физической памяти. Теперь память с адресами в пределах первого мегабайта стала называться стандартной, а выше этого предела - расширенной (extended). Размер расширенной памяти определяется во время инициализации компьютера и записывается в память CMOS, откуда ее нетрудно извлечь. Стандартная оперативная памятьПрерывание INT 12h возвращает в регистре AX размер стандартной оперативной памяти в килобайтах. Заметим, что это значение, хранящееся в области данных BIOS с адресом 0040h:0013h, не превышает 640 Кбайт, даже если в компьютере установлено более 64 Мбайт оперативной памяти. Расширенная оперативная памятьФункция 88h прерывания INT 15h позволяет определить размер доступной расширенной памяти в килобайтах, возвращая соответствующее значение в регистре AX. Учтите, что если в системе установлен драйвер расширенной памяти, такой как, например, HIMEM.SYS, указанная выше функция может вернуть нулевое значение. Это происходит из-за того что драйвер берет на себя функции управления расширенной памятью. Заметим также, что с помощью параметра /int15 вы можете указать драйверу HIMEM.SYS размер зарезервированной расширенной памяти, доступной через интерфейс прерывания INT 15h: device=c:\dos\himem.sys /int15=xxxx Программа HDWCFGПрограмма HDWCFG определяет конфигурацию аппаратных средств компьютера, пользуясь для этого описанными выше функциями BIOS. Полученная конфигурация отображается на консоли, как это показано ниже: HDWCFG (C)A. Frolov, 1997 Configuration word: C823 HDD present NPU present RAM banks: 0 Video Mode: 2 Nubber of FDD: 1 Nubber of COM ports: 2 Number of LPT ports: 3 RAM istalled: 640 Kbytes Extended RAM istalled: 0 Исходный текст программы HDWCFG представлен в листинге 1.1. Листинг 1.1. Файл hdwcfg\hdwcfg.c // ===================================================== // Получение информации о конфигурации компьютера // при помощи BIOS // // (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 <memory.h> #include <dos.h> // Битовые поля слова конфигурации typedef struct _HDWCFG { unsigned HddPresent: 1; // 0 unsigned NpuPresent: 1; // 1 unsigned AmountOfRAM: 2; // 2-3 unsigned VideoMode: 2; // 4-5 unsigned NumberOfFdd: 2; // 6-7 unsigned DmaPresent: 1; // 8 unsigned NumberOfCom: 3; // 9-11 unsigned GamePresent: 1; // 12 unsigned JrComPresent: 1; // 13 unsigned NumberOfLpt: 2; // 14-15 } HDWCFG; int main(void) { union REGS rg; HDWCFG HdwCfg; unsigned uword; printf("\nHDWCFG (C)A. Frolov, 1997"); // Вызываем прерывание INT 11h для получения // слова конфигурации компьютера rg.h.ah = 0x0; int86(0x11, &rg, &rg); // Получаем слово конфигурации и сохраняем // его в структуре HdwCfg uword = (unsigned int)rg.x.ax; memcpy(&HdwCfg, &uword, 2); // Выводим на экран конфигурацию компьютера printf("\n\nConfiguration word: %04.4X", HdwCfg); if(HdwCfg.HddPresent) printf("\nHDD present"); if(HdwCfg.NpuPresent) printf("\nNPU present"); printf("\nRAM banks: %d", HdwCfg.AmountOfRAM); printf("\nVideo Mode: %d", HdwCfg.VideoMode); printf("\nNubber of FDD: %d", HdwCfg.NumberOfFdd + 1); if(HdwCfg.DmaPresent) printf("\nDMA present"); printf("\nNubber of COM ports: %d", HdwCfg.NumberOfCom); if(HdwCfg.GamePresent) printf("\nGame adapter present"); if(HdwCfg.JrComPresent) printf("\nPCjr Com present"); printf("\nNumber of LPT ports: %d", HdwCfg.NumberOfLpt); // Вызываем прерывание INT 12h для определения // объема основной оперативной памяти компьютера rg.h.ah = 0x0; int86(0x12, &rg, &rg); // Выводим объем оперативной памяти printf("\nRAM istalled: %d Kbytes", (unsigned int)rg.x.ax); // Получаем объем расширенной оперативной памяти, // доступной через прерывание INT 15h rg.h.ah = 0x88; int86(0x15, &rg, &rg); // Выводим объем расширенной оперативной памяти printf("\nExtended RAM istalled: %ld Kbytes", (unsigned int)rg.x.ax); getch(); return 0; } Код модели компьютера и версия BIOSНа этапе инициализации BIOS записывает в свою область данных по адресу FFFFh:FFFEh байт идентификатора модели компьютера. Ниже мы привели возможные значения этого байта:
Более подробную информацию можно получить, вызвав функцию C0h прерывания BIOS INT 15h:
После выполнения прерывания регистры ES:BX будут указывать на таблицу в области ПЗУ BIOS. В этой таблице имеется более точная информация о типе компьютера, номер версии BIOS, сведения об аппаратных особенностях конкретной модели. Приведем формат указанной таблицы:
Ниже мы привели описание отдельных бит байта конфигурации аппаратных средств.
В следующей таблице приведены коды моделей, дополнительные коды моделей и версии BIOS для некоторых известных типов компьютеров:
Символ "-" в приведенной выше таблице означает, что функция C0h прерывания INT 15h для данной версии BIOS не реализована. Все, что вы можете сделать в этом случае для идентификации BIOS, это получить байт кода модели по адресу F000h:FFFEh и дату изготовления BIOS, занимающую восемь байт начиная с адреса F000h:FFF5h. Дата хранится в формате ASCII. Большинство современных так называемых IBM-совместимых персональных компьютеров имеют код модели FCh, а дополнительный код модели 01h. Такие значения, например, записаны в таблице конфигурации компьютера Compaq Deskpro 6000 с процессором Pentium Pro 200. Программа BIOSINFOПрограмма BIOSINFO получает и отображает на консоли дату изготовления версии BIOS, а также содержимое таблицы конфигурации, адрес которой определяется с помощью функции C0h прерывания BIOS INT 15h: BIOSINFO (C)A. Frolov, 1997 BIOS data: 04/18/97 BIOSINFO address: 0212:0190 BIOSINFO Size: 8 Model: FC SubModel: 1 BIOS Revision: 0 Hardvare Cfg: 70 Reserved1: 00 Reserved2: 00 Hardware configuration ---------------------- Second IRQ Controller 8259 Real Time Clock Used function 4Fh INT 15h ISA Bus installed Конфигурация в памяти CMOSКак мы уже говорили, энергонезависимая память CMOS используется в современных компьютерах для хранения текущей конфигурации аппаратных средств. Эта память состоит из набора ячеек, доступ к которым для чтения и записи выполняется через порты ввода и вывода с адресами 70h и 71h. Процедура чтения ячейки памяти CMOS состоит из двух шагов. На первом шаге программа записывает в выходной порт с адресом 70h номер ячейки, из которой необходимо прочитать информацию. На втором шаге программа читает содержимое данной ячейки из входного порта с адресом 71h: int nCellContent; outp(0x70, nCell); nCellContent = inp(0x71); Запись данных в ячейку памяти CMOS выполняется аналогично, только после записи номера ячейки в порт 70h программа должна записать новое значение для этой ячейки в порт с адресом 71h: outp(0x70, nCell); outp(0x71, nNewValue); В памяти CMOS хранится текущее время и дата, сведения о конфигурации системы, результат тестирования при включении питания и другая информация, приведенная ниже:
Рассмотрим подробно назначение отдельных ячеек CMOS-памяти. 00h - 0Dh - область часов реального времениЯчейки с адресами 00h - 0Dh используются часами реального времени. Часам реального времени будет посвящена отдельная глава, поэтому сейчас мы не станем останавливаться на этих ячейках. 0Eh - байт диагностикиБайт диагностики (расположенный в памяти CMOS по адресу 0Eh) содержит результаты выполнения диагностики при включении питания компьютера. Выполнив анализ содержимого байта 0Eh, программа может выявить неисправность НМД, часов реального времени, разрядку аккумулятора и ошибки в конфигурации. Приведем формат этого байта:
0Fh - байт отключенияБайт отключения 0Fh используется процессорами 80286, 80386, 80486 и Pentium для определения способа возврата из защищенного режима в реальный после аппаратного сброса. Вы, вероятно, знаете, что эти процессоры могут работать либо в реальном режиме, который соответствует режиму работы процессора 8086, либо в защищенном. Защищенный режим работы используется такими операционными системами, как Microsoft Windows, IBM OS/2 и UNIX. В этом режиме процессор может непосредственно адресовать всю память, лежащую выше границы 1 Мбайт. Подробное рассмотрение защищенного режима работы мы привели в 6 томе «Библиотеки системного программиста», который так и называется – «Защищенный режим процессоров Intel 80286/80386/80486». Здесь же мы только кратко расскажем о переходе процессора 80286 из реального режима в защищенный и обратно для иллюстрации использования ячейки памяти CMOS с адресом 0Fh. Для перевода процессора 80286 из реального режима в защищенный можно использовать специальную команду LMSW: mov ax,1 lmsw ax Разумеется, двух строк, приведенных выше, недостаточно для правильной работы процессора в защищенном режиме. Для того, чтобы вернуть процессор 80286 из защищенного режима в реальный, необходимо выполнить аппаратный сброс (отключение) процессора. Это можно сделать следующим образом: mov ax, 0FEh ; команда отключения out 64h, ax Перед выдачей команды отключения программа должна записать в ячейку 0Fh памяти CMOS причину отключения:
Для перевода процессоров 80386, 80486 и Pentium из реального режима в защищенный и обратно можно использовать загрузку специального управляющего регистра CR0 обычной командой MOV. Однако будет работать и метод, основанный на применении команды LMSW и команды отключения. Вы можете использовать сведения о команде отключения для организации программного перезапуска системы. 10h - тип накопителей НГМДМладшая и старшая тетрады этого байта описывают, соответственно, второй и первый НГМД:
11h - зарезервировано для IBM PC/AT, тип НМД для IBM PS/2В компьютерах IBM PS/2 ячейки памяти CMOS с адресами 11h и 12h используются для хранения типа, соответственно, первого и второго НМД. 12h - тип первого и второго НМДЭтот байт разделен на две тетрады аналогично байту, описывающему НГМД. Однако в тетраде можно закодировать только 16 различных значений, а типов НМД значительно больше. Поэтому тип 15 используется специальным образом - если тип НМД в младшей тетраде (первый физический НМД) равен 15, то правильное значение типа находится в памяти CMOS по адресу 19h. Аналогично для второго физического НМД этот тип можно взять из байта по адресу 1Ah (если старшая тетрада байта с адресом 12h равна 15). Таблица стандартных типов НМД была приведена в третьей книге первого тома, в разделе, посвященном конфигурации дисковой подсистемы. Кроме того, сведения о типах дисков, задаваемых программой BIOS Setup, обычно есть в документации, поставляемой вместе с компьютером. В современных компьютерах установлены НМД с интерфейсом IDE или SCSI. В первом случае тип диска устанавливается равным 47. Это означает. Что фактические параметры диска хранятся в старших ячейках памяти CMOS, номера которых зависят от изготовителя и версии BIOS. Тип НМД с интерфейсом SCSI задается как 1 или 0. Фактические параметры НМД определяются BIOS, расположенной в контроллере SCSI. 13h - зарезервированоЭта ячейка памяти CMOS зарезервирована. 14h - конфигурация оборудованияВ этом байте находится информация о количестве установленных НГМД, о наличии арифметического сопроцессора, а также о типе видеоадаптера, подключенного к системе. Приведем формат байта конфигурации:
15h-16h - объем стандартной оперативной памятиЯчейка 15h содержит младший байт, а ячейка 16h - старший байт объема основной памяти, например: · 0100h – 256 Kбайт; · 0200h – 512 Kбайт; · 0280h – 640 Kбайт 17h-18h - объем расширенной памятиЯчейки 17h и 18h содержат, соответственно, младший и старший байты размера расширенной памяти (расположенной выше границы 1 Мбайт) в килобайтах. 19h-1Ah тип первого и второго НМДЭти ячейки содержат типы, соответственно, первого и второго НМД, если соответствующий тип имеет значение, большее 15 (см. описание ячейки 12h). 1Bh-2Dh - зарезервированоЭти ячейки памяти CMOS зарезервированы. 2Eh-2Fh - контрольная сумма ячеек 10h - 20hДля ячеек памяти CMOS с адресами от 10h до 20h при инициализации системы BIOS выполняет проверку контрольной суммы. Эта контрольная сумма хранится также в памяти CMOS в ячейках 2Eh и 2Fh (соответственно, старший и младший байты). 30h-31h - объем расширенной памятиЯчейки 30h и 31h содержат, соответственно, младший и старший байты размера расширенной памяти (расположенной выше границы 1 Мбайт) в килобайтах. Эта значение дублирует значение, записанное в ячейках с адресами 17h-18h. 32h текущее столетиеВ компьютерах IBM PC/AT этот байт содержит текущее столетие в двоично-десятичном коде, то есть 19 столетие записано как 19h. Компьютеры модели IBM PS/2 используют эту ячейку вместе с ячейкой 33h для хранения контрольной суммы ячеек с адресами от 10h до 31h. При этом старший байт контрольной суммы хранится в ячейке 32h, а младший - 33h. 33h - различная информацияВ компьютерах IBM PC/AT этот байт используется программой BIOS Setup для собственных нужд. 34h-3Fh - зарезервированоЭто поле зарезервировано, однако вы можете использовать по своему усмотрению, например, хранить здесь пароль. Другие ячейки памяти CMOSНазначение описанных выше 64 ячеек памяти CMOS документировано и одинаково для BIOS различных изготовителей и различных версий. Тем не менее, есть исключения. BIOS компьютера IBM PS/2 использует ячейку с адресом 37h для хранения номера текущего столетия. Ячейки 38h-3Fh в модели 50 компьютера IBM PS/2 используются для хранения пароля. Обращение к этим ячейкам выполняется по адресам 78h-7Fh, которые аппаратно отображаются на адреса 38h-3Fh. Кроме того, имеются ячейки памяти CMOS с номерами, большими чем 3Fh. Их назначение зависит от изготовителя BIOS, поэтому обращайтесь к ним только в том случае, если у вас есть соответствующая документация. Программа CMOSSHOWПрограмма CMOSSHOW читает в массив первые 64 ячейки памяти CMOS и отображает содержимое некоторых из них: CMOS Show (C)A. Frolov, 1997 RTC: 22 00 30 00 17 00 03 19 08 97 a6 02 00 Diagnostics byte: 08 Shutdown byte: 00 Reserved: 00 00 00 00 00 00 00 00 00 00 00 00 Extended RAM: 16384 Kbyte Отображаются ячейки часов реального времени RTC, о которых мы расскажем позже в отдельной главе, диагностический байт и байт отключения, зарезервированные байты. Кроме того, на основании информации, хранящейся в ячейках 17h и 18h программа вычисляет размер расширенной памяти, установленной в компьютере. Исходный текст программы CMOSSHOW вы найдете в листинге 1.3. Листинг 1.3. Файл cmosshow\cmosshow.c // ===================================================== // Чтение и отображение ячеек памяти CMOS // // (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> int main() { unsigned char cmos[64]; int i; unsigned long nExtRam; printf("\nCMOS Show (C)A. Frolov, 1997\n\n"); // Читаем 64 ячейки CMOS-памяти в массив cmos for(i=0; i<64; i++) { outp(0x70,i); cmos[i]=inp(0x71); } // Отображаем ячейки часов реального времени printf("\nRTC: "); for(i=0; i<0xd; i++) { printf("%02.2x ",(unsigned)cmos[i]); } // Отображаем состояние байта диагностики // после включения питания printf("\nDiagnostics byte: %02.2x",cmos[0xe]); // Отображаем содержимое байта отключения printf("\nShutdown byte: %02.2x\n",cmos[0xf]); // Отображаем содержимое зарезервированных ячеек printf("Reserved: "); for(i=0x34; i<0x40; i++) { printf("%02.2x ",(unsigned)cmos[i]); } // Вычисляем объем расширенной памяти и отображаем // его на консоли nExtRam = ((unsigned long)cmos[0x18] << 8) + cmos[0x17]; printf("\nExtended RAM: %ld Kbyte\n", nExtRam); getch(); return 0; } Определение типа центрального процессораВ некоторых случаях эффективность работы программы можно заметно повысить, если использовать команды новых моделей процессоров 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; } |