Операционная система 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 |