home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / advos2 / ch17 / tinydisk.asm < prev    next >
Encoding:
Assembly Source File  |  1988-12-12  |  21.3 KB  |  615 lines

  1.     title    TINYDISK -- RAM Disk Device Driver
  2.         page    55,132
  3.         .286
  4.  
  5. ;
  6. ; TINYDISK.ASM
  7. ;
  8. ; A sample OS/2 block device driver that installs a 64 KB RAM disk.
  9. ;
  10. ; Assemble with:  C> masm tinydisk.asm;
  11. ; Link with:  C> link tinydisk,tinydisk.sys,,os2,tinydisk
  12. ;
  13. ; To install the driver, add "DEVICE=TINYDISK.SYS" to CONFIG.SYS
  14. ; and reboot.
  15. ;
  16. ; Copyright (C) 1988 Ray Duncan
  17. ;
  18.  
  19. maxcmd  equ     26              ; maximum allowed command code
  20.  
  21. secsize equ     512             ; bytes/sector, IBM compatible media
  22.  
  23. stdin   equ     0               ; standard device handles
  24. stdout  equ     1
  25. stderr  equ     2
  26.  
  27. cr      equ     0dh             ; ASCII carriage return
  28. lf    equ    0ah        ; ASCII linefeed
  29.  
  30. PhysToVirt   equ 15h            ; DevHlp services
  31. UnPhysToVirt equ 32h
  32. VerifyAccess equ 27h
  33. AllocPhys    equ 18h
  34.  
  35.         extrn   DosWrite:far
  36.  
  37.  
  38. DGROUP  group   _DATA
  39.  
  40. _DATA   segment word public 'DATA'
  41.  
  42.                 ; device driver header...
  43. header  dd      -1              ; link to next device driver
  44.         dw      0080h           ; device attribute word
  45.                                 ; bits 7-9 = driver level
  46.         dw      Strat           ; Strategy entry point
  47.     dw    0        ; reserved
  48.         db      0               ; units (set by OS/2)
  49.     db    15 dup (0)    ; reserved
  50.  
  51. devhlp  dd      ?               ; DevHlp entry point
  52.  
  53. wlen    dw      ?               ; receives DosWrite length 
  54.  
  55. dbase   dd      ?               ; 32-bit physical address,
  56.                 ; base of RAM disk storage
  57.  
  58. xfrsec  dw      0               ; current sector for transfer
  59. xfrcnt  dw      0               ; sectors successfully transferred
  60. xfrreq  dw      0               ; number of sectors requested   
  61. xfraddr dd      0               ; working address for transfer 
  62.  
  63. array   dw      bpb             ; array of pointers to BPB 
  64.                                 ; for each supported unit
  65.  
  66. bootrec equ     $               ; logical sector 0 boot record
  67.         jmp     $               ; JMP at start of boot sector,
  68.     nop            ; this field must be 3 bytes
  69.     db    'IBM 10.1'    ; OEM identity field
  70.                                 ; ---BIOS Parameter Block-----
  71. bpb     dw      secsize         ; 00H bytes per sector
  72.         db      1               ; 02H sectors per cluster
  73.         dw      1               ; 03H reserved sectors
  74.         db      1               ; 05H number of FATs
  75.         dw      64              ; 06H root directory entries
  76.         dw      128             ; 08H total sectors 
  77.         db      0f8h            ; 0AH media descriptor
  78.         dw      1               ; 0BH sectors per FAT
  79.         dw      1               ; 0DH sectors per track
  80.         dw      1               ; 0FH number of heads
  81.         dd      0               ; 11H hidden sectors
  82.         dd      0               ; 15H large total sectors (if 
  83.                 ;     word at offset 08H = 0)
  84.         db      6 dup (0)       ; 19H reserved
  85.                                 ; ---End of BPB, 31 bytes-----
  86. bootrec_len equ $-bootrec       ; length of boot sector data
  87.                                 ; additional words needed by
  88.                 ; Generic IOCTL Cat 8 Function 63H
  89.                                 ; Get Device Parameters call
  90.         dw      0               ; number of cylinders
  91.         db      7               ; device type = unknown
  92.         dw      1               ; device attribute word
  93. gdprec_len equ $-bpb            ; length of Generic IOCTL buffer 
  94.  
  95.                                 ; Strategy routine dispatch table
  96.                 ; for request packet command code...
  97. dispch  dw      Init            ; 0  = initialize driver
  98.         dw      MediaChk        ; 1  = media check on block device
  99.         dw      BuildBPB        ; 2  = build BIOS parameter block
  100.         dw      Error           ; 3  = reserved
  101.         dw      Read            ; 4  = read (input) from device
  102.     dw    Error        ; 5  = nondestructive read
  103.         dw      Error           ; 6  = return input status
  104.         dw      Error           ; 7  = flush device input buffers
  105.         dw      Write           ; 8  = write (output) to device
  106.         dw      Write           ; 9  = write with verify
  107.         dw      Error           ; 10 = return output status
  108.         dw      Error           ; 11 = flush output buffers
  109.         dw      Error           ; 12 = reserved
  110.         dw      Error           ; 13 = device open
  111.         dw      Error           ; 14 = device close
  112.     dw    Error        ; 15 = removable media
  113.         dw      GenIOCTL        ; 16 = generic IOCTL
  114.         dw      Error           ; 17 = reset media
  115.         dw      GSLogDrv        ; 18 = get logical drive
  116.         dw      GSLogDrv        ; 19 = set logical drive
  117.     dw    Error        ; 20 = deinstall
  118.         dw      Error           ; 21 = reserved
  119.         dw      Error           ; 22 = partitionable fixed disks
  120.         dw      Error           ; 23 = get fixed disk unit map
  121.         dw      Error           ; 24 = reserved
  122.         dw      Error           ; 25 = reserved
  123.         dw      Error           ; 26 = reserved
  124.  
  125.                                 ; start of data discarded
  126.                                 ; after initialization
  127.  
  128. ident    db    cr,lf,lf    ; successful installation message...
  129.     db    'TINYDISK 64 KB RAM disk for OS/2'
  130.         db      cr,lf
  131.     db    'RAM disk will be drive '
  132. drive   db      'X:'
  133.         db      cr,lf
  134. ident_len equ $-ident
  135.  
  136. abort   db      cr,lf           ; aborted installation message
  137.     db    'TINYDISK installation aborted'
  138.         db      cr,lf
  139. abort_len equ $-abort
  140.  
  141. volname db    'TINYDISK   '    ; volume label for RAM disk
  142.         db      08h             ; attribute byte
  143.         db      10 dup (0)      ; reserved area
  144.         dw      0               ; time = 00:00
  145.         dw      1021h           ; date = January 1, 1988
  146.         db      6 dup (0)       ; reserved area
  147. volname_len equ $-volname
  148.  
  149. _DATA   ends
  150.  
  151.  
  152. _TEXT   segment word public 'CODE'
  153.  
  154.         assume  cs:_TEXT,ds:DGROUP,es:NOTHING
  155.  
  156. Strat   proc    far             ; Strategy entry point
  157.                                 ; ES:BX = request packet
  158.  
  159.         mov     di,es:[bx+2]    ; get command code from packet
  160.         and     di,0ffh
  161.         cmp     di,maxcmd       ; supported by this driver?
  162.         jle     Strat1          ; jump if command code OK
  163.  
  164.         call    Error           ; bad command code
  165.         jmp     Strat2
  166.  
  167. Strat1: add     di,di           ; go to command code routine
  168.         call    word ptr [di+dispch]
  169.  
  170. Strat2:                         ; return with AX = status
  171.         mov     es:[bx+3],ax    ; put status in request packet
  172.         ret                     ; return to OS/2 kernel
  173.  
  174. Strat   endp
  175.  
  176.  
  177. ; Command code routines are called by the Strategy routine
  178. ; via the Dispatch table with ES:BX pointing to the request
  179. ; header.  Each routine should return ES:BX unchanged,
  180. ; and AX = status to be placed in request packet:
  181. ; 0100H if 'done' and no error
  182. ; 0000H if thread should block pending interrupt
  183. ; 81xxH if 'done' and error detected (xx = error code)
  184.  
  185.  
  186. MediaChk proc   near            ; function 1 = media check
  187.         
  188.                                 ; return 'not changed' code
  189.         mov     byte ptr es:[bx+0eh],1
  190.  
  191.         mov     ax,0100h        ; return 'done' status
  192.         ret
  193.  
  194. MediaChk endp
  195.  
  196.  
  197. BuildBPB proc   near            ; function 2 = build BPB
  198.  
  199.                                 ; put BPB address into
  200.                                 ; request packet
  201.         mov     word ptr es:[bx+12h],offset DGROUP:bpb
  202.         mov     word ptr es:[bx+14h],ds
  203.  
  204.         mov     ax,0100h        ; return 'done' status
  205.         ret
  206.  
  207. BuildBPB endp
  208.  
  209.  
  210. Read    proc    near            ; function 4 = read
  211.  
  212.         push    es              ; save request packet address
  213.         push    bx
  214.  
  215.         call    setup           ; set up transfer variables 
  216.  
  217. Read1:  mov     ax,xfrcnt       ; done with all sectors yet?
  218.         cmp     ax,xfrreq
  219.         je      read2           ; jump if transfer completed
  220.  
  221.         mov     ax,ds           ; set ES = DGROUP
  222.         mov     es,ax
  223.  
  224.         mov     ax,xfrsec       ; get sector number
  225.         call    MapDS           ; and map it to DS:SI
  226.                                 ; (may force mode switch)
  227.  
  228.         push    es              ; save DGROUP selector
  229.  
  230.                                 ; convert destination physical
  231.                 ; address to virtual address...
  232.         mov     bx,word ptr es:xfraddr
  233.         mov     ax,word ptr es:xfraddr+2
  234.         mov     cx,secsize      ; segment length
  235.         mov     dh,1            ; leave result in ES:DI
  236.         mov     dl,PhysToVirt   ; function number
  237.         call    es:devhlp       ; transfer to kernel
  238.  
  239.         mov     cx,secsize      ; transfer logical sector from
  240.     cld            ; RAM disk to requestor
  241.         rep movsb
  242.  
  243.         pop     ds              ; restore DGROUP addressing
  244.  
  245.     sti            ; PhysToVirt may mask interrupts
  246.  
  247.         inc     xfrsec          ; advance sector number
  248.  
  249.                                 ; advance transfer address
  250.         add     word ptr xfraddr,secsize
  251.         adc     word ptr xfraddr+2,0
  252.  
  253.         inc     xfrcnt          ; count sectors transferred
  254.         jmp     read1
  255.  
  256. Read2:                          ; all sectors transferred
  257.  
  258.         mov     dl,UnPhysToVirt ; function number
  259.         call    devhlp          ; transfer to kernel
  260.  
  261.         pop     bx              ; restore request packet address
  262.         pop     es
  263.  
  264.         mov     ax,xfrcnt       ; put actual transfer count
  265.         mov     es:[bx+12h],ax  ; into request packet
  266.  
  267.         mov     ax,0100h        ; return 'done' status
  268.         ret
  269.  
  270. Read    endp
  271.  
  272.  
  273. Write   proc    near            ; functions 8,9 = write
  274.  
  275.         push    es              ; save request packet address
  276.         push    bx
  277.  
  278.         call    setup           ; set up transfer variables 
  279.  
  280. Write1: mov     ax,xfrcnt       ; done with all sectors yet?
  281.         cmp     ax,xfrreq
  282.         je      write2          ; jump if transfer completed
  283.  
  284.         mov     ax,xfrsec       ; get sector number
  285.         call    MapES           ; map it to ES:DI
  286.                                 ; (may force mode switch)
  287.  
  288.         push    ds              ; save DGROUP selector
  289.  
  290.                                 ; convert source physical
  291.                 ; address to virtual address...
  292.         mov     bx,word ptr xfraddr
  293.         mov     ax,word ptr xfraddr+2
  294.         mov     cx,secsize      ; segment length
  295.         mov     dh,0            ; leave result in DS:SI
  296.         mov     dl,PhysToVirt   ; function number
  297.         call    devhlp          ; transfer to kernel
  298.  
  299.         mov     cx,secsize      ; transfer logical sector from
  300.     cld            ; requestor to RAM disk
  301.         rep movsb
  302.  
  303.         pop     ds              ; restore DGROUP addressing
  304.         sti                     ; PhysToVirt might have masked
  305.         inc     xfrsec          ; advance sector number
  306.  
  307.                                 ; advance transfer address
  308.         add     word ptr xfraddr,secsize
  309.         adc     word ptr xfraddr+2,0
  310.  
  311.         inc     xfrcnt          ; count sectors transferred
  312.         jmp     write1
  313.  
  314. Write2:                         ; all sectors transferred
  315.  
  316.         mov     dl,UnPhysToVirt ; function number
  317.         call    devhlp          ; transfer to kernel
  318.  
  319.         pop     bx              ; restore request packet address
  320.         pop     es
  321.  
  322.         mov     ax,xfrcnt       ; put actual transfer count
  323.         mov     es:[bx+12h],ax  ; into request packet
  324.  
  325.         mov     ax,0100h        ; return 'done' status
  326.         ret
  327.  
  328. Write   endp
  329.  
  330.  
  331. GenIOCTL proc   near            ; function 16 = generic IOCTL
  332.  
  333.         push    es              ; save request packet address
  334.         push    bx
  335.  
  336.         mov     ax,8103h        ; assume unknown command
  337.  
  338.                                 ; Get Device Parameters call?
  339.         cmp     byte ptr es:[bx+0dh],8
  340.     jne    Gen9        ; no, set 'done' + 'error'
  341.         cmp     byte ptr es:[bx+0eh],63h
  342.     jne    Gen9        ; no, set 'done' + 'error'
  343.  
  344.                                 ; verify user's access
  345.         mov     ax,es:[bx+15h]  ; selector
  346.         mov     di,es:[bx+13h]  ; offset 
  347.         mov     cx,gdprec_len   ; length to be written
  348.         mov     dh,1            ; need read/write access
  349.         mov     dl,VerifyAccess ; function number
  350.         call    devhlp          ; transfer to kernel
  351.  
  352.         mov     ax,810ch        ; if no access, exit with
  353.     jc    Gen9        ; 'done' + general failure
  354.  
  355.                                 ; get destination address
  356.         les     di,dword ptr es:[bx+13h]
  357.                                 ; copy device info to caller
  358.         mov     si,offset DGROUP:bpb
  359.         mov     cx,gdprec_len   ; length of parameter block
  360.         cld
  361.         rep movsb
  362.  
  363.         mov     ax,0100h        ; set 'done' status
  364.  
  365. Gen9:   pop     bx              ; restore request packet address
  366.         pop     es
  367.         ret                     ; and return with status
  368.  
  369. GenIOCTL endp
  370.  
  371.  
  372. GSLogDrv proc   near            ; function 18, 19 = get
  373.                                 ; or set logical drive
  374.  
  375.                                 ; return code indicating there
  376.                                 ; are no logical drive aliases
  377.         mov     byte ptr es:[bx+1],0
  378.  
  379.         mov     ax,0100h        ; return 'done' status
  380.         ret
  381.  
  382. GSLogDrv endp
  383.  
  384.  
  385. Error   proc    near            ; bad command code 
  386.  
  387.         mov     ax,8103h        ; error bit + 'done' status
  388.         ret                     ; + "Unknown Command" code
  389.  
  390. Error   endp
  391.  
  392.  
  393. MapES   proc    near            ; map sector number to 
  394.                                 ; virtual memory address
  395.                                 ; call with AX = logical sector
  396.                                 ; return ES:DI = memory address
  397.                                 ;        and Carry clear
  398.                                 ; or     Carry set if error
  399.  
  400.         mov     di,secsize      ; bytes per sector
  401.         mul     di              ; * logical sector number
  402.         xchg    ax,dx           ; AX:BX := 32-bit physical
  403.         mov     bx,dx           ; sector address
  404.         add     bx,word ptr dbase
  405.         adc     ax,word ptr dbase+2
  406.  
  407.         mov     cx,secsize
  408.         mov     dh,1            ; result to ES:DI
  409.         mov     dl,PhysToVirt   ; function number
  410.         call    devhlp          ; transfer to kernel
  411.  
  412.         ret                     ; return ES:DI = sector address
  413.  
  414. MapES   endp
  415.  
  416.  
  417. MapDS   proc    near            ; map sector number to 
  418.                                 ; virtual memory address 
  419.                                 ; call with AX = logical sector
  420.                                 ; return DS:SI = memory address
  421.                                 ;        and Carry clear
  422.                                 ; or     Carry set if error
  423.  
  424.         mov     si,secsize      ; bytes per sector
  425.         mul     si              ; * logical sector number
  426.         xchg    ax,dx           ; AX:BX := 32-bit physical
  427.         mov     bx,dx           ; sector address
  428.         add     bx,word ptr dbase
  429.         adc     ax,word ptr dbase+2
  430.  
  431.         mov     cx,secsize
  432.         mov     dh,0            ; result to DS:SI
  433.         mov     dl,PhysToVirt   ; function number
  434.         call    devhlp          ; transfer to kernel
  435.  
  436.         ret                     ; return DS:SI = sector address
  437.  
  438. MapDS   endp
  439.  
  440.  
  441. Setup   proc    near            ; set up for read/write
  442.                                 ; ES:BX = request packet
  443.                                 ; extracts address, start, count
  444.  
  445.         mov     ax,es:[bx+14h]  ; starting sector number
  446.         mov     xfrsec,ax
  447.  
  448.         mov     ax,es:[bx+12h]  ; sectors requested
  449.         mov     xfrreq,ax
  450.  
  451.         mov     ax,es:[bx+0eh]  ; requestor's buffer address
  452.         mov     word ptr xfraddr,ax
  453.         mov     ax,es:[bx+10h]
  454.         mov     word ptr xfraddr+2,ax
  455.  
  456.         mov     xfrcnt,0        ; initialize sectors 
  457.                                 ; transferred counter
  458.         ret
  459.  
  460. Setup   endp
  461.  
  462.                                 ; start of code discarded
  463.                                 ; after initialization
  464.  
  465. Init    proc    near            ; function 0 = initialize
  466.  
  467.         mov     ax,es:[bx+0eh]  ; get DevHlp entry point
  468.         mov     word ptr devhlp,ax
  469.         mov     ax,es:[bx+10h]
  470.         mov     word ptr devhlp+2,ax
  471.  
  472.         mov     al,es:[bx+16h]  ; unit code for this drive
  473.         add     al,'A'          ; convert to ASCII and place
  474.     mov    drive,al    ; in output string
  475.  
  476.                                 ; display sign-on message...
  477.         push    stdout          ; handle for standard output
  478.         push    ds              ; address of message
  479.         push    offset DGROUP:ident
  480.         push    ident_len       ; length of message
  481.         push    ds              ; receives bytes written
  482.         push    offset DGROUP:wlen
  483.         call    DosWrite
  484.  
  485.                                 ; set offsets to end of code
  486.                                 ; and data segments
  487.         mov     word ptr es:[bx+0eh],offset _TEXT:Init
  488.         mov     word ptr es:[bx+10h],offset DGROUP:ident
  489.  
  490.                                 ; logical units supported
  491.         mov     byte ptr es:[bx+0dh],1
  492.  
  493.                                 ; pointer to BPB array
  494.         mov     word ptr es:[bx+12h],offset DGROUP:array
  495.         mov     word ptr es:[bx+14h],ds
  496.  
  497.         push    es              ; save request packet address
  498.         push    bx
  499.  
  500.                 ; allocate RAM disk storage
  501.         mov     bx,0            ; AX:BX = size of allocated
  502.         mov     ax,1            ; block in bytes
  503.         mov     dh,0            ; request block above 1 MB
  504.         mov     dl,AllocPhys    ; function number
  505.         call    devhlp          ; transfer to kernel
  506.         jc      Init9           ; jump if allocation failed
  507.  
  508.                                 ; save physical address
  509.                                 ; of allocated block
  510.         mov     word ptr dbase,bx
  511.         mov     word ptr dbase+2,ax
  512.  
  513.     call    format        ; format the RAM disk
  514.         jc      Init9           ; jump if format failed
  515.  
  516.         pop     bx              ; restore request packet address
  517.         pop     es
  518.  
  519.         mov     ax,0100h        ; return 'done' status
  520.         ret
  521.  
  522. Init9:                          ; abort driver installation
  523.  
  524.         pop     bx              ; restore request packet address
  525.         pop     es
  526.  
  527.                                 ; display installation aborted...
  528.         push    stdout          ; handle for standard output
  529.         push    ds              ; address of message
  530.         push    offset DGROUP:abort
  531.         push    abort_len       ; length of message
  532.         push    ds              ; receives bytes written
  533.         push    offset DGROUP:wlen
  534.         call    DosWrite        ; transfer to OS/2
  535.  
  536.                                 ; set zero units
  537.         mov     byte ptr es:[bx+0dh],0
  538.  
  539.                                 ; set lengths of code and
  540.                                 ; data segments
  541.         mov     word ptr es:[bx+0eh],0
  542.         mov     word ptr es:[bx+10h],0
  543.  
  544.         mov     ax,810ch        ; return error + done +
  545.                                 ; general failure
  546.         ret
  547.  
  548. Init    endp
  549.  
  550.  
  551. Format    proc    near        ; format the RAM disk area
  552.  
  553.                                 ; calculate length of 
  554.                 ; RAM disk control areas
  555.         mov     al,byte ptr bpb+5
  556.         cbw                     ; number of FATs
  557.         mov     cx,bpb+0bh      ; * sectors per FAT
  558.         mul     cx
  559.     mov    cx,bpb+6    ; entries in root directory
  560.     shr    cx,4        ; divided by 16 for sectors
  561.         add     ax,cx           ; (FAT + dir sectors
  562.         add     ax,bpb+3        ; + reserved sectors)
  563.         mov     cx,secsize      ; * bytes/sector
  564.         mul     cx              ; = total length
  565.         mov     cx,ax
  566.  
  567.                 ; convert RAM disk base to
  568.                                 ; virtual address
  569.         mov     bx,word ptr dbase
  570.         mov     ax,word ptr dbase+2
  571.         mov     dh,1            ; leave result in ES:DI
  572.         mov     dl,PhysToVirt   ; function number
  573.         call    devhlp          ; transfer to kernel
  574.         jc      Format9         ; jump if error
  575.  
  576.         xor     ax,ax           ; now zero control areas
  577.         cld                     ; (assume CX still = length)
  578.         rep stosb
  579.  
  580.         mov     ax,0            ; get address of logical 
  581.         call    MapES           ; sector zero
  582.         jc      Format9         ; jump if error
  583.         mov     si,offset DGROUP:bootrec
  584.         mov     cx,bootrec_len  ; copy boot record
  585.         rep movsb               ; to logical sector zero
  586.  
  587.         mov     ax,word ptr bpb+3
  588.         call    MapES           ; get address of FAT sector
  589.         jc      Format9         ; jump if error
  590.         mov     al,byte ptr bpb+0ah     
  591.         mov     es:[di],al      ; media ID byte into FAT
  592.         mov     word ptr es:[di+1],-1
  593.  
  594.         mov     ax,word ptr bpb+3
  595.         add     ax,word ptr bpb+0bh
  596.         call    MapES           ; get address of directory
  597.         jc      Format9         ; jump if error
  598.         mov     si,offset DGROUP:volname
  599.         mov     cx,volname_len
  600.         rep movsb               ; copy volume label to it
  601.  
  602.         mov     dl,UnPhysToVirt ; function number
  603.         call    devhlp          ; transfer to kernel
  604.  
  605.         clc                     ; signal format successful
  606.  
  607. Format9:                        ; return with Carry = 0
  608.         ret                     ; if success, 1 if error
  609.  
  610. Format  endp
  611.  
  612. _TEXT   ends
  613.  
  614.         end
  615.