Исследование памяти ПЭВМ.
изучение приемов работы с расширенной памятью в MS DOS
Теоретическое описание:
Использование драйвера HIMEM.SYS для программирования.
Спецификация XMS содержит описание программного интерфейса
драйвера HIMEM.SYS и рекомендации по использованию области памяти
НМА.
Проверка подключения драйвера.
Первое, что должна сделать программа, которая собирается вызывать
драйвер HIMEM.SYS, - проверить, был ли установлен этот драйвер при
загрузке операционной системы.
Для этого надо загрузить в регистр АХ значение 4300h и вызвать
прерывание INT 2Fh. Если регистр AL будет содержать значение 80h,
драйвер установлен, в противном случае - нет. Приведем фрагмент
программы, проверяющей подключение драйвера:
Проверяем, установлен ли драйвер HIMEM.SYS:
mov ax. 4300h
int 2fh
cmp aI, 80h
je hmm_installed; Выполняем переход, если драйвер установлен.
Получение адреса управляющей программы.
Для вызова драйвера программа должна получить адрес специальной
управляющей программы, которая выполняет все функции по обслуживанию
расширенной памяти и области НМА.
Этот адрес можно получить, если загрузить в регистр АХ значение
4310h и вызвать прерывание INT 2Fh. Прерывание возвратит адрес управляющей
программы в регистре ES, смещение - в регистре ВХ:
Получаем адрес управляющей функции драйвера
mov ax, 4310h
int 2fh
mov word ptr cs:[HMMEntry][0]. bx
mov word ptr cs : [HMMEntry][2], es
В дальнейшем полученный адрес используется для выполнения
функций по обслуживанию расширенной памяти. Программы, которые
обращаются к управляющей функции, должны перед вызовом функции
иметь размер стека не менее 256 байтов.
Описание функции драйвера HIMEM.SYS
Все функции драйвера HIMEM.SYS могут быть разделены на следующие
пять групп:
- функции получения информации о драйвере (0h);
- функции управления областью НМА (lh, 2h);
- функции управления линией А20 (3h...7h);
- функции управления расширенной памятью (8h,.Fh);
- функции управления блоками UMB (10h,.llh).
Приведем подробное описание этих функций в соответствии со
спецификацией XMS версии 2.0.
В программе использовались приведённые ниже функции драйвера
Himem.sys
Определение размера свободной расширенной памяти:
На входе: AH = 08h.
На выходе: AX = размер наибольшего свободного блока
расширенной памяти в килобайтах;
DX = общий размер свободной расширенной памяти в
килобайтах.
Ошибки: BL = 80h, 81h, AOh.
При определении размера свободной расширенной памяти в
возвращаемое значение не включается 64 килобайта области НМА, даже
если эта область не используется программами.
Получить блок ЕМВ
На входе: AH = 09h.
DX = размер требуемого блока в килобайтах.
На выходе: AX = 000lh - если функция выполнена успешно,
0000h - если произо
1e82
шла ошибка;
DX = 16-битовый индекс (handle) полученного блока ЕМВ.
Ошибки: BL = 80h, 81h, AOh, Alh.
Функция заказывает блок ЕМВ из пула свободной расширенной памяти.
При успешном выполнении запроса функция возвращает индекс
полученного блока, который должен использоваться программой для
выполнения всех операций с блоком ЕМВ. Если блок ЕМВ программе
больше не нужен, она должна освободить его с помощью функции OAh.
Количество блоков ЕМВ, которое может быть заказано, определяется в
командной строке драйвера H1MEM.SYS параметром /NUMHANDLES=.
Значение по умолчанию - 32, максимальное значение - 128.
Освободить блок ЕМВ
На входе: AH = 0Ah.
DX = 16-битовый индекс (handle) полученного блока EMB.
На выходе: AX = 000lh - если функция выполнена успешно,
0000h - если произошла ошибка.
Ошибки: BL = 80h, 81h, A2h, B2h.
Функция освобождает блок ЕМВ, заказанный предыдущей функцией. При
этом все данные, находившиеся в блоке, будут потеряны.
Копирование блоков ЕМВ
На входе: АН = Bh.
DS:SI = указатель на управляющую структуру, определяющую,
откуда, куда и как будет выполняться копирование.
На выходе: АХ = 000lh - если функция выполнена
успешно, 0000h - если произошла ошибка.
Ошибки: BL = 80h, 81h, 82h, A3h, A4h, A5h, A6h, A7h, A8h, A9h.
Управляющая структура:
ExtMemMoveStruct struct
Length dd ? ; количество посылаемых байтов
SourceHandle dw ? ; индекс исходного блока
SourceOffset dd ? ; смешение в исходном блоке
DestHandle dw ?; индекс блока назначения
DestOf-fset dd ? ; смещение блока назначения
ExtMemMoveStruct ends
Эта функция выполняет основную операцию с блоками ЕМВ -
копирование данных. Данные могут пересылаться между обычной
памятью и блоками ЕМВ, между различными блоками ЕМВ и даже внутри
обычной памяти.
Поле Length управляющей структуры указывает количество
пересылаемых байтов. Это количество должно быть четным.
Поля SourceHandle и DestHandle указывают соответственно
индексы исходного и результирующего блоков ЕМВ. Если в качестве
индекса задано значение 0000h, это означает, что в качестве
источника или приемника данных используется обычная память.
Поля SourceOffset и DestOffset указывают 32-битовое смещение в
блоке ЕМВ или адрес в обычной памяти. В последнем случае этот
адрес имеет стандартный формат сегмент: смещение.
Функция копирования сама управляет линией А20, восстанавливая ее
состояние после выполнения копирования. Поэтому программе не
требуется управлять линией А20.
Во время выполнения копирования разрешены прерывания.
Исходный текст программы:
Код на ASM .286 .model small .data buf db 32770 dup(0) ndrv db 0 sec dw 0 nsec dw 0 handle dw 0 LenBlk dd 32768 SrcHdl dw 0 SrcOff dd 0 DstHdl dw 0 DstOff dd 0 HMMEntry dd 0 mes1 db 'Программа копирование floppy дисков', 10, 13, '$' mes2 db 'Драйвер himem.sys не установлен!', 10, 13, '$' mes3 db 'Ошибка обращения к диску!', 10, 13, '$' mes4 db 'Ошибка при работе с линией А20!', 10, 13, '$' mes5 db 'Нет свободной памяти!', 10, 13, '$' mes6 db 'Копируется диск исходник...', 10, 13, '$' mes7 db 'Ошибка при работе с расширенной памятью!', 10, 13, '$' mes8 db 'Вставьте диск приемник...', 10, 13, '$' mes9 db 'Идет запись на диск...', 10, 13, '$' mes10 db 'Ошибка при записи диска!', 10, 13, '$' mes11 db '000% $' mes12 db 'прочитано', 13, '$' mes13 db 'записано', 13, '$' mes99 db 'Диск успешно скопирован!', 10, 13, '$' mes14 db '', 10, 13, '$' .code start: mov ax, @data mov ds, ax ; проверка наличия himem.sys mov ax, 4300h int 2fh cmp al, 80h je s1 mov dx, offset mes2 ;Драйвер himem.sys не установлен jmp error ; получение адреса программы управления XMS s1: mov ax, 4310h int 2fh mov word ptr [HMMEntry][0], bx mov word ptr [HMMEntry][2], es ; считывание корневого сектора дискеты mov al, ndrv mov cx, 1 xor dx, dx mov bx, offset buf int 25h pop ax jnb s2 mov dx, offset mes3 ;Ошибка обращения к диску jmp error s2: mov ax, word ptr [bx][13h] mov sec, ax ; локальное открывание линии A20 mov ah, 05h call HMMEntry or ax, ax jnz s3 mov dx, offset mes4 ;Ошибка при работе с линией А20 jmp error s3: mov ah, 08h call HMMEntry cmp ax, 1500 jae s4 mov dx, offset mes5 ;Нет свободной памяти jmp error ; запрос блока памяти s4: mov ah, 09h mov dx, 1500 call HMMEntry or ax, ax jnz s5 mov dx, offset mes5 ;Нет свободной памяти jmp error ; первоначальное заполнение таблицы для копирования s5: mov handle, dx mov bx, offset buf mov word ptr SrcOff[0], bx mov word ptr SrcOff[2], ds mov bx, handle mov DstHdl, bx mov word ptr DstOff[0], 0 mov word ptr DstOff[2], 0 mov dx, offset mes6 ;Копируется диск исходник... mov ah, 09h int 21h mov si, offset LenBlk xor cx, cx ; считывание группы секторов nexts: push cx mov al, ndrv mov dx, nsec mov cx, 64 mov bx, offset buf int 25h pop ax jnc s6 mov dx, offset mes3 ;Ошибка обращения к диску jmp err1 ; копирование блока памяти в EMB s6: mov dx, offset mes12 ;прочитано call OutPer add nsec, 64 mov ah, 0bh ;ф-ия 0B - копирование блока call HMMEntry ;вызов драйвера or ax, ax ;проверка на ошибку jnz s7 mov dx, offset mes7 ;Ошибка при работе с расширенной памятью jmp err1 s7: add word ptr DstOff[0], 32768 ;увеличение текущего смещения в EMB adc word ptr DstOff[2], 0 ;прибавляем 32кб в первое слово и 0 - во второе pop cx add cx, 64 cmp cx, sec jne nexts mov ah, 09h ;вывод на экран сообщения mov dx, offset mes8 ;Вставьте диск приемник int 21h ; ожидание нажатия клавиши mov ah, 08h int 21h mov nsec, 0 mov DstHdl, 0 mov bx, offset buf mov word ptr DstOff[0], bx mov word ptr DstOff[2], ds mov bx, handle mov SrcHdl, bx mov word ptr SrcOff[0], 0 mov word ptr SrcOff[2], 0 mov ah, 09h mov dx, offset mes9 ;Идет запись на диск int 21h mov si, offset LenBlk ;32768 xor cx, cx ; копирование блока из EMB в память nextc: mov ah, 0bh call HMMEntry or ax, ax jnz s8 mov dx, offset mes7 ;Ошибка при работе с расширенной памятью jmp err1 s8: add word ptr SrcOff[0], 32768 adc word ptr SrcOff[2], 0 push cx ; запись группы секторов на диск mov al, ndrv mov dx, nsec mov cx, 64 mov bx, offset buf int 26h pop ax jnc s9 mov dx, offset mes10 ;Ошибка при записи диска jmp err1 s9: mov dx, offset mes13 ;записано call OutPer add nsec, 64 pop cx add cx, 64 cmp cx, sec jne nextc mov dx, offset mes99 ;Диск успешно скопирован err1: push dx ; освобождение блока памяти mov ah, 0ah mov dx, handle call HMMEntry pop dx or ax, ax jnz s10 mov dx, offset mes7 ;Ошибка при работе с расширенной памятью jmp error s10: mov ah, 06h ; локальное закрывание линии A20 call HMMEntry error: mov ah, 09h int 21h mov ax, 4c00h int 21h ; вывод результатов копирования(записи) в процентах OutPer proc near pusha mov ax, sec mov bl, 100 div bl mov bl, al mov ax, nsec div bl mov cx, 3 mov di, 2 mov bx, offset mes11 ;000% mov dl, 10 o10: xor ah, ah div dl add ah, 30h mov byte ptr [bx][di], ah dec di loop o10 mov ah, 09h mov dx, offset mes11 ;000% int 21h popa mov ah, 09h int 21h ret OutPer endp .stack db 100h dup(?) end start
Копирование всех файлов дискеты в память
Код на C++ #include <iostream.h> #include <dos.h> #include <sys\stat.h> #include <fcntl.h> #include <io.h> #include <stdio.h> #include <conio.h> #include <windows.h> #define MEGA_BYTE 1048576 unsigned long i=0; // счетчик считанных байтов unsigned long sum=0; //контрольная сумма //возвращает сумму байтов в массиве unsigned long SumByte(char *p,unsigned long i) { unsigned long s=0; p--; for(unsigned long j=i;j>0;j--,p--) { unsigned int b=*p; s+=b; } return s; } //копируе файл в память по заданному адресу char *CopyFileInMem(char *p,char *name,unsigned long size) { FILE *in; int handle; if ((handle = open(name, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1) { printf("Error Opening File\n"); exit(1); } //выделяем зарезервировнную область VirtualAlloc(p,size,MEM_COMMIT,PAGE_READWRITE); int s=read(handle,p,size);//считываем весь файл в буфер p+=s; i+=s; close(handle); return p; } //копирует всю дискету в память по заданному адресу char *CopyA_InMem(char *p) { struct ffblk ffblk;//структура найденого файла в текущем каталоге if(findfirst("*.*",&ffblk,16)==-1)return p; if(strcmp(ffblk.ff_name,".")!=0&&strcmp(ffblk.ff_name,"..")) if(!(ffblk.ff_attrib&FA_DIREC)) { //если это файл то копируем его в память p=CopyFileInMem(p,ffblk.ff_name,ffblk.ff_fsize); } else { //если это каталог то меняем директорию chdir(ffblk.ff_name); p=CopyA_InMem(p); //возврат в предыдущий каталог chdir(".."); } while(findnext(&ffblk)!=-1) if(strcmp(ffblk.ff_name,".")!=0&&strcmp(ffblk.ff_name,"..")) if(!(ffblk.ff_attrib&FA_DIREC)) { p=CopyFileInMem(p,ffblk.ff_name,ffblk.ff_fsize); } else { chdir(ffblk.ff_name); p=CopyA_InMem(p); chdir(".."); } return p; } //--------------------------------------------------------------------------- #pragma argsused int main(int argc, char **argv) { //резервирование памяти в 30 мегабайт для чтения и записи char *p=(char *)VirtualAlloc(NULL,30*MEGA_BYTE,MEM_RESERVE,PAGE_READWRITE); char C; cout<<"Input first disk (Yes/No):"; C=getch(); fputc(C,stdout); int j=2; if(C=='y') do{ setdisk(0); p=CopyA_InMem(p); //предлагается вставить следующую дискету cout<<"\nInput next disk "<<j<<"(Yes/No):"; C=getch(); fputc(C,stdout); j++; }while(C=='y'&&j<20); sum=SumByte(p,i);//конторольная сумма считанных байт //освобождаем память VirtualFree(p,30*MEGA_BYTE,MEM_DECOMMIT); cout<<"\nControl sum:"<<sum<<" i="<<i; getch(); return 0; }
|