Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система MS-DOS

© Александр Фролов, Григорий Фролов
Том 1, книги 1-2, М.: Диалог-МИФИ, 1991.

[Назад] [Содеожание]

6.10. Пример драйвера блочного устройства

Приведем пример драйвера "электронного" диска, расположенного в основной (не расширенной или дополнительной) памяти компьютера. Этот драйвер предназначен, разумеется, не для замены поставляющегося стандартно RAMDRIVE.SYS, однако на его примере можно увидеть, как устроены драйверы блочных устройств.

И если когда-нибудь Вам потребуется использовать диски ЭВМ серии ЕС в качестве винчестера персонального компьютера, то разобравшись в том, как работает приведенный ниже драйвер, Вы сможете самостоятельно приспособить его для такой задачи.

;
; Драйвер электронного диска,
; использует основную память компьютера
;
          .MODEL tiny
          .CODE        ; Драйвер состоит из одного
                                ; сегмента кода

          org 0        ; Эта строка может отсутствовать

          include sysp.inc

ram  PROC far

;=======================================================

; Заголовок драйвера

          dd   0ffffffffh       ;адрес следующего драйвера
          dw   2000h            ;байт атрибутов
          dw   dev_strategy     ;адрес процедуры стратегии
          dw   dev_interrupt    ;адрес процедуры прерывания
          db   1
          db   7 dup(?)

; Блок BPB для электронного диска

bpb   equ $

        dw 512   ; количество байтов в секторе
        db 1     ; количество секторов в кластере
        dw 1     ; количество зарезервированных секторов
        db 2     ; количество копий FAT
        dw 64    ; макс. количество файлов в корневом каталоге
        dw 360   ; общее количество секторов
        db 0fch  ; описатель среды носителя данных
        dw 2     ; количество секторов на одну копию FAT

bpb_ptr     dw bpb   ; указатель на блок BPB

; Область локальных переменных драйвера

total       dw ?  ; количество секторов
verify      db 0  ; флаг проверки при записи
start_sec   dw 0  ; номер начального сектора
vdisk_ptr   dw 0  ; сегмент начала участка памяти,
                           ; в котором расположен диск

user_dta    dw ?  ; адрес области передачи данных
                  dw ?

; Образец записи BOOT для инициализации
; первого сектора диска

boot_rec equ $

        db 3 dup(0)
        db 'MSDOS4.0'
        dw 512
        db 1
        dw 1
        db 2
        dw 64
        dw 360
        db 0fch
        dw 2

;========================================================

; Программа стратегии

dev_strategy:
                mov  cs:req_seg,es
                mov  cs:req_off,bx
                ret

; Здесь запоминается адрес заголовка запроса

req_seg         dw ?
req_off         dw ?

;=======================================================

;Обработчик прерывания

dev_interrupt:
        push es     ;сохраняем регистры
        push ds
        push ax
        push bx
        push cx
        push dx
        push si
        push di
        push bp

; Устанавливаем ES:BX на заголовок запроса

        mov  ax,cs:req_seg
        mov  es,ax
        mov  bx,cs:req_off

; Получаем код команды из заголовка запроса и умножаем
; его на два, чтобы использовать в качестве индекса
; таблицы адресов обработчиков команд

        mov  al,es:[bx]+2
        shl  al,1

        sub  ah,ah            ; Обнуляем AH
        lea  di,functions     ; DI указывает на смещение
                                          ; таблицы
        add  di,ax            ; Добавляем смещение в таблице
        jmp  word ptr [di]    ; Переходим на адрес из таблицы

functions   LABEL  WORD  ; Таблица функций

   dw   initialize
   dw   check_media
   dw   make_bpb
   dw   ioctl_in
   dw   input_data
   dw   nondestruct_in
   dw   input_status
   dw   clear_input
   dw   output_data
   dw   output_verify
   dw   output_status
   dw   clear_output
   dw   ioctl_out
   dw   Device_open
   dw   Device_close
   dw   Removable_media

; Выход из драйвера, если функция не поддерживается

ioctl_in:
nondestruct_in:
input_status:
clear_input:
output_status:
clear_output:
ioctl_out:
Removable_media:
Device_open:
Device_close:

        or   es:word ptr [bx]+3,8103h
   jmp  quit

;=======================================================

; Построение блока BPB

make_bpb:

        push  es
        push  bx

        mov   cs:WORD PTR start_sec,0
        mov   cs:WORD PTR total,1
        call  calc_adr

        push  cs
        pop   es

        lea   di,bpb
        add   si,11
        mov   cx,13
        rep   movsb

        pop   bx
        pop   es

        lea   dx,bpb
        mov   es:18[bx],dx
        mov   es:20[bx],cs

        jmp  quit


check_media:

; Проверка смены носителя данных.
; Носитель не менялся.

        mov   es:BYTE PTR 14[bx],1
        jmp  quit


; Обработчик команды вывода данных

output_verify:

; Для вывода с проверкой устанавливаем флаг проверки

        mov   cs:BYTE PTR verify,1

output_data:

        call  in_save
        mov   ax,es:WORD PTR 20[bx]
        mov   cs:start_sec,ax

        mov   ax,es:WORD PTR 18[bx]
        mov   cs:total,ax

        call  sector_write

        mov  es,cs:req_seg
        mov  bx,cs:req_off

        cmp   cs:BYTE PTR verify,0
        jz    no_verify

        mov   cs:BYTE PTR verify,0
        jmp   input_data

no_verify:

        jmp  quit


;=======================================================

; Обработчик команды ввода данных

input_data:

        call  in_save
        mov   ax,es:WORD PTR 20[bx]
        mov   cs:start_sec,ax

        mov   ax,es:WORD PTR 18[bx]
        mov   cs:total,ax

        call  sector_read

        mov  es,cs:req_seg
        mov  bx,cs:req_off

        jmp  quit


;========================================================

quit:
        or   es:word ptr [bx]+3,100h
        pop bp
        pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop ax
        pop ds
        pop es
     ret

;========================================================

; Процедура выводит на экран строку
; символов в формате ASCIIZ

dpc proc near
        push si
dpc_loop:
        cmp  ds:byte ptr [si],0
        jz   end_dpc
        mov  al,ds:byte ptr [si]
        @@out_ch al
        inc si
        jmp dpc_loop

end_dpc:
        pop si
        ret
dpc endp

;========================================================

hello db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+'
         db 13,10,'¦ *RAM/DISK* (C)Frolov A., 1990  ¦'
      db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+'
         db 13,10,0

;========================================================


; Сохранение адреса буфера и значения счетчика
; из области запроса в области локальных данных

in_save proc near

        mov   ax,es:WORD PTR 14[bx]
        mov   cs:user_dta,ax

        mov   ax,es:WORD PTR 16[bx]
        mov   cs:user_dta+2,ax

        mov   ax,es:WORD PTR 18[bx]
        xor   ah,ah
        mov   cs:total,ax

        ret

in_save endp

; Процедура пересчитывает адрес сектора
; в адрес соответствующего этому сектору
; блока памяти. В регистре DS возвращается
; сегментный адрес этого блока,
; в CX - общее количество байт во всех секторах.
; Количество секторов задается в total,
; номер начального сектора - в start_sec

calc_adr proc near

        mov   ax,cs:start_sec
        mov   cx,20h
        mul   cx

        mov   dx,cs:vdisk_ptr
        add   dx,ax
        mov   ds,dx

        xor   si,si
        mov   ax,cs:total
        mov   cx,512
        mul   cx

        or    ax,ax
        jnz   move_it

        mov   ax,0ffffh

move_it:

        xchg  cx,ax
        ret

calc_adr endp

; Чтение сектора из памяти виртуального диска

sector_read proc near

        call  calc_adr
        mov   es,cs:user_dta+2
        mov   di,cs:user_dta

        mov   ax,di
        add   ax,cx
        jnc   read_copy
        mov   ax,0ffffh
        sub   ax,di
        mov   cx,ax
read_copy:
        rep   movsb
        ret

sector_read endp

; Запись сектора в память виртуального диска

sector_write proc near

        call  calc_adr
        push  ds
        pop   es
        mov   di,si
        mov   ds,cs:user_dta+2
        mov   si,cs:user_dta

        mov   ax,si
        add   ax,cx
        jnc   write_copy
        mov   ax,0ffffh
        sub   ax,si
        mov   cx,ax
write_copy:
        rep   movsb
        ret

sector_write endp

;========================================================

E_O_P:            ;Метка конца программы

;========================================================

initialize:

        push  cs
        pop   dx

        lea   ax,cs:vdisk ; начало памяти, в которой
                                   ; расположен диск
        mov   cl,4
        ror   ax,cl
        add   dx,ax
        mov   cs:vdisk_ptr,dx

        mov   ax,2d00h    ; размер памяти, отведенной
                                   ; для диска
        add   dx,ax

; Записываем в область запроса адрес за
; концом области памяти, отведенной диску

        mov   es:word ptr [bx]+14,0
        mov   es:word ptr [bx]+16,dx

; Количество поддерживаемых логических дисков - 1

        mov   es:word ptr [bx]+13,1

; Возвращаем адрес построенного BPB

        lea   dx,bpb_ptr
        mov   es:word ptr [bx]+18,dx
        mov   es:word ptr [bx]+20,cs

; Инициализируем BOOT-сектор

        mov   es,cs:vdisk_ptr
        xor   di,di
        lea   si,boot_rec
        mov   cx,24
        rep   movsb

; Обнуляем два сектора для FAT

        mov   cs:WORD PTR start_sec,1
        mov   cs:WORD PTR total,2
        call  calc_adr

        push  ds
        pop   es
        mov   di,si
        xor   al,al
        rep   stosb

; Подготавливаем первую копию FAT

        mov   ds:BYTE PTR [si],0fch
        mov   ds:BYTE PTR 1[si],0ffh
        mov   ds:BYTE PTR 2[si],0ffh

; Подготавливаем вторую копию FAT

        push  ds
        push  si

        mov   cs:WORD PTR start_sec,3
        mov   cs:WORD PTR total,2
        call  calc_adr

        push  ds
        pop   es
        mov   di,si

        pop   si
        pop   ds

        rep   movsb

; Записываем нули в сектора корневого каталога

        mov   cs:WORD PTR start_sec,5
        mov   cs:WORD PTR total,4
        call  calc_adr

        xor   al,al
        push  ds
        pop   es
        xor   di,di
        rep   stosb


; Выводим сообщение

        mov ax,cs
        mov ds,ax
        mov si,offset hello
        call dpc

        jmp  quit

; Здесь начинается область данных, в которой
; расположен электронный диск. Эта область
; выровнена на границу параграфа.

        ALIGN 16

        vdisk equ $
ram   ENDP
         END ram
[Назад] [Содеожание]