На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 6 / Пример драйвера виртуального диска Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

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

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


Более элегантным решением изменения размеров RAM-диска является использование параметров командной строки. Вспомните, что при входе в обработчик команды INIT параметры request.bpbtabo и request.bpbtabs содержат длинный указатель на командную строку драйвера. Эта строка может быть проверена на наличие переключателей и опций, которые могут быть использованы для конфигурации драйвера. При использовании этого метода процедура INIT должна выполнить проверку, скорректировать параметры в BPB и сегментный адрес завершения драйвера.


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


                DEVICE=RDISK.SYS

При первой же перезагрузке драйвер будет установлен как драйвер следующего по порядку дисковода (вероятно как драйвер дисковода C:, если у Вас нет жесткого диска). Ничего более для установки драйвера RDISK не требуется.


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


Драйвер RDISK, приведенный в листинге 6-10, содержит простой код, который может быть использован для отладки или исследования драйверов. Он написан с использованием функций ввода/вывода уровня BIOS, приведенных в листинге 6-8. Для того, чтобы отладочный код располагался до адреса завершения драйвера, RDISK включает в себя исходный текст файла BIOSIO.ASM (см.листинг 6-9). Так как библиотечные процедуры обычно добавляются редактором связей в конец программы, их использование в драйверах устройств представляется проблематичным.


Отладочный код может быть задействован путем включения в файл RDISK оператора DEBUG EQU 1 или, при использовании Microsoft MASM версии 4 или более поздней, указанием в командной строке опции /DDEBUG.


Во время выполнения отладочный код использует ряд команд драйвера в качестве индекса в таблице message_table. Элементами таблицы message_table являются адреса строк, представляющих имена команд, находящихся в области данных, предшествующей таблице message_table.Эти текстовые строки отображаются с помощью аппаратурозависимой процедуры _biosprt. В драйвере RDISK процедура _biosprt использует адаптер EGA с цветным монитором, что позволяет легко отличать отладочный текст от обычных сообщений MS-DOS.


                           Листинг 6-8. Файл BIOSIO.INC
     ----------------------------------------------------------------------
     ; ************ BIOSIO.INC ********************************************
     ;
     ; BiosIO.Inc содержит константы для использования процедур BIOS уровня
     ; находящихся в файле STDLIB.LIB
     ;
     ; Макрокоманда @Video для использования с видеопроцедурами
     ;
     @Video MACRO   function
            mov     ah,function
            int     10h
            ENDM
     ;
     ; ************ BIOS I/O Equates **************************************
     ;
     ; Эти определения поддерживают использование ввода/вывода уровня BIOS.
     ;
     ; Определения функций видеосервиса BIOS (INT 10H)
     SET_CURSOR_POS EQU 02H ;; BH = страница, DH = строка, DL = колонка
     GET_CURSOR_POS EQU 03H ;; BH = страница; строка => DH, колонка => DL
     SET_PAGE       EQU 05H ;; AL => страница
     SCROLL_UP      EQU 06H ;; AL = #строк, BH => атрибут, C(x) = верхняя
     SCROLL_DOWN    EQU 07H ;;    левая, D(x) = нижняя правая,
                            ;;    (x)H = строка, (x)L = колонка
     READ_CHR_ATR   EQU 08H ;; BH = страница; атр. => AH, симв. => AL
     WRITE_CHR_ATR  EQU 09H ;; BH = страница, CX = 1, AL = симв., BL = атр.
     WRITE_CHAR     EQU 0AH ;; BH = страница, CX = 1, AL = симв., без атр.
     WRITE_TEXT     EQU 0EH ;; BH = страница, AL = символ
     GET_MODE       EQU 0FH ;; режим => AL, #колонок => AH, страница => BH
     ;
     ; Атрибуты символов при использовании адаптера EGA
     BLINK          EQU     10000000b
     BRIGHT         EQU     00001000b
     BLACK_F        EQU     00h
     BLUE_F         EQU     01h
     GREEN_F        EQU     02h
     CYAN_F         EQU     03h
     RED_F          EQU     04h
     MAGENTA_F      EQU     05h
     YELLOW_F       EQU     06h
     WHITE_F        EQU     07h
     BLACK_B        EQU     10h
     BLUE_B         EQU     10h
     GREEN_B        EQU     20h
     CYAN_B         EQU     30h
     RED_B          EQU     40h
     MAGENTA_B      EQU     50h
     YELLOW_B       EQU     60h
     WHITE_B        EQU     70h
     ;
     ; ************ КОНЕЦ ФАЙЛА BIOSIO.INC ********************************

                           Листинг 6-9. Файл BIOSIO.ASM
     ----------------------------------------------------------------------
     PAGE   60,132
     PUBLIC _biosprt
     ; ************ BIOSIO.ASM ********************************************
     ; BIOSIO: Содержит процедуры для выполнения ввода/вывода на
     ; уровне BIOS, используя стандартные вызовы BIOS. Эти процедуры
     ; предназначены для целей отладки.
     ;
     IFNDEF DEBUG           ; если не часть DEBUG, то должна быть часть
                            ; от LIBRARY, и должна включать наши
                            ; собственные определения
     ; ************ INCLUDES **********************************************
     ;
     INCLUD biosio.inc       ; BIOS I/O difinition
     ;
     ; ************ DGROUP (DATA) COMPONENT SEGMENTS **********************
     _DATA   SEGMENT BYTE PUBLIC 'DATA'
     _DATA   ENDS
     ;
     DGROUP  GROUP   _DATA
     ;
     ;************* PROGRAM CODE STARTS HERE ******************************
     ;
     _TEXT   SEGMENT BYTE PUBLIC 'CODE'
             ASSUME  cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP
     ENDIF
     ;
     ; Шаблон структуры, описывающей состояние стека для _BIODPRT
     bpframe STRUC
                    dw      ?                ; Старый BP
                    dw      ?                ; адрес возврата
             p1     dw      ?                ; параметр #1
             p2     dw      ?                ; параметр #2
             p3     dw      ?                ; параметр #3
             p4     dw      ?                ; параметр #4
     bpframe ENDS
     prtbase EQU    [bp]
     ;
     ; _BIOSPRT
     ; Эта подпрограмма выполняет вывод на экран на уровне BIOS и
     ; используется для отладки драйвера. Подпрограмма использует
     ; видеорежим 03h : 80*25 цветной текст
     ;
     ; Эквивалентный языку Си синтаксис вызова : biosprt(string,color)
     ;
     _biosprt        PROC    NEAR
             push    bp
             mov     bp,sp
             push    si
             push    cx
             push    bx
     ;
             @Video  GET_MODE                 ; Получить номер тек.страницы
             mov     si,word prt [prtbase.p1] ; адрес строки
             mov     bl,byte prt [prtbase.p2] ; атрибут
             mov     cx,1
     ;
     biosprtloop:
             lodsb                           ; Берем очередной символ
             or      al,al                   ; Строка завершается нулем
             jz      biosprtdone
             cmp     al,'$'                  ; или завершается "$"
             jz      biosprtdone
             push    ax
             mov     al,020h
             @Video  WRITE_CHR_ATR           ; Пробел с атрибутом
             pop     ax
             @Video  WRITE_TEXT              ; Символ в режиме TTY
             jmp     biosprtloop             ; Следующий символ
     ;
     biosprtdone
             pop     bx
             pop     cx
             pop     si
             pop     bp
             ret
     _boisprt        ENDP
     ;
     IFNDEF  DEBUG                           ; если не включено как часть
     _TEXT   ENDS                            ; DEBUG, то потребуются наши
     ENDIF                                   ; собственные ENDS
     ;
     ; ************ КОНЕЦ ФАЙЛА BIOSIO.ASM ********************************
     ;       END            ; При использовании в библиотеке, удалите ";"

     ----------------------------------------------------------------------

                  Листинг 6-10. Исходный текст драйвера 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

     ---------------------------------------------------------------------

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz