Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содеожание] [Дальше]

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

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

11 расширенная память

  • Основные понятия
  • Установка драйвера HIMEM.SYS
  • Спецификация XMS
  • Ограничения при использовании области HMA
  • Примеры программ
  • Современные компьютеры всегда оснащены расширенной памятью, располагающейся в диапазоне адресов свыше одного мегабайта. Однако операционная система MS-DOS, которая была создана для реального режима работы процессоров, не имеет полноценного доступа к этой памяти. То же относится и программам, предназначенным для выполнения в среде MS-DOS. Единственное, что MS-DOS старых версий (более ранних, чем 4.0), могла сделать с расширенной памятью - это разместить там быстродействующий электронный диск или кэш накопителя на магнитном диске.

    Однако в составе MS-DOS версии 4.0 и более поздних версий появился драйвер расширенной памяти HIMEM.SYS, который в некоторой степени облегчает жизнь программистам, составляющим программы для MS-DOS. Этот драйвер расширяет основное адресное пространство 640 Kбайт еще примерно на 64 Кбайт и предоставляет относительно удобное средство для хранения в расширенной памяти массивов данных.

    Будучи установлен в операционной системе, драйвер HIMEM.SYS обеспечивает программный интерфейс в соответствии со спецификацией XMS (eXtended Memory Specification), разработанный корпорациями Lotus, Intel, Microsoft и AST Research.

    Основные понятия

    При обсуждении спецификации XMS мы будем использовать следующие понятия и термины:

    ·          расширенная память (Extended Memory или XMS) - это память, используемая в компьютерах с процессорами 80286, 80386, 80486 и Pentium, располагающаяся в адресном пространстве выше границы 1 Мбайт;

    ·          старшая область памяти (High Memory Area или HMA) - это первые 64 Кбайт расширенной памяти, начинающиеся с адреса FFFFh:0010h. Адрес конца области HMA - FFFFh:FFFFh. Следовательно, размер области составляет 64 Кбайт без 16 байт. Следует отметить, что эта область может адресоваться процессором в реальном режиме и поэтому пригодна для обычных программ, предназначенных для работы в среде MS-DOS;

    ·          верхние блоки памяти (Upper Memory Blocks или UMB) - располагаются между границей 640 Кбайт и 1 Мбайт. Расположение и размер этих блоков могут сильно изменяться в зависимости от конфигурации аппаратуры компьютера;

    ·          расширенные блоки памяти (Extended Memory Blocks или EMB) - блоки расширенной памяти, располагающиеся выше границы HMA;

    ·          линия A20 - двадцать первая адресная линия процессора. Обычно эта линия заблокирована. Разблокировка линии открывает программам доступ к области HMA

    На рис. 11.1 схематично показано расположение различных перечисленных выше блоков памяти в адресном пространстве.

    Рис. 11.1. Расположение различных блоков памяти в адресном пространстве

    Установка драйвера HIMEM.SYS

    Для установки драйвера файл CONFIG.SYS должен содержать строку:

    
    	device=[d:][путь]himem.sys [/HMAMIN=h] [/NUMHANDLES=n]
    	

    Параметр /HMAMIN = (необязательный) задает минимальный размер памяти, который могут использовать программы в области HMA. Размер задается в килобайтах. Смысл использования этого параметра заключается в том, чтобы позволять использовать область HMA только тем программам, которые затребуют из этой области не меньше h Кбайт. Это нужно для того чтобы более эффективно использовать область HMA.

    Если параметр не задан, используется по умолчанию значение 0. Это означает, что первая же программа, запросившая область HMA, получит к ней доступ. Программа, запущенная следом и, возможно, использующая эту память эффективнее, уже не сможет воспользоваться областью HMA.

    Максимальное значение параметра h равно 63.

    Параметр /NUMHANDLES = задает максимальное количество областей расширенной памяти (блоков EMB), которое может быть запрошено программами. Диапазон задаваемых значений от 1 до 128, значение по умолчанию - 32. Задавая большие значения n, помните, что на управление каждым блоком EMB тратится 6 байт резидентной памяти.

    При установке драйвер HIMEM.SYS XE "HIMEM.SYS" может выдавать сообщения об ошибках в следующих случаях:

    ·          используется MS-DOS более старой версии, чем 3.00;

    ·          в компьютере установлен процессор 8086 или 8088;

    ·          при использовании компьютеров с нестандартными схемами управления расширенной памятью и линией A20

    Спецификация XMS

    Спецификация XMS содержит описание программного интерфейса драйвера HIMEM.SYS и рекомендации по использованию области памяти HMA.

    Проверка подключения драйвера

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

    Для этого надо загрузить в регистр AX значение 4300h и вызвать прерывание INT 2Fh. Если после этого регистр AL будет содержать значение 80h, драйвер установлен, в противном случае - нет.

    Приведем фрагмент программы, проверяющей подключение драйвера:

    
    	; Проверяем, установлен ли драйвер HIMEM.SYS
    	  mov   ax, 4300h
    	  int   2fh
    	  cmp   al, 80h
    	
    	; Если драйвер установлен, выполняем переход
    	  je    HMM_installed
    

    Получение адреса управляющей программы

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

    Этот адрес можно получить, если загрузить в регистр AX значение 4310h и вызвать прерывание INT 2Fh. Прерывание возвратит сегментный адрес управляющей программы в регистре ES, смещение - в регистре BX:

    
    	; Получаем адрес управляющей функции драйвера
    	  mov   ax, 4310h
    	  int   2fh
    	  mov   word ptr cs:[HMMEntry][0], bx
    	  mov   word ptr cs:[HMMEntry][2], es
    

    В дальнейшем полученный адрес используется для выполнения функций по обслуживанию расширенной памяти. Перед вызовом управляющей программы код требуемой функции должен быть загружен в регистр AH:

    
    	; Получаем номер версии драйвера HIMEM.SYS
    	  mov   ax,0
    	  call  [HMMEntry]
    

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

    Описание функций драйвера HIMEM.SYS

    Все функции драйвера HIMEM.SYS могут быть разделены на следующие пять групп:

    ·          функции получения информации о драйвере (0h);

    ·          функции управления областью HMA (1h...2h);

    ·          функции управления линией A20 (3h...7h);

    ·          функции управления расширенной памятью (8h...Fh);

    ·          функции управления блоками UMB (10h...11h).

    Приведем подробное описание этих функций в соответствии со спецификацией XMS версии 2.0.

    Получить версию XMS

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

    AH = 00h

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

    BX = номер внутренней модификации драйвера;

    DX = 0001h - если существует область HMA,

    DX = 0000h - если область HMA не существует

    Функция возвращает номера версии и модификации XMS в двоично-десятичном (BCD) формате. Например, если AX=0250h, это означает, что драйвер соответствует спецификации XMS версии 2.50. Дополнительно функция позволяет проверить наличие в системе области HMA.

    Запросить область HMA

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

    AH = 01h

    DX = размер памяти в байтах в области HMA, которая будет использоваться резидентными программами или драйверами. Обычная программа должна указывать значение DX, равное 0FFFFh

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 90h, 91h, 92h (описание кодов ошибок будет приведено после описания всех функций)

    С помощью этой функции программа может зарезервировать для себя область HMA. Задаваемый в регистре DX размер памяти сравнивается с указанным в параметре драйвера /HMAMIN=. Область HMA распределяется запросившей программе только в том случае, если запрошенный в регистре DX размер больше или равен указанному в параметре /HMAMIN. Такой механизм позволяет ограничить использование области HMA только теми программами, которые используют ее наилучшим образом.

    Поясним это на примере. Пусть при инициализации операционной системы из файла AUTOEXEC.BAT запускаются две программы. Одна из них использует 10 Кбайт из области HMA и запускается первой (в регистре DX функции 01h эта программа указывает значение 10240). Вторая запускаемая программа использует 40 Кбайт и запускается после первой. Очевидно, что вторая программа использует область HMA более эффективно. Но так как область HMA уже распределена первой программе, вторая программа не сможет получить ее для себя.

    Задавая параметр /HMAMIN =40, мы запретим распределение области HMA тем программам, которые используют в ней меньше 40 Кбайт. Теперь первая программа не получит доступ к области HMA, даже если она будет запускаться до второй, использующей 40 Кбайт памяти из области HMA.

    Освободить область HMA

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

    AH = 02h

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 90h, 93h

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

    После того, как программа освободила область HMA, эта область становится доступной другим программам.

    Глобальное открывание линии A20

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

    AH = 03h

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 82h

    Эта функция предназначена для тех программ, которые будут использовать область HMA. Она разрешает работу заблокированной по умолчанию 21 адресной линии процессора. Перед возвратом управления системе программа должна закрыть линию A20 с помощью функции 04h.

    Следует отметить, что для многих типов системных плат переключение линии A20 - достаточно медленная операция.

    Глобальное закрывание линии A20

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

    AH = 04h

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 82h, 94h

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

    Локальное открывание линии A20

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

    AH = 05h

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 82h

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

    Локальное закрывание линии A20

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

    AH = 06h

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 82h, 94h

    Функция отменяет разрешение линии A20, запрошенное предыдущей функцией. Она предназначена только для тех программ, которые непосредственно управляют расширенной памятью.

    Определение состояния линии A20

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

    AH = 07h

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

    AX = 0001h - если линия A20 открыта, 0000h - если линия A20 закрыта

    Ошибки:

    BL = 00h, 80h, 81h

    Функция выполняет попытку адресоваться за границу 1 Мбайт памяти и проверяет, не происходит ли при этом обращение в начало памяти (то есть "свертка памяти").

    Определение размера свободной расширенной памяти

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

    AH = 08h

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

    AX = размер наибольшего свободного блока расширенной памяти, Кбайт;

    DX = общий размер свободной расширенной памяти, Кбайт

    Ошибки:

    BL = 80h, 81h, A0h

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

    Получить блок EMB

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

    AH = 09h

    DX = размер требуемого блока, Кбайт

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка;

    DX = 16-разрядный идентификатор (handle) полученного блока EMB

    Ошибки:

    BL = 80h, 81h, A0h, A1h

    Функция заказывает блок EMB из пула свободной расширенной памяти. При успешном выполнении запроса функция возвращает идентификатор полученного блока, который должен использоваться программой для выполнения всех операций с блоком EMB. Если блок EMB программе больше не нужен, она должна освободить его с помощью функции 0Ah.

    Количество блоков EMB, которое может быть заказано, определяется в командной строке драйвера HIMEM.SYS параметром /NUMHANDLES=. Значение по умолчанию - 32, максимальное значение - 128.

    Освободить блок EMB

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

    AH = 0Ah

    DX = идентификатор освобождаемого блока EMB

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, A2h, B2h

    Функция освобождает блок EMB, заказанный предыдущей функцией. При этом все данные, находившиеся в блоке, будут потеряны.

    Копирование блоков EMB

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

    AH = 0Bh

    DS:SI = указатель на управляющую структуру, определяющую откуда, куда и как будет выполняться копирование

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, 82h, A3h, A4h, A5h, A6h, A7h, A8h, A9h

    Формат управляющей структуры представлен ниже:

    
    	ExtMemMoveStruct  struc
    	  Length         dd ?    ; количество пересылаемых байт
    	  SourceHandle   dw ?    ; индекс исходного блока
    	  SourceOffset   dd ?    ; смещение в исходном блоке
    	  DestHandle     dw ?    ; индекс блока-назначения
    	  DestOffset     dd ?    ; смещение в блоке-назначении
    	ExtMemMoveStruct  ends
    

    Эта функция выполняет основную операцию с блоками EMB - копирование данных. Данные могут пересылаться между обычной памятью и блоками EMB, между различными блоками EMB и даже внутри обычной памяти.

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

    Поля SourceHandle и DestHandle указывают, соответственно, идентификаторы исходного блока EMB и блока, в который выполняется копирование. Если в качестве идентификатора задано значение 0000h, это означает, что в качестве источника или приемника данных используется обычная память.

    Поля SourceOffset и DestOffset указывают 32-разрядное смещение в блоке EMB или адрес в обычной памяти. В последнем случае этот адрес имеет стандартный формат [сегмент:смещение].

    Функция копирования сама управляет линией A20, восстанавливая ее состояние после выполнения копирования. Поэтому программе не требуется управлять линией A20.

    Во время выполнения копирования разрешены прерывания.

    Блокирование EMB

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

    AH = 0Ch

    DX = идентификатор блока EMB

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка;

    DX:BX = 32-разрядный линейный адрес заблокированного EMB

    Ошибки:

    BL = 80h, 81h, A2h, ACh, ADh

    Функция блокирует EMB и возвращает его базовый адрес как линейный 32-разрядный адрес. Для заблокированного EMB невозможно выполнить операцию копирования. Полученный линейный адрес действителен только для заблокированного EMB.

    Разблокирование EMB

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

    AH = 0Dh

    DX = идентификатор блока EMB

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, A2h, AAh

    Функция разблокирует EMB, заблокированный при вызове предыдущей функции. Полученный от нее линейный адрес становится недействительным.

    Получить информацию об идентификаторе блока EMB

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

    AH = 0Eh

    DX = идентификатор блока EMB

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка;

    BH = содержимое счетчика блокировок EMB;

    BL = количество свободных идентификаторов блоков EMB в системе;

    DX = размер блока, Кбайт

    Ошибки:

    BL = 80h, 81h, A2h

    Эта функция используется для получения различной информации об используемых блоках EMB. Линейный адрес блока может быть получен с помощью фунции 0Ch.

    Изменить размер EMB

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

    AH = 0Fh

    DX = идентификатор блока EMB;

    BX = новый размер EMB, Кбайт

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, 81h, A0h, A1h, A2h, ABh

    Функция изменяет размер незаблокированного EMB. Если размер блока уменьшается, данные в старших адресах блока будут потеряны.

    Запросить область UMB

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

    AH = 10h

    DX = размер запрашиваемого блока UMB в параграфах

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка;

    BX = сегмент полученного UMB;

    DX = размер полученного блока или размер максимального свободного блока UMB (если невозможно выделить блок требуемого размера)

    Ошибки:

    BL = 80h, B0h, B1h

    Эта функция позволяет программе получить дступ к блокам UMB, лежащих в пределах первого мегабайта адресного пространства. Для использования этих блоков не требуется управлять линией A20.

    Если вам надо определить размер доступной области UMB, задайте при вызове этой функции DX=0FFFFh.

    Освободить область UMB

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

    AH = 11h

    DX = сегмент освобождаемого UMB

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

    AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

    Ошибки:

    BL = 80h, B2h

    После освобождения блока EMB данные, которые там находились, будут потеряны.

    Коды ошибок

    Приведем таблицу кодов ошибок, возвращаемых функциями в регистре BL:

    PRIVATEКод

    Ошибка

    00h

    Нет ошибки, нормальное завершение

    80h

    Функция не реализована в текущей версии драйвера

    81h

    Обнаружен драйвер VDISK.SYS, с этим драйвером драйвер HIMEM.SYS несовместим

    82h

    Ошибка при работе с линией A20

    8Eh

    Общая ошибка драйвера

    8Fh

    Катастрофическая ошибка драйвера

    90h

    Область HMA не существует

    91h

    Область HMA уже используется

    92h

    Содержимое регитра DX меньше парметра /HMAMIN=

    93h

    Область HMA не распределена программе

    94h

    Линия A20 все еще разблокирована

    A0h

    Вся расширенная память уже распределена

    A1h

    Больше нет свободных индексов EMB

    A2h

    Неправильный индекс EMB

    A3h

    Неправильный SourceHandle

    A4h

    Неправильный SourceOffset

    A5h

    Неправильный DestHandle

    A6h

    Неправильный DestOffset

    A7h

    Неправильный Length

    A8h

    Неразрешенное перекрытие данных при выполнении операции пересылки данных

    A9h

    Произошла ошибка четности

    AAh

    EMB не заблокирован

    ABh

    EMB заблокирован

    ACh

    Переполнение счетчика блокировок EMB

    ADh

    Не удалось выполнить блокировку EMB

    B0h

    Доступен UMB меньшего размера

    B1h

    Нет доступных блоков UMB

    B2h

    Задан неправильный сегмент UMB

    Ограничения при использовании области HMA

    К сожалению, на программы, использующие область HMA, накладываются значительные ограничения. Они связаны с тем, что MS-DOS, а также BIOS не рассчитаны на работу с адресами памяти выше границы 1 Мбайт. Приведем список этих ограничений.

    ·          нельзя передавать MS-DOS дальние указатели на данные, размещенные в области HMA. Это связано с тем, что функции MS-DOS проверяют правильность таких указателей;

    ·          не рекомендуется использование области HMA для выполнения обмена данных с диском через прерывания MS-DOS, BIOS или другими способами;

    ·          драйверы и резидентные программы, использующие область HMA, не должны держать линию A20 постоянно включенной, так как это может привести к неправильной работе программ, не рассчитанных на наличие и доступность этой области;

    ·          векторы прерываний не должны указывать в область HMA. Это результат предыдущего ограничения.

    Примеры программ

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

    Программа TESTHMA

    Первая программа с названием TESTHMA (листинг 11.1) демонстрирует проверку подключения драйвера и использование его основных функций.

    Листинг 11.1. Файл testhma\testhma.asm

    
    ; =====================================================
    ; Вызов основных функций API драйвера HIMEM.SYS
    ;
    ; (C) A. Frolov, 1997
    ;
    ; E-mail: frolov@glas.apc.org
    ; WWW:    http://www.glasnet.ru/~frolov
    ;            or
    ;         http://www.dials.ccas.ru/frolov
    ; =====================================================
    
    @@out_ch MACRO c1,c2,c3,c4,c5,c6,c7,c8,c9,c10
      mov   ah,02h
      IRP   chr,<c1,c2,c3,c4,c5,c6,c7,c8,c9,c10>
      IFB   <chr>
      EXITM
      ENDIF
      mov   dl,chr
      int   21h
      ENDM
      ENDM
    
    @@out_str MACRO
      mov   ah,9
      int   21h
      ENDM
    
    BEEP  MACRO
      mov bx,0
      mov ax, 0E07h
      int 10h
      ENDM
    
      .model small
      .STACK  100h
      .DATA
    
    msg    DB 13,10,"HIMEM.SYS API Demo", 13, 10
           DB "(C) Frolov A., 1997",13,10,13,10
           DB "$"
    
    noHMM     DB 13,10
              DB "HIMEM.SYS not installed",13,10,"$"
    yesHMM    DB 13,10,"HIMEM.SYS istalled, ", "$"
    ver1      DB "version: ", "$"
    ver2      DB ", modification: ", "$"
    errmsg    DB 13,10,"Error code ", "$"
    okmsg     DB 13,10,"Success!", "$"
    hmareq    DB 13,10,"Request HMA", "$"
    hmarel    DB 13,10,"Release HMA", "$"
    enA20     DB 13,10,"Open A20", "$"
    dsA20     DB 13,10,"Close A20", "$"
    loc_enA20 DB 13,10,"Local open A20","$"
    loc_dsA20 DB 13,10,"Local close A20", "$"
    check_A20 DB 13,10,"Check A20", "$"
    
    free_ext_mem DB 13,10,"Extended memory, Kbyte: ", "$"
    max_ext_block DB 13,10,"Max free Extended memory block, Kbyte: ", "$"
    
    HMMEntry dd ?
    
      .CODE
    begin:
    
      mov ax, DGROUP
      mov ds, ax
    
      mov ah, 9h ; Выводим заголовок
      mov dx, OFFSET msg
      int 21h
    
    ; Проверяем, установлен ли драйвер HIMEM.SYS
    
      mov ax, 4300h
      int 2fh
      cmp al, 80h
      je  HMM_installed
    
    ; Если не установлен, выводим сообщение и завершаем
    ; работу программы
    
      mov ah, 9h
      mov dx, OFFSET noHMM
      int 21h
      jmp terminate
    
    HMM_installed:
    
      mov ah, 9h
      mov dx, OFFSET yesHMM
      int 21h
    
    ; Получаем адрес управляющей функции драйвера
    
      mov ax, 4310h
      int 2fh
      mov word ptr cs:[HMMEntry][0], bx
      mov word ptr cs:[HMMEntry][2], es
    
    ; Получаем номер версии
    
      mov  ah, 9h
      mov  dx, OFFSET ver1
      int  21h
    
      mov  ax,0
      call cs:[HMMEntry]
    
    ; Выводим номер версии на экран
    
      call  Print_word
    
      mov   ah, 9h
      mov   dx, OFFSET ver2
      int   21h
    
      mov   ax, bx
      call  Print_word
    
    ; Запрашиваем область HMA
    
      mov   ah, 9h
      mov   dx, OFFSET hmareq
      int   21h
    
      mov   ax,0100h
      mov   dx,0ffffh
    
      call  cs:[HMMEntry]
      or    ax, ax
      jnz   hmareq_ok
      jmp   error
    
    hmareq_ok:
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
    ; Открываем линию A20
    
      mov   ah, 9h
      mov   dx, OFFSET enA20
      int   21h
    
      mov   ax,0300h
      call  cs:[HMMEntry]
    
      or    ax, ax
      jnz   enA20_ok
      jmp   error
    
    enA20_ok:
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
    ; Закрываем линию A20
    
      mov   ah, 9h
      mov   dx, OFFSET dsA20
      int   21h
    
      mov   ax,0400h
      call  cs:[HMMEntry]
    
      or    ax, ax
      jnz   dsA20_ok
      jmp   error
    
    dsA20_ok:
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
    ; Освобождаем область HMA
    
      mov   ah, 9h
      mov   dx, OFFSET hmarel
      int   21h
    
      mov   ax,0200h
      call  cs:[HMMEntry]
     
      or    ax, ax
      jz    error
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
    ; Получаем локальный доступ к линии A20
    
      mov   ah, 9h
      mov   dx, OFFSET loc_enA20
      int   21h
    
      mov   ax,0500h
      call  cs:[HMMEntry]
    
      or    ax, ax
      jz    error
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
    ; Проверяем линию A20
    
      mov   ah, 9h
      mov   dx, OFFSET check_A20
      int   21h
    
      mov   ax,0700h
      call  cs:[HMMEntry]
    
      or    ax, ax
      jz    error
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
    ; Определяем размер свободной расширенной памяти
    
      mov   ah, 9h
      mov   dx, OFFSET free_ext_mem
      int   21h
    
      mov   ax,0800h
      call  cs:[HMMEntry]
    
      push  ax
      mov   ax, dx
      call  Print_word
    
      mov   ah, 9h
      mov   dx, OFFSET max_ext_block
      int   21h
    
      pop   ax
      call  Print_word
    
    ; Освобождаем линию A20
    
      mov   ah, 9h
      mov   dx, OFFSET loc_dsA20
      int   21h
    
      mov   ax,0600h
      call  cs:[HMMEntry]
    
      or    ax, ax
      jz    error
    
      mov   ah, 9h
      mov   dx, OFFSET okmsg
      int   21h
    
      jmp   terminate
    
    error:
    
      push  bx
    
      mov   ah, 9h
      mov   dx, OFFSET errmsg
      int   21h
    
      pop   ax
      call  Print_word
    
    terminate:
    
    ; Завершаем работу программы и
    ; возвращаем управление операционной системе
    
      mov ax, 4C00h
      int 21h
    
    
    ; Вывод на экран содержимого регистра AX
    
    Print_word proc near
    ;--------------------
      push ax
      push bx
      push dx
    
      push ax
      mov cl,8
      rol ax,cl
      call Byte_to_hex
      mov bx,dx
      @@out_ch bh
      @@out_ch bl
    
      pop ax
      call Byte_to_hex
      mov bx,dx
      @@out_ch bh
      @@out_ch bl
    
      pop dx
      pop bx
      pop ax
      ret
    Print_word endp
    
    Byte_to_hex proc near
    ;--------------------
    ; al - input byte
    ; dx - output hex
    ;--------------------
      push ds
      push cx
      push bx
    
      lea bx,tabl
      mov dx,cs
      mov ds,dx
    
      push ax
      and al,0fh
      xlat
      mov dl,al
    
      pop ax
      mov cl,4
      shr al,cl
      xlat
      mov dh,al
    
      pop bx
      pop cx
      pop ds
      ret
    
    tabl db '0123456789ABCDEF'
    Byte_to_hex endp
     
      END begin
    

    Программа CALLHMA

    Приведем текст программы, составленная на языке программирования Си, которая вызывает функции драйвера расширенной памяти. Эта программа будет работать только в моделях памяти Small и Compact. Для других моделей памяти требуется изменить строки интерфейсного модуля hma.asm, в которых передаваемые функциям параметры извлекаются из стека и тип процедур:

    Аргументы

    Small, Compact

    Large, Huge

    Первый аргумент

    [bp+4]

    [bp+6]

    Второй аргумент

    [bp+6]

    [bp+8]

    Текст программы CALLHMA вы найдете в листинге 11.2, а текст интерфейсного модуля - в листинге 11.3.

    Листинг 11.2. Файл callhma\callhma.c

    
    // =====================================================
    // Работа с драйвером HIMEM.SYS
    //
    // (C) Фролов А.В, 1997
    //
    // E-mail: frolov@glas.apc.org
    // WWW:    http://www.glasnet.ru/~frolov
    //            или
    //         http://www.dials.ccas.ru/frolov
    // =====================================================
    #include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #include <dos.h>
    #include <string.h>
    
    struct   XMM_Move 
    {
      unsigned long  Length;
      unsigned short SourceHandle;
      unsigned long  SourceOffset;
      unsigned short DestHandle;
      unsigned long  DestOffset;
    };
    
    extern long XMM_Installed(void);
    extern long XMM_Version(void);
    extern long XMM_RequestHMA(unsigned);
    extern long XMM_ReleaseHMA(void);
    extern long XMM_GlobalEnableA20(void);
    extern long XMM_GlobalDisableA20(void);
    extern long XMM_EnableA20(void);
    extern long XMM_DisableA20(void);
    extern long XMM_QueryA20(void);
    extern long XMM_QueryLargestFree(void);
    extern long XMM_QueryTotalFree(void);
    extern long XMM_AllocateExtended(unsigned);
    extern long XMM_FreeExtended(unsigned);
    extern long XMM_MoveExtended(struct XMM_Move *);
    extern long XMM_LockExtended(unsigned);
    extern long XMM_UnLockExtended(unsigned);
    extern long XMM_GetHandleLength(unsigned);
    extern long XMM_GetHandleInfo(unsigned);
    extern long XMM_ReallocateExtended(unsigned, unsigned);
    extern long XMM_RequestUMB(unsigned);
    extern long XMM_ReleaseUMB(unsigned);
    
    void error(char *msg, long rc);
    
    int main(void) 
    {
      long ver, rc, handle;
      static char testmsg[] = "Тестовое сообщение";
      char buf[80];
      char far *ptr;
      int i;
      struct XMM_Move move_d;
    
      // Проверяем, установлен ли драйвер HIMEM.SYS,
      // если установлен, выводим его версию
      if (XMM_Installed()) 
      {
        printf("\nHIMEM.SYS installed");
        ver = XMM_Version();
        printf("\nver XMM: %4X,%4x",
          (short)ver, (short)(ver >> 16));
      }
    
      else 
      {
        printf("\nHIMEM.SYS not found");
        exit(-1);
      }
    
      // Запрашиваем управление областью HMA
      rc = XMM_RequestHMA(0xffff);
      if(rc) 
        error("Request HMA error",rc);
    
      else 
      {
        // Открываем линию A20
        rc = XMM_GlobalEnableA20();
        if(rc) 
          error("Open A20 error",rc);
    
        // Копируем тестовое сообщение сначала из
        // стандартной памяти в область HMA,
        // затем обратно в стандартную память
        FP_SEG(ptr) = 0xffff;
        FP_OFF(ptr) = 0x0010;
    
        for(i=0; testmsg[i] != 0; i++)
          ptr[i] = testmsg[i];
    
        for(i=0; ptr[i] != 0; i++)
          buf[i] = ptr[i];
        
        buf[i] = 0;
    
        // Выводим сообщение для проверки
        printf("\n%s",buf);
    
        // Закрываем линию A20 и отдаем системе область HMA
        rc = XMM_GlobalDisableA20();
        if(rc) 
          error("Close A20 eror",rc);
    
        rc = XMM_ReleaseHMA();
        if(rc) 
          error("Free HMA error",rc);
      }
    
      // Получаем блок EMB размером в 1 Кбайт
      handle = XMM_AllocateExtended(1);
      if(handle < 0) 
        error("Request XMB error",handle);
    
      // Копируем тестовое сообщение сначала из
      // стандартной памяти в блок EMB,
      // затем обратно в стандартную память
      move_d.Length = strlen(testmsg) + 1;
      move_d.SourceHandle = 0;
      (char far*)move_d.SourceOffset = (char far*)testmsg;
      move_d.DestHandle = (short)handle;
      move_d.DestOffset = 0L;
    
      rc = XMM_MoveExtended(&move_d);
      if(rc < 0) 
        error("Copy in EMB error",rc);
    
      move_d.Length = strlen(testmsg) + 1;
      move_d.DestHandle = 0;
      (char far*)move_d.DestOffset = (char far*)buf;
      move_d.SourceHandle = (short)handle;
      move_d.SourceOffset = 0L;
    
      rc = XMM_MoveExtended(&move_d);
      if(rc < 0) 
        error("Copy from EMB error",rc);
    
      // Выводим сообщение для проверки
      printf("\n%s",buf);
    
      // Освобождаем блок EMB
      rc = XMM_FreeExtended((unsigned)handle);
      if(rc) 
        error("Free XMB error",rc);
    
      return 0;
    }
    
    // Функция для вывода сообщения об ошибке
    // и кода ошибки
    void error(char *msg, long rc) 
    {
      rc = (unsigned char)(rc >> 24) ;
        printf("\n%s, error: %02.2X\n",
          msg, (unsigned char)rc);
      exit(-1);
    }
    Листинг 11.3. Файл callhma\hma.asm
    ; =====================================================
    ; Это интерфейсный модуль для вызова функций
    ; XMS из Си. Текст программы рассчитан на
    ; модель памяти Small
    ;
    ; (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
    
      .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 установлен.
    ;
    ;**
    
    _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 битах
    ;              возвращаемого значения
    ;
    ;**
    
    _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 назначена программе.
    ;
    ;**
    
    _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 освобождена.
    ;
    ;**
    
    _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 включена.
    ;
    ;**
    
    _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 выключена.
    ;
    ;**
    
    _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 включена.
    ;
    ;**
    
    _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 выключена.
    ;
    ;**
    
    _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 включена.
    ;
    ;**
    
    _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 - размер блока.
    ;
    ;**
    
    _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 - размер расширенной памяти.
    ;
    ;**
    
    _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  - младший байт содержит индекс
    ;                      полученного блока памяти.
    ;
    ;**
    
    _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  - блок освобожден.
    ;
    ;**
    
    _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  - блок скопирован успешно.
    ;
    ;**
    
    _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  - блок заблокирован, функция
    ;                      возвращает физический адрес блока
    ;                      памяти.
    ;
    ;**
    
    _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  - блок разблокирован.
    ;
    ;**
    
    _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  - длина блока в килобайтах.
    ;
    ;**
    
    _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  - младший байт - общее количество
    ;                      индексов в системе;
    ;                      старший байт - счетчик блокирования.
    ;
    ;**
    
    _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  - младший байт содержит индекс
    ;                      полученного блока памяти.
    ;
    ;**
    
    _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.
    ;
    ;**
    
    _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 освобождена.
    ;
    ;**
    
    _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
    
    [Назад] [Содеожание] [Дальше]