[Назад] [Содеожание] [Дальше]

Аппаратное обеспечение персонального компьютера

© Александр Фролов, Григорий Фролов
Том 33, М.: Диалог-МИФИ, 1997, 304 стр.

1 Определение конфигурации компьютера

  • Определение конфигурации с помощью BIOS
  • Код модели компьютера и версия BIOS
  • Конфигурация в памяти CMOS
  • Определение типа центрального процессора
  • Если ваша программа работает с устройствами компьютера на низком уровне или использует какие-либо аппаратные особенности периферии, она должна «уметь» определять конфигурацию аппаратных средств. В настоящее время выпускается много различных моделей персональных компьютеров и серверных платформ с процессором Intel, совместимых или не очень с оригинальным компьютером IBM PC/AT. В компьютере могут быть установлены процессоры различных моделей и различные версии BIOS. Что же касается номенклатуры периферийных устройств, таких как сетевые контроллеры, видеоадаптеры, сетевые и звуковые адаптеры, то она практически безгранична.

    Для наиболее распространенных моделей персональных компьютеров конфигурация аппаратных средств задается установкой перемычек на системной плате (motherboard) и платах контроллеров периферийных устройств, а также записывается в область данных BIOS и в энергонезависимую память CMOS специальной программой BIOS Setup.

    В следующем разделе мы рассмотрим средства BIOS, позволяющие определить конфигурацию компьютера. Об энергонезависимой памяти CMOS мы расскажем позже.

    Определение конфигурации с помощью BIOS

    Во время инициализации системы BIOS опрашивает порты, к которым подключены перемычки, и определяет содержимое ячеек памяти CMOS, содержащие информацию о конфигурации компьютера. Результат записывается в область данных BIOS, откуда программа может его извлечь с помощью прерываний BIOS.

    Сведения о наличии основных устройств компьютера записывается в область данных BIOS с адресом 0000:0410 размером в двухбайтовое слово - слово конфигурации. С помощью прерывания INT 11h программа может получить в регистре AX слово конфигурации из указанной выше области данных BIOS.

    Биты регистра AX

    Содержимое

    0

    В системе установлен накопитель на магнитном диске (НМД)

    1

    В системе установлен арифметический сопроцессор

    2 – 3 (все модели, кроме IBM PS/2)

    Количество банков оперативной памяти на системной плате. Для компьютера IBM PC размер одного банка равен 16 Кбайт, для IBM PC/XT – 64 Кбайт. Для определения объема оперативной памяти в более современных компьютерах следует использовать другие средства, о которых мы расскажем позже

    2 (IBM PS/2)

    Компьютер IBM PS/2 оборудован мышью

    3 (IBM PS/2)

    Не используется в IBM PS/2

    4 – 5

    Начальный режим видеоадаптера:

    00 – EGA или VGA

    01 – цветной, 40x25

    10 – цветной, 80x25

    11 – монохромный, 80x25

    6 – 7

    Количество установленных накопителей на гибких магнитных дисках (НГМД)

    8

    Установлен контроллер прямого доступа к памяти DMA

    9 – 11

    Количество установленных асинхронных последовательных портов

    12

    Установлен игровой порт

    13

    Установлен последовательный порт (только для компьютера PCjr)

    14 – 15

    Количество установленных параллельных адаптеров

    Наличие НМД

    Сейчас уже трудно найти компьютер, в котором не было бы жесткого диска (разве лишь вам встретится бездисковая рабочая станция для локальной сети или сетевой компьютер для 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 байт идентификатора модели компьютера. Ниже мы привели возможные значения этого байта:

    Байт

    Модель компьютера

    PRIVATEFF

    IBM PC

    FE

    IBM XT, Portable PC

    FD

    PCjr

    FC

    IBM PC/AT

    FB

    IBM XT с памятью 640 Кбайт на системной плате

    FA

    IBM PS/2 модель 25 или 30

    F9

    Convertible PC

    F8

    IBM PS/2 модели 55SX, 70, 80

    9A

    Compaq XT, Compaq Plus

    30

    Sperry PC

    2D

    Compaq PC

    Более подробную информацию можно получить, вызвав функцию C0h прерывания BIOS INT 15h:

    Регистры на входе:

    AH = C0h

    Регистры на выходе:

    ES:BX = адрес таблицы конфигурации, которая находится в ПЗУ BIOS;

    CF = 0 при успешном вызове прерывания;

    CF = 1 если в данной версии BIOS функция C0h не реализована

    После выполнения прерывания регистры ES:BX будут указывать на таблицу в области ПЗУ BIOS. В этой таблице имеется более точная информация о типе компьютера, номер версии BIOS, сведения об аппаратных особенностях конкретной модели.

    Приведем формат указанной таблицы:

    Смещение

    Размер, байт

    Описание

    0

    2

    Размер таблицы в байтах

    2

    1

    Код модели

    3

    1

    Дополнительный код модели

    4

    1

    Модификация версии BIOS

    5

    1

    Байт конфигурации аппаратных средств

    6

    2

    Зарезервировано и равно 0

    8

    2

    Зарезервировано и равно 0

    Ниже мы привели описание отдельных бит байта конфигурации аппаратных средств.

    Номер бита

    Описание

    0

    Зарезервирован

    1

    Если этот бит установлен в 1, то используется системная шина Micro Channel, в противном случае – шина ISA

    2

    Применяется расширенная область данных BIOS

    3

    В BIOS реализована функция ожидания внешнего события

    4

    Каждый раз после вызова прерывания от клавиатуры INT 9h вызывается функция 4Fh прерывания INT 15h

    5

    Установлены часы реального времени

    6

    Установлен второй контроллер прерываний 8259

    7

    Канал DMA номер 3 используется BIOS для работы с диском

    В следующей таблице приведены коды моделей, дополнительные коды моделей и версии BIOS для некоторых известных типов компьютеров:

    Код модели

    Доп. код модели

    Модификация версии BIOS

    Тип компьютера

    FFh

    -

    -

    Оригинальная версия IBM PC

    FEh

    -

    -

    IBM PC/XT

    FDh

    -

    -

    PCjr

    FCh

    00h

    01h

    IBM PC/AT, модель 239

    FCh

    01h

    00h

    IBM PC/AT

    FCh

    02h

    00h

    IBM PC/XT-286

    FCh

    04h

    00h

    IBM PS/2 модель 50

    FCh

    05h

    00h

    IBM PS/2 модель 60

    FBh

    00h

    01h

    IBM PC/XT

    FBh

    00h

    02h

    IBM PC/XT

    FAh

    00h

    00h

    IBM PS/2 модель 30

    FAh

    00h

    01h

    IBM PS/2 модель 30

    FAh

    01h

    00h

    IBM PS/2 модель 25

    F9h

    00h

    00h

    PC Convertible

    F8h

    00h

    00h

    IBM PS/2 модель 80 с тактовой частотой 16 Мгц

    F8h

    01h

    00h

    IBM PS/2 модель 80 с тактовой частотой 20 Мгц

    F8h

    04h

    02h, 03h

    IBM PS/2 модель 70

    F8h

    09h

    02h, 03h

    IBM PS/2 модель 70

    F8h

    0Ch

    00h

    IBM PS/2 модель 55 SX

    F8h

    1Bhh

    00h

    IBM PS/2 модель 70-486

    9Ah

    -

    -

    Compaq XT или Compaq Plus

    30h

    -

    -

    Sperry PC

    2Dh

    -

    -

    Compaq PC или Compaq Deskpro

    Символ "-" в приведенной выше таблице означает, что функция 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
    
    

    Исходный текст программы представлен в листинге 1.2.

    Листинг 1.2. Файл biosinfo\biosinfo.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 <dos.h> // Структура области данных с информацией о BIOS typedef struct _BIOSINFO { int nSize; // размер структуры unsigned char bModel; // код модели компьютера unsigned char bSubModel; // дополнительный код модели unsigned char bBIOSRevision; // номер изменений // версии BIOS unsigned char bHardwareCfg; // конфигурация аппаратуры int reserved1; // зарезервировано int reserved2; // зарезервировано } BIOSINFO; int main(void) { union REGS rg; struct SREGS srg; int i; BIOSINFO far *lpbi; void far* lp; unsigned char bHdwCfg; printf("\nBIOSINFO (C)A. Frolov, 1997"); // Конструируем указатель на дату изготовления // BIOS. Эта дата записана в ПЗУ по адресу F000h:FFF5h _FP_SEG(lp) = 0xf000; _FP_OFF(lp) = 0xfff5; // Выводим дату на экран printf("\n\nBIOS data: "); for(i=0; i<8; i++) putch(*((char far *)lp + i)); // Вызываем функцию C0h для получения адреса // таблицы конфигурации компьютера. rg.h.ah = 0xc0; int86x(0x15, &rg, &rg, &srg); // Если в BIOS нет данной функции, // читаем код модели компьютера // из ПЗУ по адресу F000h:FFFEh if(rg.x.cflag == 1) { printf("\nFunction C0h INT 15h not supported\n"); // Конструируем указатель на код модели _FP_SEG(lp) = 0xf000; _FP_OFF(lp) = 0xfffe; // Выводим код модели компьютера на экран printf("\nModel: %02.2X", (unsigned char)(*(char far *)lp)); return(-1); } // Конструируем укзатель на таблицу // информации о BIOS _FP_SEG(lpbi) = srg.es; _FP_OFF(lpbi) = rg.x.bx; // Выводим на экран содержимое таблицы printf("\nBIOSINFO address: %Fp" "\nBIOSINFO Size: %d" "\nModel: %02.2X" "\nSubModel: %d" "\nBIOS Revision: %d" "\nHardvare Cfg: %02.2X" "\nReserved1: %02.2X" "\nReserved2: %02.2X", lpbi, lpbi->nSize, lpbi->bModel, lpbi->bSubModel, lpbi->bBIOSRevision, lpbi->bHardwareCfg, lpbi->reserved1, lpbi->reserved2); // Определяем конфигурацию компьютера printf("\n\nHardware configuration" "\n----------------------"); // Запоминаем байт конфигурации bHdwCfg = lpbi->bHardwareCfg; // Расшифровываем байт конфигурации if(bHdwCfg & 0x80) printf("\nDMA Channel 3"); if(bHdwCfg & 0x40) printf("\nSecond IRQ Controller 8259"); if(bHdwCfg & 0x20) printf("\nReal Time Clock"); if(bHdwCfg & 0x10) printf("\nUsed function 4Fh INT 15h"); if(bHdwCfg & 0x8) printf("\nBIOS event wait supported"); if(bHdwCfg & 0x4) printf("\nExtended BIOS data used"); if(bHdwCfg & 0x2) printf("\nMicro Channel Bus"); if(!(bHdwCfg & 0x2)) printf("\nISA Bus installed\n"); getch(); return 0; }

    Конфигурация в памяти 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 хранится текущее время и дата, сведения о конфигурации системы, результат тестирования при включении питания и другая информация, приведенная ниже:

    Адрес ячейки

    Содержимое

    00h - 0Dh

    Используются часами реального времени

    0Eh

    Байт состояния диагностики при включении питания

    0Fh

    Байт состояния отключения

    10h

    Тип НГМД

    11h

    Зарезервировано

    12h

    Тип НМД (если меньше 15)

    13h

    Зарезервировано

    14h

    Конфигурация оборудования

    15h - 16h

    Объем основной памяти

    17h - 18h

    Объем расширенной памяти

    19h

    Тип первого НМД (если он больше 15)

    1Ah

    Тип второго НМД (если он больше 15)

    1Bh - 20h

    Зарезервировано

    21h - 2Dh

    Зарезервировано

    2Eh - 2Fh

    Контрольная сумма ячеек 10h - 20h

    30h - 31h

    Объем расширенной памяти

    32h

    Текущее столетие в двоично-десятичном коде (19h для 19-го столетия)

    33h

    Различная информация

    34h - 3Fh

    Зарезервировано

    Рассмотрим подробно назначение отдельных ячеек CMOS-памяти.

    00h - 0Dh - область часов реального времени

    Ячейки с адресами 00h - 0Dh используются часами реального времени. Часам реального времени будет посвящена отдельная глава, поэтому сейчас мы не станем останавливаться на этих ячейках.

    0Eh - байт диагностики

    Байт диагностики (расположенный в памяти CMOS по адресу 0Eh) содержит результаты выполнения диагностики при включении питания компьютера. Выполнив анализ содержимого байта 0Eh, программа может выявить неисправность НМД, часов реального времени, разрядку аккумулятора и ошибки в конфигурации. Приведем формат этого байта:

    Бит

    Описание

    0-1

    Не используется, равно 0

    2

    0 - неправильная установка часов реального времени;

    1 - часы реального времени установлены правильно

    3

    0 - НМД исправен;

    1 - неисправность НМД, невозможно загрузить операционную систему с жесткого диска

    4

    0 - размер оперативной памяти указан правильно;

    1 - фактический размер оперативной памяти не соответствует указанному в памяти CMOS

    5

    0 - конфигурация указана правильно;

    1 – ошибка в конфигурации системы, фактическая конфигурация не соответствует указанной в байте конфигурации оборудования (ячейка 14h)

    6

    0 - контрольная сумма памяти CMOS правильная;

    1 - ошибка в контрольной сумме памяти CMOS

    7

    0 – аккумулятор, питающий память CMOS, исправен и заряжен;

    1 - разрядка аккумулятора выше нормы

    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 причину отключения:

    Значение

    Причина отключения

    0

    Программный сброс при помощи комбинации клавиш <Ctrl-Alt-Delete> или неожиданный сброс. Выполняется обычный перезапуск системы, но процедура тестирования при включении питания не запускается

    1

    Сброс после определения объема памяти

    2

    Сброс после тестирования памяти

    3

    Сброс после обнаружения ошибки четности в оперативной памяти

    4

    Сброс с запросом перезагрузки

    5

    После сброса перезапускается контроллер прерываний, затем управление передается по адресу, который находится в области данных BIOS с адресом 0000h:0467h

    6, 7, 8

    Сброс после выполнения проверки работы процессора в защищенном режиме

    9

    Сброс после выполнения копирования блока памяти из основной памяти в расширенную

    0Ah

    После сброса управление немедленно передается по адресу, взятому из области данных BIOS с адресом 0000h:0467h

    Для перевода процессоров 80386, 80486 и Pentium из реального режима в защищенный и обратно можно использовать загрузку специального управляющего регистра CR0 обычной командой MOV. Однако будет работать и метод, основанный на применении команды LMSW и команды отключения.

    Вы можете использовать сведения о команде отключения для организации программного перезапуска системы.

    10h - тип накопителей НГМД

    Младшая и старшая тетрады этого байта описывают, соответственно, второй и первый НГМД:

    Значение

    Емкость НГМД

    0000

    НГМД не установлен

    0001

    360 Кбайт

    0010

    1,2 Мбайт

    0011

    720 Кбайт

    0100

    1.44 Мбайт

    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 - конфигурация оборудования

    В этом байте находится информация о количестве установленных НГМД, о наличии арифметического сопроцессора, а также о типе видеоадаптера, подключенного к системе. Приведем формат байта конфигурации:

    Бит

    Описание

    0

    1 - в системе установлены НГМД;

    0 - НГМД не используются

    1

    1 - установлен арифметический сопроцессор;

    0 - арифметический сопроцессор не установлен

    2-3

    не используются, равны 0

    4-5

    Тип видеоадаптера и видеорежим:

    00 - не используется или EGA;

    01 - CGA, EGA, VGA в режиме 40x25;

    10 - CGA, EGA, VGA в режиме 80x25;

    11 – монохромный видеоадаптер

    6-7

    Количество установленных НГМД, уменьшенное на единицу;

    00 – один НГМД;

    01 – два НГМД;

    10 – три НГМД;

    11 – четыре НГМД

    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:

    Биты

    Описание

    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 <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;
            }
    
    [Назад] [Содеожание] [Дальше]


    Hosted by uCoz