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

Аппаратное обеспечение IBM PC

© Александр Фролов, Григорий Фролов
Том 2, книга 1, М.: Диалог-МИФИ, 1992.

10. РАСШИРЕННАЯ ПАМЯТЬ

  • 10.1. Основные понятия
  • 10.2. Установка драйвера HIMEM.SYS
  • 10.3. Спецификация XMS
  • 10.4. Ограничения при использовании области HMA
  • 10.5. Примеры программ
  • 10.6. Интерфейс с Си
  • Компьютеры IBM AT, PS/2 всегда оснащены расширенной памятью, располагающейся в диапазоне адресов свыше одного мегабайта. Однако операционная система MS-DOS, использующая процессоры 80286, 80386 и 80486 в реальном режиме, не имеет полноценного доступа к этой памяти. То же относится и программам, разработанным для выполнения в среде MS-DOS. Единственное, что MS-DOS версий более ранних, чем 4.0, могла сделать с расширенной памятью - это разместить там быстродействующий электронный диск или кэш накопителя на магнитном диске.

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

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

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

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

    • Расширенная память (Extended Memory) - это память, используемая в компьютерах с процессорами 80286, 80386, 80486, располагающаяся в адресном пространстве выше одного мегабайта.
    • Старшая область памяти (High Memory Area) HMA - это первые 64 килобайта расширенной памяти, начинающиеся с адреса FFFFh:0010h. Адрес конца области HMA - FFFFh:FFFFh. Следовательно, размер области составляет 64 килобайта без 16 байтов. Следует отметить, что эта область может адресоваться процессором в реальном режиме и поэтому может быть использована обычными программами, предназначенными для работы в среде MS-DOS.
    • Верхние блоки памяти (Upper Memory Blocks) UMB - блоки памяти на машинах, использующих процессор 8086. Эти блоки памяти располагаются между границей 640 килобайт и 1 мегабайт. Расположение и размер этих блоков могут сильно изменяться в зависимости от аппаратуры.
    • Расширенные блоки памяти (Extended Memory Blocks) EMB - блоки расширенной памяти, располагающиеся выше границы HMA.
    • Линия A20 - двадцать первая адресная линия процессора. Обычно эта линия заблокирована. Разблокировка линии открывает программам доступ к области HMA.

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

    г==============================================¬
    ¦    Расширенные блоки памяти EMB              ¦
    ¦                                              ¦
    ¦----------------------------------------------¦ 1088K
    ¦                                              ¦
    ¦    Старшая область памяти HMA                ¦
    ¦                                              ¦
    ¦----------------------------------------------¦ 1024K
    ¦                                              ¦
    ¦    Верхние блоки памяти UMB                  ¦
    ¦                                              ¦
    ¦----------------------------------------------¦ 640 K
    ¦                                              ¦
    ¦    Обычная память, используемая MS-DOS       ¦
    ¦                                              ¦
    L==============================================- 0 K
    
    
    

    10.2. Установка драйвера 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 может выдавать сообщения об ошибках в следующих случаях:

    • используется MS-DOS более старой версии, чем 3.00;
    • машина использует процессор 8086, а не 80286, 80386, или 80486;
    • при использовании компьютеров с нестандартными схемами управления расширенной памятью и линией A20.

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

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

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

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

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

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

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

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

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

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

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

    • функции получения информации о драйвере (0h);
    • функции управления областью HMA (1h...2h);
    • функции управления линией A20 (3h...7h);
    • функции управления расширенной памятью (8h...Fh);
    • функции управления блоками UMB (10h...11h).

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

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

    На входе:       AH = 00h.
    
    На выходе:      AX = номер версии XMS;
    
                    BX = номер внутренней модификации драйвера;
    
                    DX = 0001h - если существует область HMA,
                         0000h - если область HMA не существует.
    
    Ошибки: нет.
    
    
    

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

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

    На входе:       AH = 01h;
    
                    DX = размер памяти в байтах в области HMA,
                    которая будет использоваться резидентными
                    программами или драйверами, обычная
                    программа должна использовать значение
                    DX=FFFFh.
    
    На выходе:      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 = 16-битовый индекс (handle) полученного
                    блока 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 = 16-битовый индекс (handle) блокируемого
                    EMB.
    
    На выходе:      AX = 0001h - если функция выполнена успешно
                    0000h - если произошла ошибка;
    
                    DX:BX = 32-битовый линейный адрес
                            заблокированного EMB.
    
    Ошибки: BL = 80h, 81h, A2h, ACh, ADh.
    
    
    

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

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

    На входе:       AH = 0Dh;
    
                    DX = 16-битовый индекс (handle) разблокируемого
                    EMB.
    
    На выходе:      AX = 0001h - если функция выполнена успешно
                    0000h - если произошла ошибка.
    
    Ошибки:         BL = 80h, 81h, A2h, AAh.
    
    
    

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

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

    На входе:       AH = 0Eh;
    
                    DX = 16-битовый индекс (handle) EMB.
    
    На выходе:      AX = 0001h - если функция выполнена успешно
                    0000h - если произошла ошибка;
    
                    BH = содержимое счетчика блокировок EMB;
    
                    BL = количество свободных индексов EMB в
                    системе;
    
                    DX = размер блока в килобайтах.
    
    Ошибки:         BL = 80h, 81h, A2h.
    
    
    

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

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

    На входе:       AH = 0Fh;
    
                    DX = 16-битовый индекс (handle)
                    незаблокированного 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=FFFFh.

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

    На входе:       AH = 11h;
    
                    DX = сегмент освобождаемого UMB.
    
    На выходе:      AX = 0001h - если функция выполнена успешно
                    0000h - если произошла ошибка.
    
    Ошибки:         BL = 80h, B2h.
    
    
    
    

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

    10.3.4. Коды ошибок

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

    Код Ошибка
    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

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

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

    • Нельзя передавать MS-DOS FAR-указатели на данные, размещенные в области HMA. Это связано с тем, что функции MS-DOS проверяют правильность таких указателей.
    • Не рекомендуется использование области HMA для выполнения обмена данных с диском через прерывания MS-DOS, BIOS или другими способами.
    • Драйверы и резидентные программы, использующие область HMA, не должны держать линию A20 постоянно включенной, так как это может привести к неправильной работе программ, не рассчитанных на наличие и доступность этой области.
    • Вектора прерываний не должны указывать в область HMA. Это результат предыдущего ограничения.

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

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

    include sysp.inc
    
              .MODEL  tiny
              DOSSEG
    
              .STACK  100h
    
              .DATA
    
    msg    DB 13,10,"Работа с драйвером HIMEM.SYS", 13, 10
              DB "Copyright ©Frolov A.,1991",13,10,13,10
              DB "$"
    
    noHMM    DB 13,10
                DB "Драйвер HIMEM.SYS не установлен",13,10,"$"
    yesHMM   DB 13,10,"Драйвер HIMEM.SYS установлен, ", "$"
    ver1     DB "версия: ", "$"
    ver2     DB ", номер модификации: ", "$"
    errmsg   DB 13,10,"Ошибка с кодом ", "$"
    okmsg    DB 13,10,"Успех!!!", "$"
    hmareq   DB 13,10,"Запрашиваем область HMA", "$"
    hmarel   DB 13,10,"Освобождаем область HMA", "$"
    enA20    DB 13,10,"Открываем линию A20", "$"
    dsA20    DB 13,10,"Закрываем линию A20", "$"
    loc_enA20 DB 13,10,"Локальный доступ к линии A20","$"
    loc_dsA20 DB 13,10,"Закрываем локальный доступ"
                    DB      " к линии A20", "$"
    check_A20 DB 13,10,"Проверяем доступность "
                    DB      "линии A20", "$"
    free_ext_mem DB 13,10,"Всего расширенной "
                    DB      "памяти, Кбайт: ", "$"
    max_ext_block DB 13,10,"Максимальный участок "
                    DB      "свободной"
                 DB " расширенной памяти, Кбайт: ", "$"
    
    HMMEntry dd ?
    
              .CODE
              .STARTUP
    
                    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:
    
                      .EXIT   0
    
    
    ; Вывод на экран содержимого регистра 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
    
    
    

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

    include sysp.inc
    
            .MODEL  tiny
             DOSSEG
            .STACK  100h
    
             .DATA
    
    msg   DB 13,10,"Работа в области HMA", 13, 10
            DB "Copyright ©Frolov A.,1991",13,10,13,10
                    DB "$"
    
    noHMM    DB 13,10,"Драйвер HIMEM.SYS "
                DB "не установлен", 13, 10, "$"
    yesHMM   DB 13,10,"Драйвер HIMEM.SYS установлен, ","$"
    errmsg   DB 13,10,"Ошибка с кодом ", "$"
    okmsg    DB 13,10,"Успех!!!", "$"
    hmareq   DB 13,10,"Запрашиваем область HMA", "$"
    hmarel   DB 13,10,"Освобождаем область HMA", "$"
    enA20    DB 13,10,"Открываем линию A20", "$"
    dsA20    DB 13,10,"Закрываем линию A20", "$"
    
    HMMEntry dd ?
    
    HMAStart dd ?
    
            .CODE
            .STARTUP
    
            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
    
    ; Запрашиваем область 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
    
    ; Записываем в двойное слово HMAStart
    ; адрес начала облсти HMA
    
            mov   word ptr cs:[HMAStart][0], 0010h
            mov   word ptr cs:[HMAStart][2], 0ffffh
    
    ; Копируем в область HMA процедуру, которая
    ; будет там выполняться
    
            cld
            lea   si, begin_HMA_code
            mov   di, 0010h
    
            mov   ax, cs
            mov   ds, ax
    
            mov   ax, 0ffffh
            mov   es, ax
    
            mov   cx, HMA_code_size
            rep movsb
    
    ; Вызываем процедуру, находящуюся в области HMA
    
            call  cs:[HMAStart]
    
    ; Закрываем линию 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
    
            jmp   terminate
    
    error:
    
            push  bx
            mov   ah, 9h
            mov   dx, OFFSET errmsg
            int   21h
    
            pop   ax
            call  Print_word
    
    terminate:
    
            .EXIT   0
    
    
    
    ; Вывод на экран содержимого регистра 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
    
    
    ; Эта процедура предназначена для
    ; выполнения в области HMA.
    ; Она просто три раза генерирует
    ; звуковой сигнал.
    
    begin_HMA_code:
    
            BEEP
            BEEP
            BEEP
            retf
    
    end_HMA_code:
    
    ; Здесь записана длина процедуры,
    ; предназначенной для выполнения в
    ; области HMA
    
    HMA_code_size dw $-begin_HMA_code
    
                      END
    
    
    

    В программе использована макрокоманда BEEP, описанная в файле sysp.inc:

    ; Макро для выдачи звукового сигнала
    
    BEEP  MACRO
             mov bx,0
             mov ax, 0E07h
             int 10h
             ENDM
    
    
    

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

    include sysp.inc
    
    ExtMemMoveStruct  struc
    
     @Length      dd ? ; количество пересылаемых байтов
     SourceHandle dw ? ; индекс исходного блока
     SourceOffset dd ? ; смещение в исходном блоке
     DestHandle  dw ?  ; индекс блока-назначения
     DestOffset  dd ?  ; смещение в блокe
    
    ExtMemMoveStruct  ends
    
    
            .MODEL  tiny
    
            DOSSEG
            .STACK  100h
    
            .DATA
    
    movestr ExtMemMoveStruct <0,0,0,0,0>
    
    msg DB 13,10,"Использование блоков EMB", 13, 10
             DB  "Copyright ©Frolov A.,1991",13,10,13,10
             DB "$"
    
    noHMM    DB 13,10,"Драйвер HIMEM.SYS не установлен",13,10,"$"
    yesHMM   DB 13,10,"Драйвер HIMEM.SYS установлен, ","$"
    errmsg   DB 13,10,"Ошибка с кодом ", "$"
    okmsg    DB 13,10,"Успех!!!", "$"
    free_ext_mem DB 13,10,"Всего расширенной памяти, Кбайт: ","$"
    max_ext_block DB 13,10,"Максимальный участок свободной"
                                      DB " расширенной памяти, Кбайт: ", "$"
    getEMBmsg  DB 13,10,"Получаем блок EMB","$"
    freeEMBmsg DB 13,10,"Освобождаем блок EMB","$"
    
    copymsg    DB 13,10,"Копируем блок данных в область EMB","$"
    copymsg1   DB 13,10,"Копируем блок данных обратно","$"
    
    testmsg DB 13,10,13,10,"Сообщение для копирования"
                      DB " в область EMB","$"
    
    len_testmsg DW $-testmsg
    
    ; Буфер для копирования сообщения
    
    testbuf DB 512 dup(?)
    
    HMMEntry dd ?
    
    EMBHandle dw ?
    
            .CODE
            .STARTUP
    
            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 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
    
    ; Получаем блок EMB
    
            mov   ah, 9h
            mov   dx, OFFSET getEMBmsg
            int   21h
    
            mov   ax,0900h
            mov   dx,1h
    
            call  cs:[HMMEntry]
            or    ax, ax
            jnz   getemb_ok
            jmp   error
    
    getemb_ok:
    
            mov   EMBHandle, dx
    
            mov   ah, 9h
            mov   dx, OFFSET okmsg
            int   21h
    
    ; Копируем строку testmsg в блок EMB
    
            mov   ah, 9h
            mov   dx, OFFSET copymsg
            int   21h
    
    ; Заполняем управляющую структуру
    
    ; Длина копируемого массива памяти
    
            mov   ax, word ptr len_testmsg
            mov   word ptr movestr.@Length, ax
    
    ; Индекс основной памяти, должен быть = 0
    
            mov   ax, 0
            mov   word ptr movestr.SourceHandle, ax
    
    ; Задаем сегмент:смещение копируемого сообщения
    
            mov   ax, OFFSET testmsg
            mov   word ptr [movestr.SourceOffset][0], ax
            mov   ax, cs
            mov   word ptr [movestr.SourceOffset][2], ax
    
    ; Задаем индекс EMB, в который будем копировать
    ; сообщение из основной памяти
    
            mov   ax, EMBHandle
            mov   movestr.DestHandle, ax
    
    ; Копируем в начало EMB, поэтому
    ; смещение = 0
    
            mov   ax, 0
            mov   word ptr [movestr.DestOffset][0], ax
            mov   word ptr [movestr.DestOffset][2], ax
    
    ; Загружаем адрес управляющей структуры в DS:SI
    
            mov   ax, cs
            mov   ds, ax
            mov   ax, OFFSET movestr
            mov   si, ax
            mov   ax,0B00h
    
    ; Вызываем функцию копирования
    
            call  cs:[HMMEntry]
            or    ax, ax
            jnz   moveemb_ok
            jmp   error
    
    moveemb_ok:
    
            mov   ah, 9h
            mov   dx, OFFSET okmsg
            int   21h
    
    ; Копируем сообщение обратно из блока EMB
    ; в буфер testbuf, расположенный в основной
    ; памяти
    
            mov   ah, 9h
            mov   dx, OFFSET copymsg1
            int   21h
    
    
    ; Подготавливаем управляющую структуру
    
            mov   ax, word ptr len_testmsg
            mov   word ptr movestr.@Length, ax
    
            mov   ax, 0
            mov   word ptr movestr.DestHandle, ax
    
            mov   ax, OFFSET testbuf
            mov   word ptr [movestr.DestOffset][0], ax
            mov   ax, cs
            mov   word ptr [movestr.DestOffset][2], ax
    
            mov   ax, EMBHandle
            mov   movestr.SourceHandle, ax
    
            mov   ax, 0
            mov   word ptr [movestr.SourceOffset][0], ax
            mov   word ptr [movestr.SourceOffset][2], ax
    
    ; Выполняем копирование
    
            mov   ax, cs
            mov   ds, ax
            mov   ax, OFFSET movestr
            mov   si, ax
            mov   ax,0B00h
    
            call  cs:[HMMEntry]
            or    ax, ax
            jnz   move1emb_ok
            jmp   error
    
    move1emb_ok:
    
            mov   ah, 9h
            mov   dx, OFFSET okmsg
            int   21h
    
    ; Выводим скопированное сообщение на экран
    ; для проверки
    
            mov   ah, 9h
            mov   dx, OFFSET testbuf
            int   21h
    
    ; Освобождаем блок EMB
    
            mov   ah, 9h
            mov   dx, OFFSET freeEMBmsg
            int   21h
    
            mov   ax,0A00h
            mov   dx,EMBHandle
    
            call  cs:[HMMEntry]
            or    ax, ax
            jnz   freeemb_ok
            jmp   error
    
    freeemb_ok:
    
            mov   EMBHandle, dx
    
            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:
    
            .EXIT   0
    
    
    ; Вывод на экран содержимого регистра 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
    
    
    

    10.6. Интерфейс с Си

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

    Аргументы           Small, Compact        Large, Huge
    
    Первый аргумент [bp+4]               [bp+6]
    Второй аргумент [bp+6]               [bp+8]
    
    
    ; Это интерфейсный модуль для вызова функций
    ; 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
    
    
    

    Приведем пример программы, демонстрирующей использование некоторых функций XMM:

    #include <stdio.h>
    #include <conio.h>
    #include "sysp.h"
    
    void main(void);
    void 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("\nДрайвер HIMEM.SYS установлен.");
                    ver = XMM_Version();
                    printf("\nВерсия XMM: %4X, изменения: %4x",
                            (short)ver, (short)(ver >> 16));
            }
    
            else {
                    printf("\nДрайвер HIMEM.SYS не установлен.");
                    exit(-1);
            }
    
    // Запрашиваем управление областью HMA.
    
            rc = XMM_RequestHMA(0xffff);
            if(rc) error("Ошибка при запросе области HMA",rc);
    
            else {
    
    // Открываем линию A20.
    
                    rc = XMM_GlobalEnableA20();
                    if(rc) error("Ошибка при разрешении линии A20",rc);
    
    // Копируем тестовое сообщение сначала из
    // стандартной памяти в область HMA,
    // затем обратно в стандартную память.
    
                    ptr = FP_MAKE(0xffff,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("Ошибка при запрещении линии A20",rc);
    
                    rc = XMM_ReleaseHMA();
                    if(rc) error("Ошибка при освобождении области HMA",rc);
            }
    
    // Получаем блок EMB размером в 1 килобайт.
    
            handle = XMM_AllocateExtended(1);
            if(handle < 0) error("Ошибка при запросе XMB",handle);
    
    // Копируем тестовое сообщение сначала из
    // стандартной памяти в блок EMB,
    // затем обратно в стандартную память.
    
            move_d.Length = strlen(testmsg) + 1;
            move_d.SourceHandle = 0;
            (char far*)move_d.SourceOffset = (char far*)testmsg;
            move_d.DestHandle = handle;
            move_d.DestOffset = 0L;
    
            rc = XMM_MoveExtended(&move_d);
            if(rc < 0) error("Ошибка при копировании в EMB",rc);
    
            move_d.Length = strlen(testmsg) + 1;
            move_d.DestHandle = 0;
            (char far*)move_d.DestOffset = (char far*)buf;
            move_d.SourceHandle = handle;
            move_d.SourceOffset = 0L;
    
            rc = XMM_MoveExtended(&move_d);
            if(rc < 0) error("Ошибка при копировании из EMB",rc);
    
    // Выводим сообщение для проверки.
    
            printf("\n%s",buf);
    
    // Освобождаем блок EMB.
    
            rc = XMM_FreeExtended(handle);
            if(rc) error("Ошибка при освобождении XMB",rc);
    
            exit(0);
    }
    
    // Функция для вывода сообщения об ошибке
    // и кода ошибки.
    
    int error(char *msg, long rc) {
    
            rc = (unsigned char)(rc >> 24) ;
            printf("\n%s, код ошибки: %02.2X\n",
                    msg, (unsigned char)rc);
    
    }
    
    [Назад] [Содеожание] [Дальше]