|
 |
Операционная система MS-DOS
© Александр Фролов, Григорий Фролов
Том 1, книги 1-2, М.: Диалог-МИФИ, 1991.
Приведем пример драйвера "электронного"
диска, расположенного в основной (не расширенной
или дополнительной) памяти компьютера. Этот
драйвер предназначен, разумеется, не для замены
поставляющегося стандартно 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
![[Назад]](prev.gif) |
![[Содеожание]](sod.gif) |
|
|