| [Назад] [Далее] | ![]() |
Спецификация доступа к дополнительной памяти (XMS) — еще один метод, позволяющий программам, запускающимся под управлением DOS в реальном режиме (или в режиме V86), использовать память, расположенную выше границы первого мегабайта.
INT 2Fh, АН = 43 — XMS- и DPMS-сервисы
| Ввод: | АХ = 4300h: проверить наличие XMS |
| Вывод: | АН = 80h, если HIMEM.SYS или совместимый драйвер загружен |
| Ввод: | АХ = 4310h: получить точку входа XMS |
| Вывод: | ES:BX = дальний адрес точки входа XMS |
После определения точки входа все функции XMS вызываются с помощью команды CALL на указанный дальний адрес.
Функция XMS 00h — Определить номер версии
| Ввод: | AH = 00h |
| Вывод: | АХ = номер версии, не упакованный BCD (0300h для 3.0) ВХ = внутренний номер модификации DX = 1, если HMA существует, 0, если нет |
Функция XMS 08h — Определить объем памяти
| Ввод: | АН = 08h BL = 00h |
| Вывод: | АХ = размер максимального доступного блока в килобайтах DX = размер всей XMS-памяти в килобайтах BL = код ошибки (A0h, если вся XMS-память занята, 00, если нет ошибок) |
Так как возвращаемый размер памяти оказывается ограниченным размером слова (65 535 Кб), начиная с версии XMS 3.0, введена более точная функция 88h.
Функция XMS 88h — Определить объем памяти
| Ввод: | AH = 88h |
| Вывод: | ЕАХ = размер максимального доступного блока в килобайтах BL = код ошибки (A0h, если вся XMS-память занята, 00 — если нет ошибок) ЕСХ = физический адрес последнего байта памяти (верный для ошибки А0h) EDX = размер XMS-памяти всего в килобайтах (0 для ошибки А0h) |
Функция XMS 09h — Выделить память
| Ввод: | АН = 09h DX = размер запрашиваемого блока (в килобайтах) |
| Вывод: | АХ = 1, если функция выполнена ВХ = идентификатор блока АХ = 0: BL = код ошибки (A0h, если не хватило памяти) |
Функция XMS 0Ah — Освободить память
| Ввод: | АН = 0Ah DX = идентификатор блока |
| Вывод: | АХ = 1, если функция выполнена Иначе — АХ = 0 и BL = код ошибки (A2h — неправильный идентификатор, ABh — участок заблокирован) |
Функция XMS 0Bh — Пересылка данных
| Ввод: | АН = 0Bh DS:SI = адрес структуры для пересылки памяти |
| Вывод: | АХ = 1, если функция выполнена Иначе — АХ = 0 и BL = код ошибки |
Структура данных, адрес которой передается в DS:SI:
+00h: 4 байта — число байт для пересылки
+04h: слово — идентификатор источника (0 для обычной памяти)
+06h: 4 байта — смещение в блоке-источнике или адрес в памяти
+0Ah: слово — идентификатор приемника (0 для обычной памяти)
+0Ch: 4 байта — смещение в блоке-приемнике или адрес в памяти
Адреса в обычной памяти записываются в соответствующие двойные слова в обычном виде — сегмент:смещение. Копирование происходит быстрее, если данные выровнены на границы слова или двойного слова; если области данных перекрываются, адрес начала источника должен быть меньше адреса начала приемника.
Функция XMS 0Fh — Изменить размер XMS-блока
| Ввод: | АН = 0Fh ВХ = новый размер DX = идентификатор блока |
| Вывод: | АХ = 1, если функция выполнена Иначе — АХ = 0 и BL = код ошибки |
Кроме того, XMS позволяет программам использовать область НМА и блоки UMB, если они не заняты DOS при запуске (так как в CONFIG.SYS не было строк DOS = HIGH или DOS = UMB).
; mem.asm
; сообщает размер памяти, доступной через EMS и XMS
;
.model tiny
.code
.186 ; для команд сдвига на 4
org 100h ; СОМ-программа
start:
cld ; команды строковой обработки
; будут выполняться вперед
; проверка наличия EMS
mov dx,offset ems_driver ; адрес ASCIZ-строки "EMMXXXX0"
mov ax,3D00h
int 21h ; открыть файл или устройство
jc no_emmx ; если не удалось открыть - EMS нет
mov bx,ax ; идентификатор в ВХ
mov ax,4400h
int 21h ; IOCTL: проверить состояние файла/устройства
jc no_ems ; если не произошла ошибка,
test dx,80h ; проверить старший бит DX,
jz no_ems ; если он - 0, EMMXXXXO - файл в текущем
; каталоге
; определение версии EMS
mov ah,46h
int 67h ; получить версию EMS
test ah,ah
jnz no_ems ; если EMS выдал ошибку - не стоит продолжать
; с ним работать
mov ah,al
and al,0Fh ; AL = старшая цифра
shr ah,4 ; AH = младшая цифра
call output_version ; выдать строку о номере версии EMS
; определение доступной EMS-памяти
mov ah,42h
int 67h ; получить размер памяти
; в 16-килобайтных страницах
shl dx,4 ; DX = размер памяти в килобайтах
shl bx,4 ; ВХ = размер свободной памяти в килобайтах
mov ax,bx
mov si,offset ems_freemem ; адрес строки для output_info
call output_info ; выдать строки о размерах памяти
no_ems:
mov ah,3Eh
int 21h ; закрыть файл/устройство EMMXXXX0
no_emmx:
; проверка наличия XMS
mov ax,4300h
int 2Fh ; проверка XMS,
cmp al,80h ; если AL не равен 80h,
jne no_xms ; XMS отсутствует,
mov ax,4310h ; иначе:
int 2Fh ; получить точку входа XMS
mov word ptr entry_pt,bx ; и сохранить ее в entry_pt
mov word ptr entry_pt+2,es ; (старшее слово - по старшему адресу!)
push ds
pop es ; восстановить ES
; определение версии XMS
mov ah,00
call dword ptr entry_pt ; Функция XMS 00h - номер версии
mov byte ptr mem_version,'X' ; изменить первую букву строки
; "EMS версии" на "X"
call output_version ; выдать строку о номере версии XMS
; определение доступной XMS-памяти
mov ah,08h
xor bx,bx
call dword ptr entry_pt ; Функция XMS 08h
mov byte ptr totalmem,'X' ; изменить первую букву строки
; "EMS-памяти" на "X"
mov si,offset xms_freemem ; строка для output_info
; вывод сообщений на экран:
; DX - объем всей памяти
; АХ - объем свободной памяти
; SI - адрес строки с сообщением о свободной памяти (разный для EMS и XMS)
output_info:
push ax
mov ax,dx ; объем всей памяти в АХ
mov bp,offset totalmem ; адрес строки - в ВР
call output_info1 ; вывод
pop ах ; объем свободной памяти - в АХ
mov bp,si ; адрес строки - в ВР
output_info1: ; вывод
mov di,offset hex2dec_word
; hex2dec
; преобразует целое двоичное число в АХ
; в строку десятичных ASCII-цифр в ES:DI, заканчивающуюся символом "$"
mov bx,10 ; делитель в ВХ
xor сх,сх ; счетчик цифр в 0
divlp: xor dx,dx
div bx ; разделить преобразуемое число на 10
add dl,'0' ; добавить к остатку ASCII-код нуля
push dx ; записать полученную цифру в стек
inc cx ; увеличить счетчик цифр
test ax,ax ; и, если еще есть, что делить,
jnz divlp ; продолжить деление на 10
store:
pop ax ; считать цифру из стека
stosb ; дописать ее в конец строки в ES:DI
loop store ; продолжить для всех СХ-цифр
mov byte ptr es:[di],'$' ; дописать '$' в конец строки
mov dx,bp ; DX - адрес первой части строки
mov ah,9
int 21h ; Функция DOS 09h - вывод строки
mov dx,offset hex2dec_word ; DX - адрес строки с десятичным числом
int 21h ; вывод строки
mov dx,offset eol ; DX - адрес последней части строки
int 21h ; вывод строки
no_xms: ret ; конец программы и процедур
; output_info и output_info1
; вывод версии EMS/XMS
; АХ - номер в неупакованном BCD-формате
output_version:
or ax,3030h ; преобразование неупакованного BCD в ASCII
mov byte ptr major,ah ; старшая цифра в major
mov byte ptr minor,al ; младшая цифра в minor
mov dx,offset mem_version ; адрес начала строки - в DX
mov ah,9
int 21h ; вывод строки
ret
ems_driver db "EMMXXXX0",0 ; имя драйвера для проверки EMS
mem_version db "EMS версии " ; сообщение о номере версии
major db "0." ; первые байты этой
minor db "0 обнаружен ",0Dh,0Ah,"$" ; и этой строк будут
; заменены реальными номерами версий
totalmem db "EMS-памяти: $"
ems_freemem db "EMS-памяти: $"
eol db "K",0Dh,0Ah,'$' ; конец строки
xms_freemem db "Наибольший свободный блок XMS: $"
entry_pt: ; сюда записывается точка входа XMS
hex2dec_word equ entry_pt+4 ; буфер для десятичной строки
end start