Использование функций драйвера
Для корректной работы с расширенной памятью задачи должны
выполнять определенную последовательность действий, а именно:
- 1. Проверить наличие менеджера, поддерживающего функции
EMS.
- 2. Получить код сегмента, на который отображается расширенная
память.
- 3. Определить наличие требуемого пространства расширенной
памяти.
- 4. Отобразить часть пространства ОЗУ на физические страницы.
- 5. В пределах сегмента работать с расширенной памятью
как с обычной.
- 6. При достижении границ сегмента повторять пункты 4
и 5.
- 7. Перед завершением задачи вернуть память менеджеру.
Выполнение первого пункта списка является скорее данью
традиции, чем необходимостью, поскольку ПК на базе 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. Его надо включить в ту часть
задачи, где выполняются подготовительные действия. Например, сразу после
команд, приведенных в примерах Б.З или Б.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. для вывода аварийного сообщения.
На следующем шаге выдается запрос на выделение блока
размером в 64 страницы. Если после возврата из драйвера регистр ah очищен,
то блок выделен, в противном случае происходит переход на метку emmerr.
В случае успешного выделения блока формируются Curpg
и Lastpg и на этом выполнение фрагмента завершено.
В примере Б.5 отсутствуют команды, обработки аварийных
ситуаций. Предполагается, что первая из них имеет метку emmerr. Что делать
в случае ошибки, решать вам, например, можно вывести на экран текст аварийного
сообщения и завершить выполнение задачи. На стадии отладки полезно предусмотреть
вывод кода ошибки, который находится в регистре ah.
Напоминаем, что после выполнения команд примера Б.5
блок только закреплен за задачей, но не доступен для записи или чтения.
Для работы с его конкретными страницами их надо отобразить на физические
страницы сегмента EMS. В этом заключается одно из существенных отличий
доступа к блокам расширенной памяти от доступа к блокам обычной памяти.
Отображение страниц
Для отображения логической страницы блока на одну из
физических страниц сегмента EMS запрашивается функция 44h. Мы рассмотрим
универсальный вариант подпрограммы отображения страниц.
В зависимости от логики выполняемых в задаче действий
может потребоваться отображение от одной до четырех страниц. Поэтому подпрограмма,
текст которой приведен в примере Б.6, имеет две точки входа.
При вызове call mapseg отображаются четыре подряд расположенные
страницы. Предварительно в регистре bx указывается номер первой логической
страницы, а в регистре dx — идентификатор блока, которому принадлежат
отображаемые страницы. Вариант вызова подпрограммы mapseg показан в примере
Б.7 (см. раздел).
При вызове call mapip дополнительно (кроме заполнения регистров bx и dx)
в регистре ах указывается номер первой физической страницы, а в регистре
сх — количество страниц.
Если отображение страниц выполнено успешно, то при возврате
из подпрограммы отсутствует признак переполнения (С-разряд очищен), в
противном случае он установлен. Следует отметить, что при работе отлаженной
задачи аварийные ситуации исключены.
Пример Б.6. Подпрограмма отображения 4-х страниц сегмента
EMS
mapseg: mov ex, 04 ; количество повторов цикла
xor al, al нулевая физическая страница
maplp : reov ah, 44h код функции отображения памяти
int 67h обращение к драйверу
or ah, ah отображение выполнено?
jne @F -> нет, переход на локальную метку
inc ax следующая физическая страница
inc bx следующая логическая страница
loop maplp управление повторами цикла
clc очистка С-разряда
ret возврат на основную программу
@@: stc установка С-разряда
ret возврат на основную программу
При входе в точку mapseg задается 4 повтора цикла отображения
начиная с нулевой физической страницы. После этого выполняется цикл отображения,
имеющий метку mapip (вторая точка входа).
Если отображение происходит без ошибок, то номера физической
и логической страницы увеличиваются на 1 и цикл повторяется до тех пор,
пока не будет отображено заданное количество страниц.
При возникновении ошибки ее код возвращается в регистре
ah. В этом случае выполнение цикла прекращается и происходит переход на
локальную метку, что приведет к возврату из подпрограммы с установленным
признаком переполнения.
Освобождение памяти
Для освобождения выделенного задаче блока выполняются
следующие действия:
mov dx, Ehndlr ; dx = идентификатор блока
mov ax, 4500h ; ах = код функции освобождения блока
int 67h ; обращение к драйверу
При исполнении запроса драйвер открепляет пространство
блока от задачи, и оно становится общедоступным.
Как уже говорилось, перед завершением задачи освобождение
выделенной для нее расширенной памяти обязательно. В противном случае
это пространство окажется недоступным для других претендентов и будет
освобождено только при выключении или перезагрузке компьютера.
Освобождаются все блоки, затребованные задачей. Для
этого описанные команды повторяются, с указанием в регистре dx идентификаторов
разных блоков, закрепленных за задачей. |