
- •1. Управление памятью
- •1.1 Типы памяти
- •1.2 Стандартная память
- •Р ис. 2. Цепочка блоков памяти
- •1.3 Отображаемая память
- •1.4 Расширенная память
- •1.5 Высокая память
- •1.6 Верхняя память
- •2. Использование средств управления памятью
- •2.1. Общие положения
- •2.2. Драйвер himem.Sys: управление расширенной и высокой памятью
- •3. Использование драйвера himem.Sys для программирования.
- •3.1. Проверка подключения драйвера
- •3.2. Получение адреса управляющей программы
- •3.3. Описание функции драйвера h1mem.Sys
- •Локальное открывание линии а20
- •Локальное закрывание линии а20
- •Освободить область umb
- •3.4. Коды ошибок
- •3.5. Ограничения при использовании области нмa
- •4. Примеры использования драйвера himem.Sys.
Освободить область umb
На входе: AH = 11h;
DX = сегмент освобождаемого UMB.
На выходе: AX = 000lh - если функция выполнена успешно,
0000h - если произошла ошибка.
Ошибки: BL = 80h, В2h.
После освобождения блока ЕМВ данные, которые там находились, будут потеряны.
3.4. Коды ошибок
Приведем таблицу кодов ошибок, возвращаемых функциями в регистре BL:
Код |
Ошибка |
00h 80h 81h
82h 8Eh 8Fh 90h 91h 92h 93h 94h A0h Alh A2h АЗh A4h A5h A6h A7h A8h A9h AAh ABh Ach ADh B0h Blh B2h |
Нет ошибки, нормальное завершение функция не реализована в текущей версии драйвера Обнаружен драйвер VDISK.SYS, с этим драйвером драйвер HIMEM.SYS несовместим Ошибка при работе с линией А20 Общая ошибка драйвера Катастрофическая ошибка драйвера Область НМА не существует Область НМА уже используется Содержимое регистра DX меньше параметра /HMAMIN- Область НМА не распределена программе Линия А20 все еще разблокирована Вся расширенная память уже распределена Больше нет свободных индексов ЕМВ Неправильный индекс ЕМВ Неправильный SourceHanale Неправильный SourceOffset Неправильный DestKandle Неправильный DcstOffset Неправильный Length Неразрешенное перекрытие данных при выполнении операции пересылки данных Произошла ошибка четности ЕМВ не заблокирован ЕМВ заблокирован Переполнение счетчика блокировок ЕМВ He удалось выполнить блокировку ЕМВ Доступен UMB меньшего размера Нет доступных блоков UMB Задан неправильный сегмент UMB |
3.5. Ограничения при использовании области нмa
К сожалению, на программы, использующие область НМА, накладываются значительные ограничения. Они связаны с тем, что MS-DOS версий 4.01 и более ранних, а также BIOS не были рассчитана на работу с адресами памяти выше границы 1 мегабайт. Приведем список этих ограничений.
• Нельзя передавать MS-DOS FAR-указатели на данные, размещенные в области НМА, т. к. функции MS-DOS проверяют правильность таких указателей.
• Не рекомендуется использование области НМА для выполнения обмена данных с диском через прерывания MS-DOS, BIOS или другими способами.
• Драйверы и резидентные программы, использующие область НМА, не должны держать линию А20 постоянно включенной, т. к. это может привести к неправильной работе программ, не рассчитанных на наличие и доступность этой области.
• Векторы прерываний не должны указывать в область НМА. Это результат предыдущего ограничения.
4. Примеры использования драйвера himem.Sys.
Данная программа копирует флоппи диск через расширенную память. Эта программа написана на Ассемблере:
.286
.MODEL TINY
JUMPS
S SEGMENT STACK
db 128 dup(?)
S ENDS
DATA SEGMENT
buffer db 32770 dup(0)
number_drive db 1
sectors dw 0
numb_s dw 0 ; номер копируемого сектора
handle dw 0
LengthBlock dd 32768
SourceHandle dw 0
SourceOffset dd 0
DestHandle dw 0
DestOffset dd 0
HMMEntryPt dd 0
all db "Всего : 0000 секторов",13,'$'
mess db 10,13,"Вставте следующий диск и нажмите любую клавишу",10,13,'$'
mess1 db "Ошибка при работе с линией A20 (82h) !",10,13,'$'
mess2 db "Вся расширенная память уже распределена!!!",10,13,'$'
mess3 db "Больше нет свободных блоков EMB.",10,13,'$'
mess4 db "Ошибка : Нет диска в дисководе.",10,13,'$'
mess5 db "Ошибка : Диск защищен от записи или нет диска в дисководе.",10,13,'$'
mess6 db "Копирование c дискеты",10,13,'$'
mess6_1 db "Запись на дискету",10,13,'$'
mess8 db "Драйвер himem.sys отсутствует",10,13,'$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:S
start:
mov bx,DATA
mov ds,bx
mov ah,09h
mov dx,offset mess7
int 21h
; считывание корневого сектора дискеты
mov al,number_drive
mov cx,1
mov dx,0
mov bx,offset buffer
int 25h
pop ax
jnb ok1
mov bl,01h
jmp Error
ok1: mov ax,word ptr [bx][13h]
mov sectors,ax
; проверка наличия himem.sys
mov ax,4300h
int 2fh
mov bl,0eeh
cmp al,80h
jne Error
mov ax,4310h
int 2Fh
mov word ptr [HMMEntryPt][0],bx ; получение адреса программы управления XMS
mov word ptr [HMMEntryPt][2],es
mov ah,05h ; локальное открывание линии A20
call HMMEntryPt
or ax,ax
jz Error
mov ah,09h ; запрос блока памяти
mov dx,1500d
call HMMEntryPt
or ax,ax
jz Error
mov handle,dx
; первоначальное заполнение таблицы для копирования
mov bx,offset buffer
mov word ptr SourceOffset[0],bx
mov word ptr SourceOffset[2],ds
mov bx,handle
mov DestHandle,bx
mov word ptr DestOffset[0],0
mov word ptr DestOffset[2],0
mov ah,09h
mov dx,offset mess6
int 21h
mov cx,45 ; кол-во секторов на диске
mov si,offset LengthBlock
next_sector:
; считывание группы секторов
mov al,number_drive
mov dx,numb_s
push cx
mov cx,64d
mov bx,offset buffer
int 25h
pop cx
pop cx
add numb_s,64d
; копирование блока памяти в EMB
mov ah,0Bh ;ф-ия 0B - копирование блока
call HMMEntryPt ;вызов драйвера
or ax,ax ;проверка на ошибку
jz Error ;если ошибка то переход на метку Error
call OutDec ;вызов процедуры OutDec
add word ptr DestOffset[0],32768d ;увеличение текущего смещения в EMB
adc word ptr Destoffset[2],0 ;прибавляем 32кб в первое слово
;и 0 - во второе
loop next_sector ;продолжение цикла
mov ah,09h ;вывод на экран сообщения
mov dx,offset mess ;"Вставьте следующий диск ..."
int 21h
mov ah,08h ; ожидание нажатия клавиши
int 21h
; первоначальное заполнение таблицы для копирования
mov numb_s,0
mov DestHandle,0
mov bx,offset buffer
mov word ptr DestOffset[0],bx
mov word ptr DestOffset[2],ds
mov bx,handle
mov SourceHandle,bx
mov word ptr SourceOffset[0],0
mov word ptr SourceOffset[2],0
mov cx,45 ; кол-во секторов на диске
mov ah,09h
mov dx,offset mess6_1
int 21h
mov si,offset LengthBlock
next_copy:
; копирование блока из EMB в память
mov ah,0Bh
call HMMEntryPt
or ax,ax
jz Error
add word ptr SourceOffset[0],32768d
adc word ptr SourceOffset[2],0
; запись группы секторов на диск
mov al,number_drive
mov dx,numb_s
push cx
mov cx,64
mov bx,offset buffer
int 26h
pop cx
jnb ok2
mov dx,offset mess5
mov ah,09h
int 21h
jmp err1
ok2: pop cx
add numb_s,64d
call OutDec
loop next_copy
err1:mov ah,0Ah ; освобождение блока памяти
mov dx,handle
call HMMEntryPt
or ax,ax
jz Error
mov ah,06h ; локальное закрывание линии A20
call HMMEntryPt
.EXIT
Error:
mov dx,offset mess8
cmp bl,0eeh
je print
mov dx,offset mess1 ; проблема с линией A20
cmp bl,82h
je print
mov dx,offset mess2 ; вся XMS распределена
cmp bl,0A0h
je print
mov dx,offset mess3 ; больше нет свободных блоков EMB
cmp bl,0A1h
je print
mov dx,offset mess4 ; нет диска в дисководе
cmp bl,01h
je print
print:
mov ah,09h
int 21h
.EXIT
; вывод результатов копирования(записи) в процентах
OutDec proc near
mov dx,0
mov bx,10
mov ax,numb_s
div bx
mov bx,offset all
add dl,30h
mov byte ptr [bx][11d],dl
mov dx,0
mov bx,10
div bx
mov bx,offset all
add dl,30h
mov byte ptr [bx][10d],dl
mov dx,0
mov bx,10
div bx
mov bx,offset all
add dl,30h
mov byte ptr [bx][9],dl
mov dx,0
mov bx,10
div bx
mov bx,offset all
add dl,30h
mov byte ptr [bx][8],dl
mov dx,offset all
mov ah,09h
int 21h
ret
OutDec endp
CODE ENDS
END start
В следующем примере приводится программа, выполняющая тоже действие ,но написанная на языке Си с подключением Ассемблерного модуля:
Файл Dcopy.cpp:
#include <bios.h>
#include <conio.h>
#include <ctype.h>
#include <dos.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define LOBYTE(w) ((unsigned char)(w))
#define HIBYTE(w) ((unsigned char)(((unsigned int)(w) >> 8) & 0xFF))
typedef unsigned char byte;
typedef unsigned int word;
typedef unsigned long dword;
extern "C"
{
word XMM_InitDriver(void);
word XMM_AllocMem(word, word *);
word XMM_FreeMem(word);
word XMM_EnableA20(void);
word XMM_DisableA20(void);
word XMM_GetMaxFree(void);
word XMM_GetTotalFree(void);
word XMM_MoveToCMA(void *, word, dword, dword);
word XMM_MoveToXMA(void *, word, dword, dword);
}
extern byte err_code;
struct diskinfo_t dinfo;
byte BPB[512];
word heads, tracks, sectors, capacity, tr_size,
ret, maxblk, handle;
bool CMA_allocated = false, XMA_allocated = false, A20_enabled = false;
void ErrMsg(const char *);
void fail(const char *);
void FreeMemory();
byte GetDriveType(int);
void GetHelp();
int c_break()
{
FreeMemory();
puts("Операция не завершена!");
return 0;
}
void main(int argc, char *argv[])
{
int err, xpos, ypos;
char disk;
dword count;
if (argc < 2)
{ GetHelp(); exit(1); }
disk = toupper(argv[1][0]);
if (disk != 'A' && disk != 'B')
{ GetHelp(); exit(1); }
ctrlbrk(c_break);
ret = XMM_InitDriver();
if (!ret)
fail("Драйвер XMS не найден.");
maxblk = XMM_GetMaxFree();
dinfo.drive = disk - 'A';
// определяем параметры дискеты
do
{
printf("Вставьте первую дискету в дисковод %c: "
"и нажмите любую клавишу...\n", disk);
bioskey(0);
err = absread(dinfo.drive, 1, 0, (void *)BPB);
if (err)
if (LOBYTE(errno) == 2)
puts("Устройство не готово.");
else
fail("Неизвестная ошибка");
} while (err);
heads = BPB[0x1a] + (BPB[0x1b] << 8); // число головок
sectors = BPB[0x18] + (BPB[0x19] << 8); // число секторов на дорожке
capacity = BPB[0x13] + (BPB[0x14] << 8); // общее число секторов
tracks = capacity / sectors / heads; // число дорожек на стороне
if (BPB[0x0b] + (BPB[0x0c] << 8) != 512)
fail("Дискета имеет нестандартный размер сектора");
capacity /= 2; tr_size = sectors * 512;
printf("Дискета в дисководе %c: ", disk);
if (GetDriveType(dinfo.drive) < 3)
printf("5.25\"");
else
printf("3.5\"");
printf(" имеет емкость ");
if (capacity < 1024)
printf("%g Кб.\n", float(capacity));
else
printf("%g Мб.\n", float(capacity) / 1000);
printf("Наибольший свободный блок расширенной памяти "
"имеет размер ");
if (maxblk < 1024)
printf("%g Кб.\n", float(maxblk));
else
printf("%g Мб.\n", float(maxblk) / 1000);
if (capacity > maxblk)
fail("Копирование невозможно.");
// выделение памяти
dinfo.buffer = (void far *)malloc(tr_size);
if (!dinfo.buffer)
fail("Недостаточно стандартной памяти");
CMA_allocated = true;
ret = XMM_EnableA20();
if (!ret) ErrMsg("Ошибка при включении линии A20: ");
A20_enabled = true;
ret = XMM_AllocMem(capacity, &handle);
if (!ret) ErrMsg("Ошибка при выделении XMS-памяти: ");
XMA_allocated = true;
// чтение дискеты
printf("Идет чтение дискеты... ");
xpos = wherex(), ypos = wherey();
count = 0;
dinfo.sector = 1; dinfo.nsectors = sectors;
for (word head = 0; head < heads; head++)
{
dinfo.head = head;
for (word track = 0; track < tracks; track++)
{
dinfo.track = track;
ret = _bios_disk(_DISK_READ, &dinfo);
if (HIBYTE(ret))
fail("\nОшибка чтения");
gotoxy(xpos, ypos);
printf("%d%%", int(count * 100 / (tracks * heads - 1)));
ret = XMM_MoveToXMA((void near *)dinfo.buffer, handle,
tr_size * count, tr_size);
if (!ret) ErrMsg("\nОшибка при записи в XMS-память: ");
count++;
}
}
puts("");
// запись дискеты
do
{
printf("Вставьте вторую дискету в дисковод %c: "
"и нажмите любую клавишу...\n", disk);
bioskey(0);
err = abswrite(dinfo.drive, 1, 0, (void *)BPB);
if (err)
if (LOBYTE(errno) == 2)
puts("Устройство не готово.");
else if (LOBYTE(errno) == 0)
puts("Дискета защищена от записи.");
else
fail("Неизвестная ошибка");
} while (err);
printf("Идет запись дискеты... ");
xpos = wherex(), ypos = wherey();
count = 0;
dinfo.sector = 1; dinfo.nsectors = sectors;
for (word head = 0; head < heads; head++)
{
dinfo.head = head;
for (word track = 0; track < tracks; track++)
{
dinfo.track = track;
ret = XMM_MoveToCMA((void near *)dinfo.buffer, handle,
tr_size * count, tr_size);
if (!ret) ErrMsg("\nОшибка при чтении из XMS-памяти: ");
ret = _bios_disk(_DISK_WRITE, &dinfo);
if (HIBYTE(ret))
fail("\nОшибка записи");
gotoxy(xpos, ypos);
printf("%d%%", int(count * 100 / (tracks * heads - 1)));
count++;
}
}
puts("\nДискета скопирована");
// освобождение памяти
FreeMemory();
}
void ErrMsg(const char *msg)
{
printf(msg);
switch (err_code)
{
case 0x80:
fail("данная служба не поддерживается");
break;
case 0x82:
fail("сбой линии A20");
break;
case 0xA0:
fail("вся расширенная память использована");
break;
case 0xA1:
fail("свободные дескрипторы отсутствуют");
break;
case 0xA2:
fail("неверный дескриптор блока");
break;
case 0xA3:
fail("неверный дескриптор источника");
break;
case 0xA4:
fail("неверное смещение источника");
break;
case 0xA5:
fail("неверный дескриптор адреса назначения");
break;
case 0xA6:
fail("неверное смещение адреса назначения");
break;
case 0xA7:
fail("неверная длина блока");
break;
default:
printf("Ошибка номер %02xh", int(err_code));
fail("");
}
}
void fail(const char *s)
{
puts(s);
FreeMemory();
exit(1);
}
void FreeMemory()
{
if (CMA_allocated)
{
CMA_allocated = false;
free((void near *)dinfo.buffer);
}
if (XMA_allocated)
{
XMA_allocated = false;
ret = XMM_FreeMem(handle);
if (!ret) ErrMsg("Ошибка при освобождении XMS-памяти: ");
}
if (A20_enabled)
{
A20_enabled = false;
ret = XMM_DisableA20();
if (!ret) ErrMsg("Ошибка при включении линии A20: ");
}
}
byte GetDriveType(int drive)
{
_AH = 0x08; _DL = drive;
geninterrupt(0x13);
return _BL;
}
void GetHelp()
{
puts("Формат: dcopy имя_диска");
}
Файл Xms.asm (Процедуры для работы с расширенной памятью):
.MODEL SMALL, C
.386
PUBLIC XMM_InitDriver, XMM_GetMaxFree, XMM_GetTotalFree, \
XMM_AllocMem, XMM_FreeMem, XMM_MoveToXMA, XMM_MoveToCMA, \
XMM_EnableA20, XMM_DisableA20
PUBLIC err_code
.DATA
ver dw 0 ; Версия драйвера himem.sys
XMS dd ? ; Адрес функции управления драйвером
err_code db ? ; Код последней ошибки
MemMoveStruct struc
Length dd ? ; 32-битовое число пересылаемых байтов
SourceHandle dw ? ; дескриптор блока источника
SourceOffset dd ? ; 32-битовое смещение в источнике
DestHandle dw ? ; дескриптор блока назначения
DestOffset dd ? ; 32-битовое смещение в блоке назначения
MemMoveStruct ends
mem_str MemMoveStruct ?
.CODE
; Инициализация himem.sys. Возвращает версию драйвера.
XMM_InitDriver proc C
; Проверка наличия драйвера himem.sys
mov ax, 4300h
int 2Fh
cmp al, 80h
jne not_avail
; Получение адреса функции управления драйвером
mov ax, 4310h
int 2Fh
mov word ptr [XMS], bx
mov word ptr [XMS+2], es
; Получение версии драйвера
mov ah, 00h
call [XMS]
mov ver, ax
ret
not_avail:
mov ver, 0
ret
XMM_InitDriver endp
; Выделить блок расширенной памяти размером size
; Передается размер блока в Кб и указатель на word (для дескриптора)
XMM_AllocMem proc C size: word, handle: near ptr word
mov ah, 09h
mov dx, size
call XMM_Functions
mov bx, handle
mov [bx], dx
ret
XMM_AllocMem endp
; Освободить блок расширеннной памяти
XMM_FreeMem proc C handle: word
mov ah, 0ah
mov dx, handle
call XMM_Functions
ret
XMM_FreeMem endp
; Получить размер наибольшего свободного блока XMA
XMM_GetMaxFree proc C
mov ah, 08h
call XMM_Functions
ret
XMM_GetMaxFree endp
; Включить линию A20 локально
XMM_EnableA20 proc C
mov ah, 05h
call XMM_Functions
ret
XMM_EnableA20 endp
; Выключить линию A20 локально
XMM_DisableA20 proc C
mov ah, 06h
call XMM_Functions
ret
XMM_DisableA20 endp
; Переместить блок из стандартной памяти в расширенную
XMM_MoveToXMA proc C uses si, \
addr: near ptr, handle: word, offs: dword, len: dword
mov [mem_str.SourceHandle], 0
mov ax, addr
mov word ptr [mem_str.SourceOffset], ax
mov ax, ds
mov word ptr [mem_str.SourceOffset+2], ax
mov ax, handle
mov [mem_str.DestHandle], ax
mov eax, offs
mov [mem_str.DestOffset], eax
mov eax, len
mov [mem_str.Length], eax
mov si, offset mem_str
mov ah, 0bh
call XMM_Functions
ret
XMM_MoveToXMA endp
; Переместить блок из расширенной памяти в стандартную
XMM_MoveToCMA proc C uses si, \
addr: near ptr, handle: word, offs: dword, len: dword
mov [mem_str.DestHandle], 0
mov ax, addr
mov word ptr [mem_str.DestOffset], ax
mov ax, ds
mov word ptr [mem_str.DestOffset+2], ax
mov ax, handle
mov [mem_str.SourceHandle], ax
mov eax, offs
mov [mem_str.SourceOffset], eax
mov eax, len
mov [mem_str.Length], eax
mov si, offset mem_str
mov ah, 0bh
call XMM_Functions
ret
XMM_MoveToCMA endp
; Получить общее количество свободной памяти XMA
XMM_GetTotalFree proc C
mov ah, 08h
call XMM_Functions
mov ax, dx
ret
XMM_GetTotalFree endp
; Вызов функций драйвера
XMM_Functions proc
cmp ver, 0 ; Драйвер не инициализирован
je err1
call [XMS]
cmp ax, 0 ; Проверка на ошибку
jne q1
test bl, 10000000b
jne q1
err1:
mov ax, 0
q1:
mov err_code, bl
ret
XMM_Functions endp
end