home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / DVNOTE.ZIP / NOTESDEV.ASM
Assembly Source File  |  1992-04-06  |  16KB  |  429 lines

  1.     title    SAMPLE CODE CHUNKS, FROM A DEVICE DRIVER
  2.     page    60,120
  3.  
  4. ;************************************************************************
  5. ; The following code sections were pruned from a 2 GIGABYTE
  6. ;    VIRTUAL RAM DISK driver    developed by Peter Norberg, Consulting
  7. ;    (CID 76260,3355).  The driver allows for 3 sets of memory to be
  8. ;    managed:
  9. ;        (1) a list of physical memory buffers which are not
  10. ;            normally accessed by OS/2,
  11. ;        (2) non-swappable memory, managed by OS/2
  12. ;        (3) swappable memory, managed by OS/2
  13. ;
  14. ;    They show some techniques for access of FLAT memory under OS/2
  15. ;    2.0; at this point, the comments far from complete!  I recommend
  16. ;    careful reading to understand the code.
  17. ;
  18. ;    I hereby release this set of sample code chunks into the public
  19. ;    domain, and I expressly deny any liability for it!  Use this at
  20. ;    your own risk -- this is intended for educational and training use.
  21. ;
  22. ; Initial assumptions:
  23. ;    During your INIT phase (or delayed, if you are allocating memory
  24. ;    beyond the first 16 meg), allocate your FLAT memory pointer
  25. ;    using the VMA_ALLOC command.  This memory may be fixed or movable,
  26. ;    non-swapping or swappable.  Place the returned flat address
  27. ;    into the global plSwapMem pointer, with the clSwapMem counter
  28. ;    describing the size of the buffer.  The following code will then
  29. ;    demonstrate read/write access to that buffer.  You must also
  30. ;    allocate 2 selectors (selGDT and selGDTUser) for use by this code.
  31. ;
  32. ;    Some simplifications are possible, depending on your application.
  33. ;    This code assumes that you have allocated two selectors (selGDT
  34. ;    and selGDTUser) for use by the code for data copies.  You may elect
  35. ;    to use the calls which generate results in DS and ES as temporary
  36. ;    selectors.  I chose the global selectors so that interrupts could be
  37. ;    enabled while accessing the data, and to allow me to keep the buffers
  38. ;    addressed for as long as I like.  However, since I am using global
  39. ;    selectors, I had to protect the code which filled the selectors from
  40. ;    reentrancy during the times the selectors are active.  All of this
  41. ;    is managed from the SingleThread/UnSingleThread pair and the
  42. ;    higher-order DrvAccessNextBuffer and its associated DrvMapUnlock
  43. ;    tool.
  44. ;
  45. ;    See the "Example" code at the end for a complete access/de-select
  46. ;    example
  47. ;
  48. ;************************************************************************
  49. ; Define a structure which stays on the stack, as a way of accessing
  50. ; flat memory.  This struction contains the lock mechanism for that memory
  51. ;************************************************************************
  52.  
  53. SWAPACCESS STRUCT 2        ; swap
  54.     plLockedRegion    dd    0    ; if fLocked is non-0, this is the start of the locked region
  55.     ulOffMem    dd    0    ; Offset to memory start
  56.     clTotLeft    dd    0    ; Total amount of memory left to transfer
  57.     cSingleThreaded    dw    0        ; non-0 means we are single threaded
  58.     idPhysMem    dw    0        ; If phys mem access, this is non-0
  59.     flocked        db    0,0        ; non-0 means memory is locked by this package
  60.     achLock        db    12 dup (0)    ; Lock Handle
  61. SWAPACCESS ENDS
  62.  
  63. ;************************************************************************
  64. ; DATA block declarations
  65. ;************************************************************************
  66. DGROUP  group   _DATA
  67.  
  68.         _DATA segment dword public use16 'DATA'
  69.  
  70.  ... Place you device header here
  71.  ...
  72.  
  73. plSwapMem    dd    0        ; Gets LINEAR address in 2.0, of swap space
  74. cbSwapMem    dd    0        ; count of memory in the swap region
  75.  
  76. sem    dd    0        ; Semaphore for serializing access to selectors
  77. selGDT    dw    0        ; global selector to use for DISK buffer access
  78. selGDTUser dw    0        ; global selector to use for USER buffers
  79.  
  80. _DATA   ends
  81.  
  82. _TEXT segment dword public use16 'CODE'
  83.         assume  cs:_TEXT, ds:DGROUP, es:NOTHING
  84.  
  85. ;************************************************************************
  86. ; SingleThread: Called with SI referencing the STACK BASED SWAPACCESS
  87. ;    structure; which has already been cleared by the caller.
  88. ;    Returns carry set if we were not allowed to go single threaded
  89. ;************************************************************************
  90.  
  91. SingleThread    proc
  92.     inc    ss:[si.SWAPACCESS.cSingleThreaded] ; Set for recursive call
  93.     cmp    ss:[si.SWAPACCESS.cSingleThreaded],1 ; See if already here
  94.     je    @F            ; nope: do the block
  95.     clc                ; else called recursively: ignore
  96.     ret                ; and leave
  97. @@:
  98.     PUSHAD
  99.   IFDEF NOSEM
  100. @@:    CLI                ; No ints for a while
  101.     clc                ; Set no error
  102.     test    byte ptr sem,1        ; See if blocked already
  103.     jz    @F            ; nope: we now own it
  104.     call    FinishBlock        ; else block for a while
  105.     jnc    @B            ; if no error, retry
  106.     mov    ss:[si.SWAPACCESS.cSingleThreaded],0 ; Set not blocked
  107.     mov    ax,08103h        ; set error
  108.     STC                ; force error report
  109.     STI                ; re-allow interrupts
  110.     POPAD
  111.     ret                ; and return: done
  112.  
  113. @@:    mov    byte ptr sem,1        ; take the semaphore over
  114.     STI                ; re-allow interrupts
  115.     POPAD
  116.     ret                ; and return
  117.   ELSE
  118.     lea    bx,sem            ; get the sem address
  119.     mov    ax,ds            ; from our dgroup
  120.     mov    cx,-1            ; set
  121.     mov    di,cx            ; the timeout
  122.     mov    dl,DevHlp_SemRequest    ; request the sem
  123.     call    [fpDevHlp]        ; and call the processor
  124.     jnc    @F            ; Worked OK
  125.     mov    ss:[si.SWAPACCESS.cSingleThreaded],0 ; Set not blocked
  126.     mov    ax,08103h        ; set error
  127. @@:
  128.     POPAD
  129.     ret                ; and return: done
  130.   ENDIF
  131. SingleThread    endp
  132.  
  133. ;************************************************************************
  134. ; UnSingleThread: Called with SI referencing the STACK BASED SWAPACCESS
  135. ;    structure; which has been properlay maintained by caller and by
  136. ;    SingleThread.  Concept is: any unlock unlocks all!
  137. ;************************************************************************
  138. UnSingleThread    proc
  139.     test    ss:[si.SWAPACCESS.cSingleThreaded],-1 ; Set for recursive call
  140.     jnz    @F            ; yep: we have been locked
  141.     clc                ; else not locked
  142.     ret                ; leave now
  143. @@:
  144.     PUSHAD
  145.  
  146.   IFDEF NOSEM
  147.     mov    byte ptr sem,0        ; set sem is cleared
  148.     call    FinishUnBlock        ; and unblock our code
  149.     clc                ; no errors
  150.   ELSE
  151.     lea    bx,sem            ; get the sem address
  152.     mov    ax,ds            ; from our dgroup
  153.     mov    dl, DevHlp_SemClear    ; clear it
  154.     call    [fpDevHlp]        ; and call the processor
  155.   ENDIF
  156.     mov    ss:[si.SWAPACCESS.cSingleThreaded],0 ; Set no longer locked
  157.     POPAD
  158.     ret                ; return; all done
  159. UnSingleThread    endp
  160.  
  161. ;************************************************************************
  162. ; V20FlatSS: Converts SS:SI into eax FLAT address.
  163. ; dl destroyed, returns Carry SET on error, CLEAR on OK.
  164. ;************************************************************************
  165.  
  166. V20FlatSS proc            ; Called with SI ref. SS memory to convert to
  167.                 ; flat, on ret eax = address
  168.     mov    ax,ss            ; Set to access
  169.     movzx    esi, si            ; the the memory
  170.     mov    dl, DevHlp_VirtToLin    ; then set to perform the Lin To Pagelist action
  171.     call    [fpDevHlp]        ; and do the action
  172.     ret                ; And return as needed
  173. V20FlatSS endp
  174.  
  175. ;************************************************************************
  176. ; On entry, si references the SWAPACCESS structure
  177. ;************************************************************************
  178. DrvMapUnlock    proc USES eax edx bx
  179.  
  180.     mov    bx,ss:[si.SWAPACCESS.idPhysMem] ; get the memory access ID
  181.     or    bx,bx        ; See if locked
  182.     jz    @F        ; nope
  183.     mov    ss:[si.SWAPACCESS.idPhysMem],0 ; else set no longer locked
  184.     push    si        ; save SI for a moment
  185.     mov    si,PDNMEM_UNLOCK ; and
  186.     call    CallPdnMem    ; call the routine to unlock
  187.     pop    si        ; then
  188. @@:
  189.     push    si        ; restore SI
  190.     test    ss:[si.SWAPACCESS.fLocked],-1    ; See if locked
  191.     jz    @F        ; not locked!
  192.     mov    ss:[si.SWAPACCESS.fLocked],0    ; set no longer locked
  193.     lea    si,ss:[si.SWAPACCESS.achLock]    ; Get the lock handle
  194.     call    V20FlatSS    ; the page list flat address
  195.     jc    @F        ; if error, ignore
  196.     mov    esi,eax            ; else
  197.     mov    dl,DevHlp_VMUnlock    ; and set
  198.     call    [fpDevHlp]        ; to unlock the memory
  199. @@:
  200.     pop    si            ; restore ref to SWAPACCESS
  201.  
  202.     call    UnSingleThread        ; And turn off single thread, if needed
  203.     ret                ; Return: done
  204. DrvMapUnlock    ENDP
  205.  
  206.  
  207.  
  208. ;************************************************************************
  209. ;DrvAccessNextBuffer: Map the sector passed into a temporary physical pointer
  210. ;       in es:di or ds:si:
  211. ;
  212. ; On entry:
  213. ;
  214. ;       DH is 0 for mapping into ds:si,
  215. ;        1 for mapping into es:di, 0 for ds:si
  216. ;        2 means do NOT assign ds or es to resulting selector
  217. ;        3 means we will write to the selector, but do not set ES or DS
  218. ;
  219. ;          SI = reference to the SWAPACCESS array on entry,
  220. ;                in the SS group
  221. ;
  222. ; On exit,
  223. ;    DX is unchanged
  224. ;    if DH was 0 or 1, the selected register pair (es:di or ds:si) are updated
  225. ;        to ref the selGDT selector
  226. ;    else ES, DS, SI, DI are unchanged on exit.
  227. ;    ECX is the count you can access this time through.
  228. ;
  229. ;    Side Effects: SWAPACCESS structure updated to reflect current conditions,
  230. ;        if access legal, you will be in SINGLE THREADED mode (i.e.,
  231. ;        re-entrancy to the subsystem is blocked), and selGDT will ref
  232. ;        the selected memory.
  233. ;
  234. ;
  235. ;       WARNING!  Must be called with DS referencing our data segment!
  236. ;************************************************************************
  237. DrvAccessNextBuffer proc near
  238.     LOCAL    fbDH:        WORD,
  239.         cbReq:        WORD,
  240.         ulOldDI:    DWORD,
  241.         npSwpa:        WORD
  242.  
  243.     mov    fbDH,dx            ; Save the storage flag
  244.     mov    npSwpa,si        ; save low half of SI; access to SWAPACCESS array
  245.     mov    ulOldDI,edi        ; save EDI
  246.  
  247.     call    DrvMapUnlock        ; Unlock prior access
  248.  
  249.     mov    ecx,ss:[si.SWAPACCESS.clTotLeft] ; 0 extend the count
  250.     cmp    ecx,MAX_BLOCK_XFER     ; see
  251.     jbe    @F            ; if at end
  252.     mov    ecx,MAX_BLOCK_XFER     ; nope: set upper limit
  253. @@:
  254.     mov    eax, ss:[si.SWAPACCESS.ulOffMem] ; get the memory ref
  255.     add    eax,plSwapMem        ; Here on in the SWAP region:
  256.     cmp    ecx,cbSwapMem        ; see if legal
  257.     ja    DrvMapBadReq        ; OK
  258.     mov    cbReq,cx        ; save count really requested
  259.     mov    ebx,eax            ; for later use
  260.     mov    ss:[si.SWAPACCESS.plLockedRegion],eax ; Save for later free
  261.  
  262.     mov    si,npSwpa        ; re-get access to swap info
  263.     lea    si,ss:[si.SWAPACCESS.achLock]        ; Set for extract of lock handle
  264.     call    V20FlatSS        ; lock page list rel to SS
  265.     jc    DrvMapOops        ; FAILED: forget it
  266.     mov    esi,eax            ; save the lock handle
  267.     sub    eax,eax            ; Lock in place, short term
  268.     mov    edi,-1            ; set no page list is to be generated
  269.     test    byte ptr fbDH+1,1    ; see if write planned
  270.     jz    @F            ; nope
  271.     mov    ax,8            ; yep: force "WE ARE WRITING" bit
  272. @@:
  273.     mov    dl,DevHlp_VMLock    ; and
  274.     call    [fpDevHlp]        ; perform the lock
  275.     jc    DrvMapOops        ; FAILED: forget it
  276.     mov    si,npSwpa        ; restore ref to info
  277.     mov    ss:[si.SWAPACCESS.fLocked],1 ; Else set LOCKED
  278.  
  279.     call    SingleThread        ; force into single threaded mode
  280.     jc    DrvMapOops        ; OOPS: No single thread! forget it
  281.     mov    ax,selGDT        ; get the selector
  282.     ; EBX is still the linear address of the buffer
  283.     ; ECX is the length of the buffer
  284.     mov    dl,DevHlp_LinToGDTSelector ; convert to GDT selector
  285.     call    [fpDevHlp]         ; do the conversion
  286.     jc    DrvMapOops        ; FAILED the mapping
  287.     mov    si,npSwpa        ; PHYS! restore ref to info
  288.     mov    edi,ulOldDI        ; restore EDI
  289.     mov    dx,fbDH            ; restore results flag
  290.     movzx    ecx,cbReq        ; and correct the count for excess
  291.     add    ss:[si.SWAPACCESS.ulOffMem],ecx ; calculate the next access offset
  292.     sub    ss:[si.SWAPACCESS.clTotLeft],ecx ; and the total left to transfer
  293.  
  294.     cmp    dh,2            ; are we all done?
  295.     jae    DrvMapOkRet        ; yep: so exit
  296.  
  297.     or    dh,dh            ; see who gets what
  298.     jz    @F            ; if 0, DS:SI
  299.     sub    di,di            ; get the SI
  300.     mov    es,selGDT        ; so get it
  301. DrvMapOkRet:
  302.     clc                ; set good access
  303.     ret                ; and return
  304. @@:    ; HERE on results in DS:SI
  305.     sub    si,si            ; get the SI
  306.     mov    ds,selGDT        ; DESTRY DS
  307.     ret                ; and return
  308.  
  309. DrvMapBadReq:
  310.     mov    eax,0AA55h        ; set special error code
  311.     mov    si,npSwpa        ; get the handle to the lock info
  312.     call    DrvMapUnlock        ; go unlock it
  313.  
  314.     stc                ; FAILED ACTION
  315.     ret                ; return quickly
  316.  
  317. DrvAccessNextBuffer endp
  318.  
  319. ;************************************************************************
  320. ; Example code section which accesses some of the above
  321. ;    Entered with:
  322. ;        dx = Read (0) or write (1) flag
  323. ;        eax = PHYSICAL address of user buffer
  324. ;        ebx = offset from start of our FLAT buffer to access
  325. ;        ecx = count of bytes to access
  326. ;************************************************************************
  327. Example proc near
  328.         LOCAL   fReadOrWrite:   WORD,
  329.         fpbfr:        DWORD,
  330.             swpa:        SWAPACCESS
  331.  
  332.     mov    fReadOrWrite, dx        ; ON ENTRY, dx = READ/WRITE flag
  333.                         ; 0 read, 1 write
  334.     mov    fpbfr,eax            ; eax = pointer to buffer to access
  335.     mov    edx,ecx                ; save count of bytes
  336.     lea    di,swpa                ; set
  337.     mov    cx, sizeof swpa            ; to init
  338.     sub    ax,ax                ; the
  339.     cld                    ; swap info structure
  340.     push    ss                ; as
  341.     pop    es                ; needed
  342.     rep    stosb                ; to all 0
  343.  
  344. ... Now have code calculate where in the buffer it needs to access:
  345. ... set swpa.ulOffMem to the offset to the start of the portion of the buffer,
  346. ... set swpa.clTotLeft to the total count of bytes left to access
  347.  
  348.     mov    swpa.clTotLeft,edx        ; save the count for access
  349.     mov    swpa.ulOffMem,ebx        ; save the memory offset from our flat buffer
  350.  
  351.  
  352. DrvRdLp:                                        ; PROCESS LOOP: loop here until transfer is done
  353.     cmp    swpa.clTotLeft,0        ; see if any left
  354.     je    DrvRWDone            ; if not, leave
  355.  
  356.     mov    dh,2                ; Set do NOT change es/ds
  357.     add    dh,byte ptr fReadOrWrite    ; convert to 3, for write
  358.     lea    si,swpa                ; get the address of the info
  359.     call    DrvAccessNextBuffer        ; do the mapping, LOCK THREAD
  360.     jc    DrvRwBadSec            ; could not lock/map!
  361.         mov     ax,word ptr fpbfr+2             ; get the user buffer
  362.         mov     bx,word ptr fpbfr               ; physical address
  363.     mov    si,selGDTUser            ; set target GDT
  364.     call    PhysToGDTSel            ; into our selector
  365.     jc    DrvRwBadSec            ; could not generate the mapping!
  366.  
  367.  
  368.  
  369.         push    ds                              ; Save our current segment
  370.         test    byte ptr fReadOrWrite,-1        ; See if READ or WRITE
  371.         jnz     @F                              ; WRITE: Process as needed
  372.  
  373.     mov    es,selGDTUser            ; USER pointer and
  374.     mov    ds,selGDT            ; and the memory base
  375.         jmp     DrvRdWrCpy                      ; go do the copy
  376.  
  377. @@:     ; HERE for WRITE action set-up
  378.     mov    es,selGDT            ; and the memory base
  379.     mov    ds,selGDTUser            ; get the USER selector
  380.  
  381.  
  382. DrvRdWrCpy:
  383.         assume  DS:NOTHING
  384.     mov    bx,cx                ; Save the transfer count
  385.     sub    di,di                ; set for target offset and
  386.     sub    si,si                ; source offsets of 0.
  387.         cld                                     ; Force correct string direction
  388.         rep     movsb                           ; and transfer the buffer
  389.  
  390.     ; OPTIMIZATION NOTE: The above could have a SHR CX,2 \ REP MOVSD
  391.     ;    if it is known that the buffer size is DWORD oriented;
  392.     ;    or similar in-line code could detect that condition
  393.  
  394.         pop     ds                              ; Restore DS
  395.         assume  DS:DGROUP                       ; and
  396.  
  397.  
  398. ; NOTE: THIS IS WHERE TC_YIELD SHOULD BE, IF USED!
  399.  
  400.     mov    ax,bx                ; calculate
  401.     add    word ptr fpBfr,bx        ; to form the
  402.         adc     word ptr fpBfr+2,0              ; next user buffer address to access
  403.     jmp    DrvRdLp                ; do next
  404.  
  405. DrvRWDone:                                      ; HERE on all done
  406.     lea    si,swpa                ; get the handle to the lock info
  407.     call    DrvMapUnlock            ; unlock the memory
  408.  
  409.  
  410.         CLC                                     ; Set OK
  411.         ret                                     ; and report as needed
  412.  
  413. DrvRWFailed:
  414.     pop    ds                ; Restore DS
  415. DrvRWBadSec:
  416.     lea    si,swpa                ; get the handle to the lock info
  417.     call    DrvMapUnlock            ; unlock the memory
  418.  
  419.         mov     ax,8103h                ; Set DRIVE NOT READY
  420.         stc                             ; Set ERROR
  421.  
  422.         ret                             ; and report in
  423.  
  424. Example endp
  425.  
  426. _TEXT   ends
  427.  
  428.         end
  429.