home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol8n12.zip / XMSDISK.ASM < prev   
Assembly Source File  |  1989-02-13  |  28KB  |  644 lines

  1.         title   XMSDISK XMS-aware RAMdisk
  2.         page    55,132
  3.  
  4. ; XMSDISK.ASM --- XMS-aware RAMdisk device driver
  5. ; Copyright (C) 1989 Ziff Davis Communications
  6. ; PC Magazine * Ray Duncan
  7. ; Also requires ITOA.ASM and ATOI.ASM.
  8. ;
  9. ; To build:     MASM XMSDISK;
  10. ;               MASM ATOI;
  11. ;               MASM ITOA;
  12. ;               LINK XMSDISK+ATOI+ITOA;
  13. ;               EXE2BIN XMSDISK.EXE XMSDISK.BIN
  14. ;               DEL XMSDISK.EXE
  15. ;
  16. ; To install:   copy XMSDISK.SYS to the boot disk, add
  17. ;
  18. ;                       DEVICE=XMSDISK.BIN  nnnK
  19. ;               to the CONFIG.SYS file.  This must follow
  20. ;               the DEVICE= line that loads the XMM (usually
  21. ;               HIMEM.SYS).  The parameter nnn is the desired
  22. ;               RAMdisk size in KB.  If nnn is missing or zero,
  23. ;               all available extended memory is used.
  24. ;
  25. _TEXT   segment public 'CODE'
  26.  
  27.         extrn   atoi:near
  28.         extrn   itoa:near
  29.  
  30.         assume  cs:_TEXT,ds:_TEXT,es:NOTHING
  31.  
  32.         org     0
  33.  
  34. maxcmd  equ     24                      ; maximum driver command code
  35.  
  36. cr      equ     0dh                     ; ASCII carriage return
  37. lf      equ     0ah                     ; ASCII line feed
  38. blank   equ     020h                    ; ASCII space code
  39. eom     equ     '$'                     ; end of message indicator
  40.  
  41. secsize equ     512                     ; bytes per sector (IBM standard)
  42. dirsize equ     256                     ; entries in root directory             
  43.  
  44. request struc                           ; request packet template
  45. len     db      ?                       ; length of request packet
  46. unit    db      ?                       ; unit number for this request
  47. command db      ?                       ; request packet's command code
  48. status  dw      ?                       ; status returned by driver
  49.         db      8 dup (?)               ; reserved area
  50. media   db      ?                       ; media descriptor byte
  51. address dd      ?                       ; memory address for transfer
  52. count   dw      ?                       ; byte/sector count value
  53. sector  dw      ?                       ; starting sector value
  54. request ends                            ; end of request packet template
  55.  
  56. header  equ     $                       ; device driver header
  57.         dd      -1                      ; link to next driver 
  58.         dw      0                       ; device attribute word
  59.         dw      strat                   ; device "Strategy" entry point
  60.         dw      intr                    ; device "Interrupt" entry point
  61.         db      1                       ; number of units, this device
  62.         db      7 dup (0)               ; reserved (block drivers)
  63.  
  64. rqptr   dd      ?                       ; far pointer to request packet
  65. savesp  dw      0                       ; save kernel SS:SP during switch
  66. savess  dw      0                       ; to driver's private stack
  67. xmm     dd      0                       ; address of XMM entry point
  68. handle  dw      0                       ; handle for extended memory block
  69. total   dw      0                       ; total extended mem available (KB)
  70. largest dw      0                       ; largest free block available (KB)
  71. alloc   dw      0                       ; extended memory allocated (KB)
  72. clust   dw      0                       ; total clusters in RAMdisk
  73. xfersec dw      0                       ; current sector for transfer
  74. xfercnt dw      0                       ; sectors successfully transferred
  75. xferreq dw      0                       ; number of sectors requested   
  76.  
  77. array   dw      bpb                     ; array of pointers to BPBs
  78.                                         ; for each logical unit
  79.  
  80. movpars equ     $                       ; XMS Function 0BH parameter block 
  81. movelen dd      0                       ; length to move in bytes
  82. shandle dw      0                       ; source handle
  83. soffset dd      0                       ; source offset or far pointer
  84. dhandle dw      0                       ; destination handle
  85. doffset dd      0                       ; destination offset or far pointer
  86.  
  87. bootrec equ     $                       ; boot record for logical sec. 0
  88.         jmp     $                       ; phony JMP at start of boot
  89.         nop                             ; sector (must be 3 bytes)
  90.         db      'IBM  3.3'              ; OEM identity field
  91.                                         ; BIOS Parameter Block (BPB)
  92. bpb     dw      secsize                 ; 0   bytes per sector
  93.         db      2                       ; 2   sectors per cluster
  94.         dw      1                       ; 3   reserved sectors
  95.         db      1                       ; 5   number of FATs
  96.         dw      dirsize                 ; 6   root directory entries
  97.         dw      0                       ; 8   total sectors
  98.         db      0f8h                    ; 0AH medium descriptor byte
  99.         dw      0                       ; 0BH sectors per FAT
  100. bootrec_len equ $-bootrec               ; length of boot record
  101.  
  102.         even                            ; force word alignment
  103.         dw      128 dup (0)
  104. stk     equ     $                       ; local stack for driver
  105.  
  106. ;
  107. ; Driver 'strategy' routine; called by MS-DOS kernel with
  108. ; ES:BX pointing to driver request packet.
  109. ;
  110. strat   proc    far                     ; driver 'strategy' routine
  111.  
  112.         mov     word ptr cs:rqptr,bx    ; save request packet address
  113.         mov     word ptr cs:rqptr+2,es
  114.         ret                             ; back to MS-DOS kernel
  115.  
  116. strat   endp
  117.  
  118. ;
  119. ; Driver 'interrupt' routine, called by MS-DOS kernel immediately
  120. ; after call to 'strategy' routine to process I/O request.
  121. ;
  122. intr    proc    far                     
  123.  
  124.         push    ax                      ; save all registers
  125.         push    bx
  126.         push    cx
  127.         push    dx
  128.         push    ds
  129.         push    es
  130.         push    di
  131.         push    si
  132.         push    bp
  133.  
  134.         mov     ax,cs                   ; make local data addressable
  135.         mov     ds,ax
  136.         mov     savess,ss               ; save DOS kernel's stack
  137.         mov     savesp,sp
  138.         mov     ss,ax                   ; set SS:SP to point to 
  139.         mov     sp,offset stk           ; (larger) local stack
  140.  
  141.         les     di,rqptr                ; ES:DI = request packet
  142.         mov     bl,es:[di.command]      ; get BX = command code
  143.         xor     bh,bh
  144.         cmp     bx,maxcmd               ; make sure it's legal
  145.         jle     intr1                   ; jump, function code is ok
  146.         mov     ax,8003h                ; return 'unknown command' error
  147.         jmp     intr2
  148.  
  149. intr1:  shl     bx,1                    ; branch to command code routine
  150.         call    word ptr [bx+dispch]    ; must return AX = status
  151.         les     di,rqptr                ; ES:DI = request packet again
  152.  
  153. intr2:  or      ax,0100h                ; merge 'done' bit into status
  154.         mov     es:[di.status],ax       ; store into request packet
  155.  
  156.         mov     ss,savess               ; restore DOS kernel's stack
  157.         mov     sp,savesp
  158.  
  159.         pop     bp                      ; restore general registers
  160.         pop     si
  161.         pop     di
  162.         pop     es
  163.         pop     ds
  164.         pop     dx
  165.         pop     cx
  166.         pop     bx
  167.         pop     ax
  168.         ret                             ; back to kernel
  169.  
  170. intr    endp
  171.  
  172. ;
  173. ; Dispatch table for driver commands
  174. ;
  175. dispch  dw      init                    ;  0 = initialize driver
  176.         dw      medchk                  ;  1 = media check on block device
  177.         dw      bldbpb                  ;  2 = build BIOS parameter block
  178.         dw      error                   ;  3 = I/O control read 
  179.         dw      read                    ;  4 = read from device
  180.         dw      error                   ;  5 = non-destructive read 
  181.         dw      error                   ;  6 = return current input status
  182.         dw      error                   ;  7 = flush device input buffers
  183.         dw      write                   ;  8 = write to device
  184.         dw      write                   ;  9 = write with verify
  185.         dw      error                   ; 10 = return current output status
  186.         dw      error                   ; 11 = flush output buffers
  187.         dw      error                   ; 12 = I/O control write 
  188.         dw      error                   ; 13 = device open        (DOS 3.0+)
  189.         dw      error                   ; 14 = device close       (DOS 3.0+)
  190.         dw      error                   ; 15 = removeable media   (DOS 3.0+)
  191.         dw      error                   ; 16 = output until busy  (DOS 3.0+)   
  192.         dw      error                   ; 17 = not used
  193.         dw      error                   ; 18 = not used
  194.         dw      error                   ; 19 = generic IOCTL      (DOS 3.2+) 
  195.         dw      error                   ; 20 = not used
  196.         dw      error                   ; 21 = not used
  197.         dw      error                   ; 22 = not used
  198.         dw      error                   ; 23 = get logical device (DOS 3.2+)
  199.         dw      error                   ; 24 = set logical device (DOS 3.2+)
  200.  
  201. ;
  202. ; Media Check routine (command code 1).  Returns code indicating
  203. ; whether medium has been changed since last access.
  204. ;
  205. medchk  proc    near
  206.  
  207.         mov     byte ptr es:[di+14],1   ; return "not changed" code
  208.         xor     ax,ax                   ; return success status
  209.         ret
  210.  
  211. medchk  endp
  212.  
  213. ;
  214. ; Build BPB routine (command code 2).  Returns pointer to valid
  215. ; BIOS Parameter Block for logical drive.
  216. ;
  217. bldbpb  proc    near
  218.  
  219.         mov     word ptr es:[di+20],cs  ; put BPB address in packet
  220.         mov     word ptr es:[di+18],offset bpb
  221.         xor     ax,ax                   ; return success status
  222.         ret
  223.  
  224. bldbpb  endp
  225.  
  226. ;
  227. ; Read routine (command code 4).  Transfers logical sector(s)
  228. ; from RAMdisk storage to specified address.
  229. ;
  230. read    proc    near
  231.  
  232.         mov     ax,es:[di.sector]       ; ES:DI = request packet
  233.         mov     xfersec,ax              ; save starting sector number
  234.         mov     ax,es:[di.count]        
  235.         mov     xferreq,ax              ; save sectors requested
  236.         mov     xfercnt,0               ; init sectors transferred count
  237.         mov     ax,word ptr es:[di.address]
  238.         mov     word ptr doffset,ax     ; requestor's buffer address
  239.         mov     ax,word ptr es:[di.address+2]
  240.         mov     word ptr doffset+2,ax
  241.         mov     ax,handle               ; source handle = extended
  242.         mov     shandle,ax              ;                 memory handle
  243.         mov     dhandle,0               ; destination handle = 0
  244.         mov     word ptr movelen,secsize; logical sector length
  245.  
  246. read1:  mov     ax,xfercnt              ; done with all sectors yet?
  247.         cmp     ax,xferreq
  248.         je      read2                   ; jump if transfer completed
  249.  
  250.         mov     ax,xfersec              ; source offset = 
  251.         mul     bpb                     ; sector no. * bytes/sector
  252.         mov     word ptr soffset,ax
  253.         mov     word ptr soffset+2,dx
  254.  
  255.         mov     ah,0bh                  ; move this sector from
  256.         mov     si,offset movpars       ; extended memory to requestor
  257.         call    xmm
  258.         or      ax,ax                   ; any error?
  259.         jz      read4                   ; yes, abort transfer
  260.  
  261.         inc     xfersec                 ; advance sector and address
  262.         add     word ptr doffset+2,(secsize/16)
  263.         inc     xfercnt                 ; count sectors transferred
  264.         jmp     read1
  265.  
  266. read2:                                  ; all sectors transferred,
  267.         xor     ax,ax                   ; return success status
  268.  
  269. read3:  les     di,rqptr                ; get address of request packet
  270.         mov     bx,xfercnt              ; return sectors transferred count
  271.         mov     es:[di.count],bx
  272.         ret
  273.  
  274. read4:  mov     ax,800bh                ; XMM error, return 'read fault'
  275.         jmp     read3
  276.  
  277. read    endp
  278.  
  279. ;
  280. ; Write (command code 8) and Write with Verify (command code 9)
  281. ; routine.  Transfers logical sector(s) from specified address
  282. ; to RAMdisk storage.
  283. ;
  284. write   proc    near
  285.  
  286.         mov     ax,es:[di.sector]       ; ES:DI = request packet
  287.         mov     xfersec,ax              ; save starting sector number
  288.         mov     ax,es:[di.count]        
  289.         mov     xferreq,ax              ; save sectors requested
  290.         mov     xfercnt,0               ; init sectors transferred count
  291.         mov     ax,word ptr es:[di.address]     
  292.         mov     word ptr soffset,ax     ; requestor's buffer address
  293.         mov     ax,word ptr es:[di.address+2]
  294.         mov     word ptr soffset+2,ax
  295.         mov     ax,handle               ; destination handle = extended
  296.         mov     dhandle,ax              ;                   memory handle
  297.         mov     shandle,0               ; zero out source handle
  298.         mov     word ptr movelen,secsize; logical sector length
  299.  
  300. write1: mov     ax,xfercnt              ; done with all sectors yet?
  301.         cmp     ax,xferreq
  302.         je      write2                  ; jump if transfer completed
  303.  
  304.         mov     ax,xfersec              ; destination offset = 
  305.         mul     bpb                     ; sector no. * bytes/sector
  306.         mov     word ptr doffset,ax
  307.         mov     word ptr doffset+2,dx
  308.  
  309.         mov     ah,0bh                  ; move this sector from
  310.         mov     si,offset movpars       ; requestor to extended memory
  311.         call    xmm
  312.         or      ax,ax                   ; any error?
  313.         jz      write4                  ; yes, abort transfer
  314.  
  315.         inc     xfersec                 ; advance sector and address
  316.         add     word ptr soffset+2,(secsize/16)
  317.         inc     xfercnt                 ; count sectors transferred
  318.         jmp     write1
  319.  
  320. write2:                                 ; all sectors successfully
  321.         xor     ax,ax                   ; transferred, return ok status
  322.  
  323. write3:
  324.         les     di,rqptr                ; get address of request packet
  325.         mov     bx,xfercnt              ; return actual transfer count
  326.         mov     es:[di.count],bx
  327.         ret
  328.  
  329. write4: mov     ax,800ah                ; XMM error, return 'write fault'
  330.         jmp     write3          
  331.  
  332. write   endp
  333.  
  334. ;
  335. ; Dummy routine for unsupported driver command codes
  336. ;
  337. error   proc    near
  338.  
  339.         mov     ax,8103h                ; return 'unknown command' error
  340.         ret
  341.  
  342. error   endp
  343.  
  344. ;
  345. ; Initialization routine, called at driver load time.  Returns
  346. ; address of 'init' label to MS-DOS as start of free memory, so
  347. ; that memory occupied by 'init' and its subroutines is reclaimed.
  348. ;
  349. init    proc    near                    ; command code 0 = initialize
  350.  
  351.         mov     ax,4300h                ; check if XMM present
  352.         int     2fh
  353.         cmp     al,80h                  ; status = installed?
  354.         je      init1                   ; yes, proceed
  355.         mov     dx,offset msg1          ; no, display error message
  356.         jmp     init8                   ; and abort installation
  357.  
  358. init1:  mov     ax,4310h                ; XMM available, request entry
  359.         int     2fh                     ; point and save it
  360.         mov     word ptr xmm,bx
  361.         mov     word ptr xmm+2,es
  362.  
  363.         mov     ah,8                    ; get available extended memory
  364.         call    xmm                     ; transfer to XMM
  365.         mov     total,dx                ; save total KB available
  366.         mov     largest,ax              ; save largest free block
  367.         cmp     largest,64              ; at least 64 KB available?
  368.         jae     init2                   ; yes, proceed
  369.         mov     dx,offset msg2          ; no, display error message
  370.         jmp     init8                   ; and abort installation
  371.  
  372. init2:  les     di,rqptr                ; let ES:DI = request packet
  373.         lds     si,es:[di+18]           ; point to CONFIG.SYS line
  374.  
  375. init3:  lodsb                           ; scan for end of driver name
  376.         cmp     al,blank
  377.         ja      init3                   ; loop while within name
  378.         dec     si                      ; point to delimiter and
  379.         call    atoi                    ; convert size parameter
  380.         push    cs                      ; make our data addressable
  381.         pop     ds
  382.         or      ax,ax                   ; size parameter missing?
  383.         jz      init4                   ; yes, use all extended memory
  384.         cmp     ax,largest              ; requested > available?
  385.         jna     init5                   ; no, jump
  386.  
  387. init4:  mov     ax,largest              ; use all of available memory
  388.  
  389. init5:  mov     alloc,ax                ; save requested size
  390.         mov     dx,ax                   ; DX = RAMdisk size in KB
  391.         mov     ah,9                    ; XMS function 9 = allocate
  392.         call    xmm                     ; transfer to XMM
  393.         or      ax,ax                   ; allocation successful?
  394.         jnz     init6                   ; yes, proceed
  395.         mov     dx,offset msg3          ; no, display error message
  396.         jmp     init8                   ; and abort installation
  397.  
  398. init6:  mov     handle,dx               ; save extended memory handle
  399.         call    makebpb                 ; set up Bios Parameter Block
  400.         call    format                  ; format the RAMdisk
  401.         jnc     init7                   ; jump if no error during format
  402.         mov     dx,offset msg4          ; formatting error, exit
  403.         jmp     init8
  404.  
  405. init7:  les     di,rqptr                ; let ES:DI = request packet
  406.         mov     al,es:[di+22]           ; get drive code from header,
  407.         add     al,'A'                  ; convert to ASCII for output
  408.         mov     ident1,al
  409.         mov     ax,total                ; convert KB available to ASCII
  410.         mov     si,offset ident2
  411.         mov     cx,10
  412.         call    itoa
  413.         mov     ax,largest              ; convert KB largest free block
  414.         mov     si,offset ident3
  415.         call    itoa
  416.         mov     ax,alloc                ; convert KB allocated to ASCII
  417.         mov     si,offset ident4
  418.         call    itoa
  419.  
  420.         mov     dx,offset ident         ; display sign-on message
  421.         mov     ah,9                    ; function 9 = display string
  422.         int     21h                     ; transfer to MS-DOS    
  423.  
  424.                                         ; set top of driver address
  425.         mov     word ptr es:[di.address],offset init
  426.         mov     word ptr es:[di.address+2],cs
  427.         mov     byte ptr es:[di+13],1   ; indicate 1 logical unit
  428.         mov     word ptr es:[di+20],cs  ; return address of BPB array
  429.         mov     word ptr es:[di+18],offset array
  430.         jmp     init9
  431.  
  432. init8:                                  ; XMSDISK initialization failed
  433.         push    dx                      ; save specific error message
  434.         mov     dx,offset errmsg        ; display error heading
  435.         mov     ah,9                    ; function 9 = display string
  436.         int     21h                     ; transfer to MS-DOS
  437.         pop     dx                      ; display error description
  438.         mov     ah,9                    ; function 9 = display string
  439.         int     21h                     ; transfer to MS-DOS
  440.  
  441.         les     di,cs:rqptr             ; let ES:DI=request packet
  442.                                         ; set driver end = driver start
  443.         mov     word ptr es:[di.address],0
  444.         mov     word ptr es:[di.address+2],cs
  445.         mov     byte ptr es:[di+13],0   ; set no. of logical units = 0
  446.  
  447. init9:  xor     ax,ax                   ; return success status 
  448.         ret
  449.  
  450. init    endp
  451.  
  452. ;
  453. ; Set up total sectors and sectors per FAT fields of BIOS Parameter
  454. ; Block according to size of RAMdisk.  Calculate and save total
  455. ; clusters (indicates whether 12-bit or 16-bit FAT will be used).
  456. ;
  457. makebpb proc    near
  458.         
  459.         mov     ax,alloc                ; get size of allocated block
  460.         mov     dx,1024                 ; convert KB to bytes
  461.         mul     dx                      ; divided by bytes/sector
  462.         div     word ptr bpb            ; gives AX = total sectors
  463.         mov     bpb+8,ax                ; update BPB with total sectors
  464.         xor     dx,dx                   ; sectors / (sectors/cluster)
  465.         xor     ch,ch                   ; = total clusters
  466.         mov     cl,byte ptr bpb+2
  467.         div     cx
  468.         mov     clust,ax                ; save total clusters   
  469.         cmp     ax,4086                 ; clusters < 4087?
  470.         jna     makeb1                  ; yes, jump 
  471.         shl     ax,1                    ; no, assume 16-bit FAT
  472.         jmp     makeb2                  ; clusters * 2 = bytes/FAT
  473.  
  474. makeb1: mov     dx,ax                   ; if clusters < 4087, 12-bit FAT
  475.         add     ax,ax                   ; clusters * 1.5 = bytes/FAT
  476.         add     ax,dx
  477.         shr     ax,1
  478.         jnc     makeb2
  479.         inc     ax                      ; round bytes up if necessary
  480.  
  481. makeb2: xor     dx,dx                   ; (bytes/FAT) / (bytes/sec)
  482.         div     word ptr bpb            ; = sectors/FAT
  483.         or      dx,dx                   ; any remainder?
  484.         jz      makeb3                  ; no,jump
  485.         inc     ax                      ; round up to next sector
  486.  
  487. makeb3: mov     bpb+0bh,ax              ; update FAT size in BPB
  488.         ret
  489.  
  490. makebpb endp
  491.  
  492. ;
  493. ; Format RAMdisk.  First write zeros into all sectors of reserved
  494. ; area, FAT, and root directory.  Then copy phony boot record to
  495. ; boot sector, initialize medium ID byte at beginning of FAT, and
  496. ; place phony volume label in first sector of root directory.
  497. ;
  498. format  proc    near            
  499.  
  500.         push    ds                      ; initialize sector buffer
  501.         pop     es                      ; to zeros so we can clear
  502.         mov     di,offset secbuf        ; out reserved area, FAT,
  503.         mov     cx,secsize              ; and root directory
  504.         xor     al,al
  505.         rep stosb
  506.  
  507.         mov     ax,bpb+6                ; no. of directory entries
  508.         mov     cx,32                   ; * (32 bytes/entry)
  509.         mul     cx                      ; = bytes in root directory
  510.         div     bpb                     ; / (bytes/sector)
  511.         or      dx,dx                   ; = sectors in root directory
  512.         jz      fmt1
  513.         inc     ax                      ; round up any partial sector
  514.  
  515. fmt1:   add     ax,bpb+3                ; + reserved sectors
  516.         add     ax,bpb+0bh              ; + sectors in FAT
  517.         mov     xferreq,ax              ; = total sectors to clear
  518.         mov     xfercnt,0               ; initialize sector counter
  519.  
  520.                                         ; set up move parameter block
  521.         mov     word ptr movelen,secsize; length to move
  522.         mov     shandle,0               ; source handle and address
  523.         mov     word ptr soffset,offset secbuf
  524.         mov     word ptr soffset+2,cs
  525.         mov     ax,handle               ; destination extended memory
  526.         mov     dhandle,ax              ; block handle
  527.         mov     word ptr doffset,0      ; initial destination offset
  528.         mov     word ptr doffset+2,0
  529.  
  530. fmt2:   mov     ah,0bh                  ; write this sector
  531.         mov     si,offset movpars       ; DS:SI = parameter block
  532.         call    xmm                     ; transfer to XMM
  533.         or      ax,ax                   ; test move status
  534.         jnz     fmt3
  535.         jmp     fmt5                    ; abort if move failed
  536.  
  537. fmt3:   add     word ptr doffset,secsize; increment destination address
  538.         adc     word ptr doffset+2,0
  539.         mov     ax,xfercnt              ; count sectors initialized
  540.         inc     ax
  541.         mov     xfercnt,ax
  542.         cmp     ax,xferreq              ; done yet?
  543.         jne     fmt2                    ; not done, write another
  544.  
  545.         mov     ax,bpb+3                ; calculate offset of first
  546.         mul     bpb                     ; FAT sector in RAMdisk buffer
  547.         mov     word ptr doffset,ax     ; set destination address
  548.         mov     word ptr doffset+2,dx
  549.  
  550.         mov     al,byte ptr bpb+0ah     ; set up medium ID byte
  551.         mov     secbuf,al               ; in first FAT sector
  552.         mov     word ptr secbuf+1,-1    ; assume 12-bit FAT
  553.         cmp     clust,4086              ; more than 4086 clusters?
  554.         jna     fmt4                    ; no, jump
  555.         mov     secbuf+3,0ffh           ; yes, use 16-bit FAT
  556.  
  557. fmt4:   mov     ah,0bh                  ; write first FAT sector
  558.         mov     si,offset movpars
  559.         call    xmm
  560.         or      ax,ax                   ; test move status
  561.         jz      fmt5                    ; abort if move failed
  562.  
  563.         mov     word ptr doffset,0      ; offset of logical sector 0
  564.         mov     word ptr doffset+2,0
  565.         mov     word ptr soffset,offset bootrec
  566.         mov     word ptr movelen,bootrec_len
  567.         mov     ah,0bh                  ; copy phony boot record
  568.         mov     si,offset movpars       ; to logical sector 0
  569.         call    xmm
  570.         or      ax,ax                   ; test move status
  571.         jz      fmt5                    ; abort if move failed
  572.  
  573.         mov     ax,bpb+0bh              ; calculate offset of first
  574.         add     ax,bpb+3                ; root directory sector
  575.         mul     bpb                     ; in RAMdisk buffer
  576.         mov     word ptr doffset,ax
  577.         mov     word ptr doffset+2,dx
  578.         mov     word ptr soffset,offset volname
  579.         mov     word ptr movelen,volname_len
  580.         mov     ah,0bh                  ; copy phony volume label
  581.         mov     si,offset movpars       ; to first directory sector
  582.         call    xmm
  583.         or      ax,ax                   ; test move status
  584.         jz      fmt5                    ; abort if move failed
  585.  
  586.         clc                             ; successful format, 
  587.         ret                             ; return CY = clear
  588.  
  589. fmt5:   stc                             ; format failed, 
  590.         ret                             ; return CY = set
  591.  
  592. format  endp
  593.  
  594. ;
  595. ; Miscellaneous data used during initialization, then discarded.
  596. ;
  597. ident   db      cr,lf,lf                ; sign-on message
  598.         db      'XMSDISK Extended Memory RAMdisk'
  599.         db      cr,lf
  600.         db      'Copyright (C) 1989 Ziff Davis Communications'
  601.         db      cr,lf
  602.         db      'PC Magazine * Ray Duncan'
  603.         db      cr,lf,lf
  604.         db      'XMSDISK will be drive '
  605. ident1  db      'X:',cr,lf
  606.         db      'Extended memory available:'
  607. ident2  db      '       KB',cr,lf
  608.         db      'Largest free memory block:'
  609. ident3  db      '       KB',cr,lf
  610.         db      'Extended memory allocated:'
  611. ident4  db      '       KB',cr,lf,eom
  612.  
  613. errmsg  db      cr,lf
  614.         db      'XMSDISK installation error:'
  615.         db      cr,lf,eom
  616.  
  617. msg1    db      'Extended Memory Manager not found.'
  618.         db      cr,lf,eom
  619.  
  620. msg2    db      'Insufficient extended memory available.'
  621.         db      cr,lf,eom
  622.  
  623. msg3    db      'Extended memory allocation failed.'
  624.         db      cr,lf,eom
  625.  
  626. msg4    db      'Unable to format RAMdisk.'
  627.         db      cr,lf,eom
  628.  
  629. volname db      'XMSDISK    '           ; phony volume label
  630.         db      08h                     ; volume label attribute byte
  631.         db      10 dup (0)
  632.         dw      0                       ; time = 00:00:00
  633.         dw      1241h                   ; date = February 1, 1989
  634.         db      6 dup (0)
  635. volname_len equ $-volname
  636.  
  637. secbuf  db      secsize dup (?)         ; sector buffer for format
  638.  
  639. _TEXT   ends
  640.         
  641.         end
  642.  
  643.