Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб_01 (XMS) Управление XMA.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
423.94 Кб
Скачать

Освободить область 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