home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 15 / 15.iso / s / s141 / 1.ddi / WINFILES.ZIP / OS2DD.DOC < prev    next >
Encoding:
Text File  |  1992-09-14  |  16.5 KB  |  391 lines

  1.  
  2. EXAMINING OS/2 DEVICE DRIVERS WITH "WINDOWS SOURCE"
  3. ---------------------------------------------------
  4.  
  5. As its name suggests, "Windows Source" is primarily intended for use with 
  6. Windows executables.  However, many OS/2 executables use the same 
  7. segmented-executable (or "new" executable, or NE) file format as Windows, 
  8. so Windows Source can be extremely helpful with OS/2.  In particular, 
  9. OS/2 device drivers, for both OS/2 1.x and 2.x, use the NE format. 
  10.  
  11. Windows Source has always worked with OS/2 device drivers, but now 
  12. (starting with WINP version 1.16, and EXEDUMP version 1.36) it will 
  13. provide you with more information.  To examine an OS/2 device driver, you 
  14. should use the -OS2DD switch.  For example: 
  15.  
  16.         C:\OS2\DRIVERS>winp -os2dd driver.sys
  17.  
  18. In this example, WINP will produce a driver.wdf file that you then pass 
  19. to Sourcer itself (both WINP and SR should be on the path): 
  20.  
  21.         C:\OS2\DRIVERS>sr driver.wdf
  22.  
  23. Sourcer will produce a driver.lst file containing the assembly-language 
  24. source for driver.sys. 
  25.  
  26. Note that some OS/2 *.SYS files do not use the NE format: in general, 
  27. files with the name V*.SYS are linear executables that use the LX format, 
  28. not currently supported by Windows Source (let us know if you want LX 
  29. support: if enough people ask for it, we'll do it!). Some *.SYS files are 
  30. just DOS device drivers that can be examined with Sourcer without WINP.  
  31. Finally, some (such as PMDD.SYS) are Presentation Manager device drivers.  
  32. These are NE files that can be examined with Windows Source, without 
  33. using the -OS2DD switch. 
  34.  
  35. In the .LST file, Sourcer will identify the Strategy function and, if 
  36. present, the IDC (inter-device communications) function.  If there are 
  37. multiple device drivers in the same .SYS file, each Strategy function 
  38. will be labelled Strategy_1, Strategy_2, and so on. Sourcer will also 
  39. identify the fields in the device-driver header(s). 
  40.  
  41.  
  42. Locating DevHlp
  43. ---------------
  44.  
  45. After quickly glancing through the .LST file, the first thing you should 
  46. do is identify the DevHlp entry point (the address of the device helper 
  47. function provided by OS/2).  Unfortunately, Sourcer can't do this 
  48. automatically.  However, it is easy to find: look through the code for 
  49. calls through a data item, where the DL register is being set with 
  50. something that looks like a function number.  For example: 
  51.  
  52.        2.0067           mov     bl,data_0014        ; (1.003A=0)
  53.        2.006B           xor     bh,bh
  54.        2.006D           mov     dl,1Ch
  55.        2.006F           call    dword ptr data_0006 ; (1.0028=0)
  56.  
  57. The data item being referenced (data_0006 in this example) will almost 
  58. definitely be DevHlp.  To double-check that it is, you need to find where 
  59. it's being initialized.  You should find something like this, somewhere 
  60. in the .LST file: 
  61.  
  62.                         les     bx,dword ptr [bp+4]
  63.                         mov     ax,es:[bx+0Eh]
  64.                         mov     word ptr data_0006,ax
  65.  
  66. The DevHlp entry point is passed to an OS/2 device driver in offset 0Eh 
  67. of an INIT request packet, and the device driver is expected to save this 
  68. away somewhere.  (We'll discuss finding the function that handles INIT 
  69. and other request packets below.) 
  70.  
  71. Having convinced yourself that the data item is the DevHlp entry point, 
  72. you should search for all occurrences of this item, and replace them with 
  73. the string "DevHlp."  In our example, all cases of "data_0006" would be 
  74. replaced with "DevHlp." 
  75.  
  76. Once you can see the DevHlp calls, you can further clarify the code using 
  77. the function numbers in DL.  Here is a list of some DevHlp calls:
  78.  
  79.         DL      Function name
  80.         ---     -------------
  81.         00h     SchedClockAddr
  82.         01h     DevDone
  83.         02h     Yield
  84.         03h     TCYield
  85.         04h     Block
  86.         05h     Run
  87.         06h     SemRequest
  88.         07h     SemClear
  89.         08h     SemHandle
  90.         09h     PushReqPacket
  91.         0Ah     PullReqPacket
  92.         0Bh     PullParticular
  93.         0Ch     SortReqPacket
  94.         0Dh     AllocReqPacket
  95.         0Eh     FreeReqPacket
  96.         0Fh     QueueInit
  97.         10h     QueueFlush
  98.         11h     QueueWrite
  99.         12h     QueueRead
  100.         13h     Lock
  101.         14h     Unlock
  102.         15h     PhysToVirt
  103.         16h     VirtToPhys
  104.         17h     PhysToUVirt
  105.         18h     AllocPhys
  106.         19h     FreePhys
  107.         1Ah     SetROMVector
  108.         1Bh     SetIRQ
  109.         1Ch     UnSetIRQ
  110.         1Dh     SetTimer
  111.         1Eh     ResetTimer
  112.         1Fh     MonitorCreate
  113.         20h     Register
  114.         21h     DeRegister
  115.         22h     MonWrite
  116.         23h     MonFlush
  117.         24h     GetDOSVar
  118.         25h     SendEvent
  119.         26h     ROMCritSection
  120.         27h     VerifyAccess
  121.         28h     Reserved
  122.         29h     Reserved
  123.         2Ah     AttachDD
  124.         2Bh     InternalError
  125.         2Ch     Reserved
  126.         2Dh     AllocGDTSelector
  127.         2Eh     PhysToGDTSelector
  128.         2Fh     RealToProt
  129.         30h     ProtToReal
  130.         31h     EOI
  131.         32h     UnPhysToVirt
  132.         33h     TickCount
  133.         34h     GetLIDEntry
  134.         35h     FreeLIDEntry
  135.         36h     ABIOSCall
  136.         37h     ABIOSCommonEntry
  137.         38h     GetDeviceBlock (?)
  138.         3Ah     RegisterStackUsage (?)
  139.         3Ch     VideoPause
  140.         3Dh     DispMsg
  141.         50h     RegisterPDD
  142.         51h     RegisterBeep
  143.         52h     Beep
  144.         53h     FreeGDTSelector
  145.         54h     PhysToGDTSel
  146.         55h     VMLock
  147.         56h     VMUnlock
  148.         57h     VMAlloc
  149.         58h     VMFree
  150.         59h     VMProcessToGlobal
  151.         5Ah     VMGlobalToProcess
  152.         5Bh     VirtToLin
  153.         5Ch     LinToGDTSelector
  154.         5Dh     GetDescInfo
  155.         5Eh     LinToPageList
  156.         5Fh     PageListToLin
  157.         60h     PageListToGDTSelector
  158.         61h     RegisterTmrDD
  159.         63h     AllocateCtxHook
  160.         64h     FreeCtxHook
  161.         65h     ArmCtxHook
  162.         66h     VMSetMem
  163.         67h     OpenEventSem
  164.         68h     CloseEventSem
  165.         69h     PostEventSem
  166.         6Ah     ResetEventSem
  167.         6Ch     DynamicAPI
  168.     
  169.     (Much of this list, like most of the information here, comes from
  170. Ray Duncan's excellent book for OS/2 1.x, "Advanced OS/2
  171. Programming", published by Microsoft Press in 1989; Chapters 17, and
  172. Part 3 of the Reference, are devoted to OS/2 device drivers; there
  173. are of course new functions added in OS/2 2.0, but Duncan's book
  174. provides the basic core of information you'll need.  For information
  175. on the newer 2.0 functions, see Steven J. Mastrianni's book "Writing
  176. OS/2 2.0 Device Drivers in C", New York: Van Nostrand Reinhold (VNR),
  177. 1992, 407 pp., ISBN 0-442-01141-5.)
  178.  
  179. As an example of how identifying the DevHlp entry point can help clarify 
  180. code, look at the following function, where the data item "sub_0006" has 
  181. already been replaced with "DevHlp": 
  182.  
  183.                  sub_0030    proc    near
  184.         2.2E35               push    bp
  185.         2.2E36               mov     bp,sp
  186.         2.2E38               mov     ax,[bp+4]
  187.         2.2E3B               mov     bh,[bp+6]
  188.         2.2E3E               mov     bl,[bp+8]
  189.         2.2E41               mov     dl,13h
  190.         2.2E43               call    dword ptr DevHlp  ; (1.0028=0)
  191.         2.2E47               jnc     short loc_0286
  192.         2.2E49               xor     ax,ax
  193.         2.2E4B               xor     dx,dx
  194.         2.2E4D               jmp     short loc_0287    ; (2E53)
  195.         2.2E4F   loc_0286:                             ;  xref 2.2E47
  196.         2.2E4F               mov     dx,ax
  197.         2.2E51               mov     ax,bx
  198.         2.2E53   loc_0287:                             ;  xref 2.2E4D
  199.         2.2E53               pop      bp
  200.         2.2E54               retn
  201.                  sub_0030    endp
  202.  
  203. By itself, this piece of code doesn't make sense.  However, from the list 
  204. of function shown above, we know that DevHlp function DL=13h is Lock.  
  205. Consulting Duncan's book (or another source of information on OS/2 device 
  206. drivers), we find: 
  207.  
  208.     Lock -- locks a memory segment so it won't be swapped or moved during 
  209.             I/O Call with: 
  210.  
  211.             AX  selector/segment
  212.             BH  duration (0=short term; 1=long term)
  213.             BL  wait/no-wait flag (0=wait until segment locked; 1=don't wait) 
  214.             DL  13h
  215.         Returns (success):
  216.             Carry clear
  217.             AX:BX   lock handle
  218.         Returns (failure):
  219.             Carry set
  220.  
  221. Suddenly, this block of code makes sense.  First, sub_0030 is nothing but 
  222. a wrapper around the DevHlp call.  We can now add signifigant information 
  223. to sub_0030 as follows:
  224.  
  225.                  DevHlp_Lock proc    near
  226.         2.2E35               push    bp
  227.         2.2E36               mov     bp,sp
  228.         2.2E38               mov     ax,[bp+4]         ;; selector/segment
  229.         2.2E3B               mov     bh,[bp+6]         ;; duration
  230.         2.2E3E               mov     bl,[bp+8]         ;; wait/no-wait
  231.         2.2E41               mov     dl,13h            ;; Lock
  232.         2.2E43               call    dword ptr DevHlp  ; (1.0028=0)
  233.         2.2E47               jnc     short loc_0286
  234.         2.2E49               xor     ax,ax             ;; failed - return 0L
  235.         2.2E4B               xor     dx,dx
  236.         2.2E4D               jmp     short loc_0287    ; (2E53)
  237.         2.2E4F   loc_0286:                             ;  xref 2.2E47
  238.         2.2E4F               mov     dx,ax           
  239.         2.2E51               mov     ax,bx             ;; success - return lock handle
  240.         2.2E53   loc_0287:                             ;  xref 2.2E4D
  241.         2.2E53               pop     bp
  242.         2.2E54               retn
  243.                  DevHlp_Lock endp
  244.  
  245. Everywhere in the program that "sub_0030" is referenced, we can replace 
  246. this with a name such as "DevHlp_Lock".  This will immediately clarify, 
  247. not only the code shown above, but every call to it.  For example, after 
  248. replacing all "sub_0030" with "DevHlp_Lock", one piece of the driver code 
  249. looks like this: 
  250.      
  251.         2.0522               push    0
  252.         2.0524               push    0
  253.         2.0526               push    word ptr [bp+6]
  254.         2.0529               call    DevHlp_Lock       ; (2E35)
  255.         2.052C               add     sp,6
  256.         2.052F               les     bx,dword ptr [bp+10h]
  257.         2.0532               mov     es:[bx],ax
  258.         2.0535               mov     es:[bx+2],dx
  259.  
  260. Clearly, [bp+6] here holds a selector or segment value, and es:[bx] and 
  261. es:[bx+2] at the end are expected to hold a lock handle.  The lock is 
  262. short-term/wait. 
  263.  
  264. If you go through this process for every DevHlp call, your assembly 
  265. listing will make a lot more sense. 
  266.  
  267.  
  268. Locating Request Handlers
  269. -------------------------
  270.  
  271. An OS/2 device driver's Strategy routine receives request packets.  (As 
  272. noted earlier, Sourcer automatically labels all Strategy routines for 
  273. you.)  The request packet has, at offset 2, a command code.  Some command 
  274. codes are: 
  275.  
  276.         00h     INIT (initialization)
  277.         01h     Media Check
  278.         02h     Build BPB (BIOS Parameter Block)
  279.         03h     Reserved
  280.         04h     Read (input)
  281.         05h     Nondestructive Read
  282.         06h     Input Status
  283.         07h     Flush Input Buffers
  284.         08h     Write (output)
  285.         09h     Write with Verify
  286.         0Ah     Output Status
  287.         0Bh     Flush Output Buffers
  288.         0Ch     Reserved
  289.         0Dh     Device Open
  290.         0Eh     Device Close
  291.         0Fh     Removeable Media
  292.         10h     Generic IOCTL
  293.         11h     Reset Media
  294.         12h     Get Logical Drive Map
  295.         13h     Set Logical Drive Map
  296.         14h     Deinstall Driver
  297.         15h     Reserved
  298.         16h     Partitionable Fixed Disk
  299.         17h     Get Fixed Disk Map
  300.         18h     Reserved
  301.         19h     Reserved
  302.         1Ah     Reserved
  303.  
  304. The code in the Strategy function that handles these requests will often 
  305. look something like this: 
  306.  
  307.         2.0011               mov     al,es:[bx+2]
  308.         2.0015               cmp     al,21h
  309.         2.0017               jbe     short loc_0002
  310.         2.0019               mov     al,21h
  311.         2.001B   loc_0002:                             ;  xref 2.0017
  312.         2.001B               xor     ah,ah
  313.         2.001D               shl     ax,1
  314.         2.001F               mov     si,ax
  315.         2.0021               push    es
  316.         2.0022               push    bx
  317.         2.0023               call    word ptr data_0009[si]  ;*(1.0066=2FD2h) 35 entries
  318.         ...
  319.  
  320. Here, data_0009 is a table of two-byte function pointers.  The first 
  321. entry contains the address of a function that handles INIT (0), the 
  322. second entry contains the address of a function that handles Media Check 
  323. (1), and so on.  In many cases, multiple entries in the table will point 
  324. to the same function.  In the assembly listing, the table will often look 
  325. something like this: 
  326.  
  327.        1.0066    data_0009   dw      offset sub_0039     ; Data table (indexed access)
  328.        1.0068    data_0010   dw      offset sub_0008     ; (2.0132)
  329.        1.006A    data_0011   dw      offset sub_0009     ; (2.0186)
  330.        1.006C    data_0012   dw      offset sub_0007     ; (2.012E)
  331.        1.006E    data_0013   dw      offset sub_0010     ; (2.01C6)
  332.        1.0070    data_0014   dw      offset sub_0007     ; (2.012E)
  333.        1.0072    data_0015   dw      offset sub_0007     ; (2.012E)
  334.        1.0074    data_0016   dw      offset sub_0007     ; (2.012E)
  335.        1.0076    data_0017   dw      offset sub_0011     ; (2.0364)
  336.        1.0078    data_0018   dw      offset sub_0011     ; (2.0364)
  337.        1.007A    data_0019   dw      offset sub_0007     ; (2.012E)
  338.        1.007C    data_0020   dw      offset sub_0007     ; (2.012E)
  339.        1.007E    data_0021   dw      offset sub_0007     ; (2.012E)
  340.        1.0080    data_0022   dw      offset sub_0006     ; (2.012A)
  341.        1.0082    data_0023   dw      offset sub_0006     ; (2.012A)
  342.        1.0084    data_0024   dw      offset sub_0006     ; (2.012A)
  343.        1.0086    data_0025   dw      offset sub_0017     ; (2.03D2)
  344.        ...       
  345.  
  346. At first glance, this isn't very useful.  However, we said that the first 
  347. entry in the table handles INIT (0), the second entry handles Media Check 
  348. (1), and so on.  Thus, we now know that sub_0039 is actually the INIT 
  349. handler!  All occurrences of sub_0039, here and elsewhere in the program, 
  350. can be replaced with "INIT".  Likewise, "sub_0008" is really 
  351. "MediaCheck".  Note how multiple entries use sub_0007; this ought to be 
  352. replaced with a name such as "Reserved". When we're done, the table looks 
  353. like this: 
  354.  
  355.        1.0066    data_0009   dw      offset INIT         ; Data table (indexed access)
  356.        1.0068    data_0010   dw      offset MediaCheck   ; (2.0132)
  357.        1.006A    data_0011   dw      offset BuildBPB     ; (2.0186)
  358.        1.006C    data_0012   dw      offset Reserved     ; (2.012E)
  359.        1.006E    data_0013   dw      offset Read         ; (2.01C6)
  360.        1.0070    data_0014   dw      offset Reserved     ; (2.012E)
  361.        1.0072    data_0015   dw      offset Reserved     ; (2.012E)
  362.        1.0074    data_0016   dw      offset Reserved     ; (2.012E)
  363.        1.0076    data_0017   dw      offset Write        ; (2.0364)
  364.        1.0078    data_0018   dw      offset Write        ; (2.0364)
  365.        1.007A    data_0019   dw      offset Reserved     ; (2.012E)
  366.        1.007C    data_0020   dw      offset Reserved     ; (2.012E)
  367.        1.007E    data_0021   dw      offset Reserved     ; (2.012E)
  368.        1.0080    data_0022   dw      offset OpenClose    ; (2.012A)
  369.        1.0082    data_0023   dw      offset OpenClose    ; (2.012A)
  370.        1.0084    data_0024   dw      offset OpenClose    ; (2.012A)
  371.        1.0086    data_0025   dw      offset GenericIOCTL ; (2.03D2)
  372.        ...       
  373.  
  374. A good double-check is that the code for INIT should contain (or at least 
  375. indirectly call) the code that initializes the DevHlp function pointer: 
  376.  
  377.                  INIT        proc    near
  378.        ...
  379.        2.301E                les     bx,dword ptr [bp+4]
  380.        2.3021                mov     ax,es:[bx+0Eh]
  381.        2.3025                mov     dx,es:[bx+10h]
  382.        2.3029                mov     word ptr DevHlp,ax  ; (1.0034=129h)
  383.        ...
  384.                  INIT        endp
  385.  
  386. For more information on OS/2 device drivers, see the books by Duncan and 
  387. Mastrianni referred to earlier in this note. 
  388. ____________________________________________________________________________ 
  389. WINDOWS SOURCE (c) 1992 V Communications, Inc.  All Rights Reserved. 
  390.  
  391.