Драйвер виртуального диска



                         Создание загрузочного файла
                             драйвера устройства


      В листинге 1 представлен  диалог  с  системой  при  создании  драйвера
"DRIVER". Этот файл ассемблируется и линкуется как обычная программа,  после
чего преобразуется в двоичный .SYS файл. Замечу, что  отсутствие  стека  для
драйвера  является  нормальным  явлением,  так  как   драйвер   при   работе
использует собственный стек MS-DOS.
      В примере,  приведенном  в  листинге  6-4,  создается  также  выходной
.LST  файл  ассемблера и выходной .MAP файл редактора  связей.  Конечно  же,
.OBJ и .EXE файлы могут быть удалены после создания .SYS файла.



                                 Листинг 1.
                     Процесс создания простого драйвера.


         C> masm driver,driver,driver;

         Microsoft Macro Assembler Version 4.00
         Copyright Microsoft Corp 1981, 1983, 1984, 1985.
         All rights reserved.

           45976 Bytes symbol space free

              0 Warning Errors
              0 severe  Errors

         C> link driver,driver,driver;

         Microsoft 8086 Object linker
         Version 3.00 Copyright Microsoft Corp 1983, 1984, 1985

         Warning: no stack segment

         C> exe2bin driver driver.sys


                        Драйвер виртуального диска


       В  листинге  2  приведен  пример  драйвера   RAM-диска   -   драйвера
виртуального диска, размещаемого в ОЗУ. Несмотря на свою простоту,   драйвер
работоспособен и может быть использован на любой  MS-DOS  системе начиная  с
версии 2.0 и выше. Данный драйвер RAM-диска, использует 360 Kбайт  системной
памяти   для   эмуляции  стандартного  пятидюймового  дисковода.    Но   при
использовании этого драйвера, система ПК должна иметь по крайней   мере  512
Kбайт памяти. Если имеется меньше памяти или нужно просто иметь  виртуальный
диск меньших  размеров,   то  можно   изменить  принимаемые   по   умолчанию
параметры,  описаные в секции драйвера "Описание RAM-диска".


      После того, как программа была  обработана  ассемблером  и  редактором
связей, надо переименовать ее в RDISK.SYS.  И  добавить  в  файл  CONFIG.SYS
командную строку :

                DEVICE=RDISK.SYS

      При первой  же  перезагрузке  драйвер  будет  установлен  как  драйвер
следующего по порядку дисковода. Ничего более для установки  драйвера  RDISK
не требуется.
            Доступ к RAM-диску возможен с помощью любых функций  MS-DOS  или
программ,  за исключением команд DISKCOPY  и  DISKCOMP.  Обе  эти  программы
 ожидают  определенные  типы  дисков  и  не  работают с RAM-дисками.



                                 Листинг 2.
                      Исходный текст драйвера RAM-диска



     PAGE 60,132
; *** RDISK.ASM : MS-DOS ДРАЙВЕР RAM-ДИСКА ***
     ;
     ; Этот файл содержит исходный текст простого MS-DOS драйвера RAM-диска
     ; эмулирующего 360K флоппи-диск.
     ;
     ; В этом примере демонстрируются основные принципы построения драйвера
     ; устройств, включая один из методов, который можно использовать для
     ; отладки драйверов. Для установки этого драйвера включите в файл
     ; CONFIG.SYS строку "DEVICE=RDISK.SYS"
     ;
     ; ======== ВСПОМОГАТЕЛЬНЫЕ ФАЙЛЫ ДЛЯ ДРАЙВЕРА =====
     ;
     INCLUDE driver.inc                     ; Константы для MS-DOS драйвера
     IFDEF   DEBUG
     INCLUDE biosio.inc                     ; Определения для отладки
     ENDIF
     ;
     ; ============ КОНСТАНТЫ ========================
     ;
     ; Ограничения,накладываемые версией MS-DOS на максимальный код команды
     ;
     CMD_PRE_30               EQU      00Ch  ;  до MS-DOS версии 3.00
     CMD_PRE_32               EQU      00Fh  ;  до MS-DOS версии 3.20
     CMD_32                   EQU      018h  ;  начиная с версии 3.20
     ;
     IFDEF           DEBUG
     CR                       EQU      0Ah   ; используются в отладочных
     LF                       EQU      0Dh   ;   сообщениях
     ENDIF
     ;
     PAGE
     ;
     ; ============ ШАБЛОНЫ СТРУКТУР ==============
     ;
     request         EQU      es:[di]        ; указатель на блок запроса
     ;
     ; Структура заголовка запроса
     ;
     reqhdr          STRUC
                     rlength  db      ?              ; размер блока запроса
                     unit     db      ?              ; номер устройства
                     command  db      ?              ; код команды
                     status   dw      ?              ; возвращаемый статус
                              db      8 DUP (?)      ; зарезервировано
     reghdr          ENDS
     ;
     ; Структура блока запроса для команды INIT
     ;
     inithdr         STRUC
                              db      (type reqhdr) DUP (?)
                     units    db      ?              ; количество устройств
                     endadro  dw      ?              ; смещение и сегмент
                     endadrs  dw      ?              ;   адреса завершения
                     bpbtabo  dw      ?              ; смещение и сегмент
                     bpbtabs  dw      ?              ;   таблицы BPB
                     devnum   db      ?              ; номер устройства
     inithdr         ENDS
     ;
     ; Структура блока запроса для команды MEDIA CHECK
     ;
     mchkhdr         STRUC
                              db       (type reqhdr) DUP (?)
                     mbd      db      ?             ; описатель носителя
                     chande   dw      ?             ; статус замены
                     volume   dd      ?             ; указатель на имя тома
     mchkhdr         ENDS
     ;
     ; Структура блока запроса для команды BUILD BPB
     ;
     bpbhdr          STRUC
                              db       (type reqhdr) DUP (?)
                              db      ?              ; описатель носителя
                              dd      ?              ; указатель на FAT
                     bpbptro  dw      ?              ; смещение BPB
                     bpbptrs  dw      ?              ; сегмент BPB
     bpbhdr          ENDS
     ;
     ; Структура блока запроса для команд чтения/записи
     ;
     iohdr           STRUC
                              db       (type reqhdr) DUP(?)
                              db      ?             ; описатель носителя
                     bufprt   dd      ?             ; адрес буфера
                     count    dw      ?             ; кол-во байт/секторов
                     start    dw      ?             ; # начального сектора
                     nuvol    dd      ?             ; адрес нов. имени тома
     iohdr           ENDS
     ;
     ; Структура блока параметров BIOS (BPB)
     ;
     bpbstrc         STRUC
                     bps      dw      ?      ; количество байтов в секторе
                     spau     db      ?      ; кол-во секторов в кластере
                     nrs      dw      ?      ; кол-во зарезервир. секторов
                     nft      db      ?      ; количество копий FAT
                     nde      dw      ?      ; кол-во элементов директория
                     nls      dw      ?      ; кол-во логических секторов
                     md       db      ?      ; байт описателя носителя
                     nfs      dw      ?      ; размер FAT в секторах
     bpbstrc         ENDS
     ;
     PAGE
     ;
     ; ============= НАЧАЛО КОДА ДРАЙВЕРА ================
     ;
     _TEXT           SEGMENT  BYTE    PUBLIC 'CODE'
                     ASSUME   CS:_TEXT, DS:_TEXT, ES:NOTHING
                     ORG      0
     ORIGIN          EQU      $
     ;
     ; ============= ЗАГОЛОВОК ДРАЙВЕРА ==============
     ;
                     dw       -1,-1          ; указатель на след. драйвер
                     dw       AT_IOCTL OR AT_OCRM OR AT_NET
                     dw       offset STRATEGRY       ; смещение СТРАТЕГИЙ
                     dw       offset ПРЕРЫВАНИЙ       ; смещение ПРЕРЫВАНИЙ
                     db       1,'CDEVICE'            ; кол-во устройств/имя
     ;
     ; ======= ТАБЛИЦА АДРЕСОВ ОБРАБОТЧИКОВ КОМАНД ======
     ;
     JUMPTAB        LABEL   WORD
                    dw      offset INIT             ; 0 - инициализация
                    dw      offset MEDIA_CHECK      ; 1 - проверка носителя
                    dw      offset BUILD_BPB        ; 2 - построить BPB
                    dw      offset IOCTL_INPUT      ; 3 - IOCTL ввод
                    dw      offset READ             ; 4 - ввод из устр-ва
                    dw      offset READ_NOWAIT      ; 5 - неразруш. ввод
                    dw      offset INPUT_STATUS     ; 6 - ввод статуса
                    dw      offset INPUT_FLUSH      ; 7 - сбросить ввод
                    dw      offset WRITE            ; 8 - вывод на устр-во
                    dw      offset WRITE_VERIFY     ; 9 - вывод с проверкой
                    dw      offset OUTPUT_STATUS    ; A - вывод статуса
                    dw      offset OUTPUT_FLUSH     ; B - сбросить вывод
                    dw      offset IOCTL_OUTPUT     ; C - вывод IOCTL
                    dw      offset DEVICE_OPEN      ; D - открыть устр-во
                    dw      offset DEVICE_CLOSE     ; E - закрыть устр-во
                    dw      offset REMOVABLE        ; F - носитель сменный?
                    dw      offset NO_COMMAND       ; 10
                    dw      offset NO_COMMAND       ; 11
                    dw      offset NO_COMMAND       ; 12
                    dw      offset GENERIC_IOCTL    ; 13 - Generic IOCTL
                    dw      offset NO_COMMAND       ; 14
                    dw      offset NO_COMMAND       ; 15
                    dw      offset NO_COMMAND       ; 16
                    dw      offset GET_LOGICAL      ; 17 - получить/устано-
                    dw      offset SET_LOGICAL      ; 18 - вить лог.устр-во
     ;
     ; ============ ОБЛАСТЬ ДАННЫХ ДРАЙВЕРА ==============
     ;
     reg_ptr        dd       ?               ; адрес блока запроса
     max_cmd        db       CMD_PRE_30      ; максимально допустимый код
     ;                                       ;   команды
     save_ss        dw       ?               ; значение SS на входе
     save_sp        dw       ?               ; значение SP на входе
     ;
     PAGE
     ;
     ; ============ ПРОГРАММА СТРАТЕГИЙ =============
     ;
     STRATEGY                PROC    FAR
                    mov     cs:word ptr [reg_ptr],bx
                    mov     cs:word ptr [reg_ptr+2],es
                    ret
     strategy               ENDP
     ;
     ; ============ ПРОГРАММА ПРЕРЫВАНИЙ ===============
     ;
     INTERRUPT               PROC     FAR
                    push    ax               ; сохранить все рабочие
                    push    cx               ;   регистры
                    push    dx
                    push    bx
                    push    bp
                    push    si
                    push    di
                    push    ds
                    push    es
     ;
                    push    cs               ; определим локальный сегмент
                    pop     ds               ;   данных
     ;
                    mov     word ptr save_ss,ss      ; сохраним входное
                    mov     word ptr save_sp,sp      ; значение SS и SP
     ;
                    mov     bx,cs                    ; установим локальный
                    mov     ax,offset local_stack - 2        ; стек
                    mov     ss,bx
                    mov     sp,ax
     ;
                    les     di,[req_ptr]             ; получить адрес блока
                    mov     bl,request.command       ; запроса и команду
     ;
     ; установим заранее код ошибки на случай если команда неверная
     ;
                    mov     ax,(ST_ERROR OR UNKNOWN_COMMAND)
                    cmp     bl,[max_cmd]     ; команда поддерживается ?
                    ja      exit             ; нет - отвергаем ее
     ;
     ; Выдаем указанную команду на выполнение соответствующему обработчику.
     ; Каждый обработчик получает управление с CS и DS установленными на
     ; сегмент драйвера и ES:DI указывающем на блок запроса. Свой статус
     ; обработчики возвращают в регистре AX.
     ;
                    xor     bh,bh            ; BX - индекс в таблице
                    shl     bx,1             ;   команд
     IFDEF          DEBUG
                    call    print_command    ; выдаем имя обрабатываемой
     ENDIF                                   ;   команды
                    call    word ptr jumptab[bx]     ; вызываем обработчик
     ;
     ; Перешлем статус из регистра AX в слово состояния блока запроса
     ;
     exit:          push    cs               ; установка локального
                    pop     ds               ;   сегмента данных
     ;
                    les     di,[req_ptr]     ; получим адрес блока запроса
                    or      ax,ST_DONE       ; установим бит DONE
                    mov     request.status,ax        ; сохраним статус
     ;
                    mov     ss,word ptr save_ss      ; восстановим значение
                    mov     sp,word ptr save_sp      ;   регистров SS:SP
     ;
                    pop     es               ; восстановим содержимое
                    pop     ds               ;   регистров
                    pop     di
                    pop     si
                    pop     bp
                    pop     bx
                    pop     dx
                    pop     cx
                    pop     ax
                    ret
     interrupt      ENDP
     ;
     PAGE
     ;
     ; ============ ОБРАБОТЧИКИ КОМАНД ==============
     ;
     NO_COMAND      PROC    NEAR     ; неподдерживаемая команда
            ret                      ; возврат с ошибкой
     NO_COMMAND     ENDP
     ;
     MEDIA_CHECK    PROC    NEAR     ; 1 - проверка носителя
            mov     request.change,NotChanged
            xor     ax,ax
            ret
     MEDIA_CHECK    ENDP
     ;
     BUILD_BPB      PROC    NEAR     ; 2 - построить BPB
            mov     request.bpbptro,offset bpb
            mov     request.bpbptrs,cs
            xor     ax,ax
            ret
     BUILD_BPB      ENDP
     ;
     IOCTL_INPUT    PROC    NEAR     ; 3 - ввод IOCTL
            xor     ax,ax
            ret
     IOCTL_INPUT    ENDP
     ;
     READ           PROC    NEAR     ; 4 - ввод из устройства
            call    verify           ; проверка и установка параметров
            jc      rd_err           ; выход по ошибке
            les     di,request.bufptr   ; считываем в буфер
            rep     movsw            ; передача
            xor     ax,ax            ; нет ошибок
     rd_err:
            ret
     READ           ENDP
     ;
     READ_NOWAIT    PROC    NEAR     ; 5 - неразрушающий ввод
            xor     ax,ax            ;     без ожидания
            ret
     READ_NOWAIT    ENDP
     ;
     INPUT_STATUS   PROC    NEAR     ; 6 - ввод статуса
            xor     ax,ax
            ret
     INPUT_STATUS   ENDP
     ;
     INPUT_FLUSH    PROC    NEAR     ; 7 - сбросить входную очередь
            xor     ax,ax
            ret
     INPUT_FLUSH    ENDP
     ;
     WRITE          PROC    NEAR     ; 8 - вывод на устройство
            call    verify           ; проверка и установка параметров
            jc      wr_err           ; выход при ошибке
            push    ds               ; сохраним сегмент "сектора"
            lds     si,request.bufptr   ; записываем из буфера
            pop     es               ; на диск
            xor     di,di            ; с нулевым смещением
            rep     movsw            ; передача
            xor     ax,ax            ; нет ошибок
     wr_err:
            ret
     WRITE          ENDP
     ;
     WRITE_VERIFY   PROC    NEAR     ; 9 - вывод с проверкой
            call    write
            ret
     WRITE_VERIFY   ENDP
     ;
     OUTPUT_STATUS  PROC    NEAR     ; A - вывод статуса
            xor     ax,ax
            ret
     OUTPUT_STATUS  ENDP
     ;
     OUTPUT_FLUSH   PROC    NEAR     ; B - сбросить выходную очередь
            xor     ax,ax
            ret
     OUTPUT_FLUSH   ENDP
     ;
     IOCTL_OUTPUT   PROC    NEAR     ; C - вывод IOCTL
            xor     ax,ax
            ret
     IOCTL_OUTPUT
     ;
     DEVICE_OPEN    PROC    NEAR     ; D - открыть устройство
            xor     ax,ax
            ret
     DEVICE_OPEN    ENDP
     ;
     DEVICE_CLOSE   PROC    NEAR     ; E - закрыть устройство
            xor     ax,ax
            ret
     DEVICE_CLOSE   ENDP
     ;
     REMOVABLE      PROC    NEAR     ; F - носитель сменный ?
            mov     ax,ST_BUSY       ; нет !
            ret
     REMOVABLE      ENDP
     ;
     GENERIC_IOCTL  PROC    NEAR     ; 13 - групповой IOCTL запрос
            xor     ax,ax
            ret
     GENERIC_IOCTL  ENDP
     ;
     GET_LOGICAL    PROC    NEAR     ; 17 - получить имя логического
            xor     ax,ax            ;      диска
            ret
     GET_LOGICAL    ENDP
     ;
     SET_LOGICAL    PROC    NEAR     ; 18 - установить имя логического
            xor     ax,ax            ;      диска
            ret
     SET_LOGICAL    ENDP
     ;
     PAGE
     ; ------------ Подпрограммы обработки запросов -----------------------
     ; Эти подпрограммы вызываются для обработки параметров любого запроса
     ; на ввод/вывод.
     ; На входе :
     ;    ES:DI - содержит адрес блока запроса
     ; Действия :
     ;    Проверка параметра "номер сектора" на допустимость.
     ;    Преобразование этого параметра в "сегмент:смещение".
     ;    Выровнять счетчик для предотвращения "перекрытия".
     ; На выходе :
     ;    DS:SI - содержит адрес "сектора" в RAM-диске
     ;    ES:DI - содержит адрес блока запроса
     ;    CX - содержит количество передаваемых слов.
     ;
     verify PROC    NEAR
     ; проверим что номера начального и конечного секторов лежат в пределах
     ; от 0 до N.
            mov     cx,request.start         ; сравним номер начального
            cmp     cx,bpb.nls               ;   сектора с количеством
            jae     out_of_range             ;   логических секторов
            add     cx,request.count         ; найдем номер конечного
            dec     cx                       ;   сектора и тоже сравним
            cmp     cx,bpb.nls               ; если номера секторов
            jb      in_range                 ;   нормальные то продолжим
     ; заданные секторы не содержатся на диске
     out_of_range:
            mov     ax,ST_ERROR OR SECTOR_NOT_FOUND
            mov     request.count,0          ; ничего не было передано
            stc                              ; возвращаемся с ошибкой
            ret
     ; вычислим сегментный адрес начального сектора
     in_range:
            mov     ax,bpb.bps               ; количество байт в секторе
            mov     cl,4                     ; разделим на 16 для получения
            shr     ax,cl                    ;   размера в параграфах
            mul     request.start            ; смещение параграфа относи-
                                             ;   тельно начала диска
            add     ax,RPARA                 ; смещение параграфа относи-
            mov     dx,cs                    ;   тельно CS
            add     ax,dx                    ; абсолютное смещ. параграфа
            mov     si,ax                    ; сохраним сегмент в SI
     ; вычислим и проверим счетчик передаваемых данных
            mov     ax,bpb.bps               ; размер сектора в байтах
            mul     request.count            ; счетчик передачи в байтах
            cmp     dx,0                     ; проверим на корректность
            jne     out_of_range
     ; выровняем счетчик в AX для предотвращения перекрытия
            mov     cx,word ptr request.bufptr
            cmp     ax,0                     ; смещение = 0
            je      set_size
            neg     cx                       ; остаток = 64K - смещение
            cmp     cx,ax                    ;   буфера
             jae      set_size                   ;   если   остаток   меньше
счетчика,
            mov     ax,cx                    ;   то передаем только остаток
     ; установим количество передаваемых секторов и счетчик передачи
     set_size:
            mov     cx,ax                    ; счетчик передачи в байтах
            shr     cx,1                     ; преобразуем в счетчик слов
            div     bpb.bps                  ; (DX был 0) кол-во секторов
            mov     request.count,ax         ; сохраним счетчик передачи
     ; загрузим в DS:SI адрес блока в памяти
            mov     ds,si
            xor     si,si
     ; установим направление передачи и вернемся без ошибок
            cld
            clc
            ret
     verify ENDP
     ;
     IFDEF  DEBUG
     INCLUDE        biosio.asm
     PAGE
     ;
     ; ************ КОД И ДАННЫЕ ДЛЯ ОТЛАДКИ *************
     ;
     ; Отладочные сообщения
     ;
     NO_COMMAND_msg    db   'NO COMMAND',CR,LF,'$'
     INIT_msg          db   'INITialization',CR,LF,'$'
     MEDIA_CHECK_msg   db   'MEDIA Check',CR,LF,'$'
     BUILD_BPB_msg     db   'Build BIOS Parameter Block',CR,LF,'$'
     IOCTL_INPUT_msg   db   'IO Control Input',CR,LF,'$'
     READ_msg          db   'Input from Device',CR,LF,'$'
     READ_NOWAIT_msg   db   'Nondestructive Input no-wait',CR,LF,'$'
     INPUT_STATUS_msg  db   'Input Status',CR,LF,'$'
     INPUT_FLUSH_msg   db   'Flush Input Queue',CR,LF,'$'
     WRITE_msg         db   'Output to Device',CR,LF,'$'
     WRITE_VERIFY_msg  db   'Output with Verify',CR,LF,'$'
     OUTPUT_STATUS_msg db   'Output Status',CR,LF,'$'
     OUTPUT_FLUSH_msg  db   'Flush Output Queue',CR,LF,'$'
     IOCTL_OUTPUT_msg  db   'IO Control Output',CR,LF,'$'
     DEVICE_OPEN_msg   db   'Open a Device',CR,LF,'$'
     DEVICE_CLOSE_msg  db   'Close a Device',CR,LF,'$'
     REMOVABLE_msg     db   'Is Media Removable',CR,LF,'$'
     GENERIC_IOCTL_msg db   'Generic IOCTL Request',CR,LF,'$'
     GET_LOGICAL_msg   db   'Get Logical Device',CR,LF,'$'
     SET_LOGICAL_msg   db   'Set Logical Device',CR,LF,'$'
     ;
     PAGE
     ;
     ; ===== ТАБЛИЦА АДРЕСОВ ОТЛАДОЧНЫХ СООБЩЕНИЙ =====
     ;
     message_table  LABEL   WORD
            dw      offset INIT_msg          ; 01 - инициализация
            dw      offset MEDIA_CHECK_msg   ; 02 - проверка носителя
            dw      offset BUILD_BPB_msg     ; 03 - построить BPB
            dw      offset IOCTL_INPUT_msg   ; 04 - ввод IOCTL
            dw      offset READ_msg          ; 05 - ввод из устройства
            dw      offset READ_NOWAIT_msg    ;  06  -  неразруш.  ввод  без
ожид.
            dw      offset INPUT_STATUS_msg  ; 07 - ввод статуса
            dw      offset INPUT_FLUSH_msg   ; 08 - сброс входной очереди
            dw      offset WRITE_msg         ; 09 - вывод на устройство
            dw      offset WRITE_VERIFY_msg  ; 10 - вывод с проверкой
            dw      offset OUTPUT_STATUS_msg ; 11 - вывод статуса
            dw      offset OUTPUT_FLUSH_msg  ; 12 - сброс выходной очереди
            dw      offset IOCTL_OUTPUT_msg  ; 13 - вывод IOCTL
            dw      offset DEVICE_OPEN_msg   ; 14 - открыть устройство
            dw      offset DEVICE_CLOSE_msg  ; 15 - закрыть устройство
            dw      offset REMOVABLE_msg     ; 16 - носитель сменный ?
            dw      offset NO_COMMAND_msg    ; 17 -
            dw      offset NO_COMMAND_msg    ; 18 -
            dw      offset NO_COMMAND_msg    ; 19 -
            dw      offset GENERIC_IOCTL_msg ; 20 - групповой IOCTL запрос
            dw      offset NO_COMMAND_msg    ; 21 -
            dw      offset NO_COMMAND_msg    ; 22 -
            dw      offset NO_COMMAND_msg    ; 23 -
            dw      offset GET_LOGICAL_msg   ; 24 - получить имя диска
            dw      offset SET_LOGICAL_msg   ; 25 - установить имя диска
     ;
     PAGE
     ; PRINT_COMMAND
     ;
     ; Эта процедура вызывает функцию BIOS для печати (_biosprt), передавая
     ; ей адрес строки, содержащей имя только что вызванной команды. При
     ; вызове этой процедуры удвоенный код  команды  передается  в  регистре
BX.
     ; Все используемые регистры сохраняются.
     ;
     print_command  PROC    NEAR
            push    ax                       ; сохраним содержимое рег. AX
            mov     ax, BLUE_F OR BRIGHT OR BLACK_B  ; установим цвет
            push    ax
            mov     ax,word ptr message_table[bx]    ; адрес строки
            push    ax
            call    _biosprt                 ; вызываем процедуру BIOS
            add     sp,4                     ; очищаем стек от параметров
            pop     ax                       ; восстанавливаем AX и выходим
            ret
     print_command  ENDP
     ENDIF
     ;
     PAGE
     ;
;** ВНУТРЕННИЙ СТЕК И КОНЕЦ ОПЕРАЦИОННОЙ ЧАСТИ ДРАЙВЕРА **
     ;
            db      32 DUP ('stack   ')      ; внутренний стек глубиной
     local_stack    EQU     $                ;   256 байт
     ;
     bpb_tab        dw      offset bpb       ; указатель на BPB
     ;
     LAST_USED      EQU     $                ; адрес завершения
     ;
;*** ХАРАКТЕРИСТИКИ RAM-ДИСКА, ПРИНИМАЕМЫЕ ПО УМОЛЧАНИЮ ***
     ;
     ; Параметры для 5-1/4" двустороннего двойной плотности диска с девятью
     ; секторами на дорожке.
     ;
     MTYPE   EQU    0FDh             ; байт описателя носителя
     TRACKS  EQU    40               ; 40 дорожек
     SECTORS EQU    9                ; 9 секторов на дорожке
     DSIZE   EQU    512              ; 512 байт в секторе
     SIDES   EQU    2                ; 2 стороны на диске
     ;
     FSECS   EQU    2                ; количество секторов в FAT
     DIREN   EQU    112              ; количество элементов директория
     DSECS   EQU    7                ; 7 секторов в директории
     CLSIZ   EQU    2                ; 2 сектора в кластере
     ;
     STOTAL  EQU    TRACKS*SECTORS*SIDES     ; всего секторов
     PTOTAL  EQU    (DSIZE/16)*STOTAL        ; всего параграфов
     ;
     ; ******** НАЧАЛО ОБЛАСТИ ДАННЫХ RAM-ДИСКА **********
     ;
     ; RAM-диск д.б. выровнен на границу параграфа
     ;
            IF      ($-ORIGIN) mod 16
            ORG     ($-ORIGIN) + 16 - (($-ORIGIN) mod 16)
            ENDIF
     RDISK  LABEL   BYTE             ; начало RAM-диска
     RPARA  EQU     ($-ORIGIN)/16    ; размер кода в параграфах
     ;
     ; ------------ Блок параметров BIOS ----------------------------------
     ;
            jmp     short boot       ; короткий JMP (2 байта)
            nop                      ; требуется для boot_record
            db      'IBM  3.1'       ; 8 байт имя и версия
     ;
     bpb    bpbstrc 
            dw      SECTORS          ; количество секторов на дорожке
            dw      SIDES            ; количество головок чтения/записи
            dw      0                ; количество скрытых секторов
     boot:
            db      (DSIZE-30) DUP (?)       ; остаток boot_sector
     ;
     ; ------------ Таблицы размещения файлов (FAT) -----------------------
     ;                                       ; первые два элемента FAT
     FAT_1  db      MTYPE,0FFh,0FFh          ; нулевой остаток FAT
            db      (DSIZE-3) DUP (0)
            db      ((FSECS-1) * DSIZE) DUP (0)
     FAT_2  db      MTYPE,0FFh,0FFh          ; первые два элемента FAT
            db      (DSIZE-3) DUP (0)        ; нулевой остаток FAT
            db      ((FSECS-1) * DSIZE) DUP (0)
     ;
     ; ------------ Сектора директория ------------------------------------
     ;
     DIREC  db      'RAM_DISK   '            ; имя тома (11 байт)
            db      08h                      ; VID
            db      10 DUP (?)               ; зарезервировано
            dw      0600h                    ; время 12:00:00 (полдень)
            dw      021h                     ; дата 1 января 1980 года
            dw      0                        ; начальный кластер 0
            dd      0                        ; размер файла 0
            db      (DSIZE-32) DUP (0)       ; нулевой остаток директория
            db      ((DSECS-1) * DSIZE) DUP (0)
     BUFFER LABEL   BYTE                     ; начало области данных
     ;
     ; ************ ПРОЦЕДУРА ИНИЦИАЛИЗАЦИИ **************
     ;
     INCLUDE        stdmac.inc
     ;
     ; ============ Область данных инициализации ===========
     ;
     $signon        db      'RAM DISK Driver Version 1.00 Installed: Drive
     $desig         db      'A'
     $crlf          db      0Dh,0Ah,'$'
     ;
     ; ============ Начало процедуры инициализации ===========
     ;
     INIT   PROC    NEAR             ; 00 - инициализация
     ;
     ; установим адрес завершения, количество устройств и указатель на
     ; таблицу BPB
     ;
            mov     request.endadro,0        ; адрес конца драйвера
            mov     request.endadrs,cs
            add     request.endadrs,(RPARA+PTOTAL)   ; последний параграф
            mov     request.units,1
            mov     request.bpbtabo,offset bpb_tab
            mov     request.bpbtabs,cs
            mov     al,$desig                ; скорректируем имя диска
            add     al,request.devnum
            mov     $desig,al
     ;
     ; вывод на экран идентификационной строки
            @DisStr $signon
     ;
     ; скорректируем значение "max_cmd" исходя из версии MS-DOS
            @GetDOSVersion                   ; получим номер версии MS-DOS
            cmp     al,3                     ; MS-DOS версии 3.00 и выше ?
            jb      init_done             ; нет - прекращаем инициализацию
            mov     [max_cmd],CMD_PRE_32     ; команды для MS-DOS 3.00
            cmp     ah,2                     ; MS-DOS версии 3.20 и выше ?
            jb      init_done             ; нет - прекращаем инициализацию
            mov     [max_cmd],CMD_32         ; команды для MS-DOS 3.20
     ;
     init_done:
            xor     ax,ax                    ; нет проблем !
            ret
     INIT   ENDP
     ;
     ; ************ КОНЕЦ ДРАЙВЕРА. КОНЕЦ ФАЙЛА ************
     ;
     _TEXT  ENDS
            END



                       Список используемой литературы