Использование функций драйвера
Для корректной работы с расширенной памятью задачи должны выполнять определенную последовательность действий, а именно:
- Проверить наличие менеджера, поддерживающего функции EMS.
- Получить код сегмента, на который отображается расширенная память.
- Определить наличие требуемого пространства расширенной памяти.
- Отобразить часть пространства ОЗУ на физические страницы.
- В пределах сегмента работать с расширенной памятью как с обычной.
- При достижении границ сегмента повторять пункты 4 и 5.
- Перед завершением задачи вернуть память менеджеру.
Выполнение первого пункта списка является скорее данью традиции, чем необходимостью, поскольку ПК на базе Intel 386 и всех последующих моделей обязательно имеют оборудование для доступа к расширенной памяти. Для проверки можно, например, с помощью функции 40h определить статус, а с помощью функции 4бп – номер версии драйвера и убедиться, что он не меньше чем 4.0. Остальные пункты списка обязательно должны выполняться, причем в той последовательности, в которой они перечислены.
Специальные переменные
При работе с Expanded memory обязательно используются код сегмента расширенной памяти и идентификаторы выделенных блоков. В некоторых случаях могут быть нужны номера последних логических страниц в выделенных блоках и другие величины. Для их хранения в разделе данных задачи надо выделить специальные переменные, количество которых зависит от количества открытых блоков.
Если задача запрашивает у драйвера только один блок большого размера, то для работы с ним нужны следующие переменные:
EBuff dw 0; код сегмента для доступа к расширенной памяти Ehndlr dw 0; идентификатор блока выделенного для задачи Curpg db 0; номер текущей логической страницы блока Lastpg db 0; номер последней логической страницы блока
Номера текущей и последней страниц нужны при работе с большими блоками, размер которых превышает 65 536 байтов (4 страницы). При работе с ними приходится многократно отображать его логические страницы на физические. Если же размер блока не превышает стандартного сегмента ОЗУ, то он отображается на физические страницы только один раз и при дальнейшей работе номера страниц не нужны.
При работе с несколькими блоками в разделе данных задачи можно организовать простую таблицу, состоящую из строк фиксированного размера, содержащих характеристики каждого блока. В таком случае характеристики выбираются из таблицы по порядковому номеру блока, и сокращается количество имен переменных.
Резервирование блока
Предположим, что для выполнения задачи требуется непрерывное пространство расширенной памяти (блок) размером в 1 Мбайт. Для резервирования такого блока задача должна запросить у драйвера исполнение функции 43h, указав в регистре bx 64 страницы (размер страницы составляет 16 Кбайт). Если это первый запрос, обращенный к драйверу, то предварительно надо выполнить функцию 4 in для определения состояния драйвера и получения кода сегмента для доступа к памяти.
Фрагмент программы, выполняющий резервирование блока размером в 1 Мбайт, приведен в примере Б.5. Его надо включить в ту часть задачи, где выполняются подготовительные действия. Например, сразу после команд, приведенных в примерах Б.3 или Б.4.
Пример Б.5. Создание в расширенной памяти блока размером 1 Мбайт.
mov ax, 4100h код функции запроса сегмента int 67h обращение к драйверу or ah, ah функция выполнена? je @F › да jmp emmerr › ошибка при исполнении функции @@: mov EBuff, bx сохраняем код сегмента mov bx, 64 размер запрашиваемого блока mov ax, 4300h код функции выделения памяти int 67h обращение к драйверу or ah, ah блок выделен? je @F › да jmp emmerr › ошибка при выделении блока @@: mov Ehndlr, dx сохраняем идентификатор блока mov Curpg, 0 номер текущей страницы блока mov Lastpg, 63 номер последней страницы блока ; Продолжение текста программы
Выполнение примера Б.5 начинается с запроса кода сегмента для доступа к расширенной памяти. Если при возврате из драйвера регистр ah очищен, то запрос исполнен успешно, в противном случае произойдет переход на метку emmerr. для вывода аварийного сообщения.