MS-DOS Device Driver >> Assembly >> Basic
I/O Request Packet(IRP)
DOS系統決定要呼叫驅動程式做事情時,會採取兩個階段的呼叫動作,而這兩個階段的關連就是依靠ES:BX的資料(IRP),Strategy Callback副程式必須先把這個IRP保存起來,等到Interrupt Callback副程式被呼叫時,再去存取該IRP的資料。
司徒使用一個Command 0(Initialization)說明一下處理流程:
Step 1. 系統將Command 0的IRP資料位址儲存在ES:BX
Step 2. 系統呼叫驅動程式的Strategy Callback副程式
Step 3. 驅動程式儲存IRP的位址
Step 4. 系統呼叫驅動程式的Interrupt Callback副程式
Step 5. 驅動程式從IRP得知這是一個Command 0的命令
Step 6. 驅動程式跳到本身處理Command 0的副程式去處理
Step 7. 驅動程式處理完後並返回控制權給DOS系統
每個IRP都是經由Header和Data Structure這兩個部份組合而成,Header的Structure是固定的格式,而Data Structure的部份,則會因IRP的不同而有所改變,意思就是Data Structure的欄位不是固定的,有些IRP甚至沒有Data Structure的欄位。
為了更容易瞭解,司徒使用Command 0(Initialization)的IRP解說一下:
CMD0_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD0_DATA dup(?) CMD0_IRP ends
從上面的Structure可以看出,IRP是由Header和Data兩個部份組合而成,Header的部份是固定的Structure,如下表示:
IRP_HEADER struc Length db ? UnitCode db ? Command db ? Status dw ? Reserved1 dd ? Reserved2 dd ? IRP_HEADER ends
Length說明IRP Header的資料長度
UnitCode代表設備的順序號碼,例如:磁碟機有兩部,第一部就是0
Command說明要處理的命令
Command | DOS | Driver | Description |
---|---|---|---|
0 | 2.0+ | Char and Block | Initialization |
1 | 2.0+ | Block | Media Check |
2 | 2.0+ | Block | Get BIOS Parameter Block |
3 | 2.0+ | Char and Block | IOCTL |
4 | 2.0+ | Char and Block | Input |
5 | 2.0+ | Char | Nondestructive Input |
6 | 2.0+ | Char | Input Status |
7 | 2.0+ | Char | Input Flush |
8 | 2.0+ | Char and Block | Output |
9 | 2.0+ | Char and Block | Output With Verify |
10 | 2.0+ | Char | Output Status |
11 | 2.0+ | Char | Output Flush |
12 | 2.0+ | Char and Block | IOCTL Output |
13 | 3.0+ | Char and Block | Open |
14 | 3.0+ | Char and Block | Close |
15 | 3.0+ | Block | Removable Media |
16 | 3.0+ | Char | Output Til Busy |
17 | 3.2+ | Char and Block | Undefined |
18 | 3.2+ | Char and Block | Undefined |
19 | 3.2+ 3.3+ |
Block Char and Block |
Generic IOCTL |
20 | 3.2+ | Char and Block | Undefined |
21 | 3.2+ | Char and Block | Undefined |
22 | 3.2+ | Char and Block | Undefined |
23 | 3.2+ | Block | Get Logical Device |
24 | 3.2+ | Block | Get Logical Device |
25 | 5.0+ | Char and Block | IOCTL Query |
Status是驅動程式回傳給系統的狀態,如下表:
Bit15 | Bit14~Bit10 | Bit9 | Bit8 | Bit7~Bit0 |
---|---|---|---|---|
Error | Reserved | Busy | Done | Error Code 0 (Write protect violation) 1 (Unknown unit) 2 (Drive not ready) 3 (Unknown command) 4 (CRC error) 5 (Bad drive request structure length) 6 (Seek error) 7 (Unknown media) 8 (Sector not found) 9 (Printer out of paper) 10 (Write fault) 11 (Read fault) 12 (General failure) 13 (Reserved) 14 (Reserved) 15 (Invalid disk change) |
Reserved1和Reserved2則是保留欄位
Data Structure的部份則因IRP的不同而有所差異,Command 0的Data Structure如下表示:
CMD0_DATA struc UnitNum db ? BreakOffset dw ? BreakSegment dw ? BPBOffset dw ? BPBSegment dw ? FirstDrive db ? CMD0_DATA ends
經由上面的解說,使用者應該對IRP有了基本的認知。
接著司徒針對那25個Command依序列出它們的IRP Structure,基本上,這部份使用者可先跳過,等之後需要使用該Command時,再回頭來參考即可。
Command 0: Initialization
初始化設定的Command,在驅動程式被載入到記憶體之後,系統會馬上傳送這個Command給驅動程式,這是驅動程式唯一可以做初始化的Command,而且使用者必須記得一點,只有該Command可以執行DOS的系統服務常式(0x01~0x0c, 0x30)
CMD0_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD0_DATA dup(?) CMD0_IRP ends CMD0_DATA struc UnitNum db ? BreakOffset dw ? BreakSegment dw ? BPBOffset dw ? BPBSegment dw ? FirstDrive db ? CMD0_DATA ends
Command 1: Media Check
這個命令是DOS在存取所有磁碟機前,都會先執行的命令,用以確認是否目錄或FAT資料有被更改過
CMD1_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD1_DATA dup(?) CMD1_IRP ends CMD1_DATA struc MediaDescriptor db ? RetStatus db ? CMD1_DATA ends
Command 2: Get BPB Parameter
這個命令用於取得磁碟機的BPB資料
CMD2_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD2_DATA dup(?) CMD2_IRP ends CMD2_DATA struc MediaDescriptor db ? BPBArrayOffset dw ? BPBArraySegment dw ? BPBInfoOffset dw ? BPBInfoSegment dw ? CMD2_DATA ends
Command 3: IOCTL Input
Input Output Control(IOCTL)命令是應用程式用於跟驅動程式做為溝通傳輸的命令,所以會有Input跟Output兩種方向,DOS的系統呼叫常式44H就是用於此目的,驅動程式想要提供IOCTL命令給應用程式呼叫時,檔頭資訊中的Attribute第14位元(SUPPORT IOCTL),必須先設定為1
CMD3_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD3_DATA dup(?) CMD3_IRP ends CMD3_DATA struc MediaDescriptor db ? BufferOffset dw ? BufferSegment dw ? Count dw ? StartSectorNum dw ? CMD3_DATA ends
Command 4: Input
從驅動程式讀取資料
CMD4_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD4_DATA dup(?) CMD4_IRP ends CMD4_DATA struc MediaDescriptor db ? BufferOffset dw ? BufferSegment dw ? Count dw ? StartSectorNum dw ? VolumeIDOffset dw ? VolumeIDSegment dw ? StartSector32 dd ? CMD4_DATA ends
Command 5: Nondestructive Input
應用程式可以使用DOS的系統呼叫常式0B取得Input Buffer裡面的資料,但是不清除Input Buffer,如果沒有資料在Input Buffer,則設定IRP Header的Status狀態(Busy=1)
CMD5_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD5_DATA dup(?) CMD5_IRP ends CMD5_DATA struc Buffer db ? CMD5_DATA ends
Command 6: Input Status
取得Input Buffer的狀態,如果Input Buffer有資料,則設定IRP Header的Status狀態(Busy=0),反之則設定Busy=1,設定值是跟Nondestructive Input相反
CMD6_IRP struc Header db size IRP_HEADER dup(?) CMD6_IRP ends
Command 7: Input Flush
清除驅動程式的Input Buffer
CMD7_IRP struc Header db size IRP_HEADER dup(?) CMD7_IRP ends
Command 8: Output
傳送資料給驅動程式
CMD8_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD8_DATA dup(?) CMD8_IRP ends CMD8_DATA struc MediaDescriptor db ? BufferOffset dw ? BufferSegment dw ? Count dw ? StartSectorNum dw ? VolumeIDOffset dw ? VolumeIDSegment dw ? StartSector32 dd ? CMD8_DATA ends
Command 9: Output with Verify
基本上,這個命令跟Command 8是一樣的,差別僅在於Verify這個功能,DOS的VERIFY旗標若被ON時,該命令才會被呼叫到,該命令能夠讓驅動程式讀回剛剛被寫出的資料,用以確保資料的正確性
CMD9_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD9_DATA dup(?) CMD9_IRP ends CMD9_DATA struc MediaDescriptor db ? BufferOffset dw ? BufferSegment dw ? Count dw ? StartSectorNum dw ? VolumeIDOffset dw ? VolumeIDSegment dw ? StartSector32 dd ? CMD9_DATA ends
Command 10: Output Status
此命令用以得知驅動程式的設備輸出狀態,如:印表機,假設印表機的輸出緩衝區有字元等待列印,則此命令可以得知緩衝區的狀態(透過IRP Header的Busy Status狀態得知)
CMD10_IRP struc Header db size IRP_HEADER dup(?) CMD10_IRP ends
Command 11: Output Flush
清除Output Bufferi
CMD11_IRP struc Header db size IRP_HEADER dup(?) CMD11_IRP ends
Command 12: IOCTL Output
IOCTL的Ouput輸出(到驅動程式),驅動程式如要提供IOCTL命令給應用程式呼叫時,檔頭資訊中的Attribute第14位元(SUPPORT IOCTL),必須先設定為1
CMD12_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD12_DATA dup(?) CMD12_IRP ends CMD12_DATA struc MediaDescriptor db ? BufferOffset dw ? BufferSegment dw ? Count dw ? StartSectorNum dw ? CMD12_DATA ends
Command 13: Open
該命令就是當應用程式開啟該驅動程式時,DOS會透過此命令呼叫該驅動程式,至於應用程式如何知道它要開啟該驅動程式的名稱為何呢?答案就是驅動程式的檔頭資訊,在檔頭資訊中,有一個DriverName的欄位,該欄位就是代表該驅動程式的名稱,應用程式只要使用該名稱開啟即可,不過大家還是要注意一點,想要支援此功能,檔頭資訊中的Attribute第11位元(支援OPEN/CLOSE/REMOVABLE MEDIA設備),必須先設定為1
CMD13_IRP struc Header db size IRP_HEADER dup(?) CMD13_IRP ends
Command 14: Close
該命令就是用來關閉剛剛使用Open命令開啟的驅動程式,想要支援此功能,該驅動程式的檔頭資訊中的Attribute第11位元(支援OPEN/CLOSE/REMOVABLE MEDIA設備),必須先設定為1
CMD14_IRP struc Header db size IRP_HEADER dup(?) CMD14_IRP ends
Command 15: Removable Media
這個命令提供磁片是否可以更換的訊息給應用程式,應用程式可以使用DOS系統服務常式44H來詢問磁片是否可更換(08H),想要支援此功能,檔頭資訊中的Attribute第11位元(支援OPEN/CLOSE/REMOVABLE MEDIA設備),必須先設定為1,驅動程式回應在IRP Header的Status欄位(Busy)
CMD15_IRP struc Header db size IRP_HEADER dup(?) CMD15_IRP ends
Command 16: Output til Busy
輸出字元並等待所有字元寫完或設備發出Busy信號為止
CMD16_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD16_DATA dup(?) CMD16_IRP ends CMD16_DATA struc MediaDescriptor db ? BufferOffset dw ? BufferSegment dw ? Count dw ? CMD16_DATA ends
Command 19: Generic IOCTL
這個IOCTL命令跟IOCTL Output命令是類似的觀念,差別僅在於此命令是以控制碼的觀念傳輸給驅動程式,一般應用程式可以使用DOS系統服務常式44H並指定使用Generic IOCTL(0DH),驅動程式想要提供此命令給應用程式呼叫時,檔頭資訊中的Attribute第6位元(GENERIC IOCTL),必須先設定為1
CMD19_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD19_DATA dup(?) CMD19_IRP ends CMD19_DATA struc Major db ? Minor db ? SI dw ? DI dw ? PacketOffset dw ? PacketSegment dw ? CMD19_DATA ends
Command 23: Get Logical Device
取得邏輯設備的資料
CMD23_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD23_DATA dup(?) CMD23_IRP ends CMD23_DATA struc IO db ? Command db ? RetStatus dw ? Reserved dd ? CMD23_DATA ends
Command 24: Set Logical Device
設定邏輯設備的資料
CMD24_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD24_DATA dup(?) CMD24_IRP ends CMD24_DATA struc IO db ? Command db ? RetStatus dw ? Reserved dd ? CMD24_DATA ends
Command 25: IOCTL Query
該命令用來詢問驅動程式是否支援某些IOCTL,一般應用程式可以呼叫DOS的系統服務常式4401H和4411H要求驅動程式執行此要求,要使用該命令功能時,檔案標頭的Attribute第7位元必須被設定為1
CMD25_IRP struc Header db size IRP_HEADER dup(?) Data db size CMD25_DATA dup(?) CMD25_IRP ends CMD25_DATA struc Major db ? Minor db ? SI dw ? DI dw ? PacketOffset dw ? PacketSegment dw ? CMD25_DATA ends