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

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

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

11. ДОПОЛНИТЕЛЬНАЯ ПАМЯТЬ

  • 11.1. Драйверы дополнительной памяти
  • 11.2. Проверка подключения драйвера
  • 11.3. Вызов функций драйвера
  • 11.4. Стандартные функции EMM
  • 11.5. Дополнительные функции EMM
  • 11.6. Коды ошибок
  • 11.7. Программа, использующая EMS
  • В отличие от расширенной памяти дополнительная память с помощью специальной аппаратуры и программного обеспечения отображается в диапазон адресов, лежащий ниже границы 1 Мбайт. Такой способ пригоден для компьютеров, использующих процессор Intel 8086, не обладающий возможностью адресации расширенной памяти.

    Чтобы понять, как происходит отображение, вспомним распределение первого мегабайта оперативной памяти. Область с адресами от 00000 до 9FFFF - это стандартная память размером 640К. (Мы используем здесь физический 20-разрядный адрес). Диапазон адресов от A0000 до BFFFF используется видеоадаптерами. Наконец, 256 Кбайтов с адресами C0000 - FFFFF используется для BIOS.

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

    В практике построения вычислительных систем на основе микропроцессоров такая техника используется уже давно. Для компьютеров IBM PC/XT/AT корпорации Lotus Development, Intel и Microsoft разработали спецификацию расширенной памяти (Expanded Memory Specification - EMS). В настоящий момент распространены версии 3.2 и 4.0 этой спецификации.

    Существует альтернативная спецификация Extended Expanded Memory Specification - EEMS), отличающаяся от версии EMS 3.2 в основном наличием поддержки мультизадачных операционных систем. Эта спецификация была разработана другой группой крупных производителей компьютерного оборудования: AST Research, Ashton-Tate, Quadram. Однако эта спецификация не получила широкого распространения. Версия 4.0 EMS включила в себя все расширения спецификации EEMS.

    В спецификации EMS в качестве окна для доступа к дополнительной памяти используются 64 килобайта, расположенные по адресам C0000h - EFFFFh. Это окно в спецификации называется "page frame". Окно разбивается на четыре сегмента по 16 килобайтов. Вся дополнительная память разбивается на логические страницы (logical page) размером по 16 килобайтов. Любая логическая страница может быть отображена на любой сегмент окна доступа. Таким образом, используя четыре сегмента, программа может адресоваться одновременно к любым четырем логическим страницам дополнительной памяти.

    На рисунке схематически показано отображение логических страниц дополнительной памяти на сегменты 64-килобайтного окна, расположенного в области адресов ПЗУ:

    11.1. Драйверы дополнительной памяти

    Для использования дополнительной памяти в компьютер должна быть вставлена плата дополнительной памяти и в файле CONFIG.SYS подключен специальный драйвер, который обычно поставляется вместе с платой памяти. Драйвер выполняет управление дополнительной памятью и называется EMM (Expanded Memory Manager).

    Операционная система MS-DOS версии 4.01 содержит драйвер XMA2EMS.SYS, реализующий функции управления дополнительной памятью. Этот драйвер должен быть подключен в файле CONFIG.SYS следующим образом:

    DEVICE=XMA2EMS.SYS [FRAME=xxxx] [Pnnn=xxxx] [/X:pages]
    
    
    
    

    Параметр FRAME задает базовый адрес для 64-килобайтового окна доступа в виде шестнадцатеричного сегментного адреса, например C000. Этот адрес должен находиться в диапазоне C000 - E000.

    Параметр Pnnn позволяет задать базовый адрес для конкретной страницы дополнительной памяти. Здесь nnn - это номер страницы (0-255), xxxx - сегментный адрес в шестнадцатеричном формате. При использовании параметра FRAME нельзя указывать параметры P0, P1, P2, P3.

    Параметр /X:pages определяет, сколько страниц дополнительной памяти будет использовано. По умолчанию используется вся дополнительная память.

    Если ваш компьютер имеет процессор 80386 и расширенную память, вы можете использовать драйвер EMM386.SYS, поставляемый в составе MS-DOS версии 4.01. Этот драйвер эмулирует дополнительную память на расширенной памяти. При этом несколько снижается производительность системы.

    Драйвер может быть подключен следующим образом:

         DEVICE=EMM386.SYS [size]  [X:mmmm-nnnn] [Mx]
    
    
    
    

    Параметр size определяет количество используемой драйвером расширенной памяти в килобайтах. Значение по умолчанию - 256 Кбайт.

    Параметр X:mmmm-nnnn определяет диапазон памяти, которая не должна быть использована для размещения окон доступа.

    Параметр Mx задает расположение окна доступа, используемого для отображения логических страниц дополнительной памяти. Соответствие параметра x сегментному адресу окна приведено в таблице:

       x         Адрес окна доступа
    
       0         C000
       1         C400
       2         C800
       3         CC00
       4         D000
       5         D400
       6         D800
       7         DC00
       8         E000
    
    
    
    

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

    Драйвер дополнительной памяти устанавливает вектор прерывания INT 67h таким образом, что этот вектор указывает на заголовок драйвера. При изучении драйверов мы рассказывали вам о формате заголовка. Сейчас для нас важно, что со смещением 10 в заголовке располагается имя драйвера - "EMMXXXX0". Следовательно, для проверки подключения драйвера мы можем, получив адрес заголовка, сравнить восемь байтов имени устройства со строкой "EMMXXXX0". При совпадении мы можем считать, что драйвер дополнительной памяти установлен.

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

    /**
    *.Name         ems_init
    *.Title        Функция проверяет установку драйвера EMS
    *
    *.Descr        Эта функция проверяет наличие драйвера EMS
    *
    *.Proto        int ems_init(void);
    *
    *.Params       Не используются
    *
    *.Return       0 - драйвер EMS установлен;
    *              1 - драйвер EMS не установлен.
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    int ems_init(void) {
    
            void (_interrupt _far *EMS_driver_adr)(void);
            char _far *EMS_driver_name;
            char test_name[8];
            int i;
    
            EMS_driver_adr = _dos_getvect(0x67);
    
            FP_SEG(EMS_driver_name) = FP_SEG (EMS_driver_adr);
            FP_OFF(EMS_driver_name) = 10;
    
            for(i=0; i<8; i++) test_name[i] = EMS_driver_name[i];
    
            if(strncmp(test_name, "EMMXXXX0", 8) == 0) return(0);
            else return(1);
    
    }
    
    
    
    

    11.3. Вызов функций драйвера

    Для вызова функций драйвера дополнительной памяти программа должна загрузить код функции в регистр AH, код подфункции (обычно 0) в регистр AL, и затем вызвать прерывание INT 67h.

    После возврата из прерывания в регистр AH будет записано слово состояния. При успешном выполнении функции оно равно 0.

    11.4. Стандартные функции EMM

    Стандартные функции - это небольшое подмножество функций EMM, необходимое для работы обычных прикладных программ (не резидентных и не драйверов). Все эти функции поддерживаются EMM версии 3.2.

    11.4.1. Получить состояние EMM

    На входе:       AX = 4000h.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

    Эта функция используется для проверки состояния драйвера EMM. Она должна использоваться только после того, как программа убедилась в наличии драйвера EMM.

    Для получения состояния EMM используйте следующую функцию:

    /**
    *.Name         ems_stat
    *.Title        Определение состояния драйвера EMS
    *
    *.Descr        Эта функция возвращает байт состояния
    *              драйвера EMS
    *
    *.Proto        char ems_stat(void);
    *
    *.Params       Не используются
    *
    *.Return       Байт состояния драйвера EMS
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    char ems_stat(void) {
    
            union REGS reg;
            struct SREGS sreg;
    
            reg.x.ax = 0x4000;
            int86(0x67, &reg, &reg);
            return(reg.h.ah);
    }
    
    
    
    

    11.4.2. Получить сегмент окна

    На входе:       AX = 4100h.
    
    На выходе:      AH = байт состояния EMM;
    
                    BX = сегмент окна для доступа к логическим
                    страницам дополнительной памяти.
    
    
    
    

    Функция позволяет получить сегмент 64-килобайтного окна, используемого драйвером EMS для доступа к логическим страницам расширенной памяти.

    /**
    *.Name         ems_fram
    *.Title        Определение сегмента окна доступа
    *
    *.Descr        Эта функция возвращает сегментный адрес
    *              окна, которое используется для доступа к
    *              дополнительной памяти.
    *
    *.Proto        char ems_fram(unsigned *frame);
    *
    *.Params       unsigned *frame - Указатель на переменную,
    *                 в которую будет записан сегментный
    *                 адрес окна доступа.
    *
    *.Return       Сосотояние EMM.
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    char ems_fram(unsigned *frame) {
    
            union REGS reg;
            struct SREGS sreg;
    
            reg.x.ax = 0x4100;
            int86(0x67, &reg, &reg);
            *frame = reg.x.bx;
    
            return(reg.h.ah);
    }
    
    
    
    

    11.4.3. Получить размер доступной памяти EMS

    На входе:       AX = 4200h.
    
    На выходе:      AH = байт состояния EMM;
    
                    DX = общее количество 16-килобайтных
                    страниц EMS в системе;
    
                    BX = число доступных в настоящее время
                    страниц EMS.
    
    
    
    

    Эта функция позволяет вам получить информацию о наличии и доступности страниц дополнительной памяти.

    /**
    *.Name         ems_page
    *.Title        Определение количества страниц EMS
    *
    *.Descr        Эта функция предназначена для определения
    *              общего количества страниц EMS и количества
    *              страниц, доступных в настоящее время.
    *
    *.Proto        char ems_page(unsigned *total, unsigned *free);
    *
    *.Params       unsigned *total - указатель на переменную,
    *                 в которую будет записано общее количество
    *                 страниц памяти EMS;
    *              unsigned *free - указатель на переменную,
    *                 в которую будет записано количество
    *                 доступных страниц памяти EMS;
    *
    *.Return       Сосотояние EMM.
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    char ems_page(unsigned *total, unsigned *free) {
    
            union REGS reg;
    
            reg.x.ax = 0x4200;
            int86(0x67, &reg, &reg);
            *total = reg.x.dx;
            *free  = reg.x.bx;
    
            return(reg.h.ah);
    }
    
    
    
    

    11.4.4. Открыть индекс EMM

    На входе:       AX = 4300h;
    
                    BX = требуемое в данном пуле количество
                    логических страниц.
    
    На выходе:      AH = байт состояния EMM;
    
                    DX = индекс пула EMS, он будет использоваться
                    в операциях с пулом логических страниц.
    
    
    
    

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

    /**
    *.Name         ems_open
    *.Title        Открытие индекса пула страниц EMS
    *
    *.Descr        Эта функция открывает индекс пула страниц
    *              EMS, делая доступными логические страницы
    *              дополнительной памяти.
    *
    *.Proto        int ems_open(int n_pages, int *handle);
    *
    *.Params       int n_pages - количество требуемых логических
    *                 страниц;
    *              int *handle - указатель на слово, в которое
    *                 будет записан индекс полученного пула.
    *
    *.Return       Байт состояния драйвера EMS
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    int ems_open(int n_pages, int *handle) {
    
            union REGS reg;
    
            reg.x.ax = 0x4300;
            reg.x.bx = n_pages;
            int86(0x67, &reg, &reg);
    
            *handle = reg.x.dx;
            return(reg.h.ah);
    }
    
    
    
    

    11.4.5. Отобразить память

    На входе:       AH = 44h;
    
                    AL = номер физической страницы окна доступа
                    (от 0 до 3);
    
                    BX = номер логической страницы из числа
                    находящихся в пуле страниц (от 0 до n-1,
                    где n - количество логических страниц
                    в пуле);
                    для версии EMS 4.0 задание значения
                    0FFFFh приводит к запрещению отображения
                    физических страниц пула, для разрешения
                    их отображения необходимо вызвать эту
                    функцию еще раз, указав правильный
                    номер страницы;
    
                    DX = индекс EMM, полученный от функции 43h.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

    Функция выполняет отображение (привязку) одной из логических страниц пула к одному их четырех 16-килобайтных сегментов окна просмотра, т.е. к физическим страницам.

    /**
    *.Name         ems_map
    *.Title        Отобразить память EMS
    *
    *.Descr        Эта функция отображает логические страницы
    *              пула дополнительной памяти на физические.
    *
    *.Proto        int ems_map(int phys_page, int log_page,
    *                          int handle);
    *
    *.Params       int phys_pages - номер физической страницы
    *                 окна доступа (от 0 до 3), на которую необходимо
    *                 отобразить логическую страницу пула;
    *
    *              int_log_page - номер логической страницы пула;
    *
    *              int *handle - индекс полученного пула;
    *
    *.Return       Байт состояния драйвера EMS
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    int ems_map(int phys_page, int log_page, int handle) {
    
            union REGS reg;
    
            reg.h.ah = 0x44;
            reg.h.al = phys_page;
            reg.x.bx = log_page;
            reg.x.dx = handle;
            int86(0x67, &reg, &reg);
    
            return(reg.h.ah);
    }
    
    
    
    

    11.4.6. Закрыть индекс EMM

    На входе:       AX = 4500h;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    
    

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

    /**
    *.Name         ems_clos
    *.Title        Закрытие индекса пула страниц EMS
    *
    *.Descr        Эта функция закрывает индекс пула страниц,
    *              полученный функцией ems_open().
    *
    *.Proto        int ems_clos(int *handle);
    *
    *.Params       int *handle - указатель на слово, в которое
    *                 будет записан индекс полученного пула.
    *
    *.Return       Байт состояния драйвера EMS
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    int ems_clos(int *handle) {
    
            union REGS reg;
    
            reg.x.ax = 0x4500;
            reg.x.dx = *handle;
            int86(0x67, &reg, &reg);
    
            return(reg.h.ah);
    }
    
    
    
    

    11.4.7. Получить номер версии EMM

    На входsе:      AX = 4600h.
    
    На выходе:      AH = байт состояния EMM;
    
                    AL = номер версии в двоично-десятичном (BCD)
                    формате, 32h соответствует версии 3.2.
    
    
    
    

    Версия 4.0 EMM поддерживает больше функций по управлению дополнительной памятью, чем версия 3.2. Прежде чем использовать такие функции, следует определить номер используемой версии EMM с помощью функции 46h.

    /**
    *.Name         ems_ver
    *.Title        Определение версии драйвера EMS
    *
    *.Descr        Эта функция возвращает номер версии
    *              драйвера EMS в двоично-десятичном формате.
    *
    *.Proto        int ems_ver(char *ver);
    *
    *.Params       char *ver - указатель на байт, в который
    *                 будет записан номер версии.
    *
    *.Return       Номер версии драйвера EMS в формате BCD
    *
    *.Sample       ems_test.c
    **/
    
    #include <stdio.h>
    #include <dos.h>
    #include "sysp.h"
    
    int ems_ver(char *ver) {
    
            union REGS reg;
    
            reg.x.ax = 0x4600;
            int86(0x67, &reg, &reg);
    
            *ver = reg.h.al;
            return(reg.h.ah);
    }
    
    
    
    

    11.5. Дополнительные функции EMM

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

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

    Специальные функции с номерами 47h - 4Eh поддерживаются EMM версии 3.2, функции с номерами 4Fh - 58h - только EMM версии 4.0.

    11.5.1. Сохранить контекст отображения

    На входе:       AX = 4700h;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

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

    11.5.2. Восстановить контекст отображения

    На входе:       AX = 4800h;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

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

    11.5.3. Определить количество страниц в пуле

    На входе:       AX = 4B00h;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM;
    
                    BX = количество логических страниц в пуле.
    
    
    
    

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

    11.5.4. Определить количество активных пулов

    На входе:       AX = 4C00h;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM;
    
                    BX = количество активных пулов дополнительной
                    памяти.
    
    
    
    

    Функция предназначена для определения количества текущих активных пулов и может вызываться перед использованием следующей функции (с номером 4Dh).

    11.5.5. Получить информацию о пулах

    На входе:       AX = 4D00h;
    
                    ES:DI = адрес буфера для информации.
    
    На выходе:      AH = байт состояния EMM;
    
                    BX = количество активных пулов дополнительной
                    памяти.
    
    
    
    

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

    11.5.6. Получить/установить отображение всех страниц

    На входе:       AH = 4Eh;
    
                    AL = код подфункции:
    
                    0 - получить содержимое всех регистров
                             отображения в буфер ES:DI;
    
                    1 - восстановить содержимое всех регистров
                             отображения из буфера ES:DI;
    
                    2 - получить и установить все регистры
                             отображения в буфер ES:DI
                             или восстановить из буфера ES:DI 
                             (т.е. комбинация подфункций 0 и 1);
    
                    3 - Определить размер требуемого буфера;
     
                    ES:DI = адрес буфера для информации;
    
    На выходе:      AH = байт состояния EMM;
    
                    AL = для подфункции 3 - размер буфера.
    
    
    
    

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

    11.5.7. Получить/установить отображение части страниц

    На входе:       AH = 4Fh;
    
                    AL = код подфункции:
    
                    0 - получить содержимое регистров
                             отображения в буфер ES:DI;
    
                    1 - восстановить содержимое регистров
                             отображения из буфера ES:DI;
    
                    2 - определить размер требуемого буфера;
    
                    ES:DI = адрес буфера для информации;
    
                    DS:SI = адрес массива 16-битовых слов,
                            содержащих сегментные адреса страниц,
                            для которых необходимо сохранить
                            контекст отображения; самое первое
                            слово массива - это размер массива
                            в словах.
    
    На выходе:      AH = байт состояния EMM;
    
                    AL = для подфункции 2 - размер буфера.
    
    
    
    

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

    11.5.8. Отображение/запрещение группы страниц

    На входе:       AH = 50h;
    
                    AL = код подфункции:
    
                    0 - разрешить или запретить отображение
                             страниц, используя номера страниц;
    
                    1 - аналогично подфункции 0, но
                             используются не номера страниц, а
                             адреса сегментов;
    
                    DS:SI = адрес массива структур, состоящий из
                            двух слов, первое слово - номер
                            логической страницы, второе -
                            номер физической страницы;
                            указание логической страницы 0FFFFh
                            запрещает отображение страницы;
    
                    CX = размер массива DS:SI в количестве
                    структур.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

    Функция позволяет за один вызов разрешить и запретить использование нескольких страниц.

    11.5.9. Изменение размера пула

    На входе:       AX = 5100h;
    
                    BX = новый размер пула в логических страницах;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

    С помощью этой функции программа может изменить размер уже заказанного ранее пула страниц дополнительной памяти.

    11.5.10. Получить/установить атрибуты пула

    На входе:       AH = 52h;
    
                    AL = код подфункции:
    
                    0 - получить атрибуты пула;
    
                    1 - установить атрибуты пула;
    
                    2 - определить возможность использования
                             атрибута неразрушаемой памяти;
    
                    BL = новые атрибуты;
     
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM;
    
                    AL = для подфункции 0: атрибуты пула;
    
                    для подфункции 2:
    
                            0 - атрибут неразрушаемой памяти
                                    недоступен;
    
                            1 - атрибут неразрушаемой памяти
                                    доступен.
    
    
    
    

    Функция дает возможность установить для некоторых пулов атрибут неразрушаемой памяти. Содержимое таких пулов не исчезает при теплой перезагрузке операционной системы (после нажатии комбинации клавиш Ctrl-Alt-Del).

    11.5.11. Установить/прочитать имя пула

    На входе:       AH = 53h;
    
                    AL = код подфункции:
    
                    0 - получить имя пула;
                    1 - установить имя пула;
    
                    ES:DI = адрес буфера имени пула, длина
                            этого буфера должна быть 8 байтов;
    
                    DX = индекс EMM.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

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

    11.5.12. Найти имя пула

    На входе:       AH = 54h;
    
                    AL = код подфункции:
    
                    0 - получить каталог пулов;
                    1 - найти пул по имени;
                    2 - определить количество открытых пулов;
    
                    DS:SI = адрес буфера имени пула для
                            подфункции 1, длина
                            этого буфера должна быть 8 байтов;
    
                    ES:DI = адрес массива 10-байтовых элементов;
                            в первое слово элемента будет
                            записан индекс пула, в остальные 8 -
                            имя пула.
    
    На выходе:      AH = байт состояния EMM;
    
                    AL = количество элементов в  массиве
                      (подфункция 0);
    
                    DX = индекс найденного пула (для 
                      подфункции 1);
    
                    BX = количество открытых пулов (для
                      подфункции 2).
    
    
    
    

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

    11.5.13. Отобразить страницу и перейти по адресу

    На входе:       AH = 55h;
    
                    AL = код подфункции:
    
                    0 - использовать массив номеров
                             физических страниц;
    
                    1 - использовать массив сегментных
                             адресов;
    
                    DS:SI = адрес структуры MapAndJump длиной
                            9 байтов.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

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

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

    11.5.14. Отобразить страницу и вызвать процедуру

    На входе:       AH = 56h;
    
                    AL = код подфункции:
    
                    0 - использовать массив номеров
                             физических страниц;
    
                    1 - использовать массив сегментных
                             адресов;
    
                    2 - получить размер стека, необходимого
                             для использования подфункций 0 и 1;
    
                    DS:SI = адрес структуры MapAndCall длиной
                            22 байта.
    
    На выходе:      AH = байт состояния EMM;
    
                    BX = требуемый размер стека (заполняется при
                      выполнении подфункции 2).
    
    
    
    

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

    Первые 9 байтов структуры MapAndCall соответствуют структуре MapAndJump. Далее идет еще один байт длины таблицы отображения и 4 байта адреса другой таблицы отображения. Вторая таблица описывает отображение страниц, которое будет установлено после вызова процедуры. Последние 8 байтов структуры зарезервированы для дальнейшего использования.

    11.5.15. Переслать/обменять область памяти

    На входе:       AH = 57h;
    
                    AL = код подфункции:
    
                    0 - переслать область памяти;
                    1 - обменять область памяти;
    
                    DS:SI = адрес структуры MoveInfo длиной
                            18 байтов.
    
    На выходе:      AH = байт состояния EMM.
    
    
    
    

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

    Структура MoveInfo содержит всю необходимую информацию о расположении блоков памяти:

    Смещение  Размер   Описание
    
    
    (+0)      4        Размер блока в байтах
    
    (+4)      1        Тип исходной памяти:
                         0 - стандартная, 1 - EMS
    
    (+5)      2        Индекс исходной памяти:
                         0 для стандартной памяти,
                         индекс пула для EMS
    
    (+7)      2        Смещение для исходной памяти (внутри
                         сегмента или страницы)
    
    (+9)      2        Адрес исходного сегмента или номер
                         для исходной страницы
    
    (+11)     1        Тип результирующей памяти:
                         0 - стандартная, 1 - EMS
    
    (+12)     2        Индекс результирующей памяти:
                         0 для стандартной памяти,
                         индекс пула для EMS
    
    (+14)     2        Смещение для результирующей памяти
                       (внутри сегмента или страницы)
    
    (+16)     2        Адрес результирующего сегмента или
                         номер для исходной страницы
    
    
    
    

    Получить массив адресов отображения

    На входе:       AH = 58h;
    
                    AL = код подфункции:
    
                    0 - получить массив отображения;
                    1 - получить размер массива отображения;
    
                    ES:DI = адрес буфера для массива отображения.
    
    На выходе:      AH = байт состояния EMM;
    
                    CX = количество элементов в массиве
                    отображения (для подфункции 1)
    
    
    
    

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

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

    Все функции EMM возвращают код ошибки в регистре AH:

    Код Ошибка
    00h Нет ошибки, нормальное завершение
    80h Внутренняя ошибка драйвера EMM
    81h Ошибка аппаратуры EMS-памяти
    82h EMM занят
    83h Неправильный индекс пула
    84h Неправильный номер запрошенной функции
    85h Больше нет доступных индексов пулов
    86h Ошибка при выполнении сохранения или восстановления контекста отображения
    87h Запрошено больше памяти, чем общее количество доступной EMS-памяти
    88h Запрошено больше страниц, чем доступно
    89h Нельзя открыть индекс пустого пула
    8Ah Пул не содержит так много страниц
    8Bh Неправильное отображение, заданы номера
      физических страниц, отличные от 0 - 3
    8Ch Переполнена область сохранения контекста отображения
    8Dh Многократное сохранение контекста для одного пула
    8Eh Попытка восстановления несохраненного контекста
    8Fh Неправильный номер подфункции в регистре AL
    90h Неправильный тип атрибута
    91h Не поддерживается неразрушаемая память
    92h Произошло перекрытие исходной и результирующей областей (это не ошибка, а предупреждение)
    93h Область назначения, заданная индексом, слишком мала
    94h Стандартная память перекрывается дополнительной памятью
    95h Слишком большое смещение при пересылке блока
    96h Слишком большой размер блока, больше 1 мегабайта
    97h Заданы одинаковые исходный и результирующий индексы
    98h Задан неправильный тип памяти (смещение 4)
    A0h Заданному имени не соответствует ни один пул
    A1h Заданное имя уже существует
    A2h Длина исходной области больше 1 мегабайта
    A3h Содержимое заданного блока данных неверно
    A4h Доступ к этой функции запрещен

    11.7. Программа, использующая EMS

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

    #include <stdio.h>
    #include <conio.h>
    #include "sysp.h"
    
    void main(void);
    void main(void) {
    
            unsigned frame, err;
            unsigned total, free;
            unsigned handle;
            char ver;
    
    // Это сообщение будет переписано сначала из
    // области стандартной памяти в область дополнительной,
    // затем обратно в область основной.
    
            static char test_msg[] = "Тестовое сообщение для "
                                                    "записи в область EMS.";
    
            char buf[80];
            char _far *ptr;
            int i;
    
    // Проверяем, установлен ли драйвер EMS.
    
            if(ems_init() != 0) {
                    printf("\nДрайвер EMS не установлен.");
                    exit(-1);
            }
    
    // Если драйвер установлен, определяем его состояние.
    
            printf("\nДрайвер EMS установлен, состояние: %02.2X.",
                    ems_stat());
    
    // Выводим номер версии драйвера
    
            if((err = ems_ver(&ver)) != 0) {
                    printf("\nОшибка: %02.2X", err);
                    exit(-1);
            }
            printf("\nВерсия EMM: %02.2X", ver);
    
    // Определяем сегмент окна доступа
    
            if((err = ems_fram(&frame)) != 0) {
                    printf("\nОшибка: %02.2X", err);
                    exit(-1);
            }
    
            printf("\nСегмент окна доступа: %04.4X",
                    frame);
    
    // Определяем общее количество страниц и
    // количество доступных страниц.
    
            if((err = ems_page(&total, &free)) != 0) {
                    printf("\nОшибка: %02.2X", err);
                    exit(-1);
            }
    
            printf("\nОбщее количество страниц EMS: %d"
                             "\nКоличество доступных страниц: %d",
                             total, free);
    
    // Заказываем пул в дополнительной памяти.
    
            if((err = ems_open(free, &handle)) != 0) {
                    printf("\nОшибка: %02.2X", err);
                    exit(-1);
            }
    
    // Отображаем нулевую физическую страницу
    // на нулевую логическуб страницу пула.
    
            if((err = ems_map(0, 0, handle)) != 0) {
                    printf("\nОшибка: %02.2X", err);
                    exit(-1);
            }
    
    // Конструируем указатель на физическую страницу.
    
            ptr = FP_MAKE(frame,0);
    
    // Копируем тестовое сообщение в
    // дополнительную память.
    
            printf("\nКопируем в EMS: %s",test_msg);
    
            for(i=0; test_msg[i] != 0; i++)
                    ptr[i] = test_msg[i];
    
    // Теперь копируем это сообщение обратно
    // в стандартную память.
    
            for(i=0; ptr[i] != 0; i++)
                    buf[i] = ptr[i];
            buf[i] = 0;
    
    // Выводим сообщение на экран для
    // проверки.
    
            printf("\nСкопировано из EMS: %s",buf);
    
    // Закрываем пул.
    
            if((err = ems_clos(&handle)) != 0) {
                    printf("\nОшибка: %02.2X", err);
                    exit(-1);
            }
    
            exit(0);
    }
    
    [Назад] [Содеожание] [Дальше]