Главная ]
9.Приложение
Программирование
Базы данных



Регистр EFLAGS

В этой таблице описан формат регистра флагов для процессоров i80386 и i80486 (регистр флагов процессора i80286 называется FLAGS и представляет собой младшее 16-разрядное слово регистра EFLAGS):

 

Номер бита

Назначение

0 - CF

Флаг переноса

1 - 1

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

2 - PF

Флаг чётности

3 - 0

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

4 - AF

Флаг вспомогательного переноса

5 - 0

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

6 - ZF

Флаг нуля

7 - SF

Флаг знака

8 - TF

Флаг ловушки

9 - IF

Флаг разрешения прерываний

10 - DF

Флаг направления

11 - OF

Флаг переполнения

12-13 - IOPL

Уровень привилегий ввода/вывода

14 - NT

Флаг вложенной задачи

15 - 0

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

16 - RF

Флаг возобновления (только i80386 и i80486)

17 - VM

Флаг режима виртуального процессора 8086 (только i80386 и i80486)

18 - AC

Флаг проверки выравнивания (только i80486)

19-31 - 0

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

     Управляющие регистры процессора i80386

Регистр

Назначение

CR0

Регистр состояния процессора

CR1

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

CR2

Линейный адрес отказа страницы

CR3

Базовый адрес каталога страницы

Формат регистра CR0 процессора i80386

 

Номер бита

Назначение

0 - PE

Включение защищённого режима работы процессора.

1 - MP

Присутствие сопроцессора.

2 - EM

Эмуляция сопроцессора.

3 - TS

Переключение задачи.

4 - ET

Тип сопроцессора - i80287 или i80387.

5-14

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

15 - PG

Включение механизма трансляции страниц

Формат регистра CR0 процессора i80486

Номер бита

Назначение

0 - PE

Включение защищённого режима работы процессора.

1 - MP

Присутствие сопроцессора.

2 - EM

Эмуляция сопроцессора.

3 - TS

Переключение задачи.

4 - ET

Тип сопроцессора - i80287 или i80387.

5 - NE

Числовая ошибка. Разрешает обработку ошибок при операциях с плавающей точкой.

6-15

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

16 - WP

Защита записи. При установке этого бита страницы пользователя защищены от записи в режиме супервизора.

17

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

18 - AM

Бит маски выравнивания. Этот бит разрешает или запрещает контроль выравнивания операндов команд в памяти. Контроль выравнивания разрешён только для программ, работающих в третьем кольце, при условии что установлен бит AM.

19-28

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

29 - NW

Разрешение сквозной записи. Используется в механизме управления кэшированием.

30 - CD

Запрещение кэширования. Если этот бит установлен, внутреннее кэширование запрещено.

31 - PG

Включение механизма трансляции страниц

Формат регистра CR3 процессора i80486

Номер бита

Назначение

0-2

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

3 - PWT

Прозрачность записи на уровне страниц. Используется для управления записью во внешний кэш.

4 - PCD

Запрещение кэширования на уровне страниц. Используется для управления работой внешнего кэша.

5-31 - PBDR  

Базовый регистр каталога страниц

Системные команды процессоров i80286/i80386/i80486

Системные команды предназначены для использования, главным образом, в модулях операционных систем (в модулях ядра операционной системы, в драйверах и т.д.). Некоторые из перечисленных ниже команд полезны и при разработке прикладных программ, работающих в защищённом режиме. Мы приведём только краткий перечень основных системных команд, подробности вы можете узнать из справочных руководств по процессорам (см. список литературы).

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

     ARPL Коррекция поля привилегий инициатора запроса в селекторе

Эта команда используется системными модулями для проверки уровня запрашиваемых привилегий в передаваемых им в качестве параметров селекторов. Прикладная программа не должна запрашивать привилегии, превышающие её собственные.

Первый операнд команды - 16-разрядный регистр или слово памяти, содержащие значение проверяемого селектора. Второй операнд - регистр, в который записано содержимое CS прикладной программы.

Если команда не изменяла уровень привилегий, в регистре FLAGS (EFLAGS для процессоров i80386 и i80486) устанавливается флаг нуля. В противном случае этот флаг сбрасывается.

Пример использования команды:

mov dx, cs
mov ax, TESTED_SELECTOR
arpl dx, ax

CLTS Сброс флага TS переключения задачи в регистре CR0

Каждый раз при переключении задачи флаг TS устанавливается в 1. Команда CLTS позволяет сбросить этот флаг.

LAR Загрузка байта прав доступа

Для процессора i80286 команда LAR загружает в первый операнд (регистр) байт доступа дескриптора, выбираемого вторым операндом. Второй операнд является селектором, указывающим на используемый дескриптор.

В процессорах i80386 и i80486 команда LAR использует в качестве первого операнда 32-разрядный регистр. Кроме байта прав доступа в этот регистр заносятся биты типа сегмента (9-11), DPL (14), бит присутствия (15), бит дробности (23).

LGDT Загрузка регистра GDTR

Команда выполняет инициализацию регистра GDTR, указывающего расположение в памяти и размер глобальной таблицы дескрипторов.

LIDT Загрузка регистра IDTR

Команда выполняет инициализацию регистра IDTR, указывающего расположение в памяти и размер дескрипторной таблицы прерываний.

LLDT Загрузка регистра LDTR

Команда выполняет инициализацию регистра LDTR, указывающего расположение в памяти и размер локальной таблицы дескрипторов.

LMSW Загрузка слова состояния процессора

С помощью этой команды можно выполнить загрузку младшего слова регистра CR0 из регистра - операнда команды.

Эта команда может использоваться для переключения процессора в защищённый режим. Обратного переключения эта команда не обеспечивает (даже для процессоров i80386 и i80486).

LSL Загрузка предела сегмента

Команда имеет два операнда. Граница сегмента, селектор которого используется в качестве второго операнда (задаётся в регистре), загружается в регистр, указанный в качестве первого операнда.

LTR Загрузка регистра задачи

Команда предназначена для загрузки регистра TR - регистра задачи. Загрузка этого регистра не приводит к переключению задачи.

MOV Загрузка системных регистров

Для процессоров i80386 и i80486 в качестве операндов обычной команды MOV допустимо (на нулевом уровне привилегий) указывать системные регистры - CR0, CR2, CR3, DR0, DR1, DR2, DR3, DR6, DR7, TR6, TR7. Команда MOV может быть использована процессорами i80386 и i80486 для возврата процессора из защищённого режима в реальный.

SGDT Запись в память содержимого регистра GDTR

Команда позволяет узнать текущее содержимое регистра глобальной дескрипторной таблицы GDTR, обычное её используют в системных отладчиках.

SIDT Записать в память содержимое регистра IDTR

Команда позволяет узнать текущее содержимое регистра глобальной дескрипторной таблицы прерываний IDTR, используется в системных отладчиках.

SLDT Записать в память содержимое регистра LDTR

Команда позволяет узнать текущее содержимое регистра локальной дескрипторной таблицы LDTR, используется в системных отладчиках.

SMSW Записать слова состояния процессора

Команда записывает в память или 16-битовый регистр младшее слово регистра CR0 и может быть использована в системных отладчиках.

STR Запись регистра задачи

Команда записывает текущее содержимое регистра задачи TR в 16-разрядную ячейку памяти или 16-разрядный регистр. Может использоваться в системных отладчиках.

VERR Проверить сегмент на возможность чтения

VERW Проверить сегмент на возможность записи

С помощью этих двух команд можно проверить доступность выбранного селектором сегмента на чтение и запись, соответственно. Если операция чтения или записи доступна, флаг нуля ZF устанавливается в единицу, в противном случае он сбрасывается в ноль.

Основное назначение этой команды - предотвратить возникновение исключения по защите памяти при попытке обращения к сегменту. Прежде чем выполнять обращение, программа может проверить доступность сегмента и сделать соответствующие выводы.

Недокументированная команда LOADALL

Оказывается, для процессора i80286 существует способ получения доступа к расширенной памяти, не переключаясь в защищённый режим. Для этого может быть использована недокументированная команда LOADALL, имеющая код 0F05h (команда не имеет операндов). Эта команда не описана в справочниках по процессору i80286, информация о ней поставляется фирмой Intel по запросу. Те сведения о команде LOADALL, которые приведены в нашей книге, получены по электронной почте из BBS и могут быть использованы только для расширения вашего кругозора и для оценки полезности этой команды в ваших разработках.

Команда LOADALL первоначально была задумана фирмой Intel как тестовая. Однако оказалось, что она пригодна и для обращения к расширенной памяти в реальном режиме. Широко известный драйвер расширенной памяти HIMEM.SYS обращается в область адресов выше первого мегабайта именно с помощью команды LOADALL (а не переключаясь в защищённый режим и возвращаясь обратно, как это можно было бы предположить).

Команда LOADALL сокращает время, требуемое драйверу HIMEM.SYS на доступ к расширенной памяти, так как время на переключение в защищённый режим и обратное переключение достаточно велико по сравнению с временем, необходимым на копирование данных из основной памяти в расширенную или обратно.

Другое применение команды - драйвер электронного диска Microsoft RAMDRIVE.SYS и блок совместимости операционной системы Microsoft OS/2 версии 1.x.

Секрет команды LOADALL заключается в том, что она загружает ВСЕ регистры процессора, и может выполняться в реальном режиме. Изменяя поле базы регистра кэша дескриптора (внутренний системный регистр процессора) программа может обратиться к сегменту, лежащему за пределами первого мегабайта адресного пространства.

Как мы уже говорили, команда LOADALL не имеет операндов. Регистры загружаются из буфера, который имеет длину 102 байта и должен быть подготовлен в области памяти с физическим адресом 00800h.

Формат буфера представлен в следующей таблице:

 

Таблица 16. Формат буфера для команды LOADALL.

 

Адрес

Регистры процессора

800h-805h

Не используется

806h-807h

Слово состояния процессора MSW (Machine Status Word)

808h-815h

Не используется

816h-817h

Регистр задачи TR (Task Register)

818h-819h

Регистр флагов

81Ah-81Bh

Регистр IP (Instruction Pointer)

81Ch-81Dh

Селектор LDT (Local Descriptor Table)

81Eh-81Fh

Регистр DS (Data Segment Selector)

820h-821h

Регистр SS (Stack Segment Selector)

822h-823h

Регистр CS (Code Segment Selector)

824h-825h

Регистр ES (Extra Segment Selector)

826h-827h

Регистр DI (Destination Index)

818h-829h

Регистр SI (Source Index)

82Ah-82Bh

Регистр BP (Base Pointer)

82Ch-82Dh

Регистр SP (Stack Pointer)

82Eh-82Fh

Регистр BX (Data Register BX)

830h-831h

Регистр DX (Data Register DX)

832h-833h

Регистр CX (Data Register CX)

834h-835h

Регистр AX (Accumulator)

836h-83Bh

Кэш дескриптора ES

83Ch-841h

Кэш дескриптора CS

842h-847h

Кэш дескриптора SS

848h-84Dh

Кеш дескриптора DS

84Eh-853h

Регистр GDTR (Global Descriptor Table Register)

854h-859h

Кэш дескриптора LDT

85Ah-85Fh

Регистр IDTR (Interrupt Descriptor Table Register)

860h-865h

Кэш дескриптора TSS (Task State Segment)

 

Для ускорения доступа к содержимому дескрипторных таблиц в процессоре имеются так называемые теневые регистры или регистры кэша дескрипторов. Когда процессор загружает селектор в сегментный регистр, автоматически выполняется загрузка соответствующего регистра кэша дескриптора. Не существует какого-либо иного способа загрузить кэш дескриптора явно из программы с помощью обычных команд. Однако вы можете воспользоваться для этого командой LOADALL, подготовив в описанном выше буфере необходимые значения.

Формат кэша дескриптора приведён в следующей таблице:

 

Таблица 17. Формат кэша дескриптора.

Смещение поля

Назначение поля

0-2

24-битовый базовый адрес сегмента

3

Байт доступа, его формат полностью аналогичен формату байта доступа дескриптора, за исключением бита присутствия. На месте этого бита находится бит VALID. Если этот бит сброшен в 0, при попытке использовать дескриптор для адресации памяти произойдёт исключение 13 с кодом ошибки 0.

4-5

16-битовый предел сегмента

 

Можно предложить следующий алгоритм использования команды LOADALL:

  • Запретитите прерывания.

  • Сохраните где-нибудь в буфере программы область памяти, начинающуюся с адреса 00800h и имеющую длину 102 байта.

  • Заполните буфер для команды LOADALL необходимыми значениями для всех загружаемых регистров. Базовый адрес в области кэша дескриптора сегмента данных должен указывать на необходимый вам участок расширенной памяти.

  • Выполните команду LOADALL. Сегмент данных теперь будет указывать на область расширенной памяти.

  • Выполните запись или чтение области расширенной памяти.

  • Восстановите базовый адрес сегмента данных в кэше дескриптора данных в буфре, расположенном по адресу 00800h.

  • Выполните команду LOADALL ещё раз.

  • Восстановите содержимое сохранённого ранее буфера.

  • Разрешите прерывания.

При выполнении команды LOADALL не делается никаких проверок. Вам необходимо самим позаботиться о том, чтобы загружаемые в регистры процессора значения имели какой-нибудь смысл. В противном случае состояние процессора окажется непредсказуемым.

Команда LOADALL может выполняться в защищённом режиме в нулевом приоритетном кольце. Но, к сожалению, эту команду нельзя использовать для переключения процессора из защищённого в реальный режим.

Процессор i80387 также имеет команду LOADALL, но её код и выполняемые функции другие.

Утилита MEMOSCOP

Для определения активных интерфейсов с защищённым режимом можно использовать предлагаемую утилиту MEMOSCOP. Эта утилита проверяет присутствие всех уровней поддержки программ, работающих в защищённом режиме или с расширенной памятью - от BIOS до DPMI.

*MEMOSCOP*, © Frolov A.V., 1992
-----------------------------
Файл memoscop.c

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>

void main(void) {

 extern int getcpu(void);
 unsigned cpu_type, ver;
 unsigned err;
 char ver_hi, ver_lo, verems;
 unsigned hostdata_seg, hostdata_size, dpmi_flags;
 void (far *pm_entry)();

 union REGS regs;
 struct SREGS segregs;


 printf("\n*MemoScop* v 1.0, © Frolov A.V., 1992\n"
 "---------------------\n");

// Определяем тип центрального процессора. Если программа
// работает на процессоре i8086, завершаем выполнение,
// так как в этом случае интерфейсы с защищенным режимом
// недоступны.

 printf("Тип процессора: 80%d\n", (cpu_type = getcpu()));
 if(cpu_type == 86) {
 printf("\nНа этом процессоре нам работать не интересно...");
 exit(0);
 }

// Определяем размер доступной через прерывание INT 15h
// расширенной памяти.

 printf("\n------------ Уровень BIOS -------------\n");

 regs.h.ah = 0x88;
 int86(0x15, &regs, &regs);
 printf("Размер расширенной памяти, доступной через INT 15:"
 " \t%d Кбайт\n", regs.x.ax);

// Проверяем, установлен ли драйвер HIMEM.SYS,
// если установлен, выводим его версию.

 printf("\n------------ Уровень XMM --------------\n");


 if (XMM_Installed()) {
 printf("Установлен драйвер HIMEM.SYS");
 ver = XMM_Version();
 printf(", версия: %4X, изменения: %4X\n",
  (short)ver, (short)(ver >> 16));
 printf("Размер свободной расширенной памяти, доступной через XMM:"
   " %ld Кбайт\n", (long)XMM_QueryLargestFree());
 printf("Общий размер расширенной памяти, доступной через XMM:"
   " \t %ld Кбайт\n", (long)XMM_QueryTotalFree());

 }
 else printf("\nДрайвер HIMEM.SYS не установлен.");


 printf("\n------------ Уровень EMS/VCPI -------------\n");

// Проверяем наличие драйвера EMS/VCPI

 if(ems_init()) printf("Драйвер EMS/VCPI не загружен\n");
 else {
 printf("Драйвер EMS/VCPI загружен, ");

// Выводим номер версии драйвера

 if((err = ems_ver(&verems)) != 0) {
  printf("\nОшибка %02.2X при определении версии EMM", err);
  exit(-1);
 }
 printf("версия EMM: %02.2X", verems);

// Определяем присутствие VCPI и его версию

 if(vcpi_ver(&ver_hi, &ver_lo) != 0) {
  printf("\nДрайвер EMM не поддерживает VCPI\n");
  exit(-1);
 }
 printf("\nВерсия VCPI: %02.2X.%02.2X\n", ver_hi, ver_lo);
 }


 printf("\n------------ Уровень DPMI --------------");


// Проверяем доступность и параметры сервера DPMI

 regs.x.ax = 0x1687;
 int86x(0x2F, &regs, &regs, &segregs);
 if(regs.x.ax != 0) {
 printf("\nСервер DPMI не активен"); exit(-1);
 }

// Определяем версию сервера DPMI

 printf("\nВерсия сервера DPMI: \t\t\t%d.%d\n",
 regs.h.dh, regs.h.dl);

// Определяем тип процессора

 printf("Тип процессора:\t\t\t\t");
 if(regs.h.cl == 2) printf("80286");
 else if(regs.h.cl == 3) printf("80386");
 else if(regs.h.cl == 4) printf("80486");

// Определяем возможность работы с 32-разрядными
// программами

 dpmi_flags = regs.x.bx;
 printf("\nПоддержка 32-разрядных программ:\t");
 if(dpmi_flags && 1) printf("ПРИСУТСТВУЕТ");
 else printf("ОТСУТСТВУЕТ");

// Определяем размер области памяти для сервера DPMI

 hostdata_size = regs.x.si;
 printf("\nРазмер памяти для сервера DPMI:\t\t%d байт",
 hostdata_size * 16);

// Определяем адрес точки входа в защищённый режим

 FP_SEG(pm_entry) = segregs.es;
 FP_OFF(pm_entry) = regs.x.di;
 printf("\nАдрес точки входа в защищённый режим: \t%Fp\n",
 pm_entry);

 getch();

}

/**
*.Name ems_init
*.Title Функция проверяет установку драйвера EMS
*
*.Descr Эта функция проверяет наличие драйвера EMS
*
*.Proto int ems_init(void);
*
*.Params Не используются
*
*.Return 0 - драйвер EMS установлен;
* 1 - драйвер EMS не установлен.
*
*.Sample ems_test.c
**/

int ems_init(void) {

 void (_interrupt _far *EMS_driver_adr)(void);
 char _far *EMS_driver_name;
 char test_name[8];
 int i;

 EMS_driver_adr = _dos_getvect(0x67);

 FP_SEG(EMS_driver_name) = FP_SEG (EMS_driver_adr);
 FP_OFF(EMS_driver_name) = 10;

 for(i=0; i<8; i++) test_name[i] = EMS_driver_name[i];

 if(strncmp(test_name, "EMMXXXX0", 8) == 0) return(0);
 else return(1);

}

/**
*.Name ems_ver
*.Title Определение версии драйвера EMS
*
*.Descr Эта функция возвращает номер версии
* драйвера EMS в двоично-десятичном формате.
*
*.Proto int ems_ver(char *ver);
*
*.Params char *ver - указатель на байт, в который
* будет записан номер версии.
*
*.Return Номер версии драйвера EMS в формате BCD
*
*.Sample ems_test.c
**/

int ems_ver(char *ver) {

 union REGS reg;

 reg.x.ax = 0x4600;
 int86(0x67, &reg, &reg);

 *ver = reg.h.al;
 return(reg.h.ah);
}

int vcpi_ver(char *ver_hi, char *ver_lo) {

 union REGS reg;

 reg.x.ax = 0xDE00;
 int86(0x67, &reg, &reg);

 *ver_hi = reg.h.bh;
 *ver_lo = reg.h.bl;
 return(reg.h.ah);
}

Исходные тексты функций, вызываемых утилитой MEMOSCOP приведены ниже:

*MEMOSCOP*, © Frolov A.V., 1992
-----------------------------
Файл cpu.asm


DEAL

MODEL SMALL

P386

PUBLIC _getcpu

CODESEG

PROC _getcpu NEAR

; -----------------------------
; Пытаемся установить старшую тетраду регистра флагов в 0.
; Если программа работает на процессоре 8086, в этом
; байте все биты будут установлены в 1
; -----------------------------

 mov dx, 86 ; Тип процессора - 8086

 pushf
 pop bx
 and bh,0Fh
 push bx
 popf
 pushf
 pop ax
 and ah,0F0h
 cmp ah,0F0h
 je cpu_end

; -----------------------------
; Для теста на процессор 80286 пытаемся установить старшую
; тетраду регистра флагов в единицы. Если программа
; выполняется на процессоре 80286, эти биты останутся
; равными нулю
; -----------------------------

 mov dx, 286 ; Тип процессора - 80286

 or bh,0F0h
 push bx
 popf
 pushf
 pop ax
 test ah,0F0h
 jz cpu_end

; -----------------------------
; Для того, чтобы отличить процессор 80386 от процессора
; 80486, используем бит 18 регистра флагов EFLAGS.
; Если программа может изменить состояние этого бита,
; она выполняется на процессоре 80486. В противном случае
; используется процессор 80386.
; -----------------------------

; Созраняем указатель стека

 mov edx,esp

; Выравниваем указатель стека для предотвращения
; исключения при установке флага AC

 and esp,not 3

; Копируем регистр EFLAGS в регистр EAX

 pushfd
 pop eax

; Сохраняем начальное значение регистра EFLAGS

 mov ecx,eax

; Переключаем флаг AC

 xor eax,40000H

; Пытаемся записать измененное значение обратно в регистр
; EFLAGS

 push eax
 popfd

; Копируем регистр EFLAGS в регисрр EAX

 pushfd
 pop eax

; Сравниваем старое и новое значения бита AC

 xor eax,ecx
 shr eax,18
 and eax,1
 push ecx

; Восстанавливаем регситр EFLAGS

 popfd

; Восстанавливаем указатель стека

 mov esp,edx

; Теперь если программа выполняется на процессоре 80386,
; регистр AX содержит значение 0, а если на процессоре
; 80486 - значение 1.

 mov dx,386 ; Тип процессора - 80386

 test ax,ax
 jz cpu_end

 mov ax,486 ; Тип процессора - 80486

cpu_end:
 mov ax, dx
 ret
ENDP _getcpu

END

Для работы с функциями драйвера HIMEM.SYS используется интерфейс, описанный нами в томе 2 "Библиотеки системного программиста":

*MEMOSCOP*, © Frolov A.V., 1992
-----------------------------
Файл xmmc.asm


; Это интерфейсный модуль для вызова функций
; XMS из Си. Текст программы рассчитан на
; модель памяти Small.

 .model small,c
 .DATA

; В этом месте будет храниться адрес
; управляющей функции XMM

XMM_Control dd ?

 .CODE

; Макроопределения для выполнения соглашения об
; использовании регистров в процедурах Си

c_begin macro
  push bp
  mov bp,sp
  push si
  push di
 endm

c_end macro
  pop di
  pop si
  mov sp,bp
  pop bp
  ret
 endm

; Все процедуры должны быть public

 public XMM_Installed
 public XMM_Version
 public XMM_RequestHMA
 public XMM_ReleaseHMA
 public XMM_GlobalEnableA20
 public XMM_GlobalDisableA20
 public XMM_EnableA20
 public XMM_DisableA20
 public XMM_QueryA20
 public XMM_QueryLargestFree
 public XMM_QueryTotalFree
 public XMM_AllocateExtended
 public XMM_FreeExtended
 public XMM_MoveExtended
 public XMM_LockExtended
 public XMM_UnLockExtended
 public XMM_GetHandleLength
 public XMM_GetHandleInfo
 public XMM_ReallocateExtended
 public XMM_RequestUMB
 public XMM_ReleaseUMB

;**
;.Name XMM_Installed
;.Title Получение адреса управляющей функции
;
;.Descr Эта функция проверяет наличие драйвера
; HIMEM.SYS и в случае его присуствия
; запоминает адрес управляющей функции.
;
;.Proto unsigned XMM_Installed(void);
;
;.Params Не используются
;
;.Return 0 - драйвер HIMEM.SYS не установлен;
; 1 - драйвер HIMEM.SYS установлен.
;
;.Sample xms_test.c
;**

XMM_Installed proc near
  c_begin

  mov ax, 4300h
 int 2fh
 cmp al, 80h
  jne NotInstalled

  mov ax, 4310h
 int 2fh
 mov word ptr [XMM_Control], bx
 mov word ptr [XMM_Control+2], es
  mov ax,1
  jmp Installed

NotInstalled:
  mov ax, 0
Installed:
  c_end
XMM_Installed endp

;**
;.Name XMM_Version
;.Title Определение версии драйвера HIMEM.SYS
;
;.Descr Эта функция определяет версию драйвера
; HIMEM.SYS
;
;.Proto long XMM_Version(void);
;
;.Params Не используются
;
;.Return Номер версии в младших 16 битах,
; номер изменений - в старших 16 битах
; возвращаемого значения
;
;.Sample xms_test.c
;**

XMM_Version proc near
 push si
  push di
  xor ah,ah
  call [XMM_Control]
  mov dx, bx
 pop di
 pop si
 ret
XMM_Version endp

;**
;.Name XMM_RequestHMA
;.Title Запросить область HMA
;
;.Descr Эта функция пытается зарезервировать для
; программы область HMA
;
;.Proto long XMM_RequestHMA(unsigned space);
;
;.Params space - размер требуемой области для
;  TSR-программы или драйвера,
;  0xffff для прикладной программы;
;
;.Return < 0 - область HMA не назначена программе,
;  код ошибки находится в старшем байте.
; 0L - область HMA назначена программе.
;
;.Sample xms_test.c
;**

XMM_RequestHMA proc near
  c_begin
  mov ah, 1
  mov dx, [bp+4]
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success
 mov dh, bl
@success:
  c_end
XMM_RequestHMA endp


;**
;.Name XMM_ReleaseHMA
;.Title Освободить область HMA
;
;.Descr Эта функция пытается освободить
; область HMA
;
;.Proto long XMM_ReleaseHMA(void);
;
;.Params Не используются
;
;.Return < 0 - область HMA не освобождена,
;  код ошибки находится в старшем байте.
; 0L - область HMA освобождена.
;
;.Sample xms_test.c
;**

XMM_ReleaseHMA proc near
  c_begin
 mov ah, 2
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success1
 mov dh, bl
@success1:
  c_end
XMM_ReleaseHMA endp

;**
;.Name XMM_GlobalEnableA20
;.Title Глобальное разрешение линии A20
;
;.Descr Эта функция разрешает программе, получившей
; доступ к области HMA использовать линию A20
;
;.Proto long XMM_GlobalEnableA20(void);
;
;.Params Не используются
;
;.Return < 0 - линия A20 не включена,
;  код ошибки находится в старшем байте.
; 0L - линия A20 включена.
;
;.Sample xms_test.c
;**

XMM_GlobalEnableA20 proc near
  c_begin
  mov ah, 3
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success2
 mov dh, bl
@success2:
  c_end
XMM_GlobalEnableA20 endp

;**
;.Name XMM_GlobalDisableA20
;.Title Глобальное запрещение линии A20
;
;.Descr Эта функция запрещает программе, получившей
; доступ к области HMA использовать линию A20
;
;.Proto long XMM_GlobalDisableA20(void);
;
;.Params Не используются
;
;.Return < 0 - линия A20 не выключена,
;  код ошибки находится в старшем байте.
; 0L - линия A20 выключена.
;
;.Sample xms_test.c
;**

XMM_GlobalDisableA20 proc near
  c_begin
  mov ah, 4
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success3
 mov dh, bl
@success3:
  c_end
XMM_GlobalDisableA20 endp

;**
;.Name XMM_EnableA20
;.Title Локальное разрешение линии A20
;
;.Descr Эта функция разрешает программе управлять
; областью расширенной памяти.
;
;.Proto long XMM_EnableA20(void);
;
;.Params Не используются
;
;.Return < 0 - линия A20 не включена,
;  код ошибки находится в старшем байте.
; 0L - линия A20 включена.
;
;.Sample xms_test.c
;**

XMM_EnableA20 proc near
  c_begin
 mov ah, 5
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success4
 mov dh, bl
@success4:
  c_end
XMM_EnableA20 endp

;**
;.Name XMM_DisableA20
;.Title Локальное запрещение линии A20
;
;.Descr Эта функция запрещает программе управлять
; областью расширенной памяти.
;
;.Proto long XMM_DisableA20(void);
;
;.Params Не используются
;
;.Return < 0 - линия A20 не выключена,
;  код ошибки находится в старшем байте.
; 0L - линия A20 выключена.
;
;.Sample xms_test.c
;**

XMM_DisableA20 proc near
  c_begin
 mov ah, 6
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success5
 mov dh, bl
@success5:
  c_end
XMM_DisableA20 endp

;**
;.Name XMM_QueryA20
;.Title Проверить состояние линии A20
;
;.Descr Эта функция проверяет доступность
; линии A20
;
;.Proto long XMM_QueryA20(void);
;
;.Params Не используются
;
;.Return < 0 - ошибка,
;  код ошибки находится в старшем байте.
; 0L - линия A20 выключена,
; 1L - линия A20 включена.
;
;.Sample xms_test.c
;**

XMM_QueryA20 proc near
  c_begin
 mov ah, 7
 call [XMM_Control]
 xor dx, dx
 or ax, ax
  jnz @success6
 mov dh, bl
@success6:
  c_end
XMM_QueryA20 endp

;**
;.Name XMM_QueryLargestFree
;.Title Определить максимальный размер блока
;
;.Descr Эта функция возвращает размер максимального
; непрерывного блока расширенной памяти,
; который доступен программе.
;
;.Proto long XMM_QueryLargestFree(void);
;
;.Params Не используются
;
;.Return < 0 - ошибка,
;  код ошибки находится в старшем байте.
; >= 0 - размер блока.
;
;.Sample xms_test.c
;**

XMM_QueryLargestFree proc near
  c_begin
 mov ah, 8
 call [XMM_Control]
 xor dx, dx
 or ax, ax
  jnz @success7
 mov dh, bl
@success7:
  c_end
XMM_QueryLargestFree endp

;**
;.Name XMM_QueryTotalFree
;.Title Определить размер расширенной памяти
;
;.Descr Эта функция возвращает размер
; всей имеющейся расширенной памяти.
;
;.Proto long XMM_QueryTotalFree(void);
;
;.Params Не используются
;
;.Return < 0 - ошибка,
;  код ошибки находится в старшем байте.
; >= 0 - размер расширенной памяти.
;
;.Sample xms_test.c
;**

XMM_QueryTotalFree proc near
  c_begin
  mov ah, 8
 call [XMM_Control]
 or ax, ax
 mov ax, dx
  mov dx, 0
  jnz @success8
 mov dh, bl
@success8:
  c_end
XMM_QueryTotalFree endp

;**
;.Name XMM_AllocateExtended
;.Title Запросить блок расширенной памяти
;
;.Descr Эта функция выделяет программе блок
; расширенной памяти, в случае успеха
; возвращает индекс полученного блока.
;
;.Proto long XMM_AllocateExtended(unsigned space);
;
;.Params space - размер требуемого блока памяти
;  в килобайтах;
;
;.Return < 0 - блок не распределен,
;  код ошибки находится в старшем байте.
; > 0L - младший байт содержит индекс
;  полученного блока памяти.
;
;.Sample xms_test.c
;**


XMM_AllocateExtended proc near
  c_begin
  mov ah, 9
  mov dx, [bp+4]
 call [XMM_Control]
 or ax, ax
 mov ax, dx
  mov dx, 0
  jnz @success9
 mov dh, bl
@success9:
  c_end
XMM_AllocateExtended endp

;**
;.Name XMM_FreeExtended
;.Title Освободить блок расширенной памяти
;
;.Descr Эта функция освобождает блок
; расширенной памяти, полученный функцией
; XMM_AllocateExtended().
;
;.Proto long XMM_FreeExtended(unsigned handle);
;
;.Params handle - индекс освобождаемого блока памяти;
;
;.Return < 0 - блок не распределен,
;  код ошибки находится в старшем байте.
; 0L - блок освобожден.
;
;.Sample xms_test.c
;**

XMM_FreeExtended proc near
  c_begin
 mov ah, 0Ah
  mov dx, [bp+4]
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @successA
 mov dh, bl
@successA:
  c_end
XMM_FreeExtended endp

;**
;.Name XMM_MoveExtended
;.Title Копировать блок расширенной памяти
;
;.Descr Эта функция копирует блок
; расширенной памяти, используя структуру
; struct XMM_Move:
;
; struct XMM_Move {
;  unsigned long Length;
;  unsigned short SourceHandle;
;  unsigned long SourceOffset;
;  unsigned short DestHandle;
;  unsigned long DestOffset;
; };
;
;.Proto long XMM_MoveExtended(struct
;  XMM_Move *move_descr);
;
;.Params struct XMM_Move *move_descr -
; указатель на структуру, описывающую
; что, откуда и куда надо копировать.
;
;.Return < 0 - ошибка при копировании,
;  код ошибки находится в старшем байте.
; 0L - блок скопирован успешно.
;
;.Sample xms_test.c
;**

XMM_MoveExtended proc near
  c_begin
 mov ah, 0Bh
  mov si, [bp+4];
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @successB
 mov dh, bl
@successB:
  c_end
XMM_MoveExtended endp

;**
;.Name XMM_LockExtended
;.Title Заблокировать блок расширенной памяти
;
;.Descr Эта функция блокирует блок расширенной
; памяти и возвращает 31 разряд его
; физического адреса.
;
;.Proto long XMM_LockExtended(unsigned handle);
;
;.Params handle - индекс блокируемого блока памяти;
;
;.Return < 0 - блок не заблокирован,
;  код ошибки находится в старшем байте.
; > 0L - блок заблокирован, функция
;  возвращает физический адрес блока
;  памяти.
;
;.Sample xms_test.c
;**

XMM_LockExtended proc near
  c_begin
 mov ah, 0Ch
  mov dx, [bp+4]
 call [XMM_Control]
  xchg ax, bx
  dec bx
 jz XMML_Success
 mov dh, al
XMML_Success:
  c_end
XMM_LockExtended endp

;**
;.Name XMM_UnLockExtended
;.Title Разблокировать блок расширенной памяти
;
;.Descr Эта функция разблокирует блок расширенной
; памяти.
;
;.Proto long XMM_UnLockExtended(unsigned handle);
;
;.Params handle - индекс блока памяти;
;
;.Return < 0 - блок не разблокирован,
;  код ошибки находится в старшем байте.
; 0L - блок разблокирован.
;
;.Sample xms_test.c
;**

XMM_UnLockExtended proc near
  c_begin
 mov ah, 0Dh
  mov dx, [bp+4]
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @successC
 mov dh, bl
@successC:
  c_end
XMM_UnLockExtended endp

;**
;.Name XMM_GetHandleLength
;.Title Получить длину блока расширенной памяти
;
;.Descr Эта функция возвращает длину блока
; расширенной памяти по его индексу.
;
;.Proto long XMM_GetHandleLength(unsigned handle);
;
;.Params handle - индекс блока памяти;
;
;.Return < 0 - произошла ошибка,
;  код ошибки находится в старшем байте.
; > 0L - длина блока в килобайтах.
;
;.Sample xms_test.c
;**

XMM_GetHandleLength proc near
  c_begin
 mov ah, 0Eh
  mov dx, [bp+4]
 call [XMM_Control]
 or ax, ax
 mov ax, dx
  mov dx, 0
  jnz @successD
 mov dh, bl
@successD:
  c_end
XMM_GetHandleLength endp

;**
;.Name XMM_GetHandleInfo
;.Title Получить информацию о блоке расширенной памяти
;
;.Descr Эта функция возвращает общее
; количество индексов в системе и
; содержимое счетчика блокирования для
; заданного индекса.
;
;.Proto long XMM_GetHandleInfo(unsigned handle);
;
;.Params handle - индекс блока памяти;
;
;.Return < 0 - произошла ошибка,
;  код ошибки находится в старшем байте.
; > 0L - младший байт - общее количество
;  индексов в системе;
;  старший байт - счетчик блокирования.
;
;.Sample xms_test.c
;**

XMM_GetHandleInfo proc near
  c_begin
 mov ah, 0Eh
  mov dx, [bp+4]
 call [XMM_Control]
 mov dx, bx
 or ax, ax
 mov ax, dx
  mov dx, 0
  jnz @successE
 mov dh, bl
@successE:
  c_end
XMM_GetHandleInfo endp

;**
;.Name XMM_ReallocateExtended
;.Title Изменить размер блока расширенной памяти
;
;.Descr Эта функция изменяет размер выделенного
; блока расширенной памяти.
;
;.Proto long XMM_ReallocateExtended(unsigned handle,
; unsigned new_size);
;
;.Params handle - индекс блока памяти;
; new_size - новый размер блока памяти
;  в килобайтах;
;
;.Return < 0 - блок не распределен,
;  код ошибки находится в старшем байте.
; > 0L - младший байт содержит индекс
;  полученного блока памяти.
;
;.Sample xms_test.c
;**

XMM_ReallocateExtended proc near
  c_begin
 mov ah, 0Fh
  mov dx, [bp+4]
  mov bx, [bp+6]
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @successF
 mov dh, bl
@successF:
  c_end
XMM_ReallocateExtended endp

;**
;.Name XMM_RequestUMB
;.Title Запросить область UMB
;
;.Descr Эта функция пытается зарезервировать для
; программы область UMB
;
;.Proto long XMM_RequestUMB(unsigned space);
;
;.Params space - размер требуемой области
;  в параграфах;
;
;.Return < 0 - область UMB не назначена программе,
;  код ошибки находится в старшем байте;
;  максимальный размер доступного блока
;  в младшем слове (16 разрядов);
; > 0L - область UMB назначена программе,
;  младшее слово содержит сегмент блока
;  UMB, старший - размер выделенного
;  блока UMB.
;
;.Sample xms_test.c
;**

XMM_RequestUMB proc near
  c_begin
 mov ah, 10h
  mov dx, [bp+4]
 call [XMM_Control]
  xchg bx, ax
  dec bx
 jz RUMB_Success
  xchg ax, dx
  mov dh, dl
RUMB_Success:
  c_end
XMM_RequestUMB endp

;**
;.Name XMM_ReleaseUMB
;.Title Освободить область UMB
;
;.Descr Эта функция пытается освободить
; область UMB
;
;.Proto long XMM_ReleaseUMB(unsigned segment);
;
;.Params segment - сегмент освобождаемого блока UMB*
;
;.Return < 0 - область UMB не освобождена,
;  код ошибки находится в старшем байте.
; 0L - область UMB освобождена.
;
;.Sample xms_test.c
;**

XMM_ReleaseUMB proc near
  c_begin
 mov ah, 11h
  mov dx, [bp+4]
 call [XMM_Control]
 xor dx, dx
 dec ax
  jz @success10
 mov dh, bl
@success10:
  c_end
XMM_ReleaseUMB endp

  END

Защита программ от отладки

Если вы разрабатываете программное обеспечение, защищённое от несанкционированного копирования, вам необходимо позаботиться о том, чтобы потенциальные взломщики ("кракеры" и "хакеры") не смогли выполнить программу инсталляции под управлением отладчика. Если взломщик сможет "подглядеть" за работой вашей программы, он рано или поздно разгадает ваш замысел и сведёт на нет все ваши усилия по защите программы от копирования.

В третьей книге первого тома "Библиотеки системного программиста" мы излагали некоторые соображения по организации защиты программ от несанкционированного копирования. Мы, в частности, рассказали о некоторых методах защиты программ от отладки - использование таймера, внутренней очереди команд процессора и другие.

Защищённый режим работы процессора открывает перед вами новую возможность. Возьмите любую программу, приведённую в этой книге и попытайтесь запустить её под управлением какого-либо отладчика (например, попробуйте Turbo Debugger или Code View). Всё будет хорошо до тех пор, пока ваша программа не попытается загрузить регистр IDTR при помощи команды LIDT. После выполнения этой команды отладчик зависает и единственное средство вновь оживить компьютер - нажать на кнопку сброса, расположенную на системном блоке.

Причина очевидна - изменились расположение и формат дескрипторной таблицы прерываний. Она подготовлена для работы в защищённом режиме, но отладчик работает в реальном режиме. Поэтому обработка всех прерываний, в том числе и от клавиатуры, невозможна.

Идея использования защищённого режима работы процессора при создании программ, защищённых от несанкционированного копирования, очевидна. Используя примеры программ, приведённые в книге, вы сможете во время работы программы инсталляции перевести процессор в защищённый режим и выполнить часть работы по инсталляции в защищённом режиме.

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

Далее процессор можно вернуть в реальный режим и продолжить процесс инсталляции.

Находясь в защищённом режиме, вы можете читать и писать сектора дискеты только используя уровень портов ввода/вывода контроллера флоппи-диска. Программирование контроллера флоппи-диска описано в третьей книге первого тома "Библиотеки системного программиста". Обрабатывать прерывания в защищённом режиме вы уже умеете.

Очевидный недостаток применения защищённого режима при организации защиты от копирования заключается в необходимости использования процессоров i80286, i80386 или i80486. Это означает, что указанный метод непригоден для компьютеров IBM PC/XT, использующих процессор i8086 или i8088.

Однако в последнее время большинство программных комплексов требует наличия в компьютере по крайней мере процессора i80286, поэтому указанным недостатком можно пренебречь. К тому же следует учесть резкое увеличение стойкости инсталлятора, работающего в защищённом режиме, к попыткам взлома.

 

<< Назад ] Содержание ] Далее >> ]

Дизайн: Piton Alien
Rambler's Top100 Рейтинг@Mail.ru
Сайт создан в системе uCoz