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

# 0 - Инициализация драйвера


Эта функция выполняется только один раз при загрузке драйвера и подключении его к операционной системе.

Функция инициализации должна поддерживаться любым драйвером, так как она сообщает операционной системе сведения, необходимые DOS для правильного подключения и использования драйвера.

Приведем формат запроса для команды инициализации:



(0) 13 header Заголовок запроса.
(+13) 1 n_units Количество устройств, обслуживаемых драйвером. Это поле заполняется только блочным драйвером.
(+14) 4 end_addr Конечный FAR-адрес резидентной части кода драйвера. В это поле драйвер записывает адрес байта памяти, следующего за той частью кода драйвера, которая должна стать резидентной.
(+18) 4 parm FAR-адрес строки параметров инициализации драйвера из файла CONFIG.SYS. Эта строка содержит все, что находится в строке файла после команды 'DEVICE=', она заканчивается символами перевода строки и возврата каретки 0Ah, 0Dh. При возврате драйвер блочного устройства должен записать в это поле адрес массива указателей на блоки параметров BIOSBIOS (BPB), по одному указателю на каждое устройство, обслуживаемое драйвером.
(+22) 1 drive Номер устройства. Для версии DOS 3.0 и более поздних версий в это поле при загрузке драйвера операционная система заносит номер, назначенный устройству, обслуживаемому драйвером. Например, для устройства А: это 0, для B: - 1 и т.д.

При инициализации драйвер символьного устройства сохраняет в своей внутренней области данных параметры инициализации, используя адрес parm. Если параметры содержат числовые величины, программа инициализации может произвести их перекодировку и сохранить значения в двоичном формате.

Затем драйвер может выполнить инициализацию обслуживаемого физического устройства ввода/вывода, инициализацию своих внутренних переменных, вывести на экран какие-либо сообщения либо даже запросить у оператора дополнительные данные - функция инициализации может пользоваться для организации диалога с оператором и других действий функциями прерывания 21h с номерами от 01h до 0Ch, 25h, 30h, 35h и функциями BIOS.


Кроме этого, драйвер должен заполнить поле end_addr адресом конца резидентной части драйвера. Так как программа инициализации выполняется только один раз, обычно ее располагают в конце драйвера и для экономии памяти не оставляют резидентной.

Драйверы блочных устройств дополнительно должны возвратить DOS количество обслуживаемых устройств (в поле n_units) и указатель на массив указателей на блоки BPB (в поле parm).

Количество устройств используется DOS для определения логических имен устройств. Например, если Ваш драйвер обслуживает три логических устройства, и на момент его загрузки в системе имеются устройства A:, B: и C:, то устройства, обслуживаемые Вашим драйвером, получат имена D:, E: и F:. Количество устройств необходимо указывать также и в заголовке драйвера, в первом байте поля имени устройства dev_name.

Для каждого логического устройства драйвер должен содержать так называемый блок параметров BIOS (BIOS Parameter Block) BPB.

Блок BPB содержится в загрузочном секторе диска и содержит информацию, необходимую BIOS для работы с диском. Приведем формат BPB:

(0) 2 sect_siz Количество байтов в одном секторе диска.
(+2) 1 clustsiz Количество секторов в одном кластере.
(+3) 2 res_sect Количество зарезервированных секторов.
(+5) 1 fat_cnt Количество таблиц FAT.
(+6) 2 root_siz Максимальное количество дескрипторов файлов, содержащихся в корневом каталоге диска.
(+8) 2 tot_sect Общее количество секторов на носителе данных (в разделе DOS).
(+10) 1 media Байт-описатель среды носителя данных.
(+11) 2 fat_size Количество секторов, занимаемых одной копией FAT.
Подробно формат и назначение полей BPB будут описаны в разделе, посвященном файловой системе DOS.

Приведем фрагмент исходного текста драйвера, возвращающего при инициализации указатель на массив BPB:

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

В этом примере предполагается, что ES:BX содержит адрес заголовка запроса.

Область данных может содержать, например, такое описание bpb_ptr:



bpb: DW 512 ; количество байтов на сектор DB 1 ; количество секторов на кластер DW 1 ; зарезервировано секторов DB 2 ; количество копий FAT DW 64 ; максимальное количество файлов ; в корневом каталоге DW 360 ; общее число секторов на диске DB 0FCh ; описатель среды DW 2 ; количество секторов в FAT ; bpb_ptr DW bpb ; таблица для трех одинаковых DW bpb ; логических устройств DW bpb

Если Ваш драйвер работает с несколькими разными по параметрам логическими устройствами, для каждого устройства необходимо подготовить свой BPB и занести его адрес в соответствующее порядковому номеру устройства место таблицы указателей на блоки BPB.

Какие действия должна выполнить функция инициализации, если выяснилось, что по тем или иным причинам установка драйвера невозможна? Например, ошибочно заданы параметры, не хватает оперативной памяти, других ресурсов или, наконец, отсутствует само обслуживаемое устройство.

Драйвер символьного устройства при этом может указать в качестве конечного адреса резидентной части программы адрес начала драйвера, т.е. адрес заголовка драйвера. Размер резидентной части при этом будет равен нулю.

Блочные драйверы дополнительно должны записать ноль в поле количества обслуживаемых логических устройств n_units.

В обоих случаях включения драйвера в состав операционной системы не произойдет.

Приведем пример простейшего драйвера символьного устройства, который обслуживает только команду инициализации. Фактически этот драйвер не работает ни с каким физическим устройством. Он просто стирает содержимое экрана при инициализации, выводит сообщение и ожидает нажатия оператором любой клавиши. После нажатия драйвер завершает свою работу без включения себя в состав DOS.

Исходный текст драйвера:

.MODEL tiny .CODE ; Драйвер состоит из одного ; сегмента кода

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

include sysp.inc

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

simple PROC far ; Драйвер - это FAR-процедура

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



E_O_P: ;Метка конца программы, ;устанавливаем ее в начало ;драйвера, т.к. не надо ;оставлять драйвер резидентно ;в памяти

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

dd 0ffffffffh ; адрес следующего драйвера dw 8000h ;байт атрибутов dw dev_strategy ;адрес процедуры стратегии dw dev_interrupt ;адрес процедуры прерывания db 'SIMPLE_D' ;имя устройство (дополненное ;пробелами)

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

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

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

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

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

or es:word ptr [bx]+3,8103h 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,'¦ *SIMPLE* (C)Frolov A., 1990 ¦' db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+' db 13,10 db 13,10,'Hit any key...' db 13,10,0

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

initialize:

lea ax,E_O_P ;смещение конца программы в AX mov es:word ptr [bx]+14,ax ;помещаем его в заголовок mov es:word ptr [bx]+16,cs ;

; Стираем экран

mov dh,18h mov dl,80h

xor cx,cx mov bh,7 xor al,al mov ah,6 int 10h

; Устанавливаем курсор в левый верхний угол экрана

mov bh,0 xor dx,dx mov ah,2 int 10h

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

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

; Ожидаем нажатия на любую клавишу

mov ax,0 int 16h

jmp quit

simple ENDP

END simple

В программе используется макро @@out_ch, описанное в файле sysp.inc и предназначенное для вывода символов на экран дисплея. Файл sysp.inc имеется на дискете, прилагающейся к книге. Приведем текст макро @@out_ch:

@@out_ch MACRO c1,c2,c3,c4,c5,c6,c7,c8,c9,c10 mov ah,02h IRP chr,<c1,c2,c3,c4,c5,c6,c7,c8,c9,c10> IFB <chr> EXITM ENDIF mov dl,chr int 21h ENDM ENDM

Текст этого драйвера транслировался при помощи ассемблера, входящего в состав QuickC 2.01. Полученный объектный модуль обрабатывался пакетным файлом:

link %1.obj; exe2bin %1.exe %1.sys

Вы можете также использовать макроассемблер MASM версии 5.0 или более поздней версии.

Нетрудно заметить, что процедура получения загрузочного модуля драйвера действительно похожа на процедуру получения COM-программы. Сообщение редактора об отсутствии сегмента стека следует проигнорировать, сегмента стека действительно нет и быть не может, так как драйвер состоит из единственного сегмента кода.

Для испытания этого и других драйверов запишите драйвер в корневой каталог системной дискеты (с которой можно загрузить операционную систему) и поместите в файл CONFIG.SYS, находящийся на этой дискете строку:

DEVICE=a:\simple.sys

Когда Ваш драйвер будет отлажен, его можно переписать на диск и подключить к файлу CONFIG.SYS, находящемуся на диске С:.


Содержание раздела