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)

Reserved1Reserved2則是保留欄位

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


返回上一頁