Защищенный режим процессоров Intel 80286/80386/80486© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 234 стр. 9.8. Утилита MEMOSCOPДля определения активных интерфейсов с защищённым режимом можно использовать предлагаемую утилиту MEMOSCOP. Эта утилита проверяет присутствие всех уровней поддержки программ, работающих в защищённом режиме или с расширенной памятью - от BIOS до DPMI.
*MEMOSCOP*, © Frolov A.V., 1992
--------------------------------------------------------
Файл memoscop.c
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
void main(void) {
extern int getcpu(void);
unsigned cpu_type, ver;
unsigned err;
char ver_hi, ver_lo, verems;
unsigned hostdata_seg, hostdata_size, dpmi_flags;
void (far *pm_entry)();
union REGS regs;
struct SREGS segregs;
printf("\n*MemoScop* v 1.0, © Frolov A.V., 1992\n"
"---------------------------------------\n");
// Определяем тип центрального процессора. Если программа
// работает на процессоре i8086, завершаем выполнение,
// так как в этом случае интерфейсы с защищенным режимом
// недоступны.
printf("Тип процессора: 80%d\n", (cpu_type = getcpu()));
if(cpu_type == 86) {
printf("\nНа этом процессоре нам работать не интересно...");
exit(0);
}
// Определяем размер доступной через прерывание INT 15h
// расширенной памяти.
printf("\n------------------------ Уровень BIOS -------------------------\n");
regs.h.ah = 0x88;
int86(0x15, ®s, ®s);
printf("Размер расширенной памяти, доступной через INT 15:"
" \t%d Кбайт\n", regs.x.ax);
// Проверяем, установлен ли драйвер HIMEM.SYS,
// если установлен, выводим его версию.
printf("\n------------------------ Уровень XMM --------------------------\n");
if (XMM_Installed()) {
printf("Установлен драйвер HIMEM.SYS");
ver = XMM_Version();
printf(", версия: %4X, изменения: %4X\n",
(short)ver, (short)(ver >> 16));
printf("Размер свободной расширенной памяти, доступной через XMM:"
" %ld Кбайт\n", (long)XMM_QueryLargestFree());
printf("Общий размер расширенной памяти, доступной через XMM:"
" \t %ld Кбайт\n", (long)XMM_QueryTotalFree());
}
else printf("\nДрайвер HIMEM.SYS не установлен.");
printf("\n------------------------ Уровень EMS/VCPI ----------------------\n");
// Проверяем наличие драйвера EMS/VCPI
if(ems_init()) printf("Драйвер EMS/VCPI не загружен\n");
else {
printf("Драйвер EMS/VCPI загружен, ");
// Выводим номер версии драйвера
if((err = ems_ver(&verems)) != 0) {
printf("\nОшибка %02.2X при определении версии EMM", err);
exit(-1);
}
printf("версия EMM: %02.2X", verems);
// Определяем присутствие VCPI и его версию
if(vcpi_ver(&ver_hi, &ver_lo) != 0) {
printf("\nДрайвер EMM не поддерживает VCPI\n");
exit(-1);
}
printf("\nВерсия VCPI: %02.2X.%02.2X\n", ver_hi, ver_lo);
}
printf("\n------------------------ Уровень DPMI --------------------------");
// Проверяем доступность и параметры сервера DPMI
regs.x.ax = 0x1687;
int86x(0x2F, ®s, ®s, &segregs);
if(regs.x.ax != 0) {
printf("\nСервер DPMI не активен"); exit(-1);
}
// Определяем версию сервера DPMI
printf("\nВерсия сервера DPMI: \t\t\t%d.%d\n",
regs.h.dh, regs.h.dl);
// Определяем тип процессора
printf("Тип процессора:\t\t\t\t");
if(regs.h.cl == 2) printf("80286");
else if(regs.h.cl == 3) printf("80386");
else if(regs.h.cl == 4) printf("80486");
// Определяем возможность работы с 32-разрядными
// программами
dpmi_flags = regs.x.bx;
printf("\nПоддержка 32-разрядных программ:\t");
if(dpmi_flags && 1) printf("ПРИСУТСТВУЕТ");
else printf("ОТСУТСТВУЕТ");
// Определяем размер области памяти для сервера DPMI
hostdata_size = regs.x.si;
printf("\nРазмер памяти для сервера DPMI:\t\t%d байт",
hostdata_size * 16);
// Определяем адрес точки входа в защищённый режим
FP_SEG(pm_entry) = segregs.es;
FP_OFF(pm_entry) = regs.x.di;
printf("\nАдрес точки входа в защищённый режим: \t%Fp\n",
pm_entry);
getch();
}
/**
*.Name ems_init
*.Title Функция проверяет установку драйвера EMS
*
*.Descr Эта функция проверяет наличие драйвера EMS
*
*.Proto int ems_init(void);
*
*.Params Не используются
*
*.Return 0 - драйвер EMS установлен;
* 1 - драйвер EMS не установлен.
*
*.Sample ems_test.c
**/
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);
}
/**
*.Name ems_ver
*.Title Определение версии драйвера EMS
*
*.Descr Эта функция возвращает номер версии
* драйвера EMS в двоично-десятичном формате.
*
*.Proto int ems_ver(char *ver);
*
*.Params char *ver - указатель на байт, в который
* будет записан номер версии.
*
*.Return Номер версии драйвера EMS в формате BCD
*
*.Sample ems_test.c
**/
int ems_ver(char *ver) {
union REGS reg;
reg.x.ax = 0x4600;
int86(0x67, ®, ®);
*ver = reg.h.al;
return(reg.h.ah);
}
int vcpi_ver(char *ver_hi, char *ver_lo) {
union REGS reg;
reg.x.ax = 0xDE00;
int86(0x67, ®, ®);
*ver_hi = reg.h.bh;
*ver_lo = reg.h.bl;
return(reg.h.ah);
}
Исходные тексты функций, вызываемых утилитой MEMOSCOP приведены ниже:
*MEMOSCOP*, © Frolov A.V., 1992
--------------------------------------------------------
Файл cpu.asm
DEAL
MODEL SMALL
P386
PUBLIC _getcpu
CODESEG
PROC _getcpu NEAR
; --------------------------------------------------------
; Пытаемся установить старшую тетраду регистра флагов в 0.
; Если программа работает на процессоре 8086, в этом
; байте все биты будут установлены в 1
; --------------------------------------------------------
mov dx, 86 ; Тип процессора - 8086
pushf
pop bx
and bh,0Fh
push bx
popf
pushf
pop ax
and ah,0F0h
cmp ah,0F0h
je cpu_end
; --------------------------------------------------------
; Для теста на процессор 80286 пытаемся установить старшую
; тетраду регистра флагов в единицы. Если программа
; выполняется на процессоре 80286, эти биты останутся
; равными нулю
; --------------------------------------------------------
mov dx, 286 ; Тип процессора - 80286
or bh,0F0h
push bx
popf
pushf
pop ax
test ah,0F0h
jz cpu_end
; --------------------------------------------------------
; Для того, чтобы отличить процессор 80386 от процессора
; 80486, используем бит 18 регистра флагов EFLAGS.
; Если программа может изменить состояние этого бита,
; она выполняется на процессоре 80486. В противном случае
; используется процессор 80386.
; --------------------------------------------------------
; Созраняем указатель стека
mov edx,esp
; Выравниваем указатель стека для предотвращения
; исключения при установке флага AC
and esp,not 3
; Копируем регистр EFLAGS в регистр EAX
pushfd
pop eax
; Сохраняем начальное значение регистра EFLAGS
mov ecx,eax
; Переключаем флаг AC
xor eax,40000H
; Пытаемся записать измененное значение обратно в регистр
; EFLAGS
push eax
popfd
; Копируем регистр EFLAGS в регисрр EAX
pushfd
pop eax
; Сравниваем старое и новое значения бита AC
xor eax,ecx
shr eax,18
and eax,1
push ecx
; Восстанавливаем регситр EFLAGS
popfd
; Восстанавливаем указатель стека
mov esp,edx
; Теперь если программа выполняется на процессоре 80386,
; регистр AX содержит значение 0, а если на процессоре
; 80486 - значение 1.
mov dx,386 ; Тип процессора - 80386
test ax,ax
jz cpu_end
mov ax,486 ; Тип процессора - 80486
cpu_end:
mov ax, dx
ret
ENDP _getcpu
END
Для работы с функциями драйвера HIMEM.SYS используется интерфейс, описанный нами в томе 2 "Библиотеки системного программсита":
*MEMOSCOP*, © Frolov A.V., 1992
--------------------------------------------------------
Файл xmmc.asm
; Это интерфейсный модуль для вызова функций
; 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
|

