home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 1999 Hardware / PCWExtra.iso / sharewar / pcproble / CMOSSV.EXE / CMOS.ASM < prev    next >
Encoding:
Assembly Source File  |  1997-07-08  |  21.1 KB  |  936 lines

  1.     PAGE    60,132
  2. NAME    CMOSSAVE
  3.     TITLE    CMOSSave Save CMOS to a file on disk or floppy
  4. Comment |
  5.     Version 3.0 by Roedy Green
  6.     works with MASM 6.0 and Optasm
  7.     This assembler code generates all three programs:
  8.     CMOSSAVE.COM CMOSREST.COM and CMOSCHK.COM.
  9.  
  10. Note that we never compute or verify a checksum.  Every vendor computes
  11. may compute it a slightly different way.
  12.  
  13. To come:
  14.   /V:xx - additional volatile byte
  15.  
  16. See CMOS.TXT for details on use.
  17.  
  18.   USAGE:
  19.  
  20. Examples:
  21. *********
  22.  
  23. CMOSSave A:\MyCMOS.Sav /Q
  24.  
  25. CMOSRest A:\MyCMOS.Sav /Q
  26.  
  27. CMOSChk  A:\ByCMOS.Sav /Q
  28.  
  29. Syntax errors or missing file trouble generates an ERRORLEVEL 4.
  30. CMOSChk generates an ERRORLEVEL 1 if the CMOS has changed since
  31. the CMOSSave was done.
  32.  
  33. Version History
  34. ***************
  35.  
  36. Version 1.0
  37. - released to BIX 91/09/07
  38.  
  39. Version 1.1
  40. - released to BIX 91/09/18
  41. - added special check for small 64 character CMOSes.
  42.  
  43. Version 1.2
  44. - fix spelling errors
  45. - use CMOS.SAV instead of MyCMOS.SAV in examples
  46.  
  47. Version 1.3
  48. - now consider fewer bytes volatile, restore more stuff.
  49. - hints in docs about clearing CMOS.
  50.  
  51. Version 1.4
  52. - now consider flags Status register C, offset 0C as volatile.
  53.   fixes false alarms.
  54.  
  55. Version 1.5 1994 June 1
  56. - change of address and phone number
  57. - address now appears in the banner.
  58.  
  59. Version 1.6 1994 August 29
  60. - more information about how CMOS bits are used.
  61.  
  62. Version 2.0 1994 October 1
  63. - easier configuration of CHKCMOS volatile bytes.
  64. - smarter bat files.
  65. - docs on different ways to use.
  66.  
  67. Version 2.2 1995 April 16
  68. - docs on use before experimentation
  69.  
  70. Version 2.3 1995 July 24
  71. - add 3F as volatile byte.  PCI Pentiums are volatile.
  72.  
  73. Version 2.4 1995 August 7
  74. - add /Q switch to suppress banners, only complain
  75. - presume installation done to C:\CMP and that files saved there too.
  76.  
  77. Version 2.5 1996 January 27
  78. - better documentation
  79.  
  80. Version 2.6 1996 June 3
  81. - better documentation. Win 95 explanations.
  82.  
  83. Version 2.7 1996 August 19
  84. - treat hex 3F differently in CMOSRest and CMOSChk
  85.  
  86. Version 2.8 1996 October  23
  87. - POB in Quathiaski address.  Back to C:\SAFE as presumed directory
  88. - lower cost $10, combined site licence.
  89.  
  90. Version 2.9 1996 November 22
  91. - fix missing com files.
  92.  
  93. Version 3.0 1997 July 8
  94. - notes on Y2K checking
  95. - notes on separate rescue diskettes.
  96.  
  97. CMOS Usage - see also CMOS.OFS
  98.  
  99. How to Assemble
  100. ***************
  101.  
  102. Manually set the GENERATING equate embedded in this code, then:
  103.  
  104. to assemble with MASM 6.0 use:
  105. ML.EXE /AT /c /Fl /VM /Zf /Zm CMOS.Asm
  106. LINK.EXE /TINY /MAP CMOS.Obj,CMOS.com,CMOS.map;
  107. copy cmos.com cmossave.com
  108.  
  109. to assemble with OPTASM use:
  110. Optasm     CMOS.Asm,CMOS.Obj,CMOS.Lst/L/N/G/S
  111. OLINK     CMOS.Obj,CMOS.COM,/MAP/TINY;
  112. copy cmos.com cmossave.com
  113.  
  114. Register Conventions
  115. ********************
  116.  
  117. Subroutines may trash all registers except those explicity
  118. documented as input or output.
  119.  
  120. | ; end of comment
  121.  
  122.  
  123. ;    E Q U A T E S
  124.  
  125. CMOSSAVE    EQU    1
  126. CMOSREST    EQU    2
  127. CMOSCHK     EQU    3
  128.  
  129. ; use /DGenerating#CMOSSAVE
  130. ;     /DGenerating#CMOSREST
  131. ;     /DGenerating#CMOSCHK
  132. ; on the assembler command line to select which version
  133. ; of the code to assemble.
  134. ;    Or add code following of the form:
  135.  
  136. ; GENERATING EQU CMOSSave
  137.  
  138.  
  139.     If    Generating eq CMOSSave
  140. %OUT Generating CMOSSave.Com
  141.     Endif
  142.  
  143.     If    Generating eq CMOSRest
  144. %OUT Generating CMOSRest.Com
  145.     endif
  146.  
  147.     If    Generating eq CMOSChk
  148. %OUT Generating CMOSChk.Com
  149.     endif
  150. ;==============================================================
  151.  
  152.  
  153. stack    segment stack        ; keep MS link happy by providing null stack
  154. stack    ends
  155.  
  156. CODE    SEGMENT PARA        ; start off in code.
  157.  
  158. ;==============================================================
  159.  
  160. data    segment byte        ; provide a separate DATA segment
  161.                 ; actually all come after the code
  162. ;==============================================================
  163. ;  V A R I A B L E S
  164.  
  165.  
  166.     If    Generating eq CMOSSave
  167.  
  168. BannerMsg    label    byte
  169.     DB    '░▒▓█ CMOSSave 3.0 █▓▒░',13d,10d
  170.     DB    13d,10d
  171.     DB    'Saves contents of CMOS to a file on hard disk or floppy.',13,10
  172.     DB    'Copyright (c) 1991,1996 Roedy Green Canadian Mind Products.',13,10
  173.     DB    'POB 707 Quathiaski Cove, Quadra Island, BC Canada V0P 1N0',13,10
  174.     DB    'Telephone: (250) 285-2954          Internet:roedy@bix.com',13,10
  175.     DB    'Shareware to freely distribute and use for any purpose except military.',13,10
  176.     DB    13,10
  177.     db    '$'
  178.  
  179. UsageMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  180.         DB 'Insert a formatted diskette.',13,10
  181.         DB 'then try:',13,10
  182.         DB 'CMOSSave A:\CMOS.Sav',13,10
  183.         DB 'or if want to save on hard disk try:',13,10
  184.         DB 'CMOSSave C:\SAFE\CMOS.Sav',13,10
  185.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  186.         db '$'
  187.  
  188. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  189.         DB 'Cannot create the disk file.',13,10
  190.         db '$'
  191.  
  192. WorkedMsg    DB 'CMOS successfully saved',13,10
  193.         db '$'
  194.  
  195.     EndIf
  196.  
  197.  
  198.     If    Generating eq CMOSRest
  199. BannerMsg    label    byte
  200.     DB    '░▒▓█ CMOSRest 3.0 █▓▒░',13d,10d
  201.     DB    13d,10d
  202.     DB    'Restores CMOS from a CMOSSave file on hard disk or floppy.',13,10
  203.     DB    'Copyright (c) 1991,1996 Roedy Green Canadian Mind Products.',13,10
  204.     DB    'POB 707 Quathiaski Cove, Quadra Island, BC Canada V0P 1N0',13,10
  205.     DB    'Telephone: (250) 285-2954          Internet:roedy@bix.com',13,10
  206.     DB    'Shareware to freely distribute and use for any purpose except military.',13,10
  207.     DB    13,10
  208.     db    '$'
  209.  
  210. UsageMsg    DB '░▒▓█ Error █▓▒░',13,10
  211.         DB 'Insert the diskette you used for CMOSSave.',13,10
  212.         DB 'then try:',13,10
  213.         DB 'CMOSRest A:\CMOS.Sav',13,10
  214.         DB 'or if the file is on hard disk try:',13,10
  215.         DB 'CMOSRest C:\SAFE\CMOS.Sav',13,10
  216.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  217.         db '$'
  218.  
  219. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  220.         DB 'Cannot find/read the disk file.',13,10
  221.         db '$'
  222.  
  223. WorkedMsg    DB 'CMOS successfully restored',13,10
  224.         db '$'
  225.  
  226.     EndIf
  227.  
  228.     If    Generating eq CMOSChk
  229. BannerMsg    label    byte
  230.     DB    '░▒▓█ CMOSChk 3.0 █▓▒░',13d,10d
  231.     DB    13d,10d
  232.     DB    'Ensures CMOS not corrupted or changed.',13,10
  233.     DB    'Copyright (c) 1991,1996 Roedy Green Canadian Mind Products.',13,10
  234.     DB    'POB 707 Quathiaski Cove, Quadra Island, BC Canada V0P 1N0',13,10
  235.     DB    'Telephone: (250) 285-2954          Internet:roedy@bix.com',13,10
  236.     DB    'Shareware to freely distribute and use for any purpose except military.',13,10
  237.     DB    13,10
  238.     db    '$'
  239.  
  240. UsageMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  241.         DB 'Insert the diskette you used for CMOSSave.',13,10
  242.         DB 'then try:',13,10
  243.         DB 'CMOSChk A:\CMOS.Sav',13,10
  244.         DB 'or if you have the file on hard disk try:',13,10
  245.         DB 'CMOSChk C:\SAFE\CMOS.Sav',13,10
  246.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  247.         db '$'
  248.  
  249. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  250.         DB 'Cannot find/read the disk file.',13,10
  251.         db '$'
  252.  
  253. MatchTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
  254.         DB 'CMOS has been corrupted! at hex offset:value:expected ',13,10
  255.         db '$'
  256.  
  257. ColonMsg    db ':','$'
  258.  
  259. NextTripleMsg    db 13,10,'$'
  260.  
  261.  
  262. WorkedMsg    DB 'CMOS is OK, i.e. unchanged since the last CMOSSave.',13,10
  263.         db '$'
  264.  
  265.     EndIf
  266.  
  267. ParmIndex    DW    0
  268.  
  269.  
  270. Filename    DB    64 dup (0)
  271.             ; asciiz filename
  272.  
  273. SlashQuiet    DB    0
  274.             ; -1 means quiet mode /Q
  275.  
  276. CMOSSize    DB    0
  277.             ; size of cmos in bytes
  278.  
  279. CMOSBuff    db 0    ; dynamic buffer will grow to 128
  280.             ; it hangs out past the end of the program
  281.  
  282. data        ends
  283.  
  284. com    group    code,data    ; force data segment to go at the end
  285.  
  286.     ASSUME    CS:com,DS:com,ES:com,SS:com
  287.                 ; seg regs cover everything
  288.     ORG    100H        ; in Code segment
  289.  
  290. ;==========================
  291.  
  292. Main    proc    far
  293.  
  294. ;    M A I N L I N E   R O U T I N E
  295. Start:
  296.     Call    Parse        ; get filename and /Q from command line
  297.  
  298.     lea    dx,BannerMsg    ; display the banner if no /Q
  299.     Call    SayQ
  300.  
  301.     If    Generating eq CMOSSave
  302.     call    GetCMOS     ; fetch CMOS to buffer
  303.     call    WriteCMOS    ; write CMOS contents to file
  304.     lea    dx,WorkedMsg    ; crow about success
  305.     Call    Say
  306.     EndIf
  307.  
  308.     If    Generating eq CMOSRest
  309.     call    ReadCMOS    ; read CMOS contents from file
  310.     call    CalcCMOSSize    ; it is 64 or 128 bytes long?
  311.     call    PutCMOS     ; store buffer to CMOS
  312.     lea    dx,WorkedMsg    ; crow about success
  313.     Call    Say
  314.     EndIf
  315.  
  316.     If    Generating eq CMOSChk
  317.     call    ReadCMOS    ; read CMOS contents from file
  318.     call    CalcCMOSSize    ; it is 64 or 128 bytes long?
  319.     call    CompareCMOS    ; compare CMOS with buffer
  320.     lea    dx,WorkedMsg    ; crow about success
  321.     Call    SayQ
  322.     EndIf
  323.  
  324. Done:
  325.     mov    ax,4c00h
  326.     int    21h        ;normal termination
  327.  
  328. Main    EndP
  329.  
  330. ;===============================================================
  331.  
  332. Trouble proc    near
  333.  
  334. FileTrouble:
  335.     Lea    dx,FileTroubleMsg    ; display file trouble
  336.     Call    Say
  337.     Jmp    Abort
  338.  
  339. SyntaxTrouble:
  340.     lea    dx,BannerMsg
  341.     Call    Say
  342.     LEA    dx,UsageMsg
  343.     Call    Say
  344.     Jmp    Abort
  345.  
  346. abort:
  347.                 ; error exit
  348.     mov    ax, 4c04h    ; ERRORLEVEL = 4
  349.     int    21h        ; DIE
  350.  
  351. Trouble endp
  352.  
  353. ;===============================================================
  354.  
  355. SayQ    Proc
  356. ;    on entry DX points to a string to display
  357. ;    Only displays string if /Q not on
  358.     test    SlashQuiet,-1
  359.     jnz    Quietly
  360.     call    Say
  361. Quietly:
  362.     ret
  363. SayQ    Endp
  364.  
  365. ;========================================
  366.  
  367. Say    Proc
  368.  
  369. ;    on entry DX points to a string to display
  370.     push    ax
  371.     MOV    AH,9
  372.     Int    21h
  373.     pop    ax
  374.     ret
  375.  
  376. Say    EndP
  377.  
  378. ;======================================
  379.  
  380.     If    Generating eq CMOSSave
  381.  
  382. GetCMOS Proc    Near
  383.  
  384. ;    Get 128 byte contents of CMOS into a buffer.
  385.  
  386.     mov    cx,128        ; count of times through loop
  387.     lea    bx,CMOSBuff    ; where to put the contents
  388.     sub    al,al        ; start offset in CMOS
  389. GetLoop:
  390.     Call    PeekCmos    ; al=offset ah=contents
  391.     mov    byte ptr[bx],ah
  392.     inc    al
  393.     inc    bx
  394.     loop    GetLoop
  395.     ret
  396.  
  397. GetCMOS EndP
  398.  
  399.     EndIf
  400.  
  401. ;===============================================================
  402.  
  403.     If    Generating eq CMOSRest
  404.  
  405. PutCMOS Proc    Near
  406.  
  407. ;    Put 128-byte contents of buffer into CMOS.
  408. ;    do not touch the volatile bytes
  409.  
  410.     mov    cx,128        ; count of times through loop
  411.     lea    bx,CMOSBuff    ; where to put the contents
  412.     sub    al,al        ; start offset in CMOS
  413. PutLoop:
  414.     call    Volatile    ; test if this is a volatile byte
  415.                 ; test offset in al
  416.     jc    LeaveItAlone
  417.     mov    ah,byte ptr[bx]
  418.     Call    PokeCMOS    ; al=offset ah=contents
  419.  
  420. LeaveItAlone:
  421.     inc    bx
  422.     inc    al
  423.     loop    PutLoop
  424.     ret
  425.  
  426. PutCMOS EndP
  427.  
  428.     EndIf
  429.  
  430. ;===============================================================
  431.  
  432.     If    Generating eq CMOSChk
  433.  
  434. hexPAD    DB    '00$'    ; where numeric output built by SayHexByte
  435.  
  436. SayHexByte    proc    Near
  437.     ;    al contains hex byte to display:
  438.  
  439.     push    ax        ; preserve regs
  440.     push    bx
  441.     push    cx
  442.     push    dx
  443.     mov    dl,al        ; save input
  444. ;    Do first (leftmost digit)
  445.     mov    cl,4
  446.     shr    al,cl
  447.     and    al,0fh        ; get first digit
  448.     cmp    al,9
  449.     jg    HexChar1
  450.     add    al,'0'        ; convert digit to ASCII
  451.     jmp    StoreChar1
  452. HexChar1:
  453.     add    al,'A'-0AH    ; convert to uppercase A..H
  454. StoreChar1:
  455.     mov    hexPad,al
  456.  
  457. ;    Do second (rightmost digit)
  458.     mov    al,dl
  459.     and    al,0fh        ; get last digit
  460.     cmp    al,9
  461.     jg    HexChar2
  462.     add    al,'0'        ; convert digit to ASCII
  463.     jmp    StoreChar2
  464. HexChar2:
  465.     add    al,'A'-0AH    ; convert to uppercase A..H
  466. StoreChar2:
  467.     mov    hexPad+1,al
  468.  
  469. ;    Number is ready
  470.     lea    dx,Hexpad
  471.     mov    AH,09h        ; BIOS put string terminated by $
  472.     int    21h
  473.     pop    dx
  474.     pop    cx
  475.     pop    bx
  476.     pop    ax
  477.     ret
  478.  
  479. SayHexByte    ENDP
  480.  
  481.     EndIf
  482.  
  483. ;===============================================================
  484.  
  485.     If    Generating eq CMOSChk
  486. CompareCMOS    proc    Near
  487.  
  488. ;    compares buffer version of CMOS with contents of actual CMOS
  489. ;    ignores mismatches of volatile bytes.
  490. ;    Aborts if finds a mismatch
  491.  
  492.     mov    cx,128        ; count of times through loop
  493.     lea    bx,CMOSBuff    ; where to find comparison set
  494.     sub    al,al        ; start offset in CMOS
  495.     push    si
  496.     sub    si,si        ; count of mismatches
  497. CompLoop:
  498.     call    Volatile    ; test if this is a volatile byte
  499.                 ; test offset in al
  500.     jc    MatchedOk
  501.     Call    PeekCMOS    ; al=offset ah=contents
  502.     cmp    ah,byte ptr[bx] ; compare CMOS with buffer
  503.     je    MatchedOk
  504.  
  505. ;    Mismatch
  506.     test    si,si            ; only complain on first mismatch
  507.     jnz    AlreadyComplained
  508.     lea    dx,MatchTroubleMsg    ; display CMOS mismatch
  509.     call    Say
  510. AlreadyComplained:
  511.     push    ax
  512.     inc    si        ; count of how many mismatches found
  513.     Call    SayHexByte    ; report offset
  514.     lea    dx,ColonMsg
  515.     call    Say
  516.     mov    al,ah        ; report bad value in CMOS
  517.     Call    SayHexByte
  518.     lea    dx,ColonMsg
  519.     call    Say
  520.     mov    al,byte ptr[bx] ; report what value should be from file.
  521.     call    SayHexByte
  522.     lea    dx,NextTripleMsg
  523.     call    Say
  524.     pop    ax
  525.  
  526. MatchedOk:
  527.     inc    bx
  528.     inc    al
  529.     loop    CompLoop
  530.  
  531.     test    si,si
  532.     jz    NoMismatches
  533.  
  534.     mov    ax, 4c01h        ; ERRORLEVEL = 1
  535.     int    21h            ; DIE
  536.  
  537. NoMisMatches:
  538.     pop    si
  539.     ret
  540.  
  541. CompareCMOS    EndP
  542.  
  543.     EndIf
  544.  
  545. ;===============================================================
  546.  
  547.     If    Generating ne CMOSSave
  548.  
  549. ;    Add to this list if you need more volatile bytes.
  550. ;    Remember the trailing h.
  551. ;    Volatile bytes are not checked or restored.
  552.  
  553. ;    0..09 are volatile
  554. ;    0ch is status byte
  555. ;    032h is century byte
  556. ;    03Fh is Pentium volatile byte
  557.  
  558.  
  559.     if    Generating eq CMOSChk
  560. VolatileList    db    0ch,032h,03Fh
  561. ;    see restore list below
  562.     Endif
  563.  
  564.     if    Generating eq CMOSRest
  565. VolatileList    db    0ch,032h
  566. ;    leave off 03Fh
  567.     Endif
  568.  
  569. VolatileCount    equ    $-VolatileList
  570.  
  571.  
  572. Volatile    Proc    near
  573.  
  574. ;    Is cmos offset in AL volatile?    If so set carry.
  575. ;    These bytes will be undisturbed.
  576. ;    Preserves all registers.
  577. ;    00..09, 0C, 32 and 3F are volatile, rest are not.
  578. ;    0A 0B 0D 0E 0F used to be considered volatile, now are not.
  579. ;    if cmos is small, all bytes past end are considered volatile
  580.  
  581.     cmp    al,CMOSSize        ; bytes past end are volatile
  582.     jae    IsVolatile
  583.     cmp    al,09h
  584.     jbe    IsVolatile        ; early bytes are for timing
  585.     push    cx
  586.     push    di
  587.     mov    cx,VolatileCount
  588.     lea    di,VolatileList
  589.     repne    scasb            ; search till find a match
  590.     pop    di
  591.     pop    cx
  592.     je    IsVolatile
  593.  
  594. IsNotVolatile:
  595.     clc                ; clear carry
  596.     ret
  597.  
  598. IsVolatile:
  599.     stc
  600.     ret
  601.  
  602. Volatile    EndP
  603.     EndIf
  604.  
  605. ;===============================================================
  606.  
  607.     If    Generating ne CMOSSave
  608.  
  609. CalcCMOSSize    Proc    near
  610.  
  611. ;    Is CMOS 64 or 128 bytes long?
  612. ;    It is 64 if bytes at 10..2F match those at 50..6F.
  613. ;    Otherwise it is 128 bytes.
  614. ;    Preserves all registers.
  615.  
  616.     push    si
  617.     push    di
  618.     push    cx
  619.     lea    si,CMOSBuff+10h
  620.     lea    di,CMOSBuff+50h
  621.     mov    cx,02fh+1-10h
  622.     repe    cmpsb
  623.     je    IsCMOS64
  624.  
  625. IsCMOS128:
  626.     mov    CMOSSize,128    ; differ, must be a big CMOS
  627.     jmp    CalcCMOSSizeDone
  628.  
  629. IsCMOS64:
  630.     mov    CMOSSize,64    ; all same, small CMOS
  631.  
  632. CalcCMOSSizeDone:
  633.     pop    cx
  634.     pop    di
  635.     pop    si
  636.  
  637.     ret
  638.  
  639. CalcCMOSSize    EndP
  640.     EndIf
  641.  
  642. ;===============================================================
  643.  
  644.     if    Generating ne CMOSRest
  645.  
  646. PeekCMOS    proc    near
  647.  
  648. ;    Reads one byte from cmos.
  649. ;    on entry al has offset desired
  650. ;    on exit ah has the contents of that byte.
  651. ;    preserves all registers
  652.  
  653. ;    See page 5-81 IBM AT Tech ref BIOS listing for how to read CMOS
  654. ;    We always enable the NMI with bit 7 on.
  655.  
  656.     push    bx
  657.     push    ax
  658.     cli                ; disable interrupts
  659.     or    al,80h            ; disable NMI
  660.                      ; controlled by port 70
  661.     out    70h,al            ; output the byte address to CMOS
  662.     jmp    $+2            ; delay, safer than nop
  663.     in    al,71h            ; read the CMOS byte
  664.     jmp    $+2            ; delay, safer than nop
  665.     mov    bl,al
  666.                     ; re-enable the NMI, high bit off
  667.     mov    al,0dh            ; point to battery status register
  668.     out    70h,al            ; leave pointing at a safe r/o register
  669.     sti                ; restore interrupts
  670.     pop    ax
  671.     mov    ah,bl
  672.     pop    bx
  673.     ret
  674.  
  675. PeekCMOS    EndP
  676.  
  677.     EndIf
  678.  
  679. ;===============================================================
  680.  
  681.     If    Generating eq CMOSRest
  682.  
  683. PokeCMOS    proc    near
  684.  
  685. ;    Stuffs one byte into cmos.
  686. ;    on entry al has offset desired, ah has the value to stuff.
  687. ;    Preserves all registers.
  688.  
  689. ;    See page 5-81 IBM AT Tech ref BIOS listing for how to write CMOS
  690. ;    We always enable the NMI with bit 7 on.
  691.  
  692.     push    ax
  693.     cli                ; disable interrupts
  694.     or    al,80h            ; disable NMI
  695.     out    70h,al            ; output the byte address to CMOS
  696.     jmp    $+2            ; delay, safer than nop
  697.  
  698.     mov    al,ah            ; get contents
  699.     out    71h,al            ; poke the CMOS byte
  700.     jmp    $+2            ; delay, safer than nop
  701.                     ; re-enable the NMI
  702.     mov    al,0dh            ; point to battery status register
  703.     out    70h,al            ; leave pointing at a safe r/o register
  704.     sti                ; restore interrupts
  705.     pop    ax
  706.     ret
  707.  
  708. PokeCMOS    EndP
  709.  
  710.     EndIf
  711.  
  712. ;===============================================================
  713.  
  714.     If    Generating ne CMOSSave
  715.  
  716. ReadCMOS    Proc    Near
  717.  
  718. ;    Open a file read the CMOS into a buffer
  719.  
  720.     lea    dx,FileName    ; DS:DX point to file
  721.     xor    al,al        ; AL=0 is attribute read/only
  722.     mov    ah,03Dh     ; DOS open function
  723.     int    21h
  724.     jc    FileTrouble
  725.     mov    bx,ax        ; save handle
  726.     mov    cx,128        ; read 128 bytes
  727.     lea    dx,CMOSBuff    ; buffer address
  728.     mov    ah,3fH        ; DOS read
  729.     int    21h
  730.     jc    FileTrouble
  731.     cmp    ax,128
  732.     jne    FileTrouble
  733.     mov    ah,3eh        ; DOS close
  734.     int    21h
  735.     jc    FileTrouble
  736.     ret
  737.  
  738. ReadCMOS    EndP
  739.  
  740.     EndIf
  741.  
  742. ;===============================================================
  743.  
  744.     if    Generating eq CMOSSave
  745.  
  746. WriteCMOS    Proc    Near
  747.  
  748. ;    Create a file; write CMOS to it
  749.  
  750.     lea    dx,FileName    ; DS:DX point to file
  751.     xor    cx,cx        ; CX=0 is attribute
  752.     mov    ah,03ch     ; DOS create function
  753.     int    21h
  754.     jc    FileTrouble
  755.     mov    bx,ax        ; SAVE HANDLE
  756.     MOV    CX,128        ; write 128 bytes
  757.     lea    dx,CMOSBuff    ; buffer address
  758.     mov    ah,40h        ; DOS write
  759.     int    21h
  760.     jc    FileTrouble
  761.     cmp    ax,128
  762.     jne    FileTrouble
  763.     mov    ah,3eh        ; DOS close
  764.     int    21h
  765.     jc    FileTrouble
  766.     ret
  767.  
  768. WriteCMOS    EndP
  769.  
  770.     EndIf
  771.  
  772. ;===============================================================
  773.  
  774. Parse    Proc    near
  775. ;    Parse the command line and process each parameter.
  776. ;    sample inputs
  777. ;    CMOSSAVE A:\CMOS.SAV /Q
  778. ;    CMOSREST C:\CMP\CMOS.SAV
  779.                 ; counted string at HEX 80 PSP
  780.                 ; contains command line.
  781.                 ; Preceeded by unwanted spaces.
  782.                 ; possibly followed by unwanted spaces.
  783.                 ; currently missing a trailing null.
  784.                 ; Both ES and DS cover the command line
  785.                 ; since this is a COM file.
  786.                 ; However to make code compatible with EXE
  787.                 ; files we use ES: to cover the command line.
  788.     call    CommandLine    ; string addr ES:bx, length cx.
  789.     jcxz    NullParms
  790.  
  791.     mov    ParmIndex,1    ; start parsing with the 1st parm
  792.                 ; note start with 1 not 0!
  793.                 ; We don't want the the program name.
  794.     jmp    Short Parseloop
  795.  
  796. NullParms:
  797. NoMoreParms:
  798.     test    fileName,-1    ; ensure some sort of filename provided
  799.     jz    BadCmd        ; by the time all done
  800.     mov    ax,DS
  801.     mov    ES,ax        ; restore ES to match DS
  802.     ret            ; we are done
  803.  
  804. Parseloop:
  805.     call    CommandLine    ; commmandline=ES:bx, length=cx
  806.     mov    dx,ParmIndex
  807.     call    NthParm     ; work left to right
  808.     jcxz    NoMoreParms    ; null param means no more
  809.                 ; e.g. ES:bx points to A: or /Q
  810.                 ; cx is length of that piece
  811.     mov    ax,ES:[bx]    ; al=A ah=:  or  al=/ ah=Q
  812.     call    ToUc        ; Convert both chars to upper case
  813.     xchg    ah,al
  814.     call    ToUc
  815.     cmp    ah,'/'        ; drive or Switch?
  816.     jne    ProcessDrive
  817.                 ; it was a switch with slash
  818.                 ; was it /Q?
  819.     cmp    al,'Q'
  820.     JE    ProcessQ
  821.                 ; something else, give up.
  822. BadCmd:
  823.     jmp    SyntaxTrouble
  824.  
  825. ProcessDrive:
  826.                 ; don't insist on drive letter.
  827.                 ; should have C:\CMP\CMOS.SAV
  828.                 ; copy string to FileName
  829.                 ; followed by a null
  830.  
  831.     mov    si,bx
  832.     lea    di,FileName    ; ES:si -> DS:di ( segs are backwards )
  833.     push    ES        ; swap ES DS
  834.     push    DS
  835.     pop    ES
  836.     pop    DS
  837.     rep movsb        ; copy filename DS:si -> ES:di
  838.     mov    ES:[di],byte ptr 0 ; append a null
  839.     push    ES        ; swap ES DS back to normal
  840.     push    DS
  841.     pop    ES
  842.     pop    DS
  843.     jmp    short Next
  844.  
  845. ProcessQ:            ; handle /Quiet
  846.     mov    SlashQuiet,-1
  847.  
  848. Next:
  849.     inc    ParmIndex    ; bump loop counter
  850.     jmp    Parseloop    ; loop till hit null param
  851.  
  852. Parse    EndP
  853.  
  854. ;===============================================================
  855.  
  856. CommandLine Proc  near
  857. ;    gets command line into ES:bx with length in cx.
  858. ;    This version works for a COM file only.
  859.     xor    ch,ch
  860.     mov    cl,ES:80H
  861.     mov    bx,81H
  862.     ret
  863. CommandLine EndP
  864.  
  865. ;===============================================================
  866. NthParm Proc    near
  867. ;    Parses string for Nth Parameter delimited by blanks
  868. ;    e.g.  "  A: /Q " with bx=1 would give string "/Q"
  869. ;    on entry:
  870. ;    ES:bx - string, usually the command line
  871. ;    cx - length of string
  872. ;    dx - which parm wanted 1=parm1 2=parm2 etc.
  873. ;    NthParm only finds one parm per call.
  874. ;    On exit ES:bx points to string and cx is its length.
  875. ;    If there is no parm, the length will be 0.
  876. ;    It also handles multiple leading/trailing blanks on parms.
  877.     mov    al,20h        ; al = blank  -- the search char
  878.     mov    di,bx
  879. Parmloop:
  880. ;    Remove leading blanks on parm
  881.     jcxz    NullParm    ; jump if null string
  882.     repe    scasb        ; scan ES:di forwards till hit non blank
  883.  
  884.                 ; di points just after it
  885.                 ; cx is one too small, or 0 if none found
  886.     je    NullParm    ; jump if entire string was blank
  887.     inc    cx        ; cx is length of remainder of string
  888.     dec    di        ; di points to non-blank
  889.     mov    si,di        ; remember start of string
  890. ;    Search for terminating blank on parm
  891.     jcxz    NullParm    ; jump if null string
  892.     repne    scasb        ; scan ES:di forwards till hit blank
  893.                 ; di points just after it
  894.                 ; cx is one too small, or 0 if none found
  895.     jne    NoBlank     ; jump if entire string was non blank
  896.     inc    cx        ; cx is length of remainder of string
  897.     dec    di        ; backup di to point to blank at string end
  898. NoBlank:
  899.                 ; di=addr tail end of command string,
  900.                 ; cx=len tail end of command string
  901.                 ; si=addr parm just parsed
  902. ;    Major loop for each parm
  903.     dec    dx
  904.     jnz    Parmloop    ; loop once for each parm
  905.  
  906.     mov    cx,di
  907.     sub    cx,si        ; cx is length of parameter.
  908.     mov    bx,si
  909.     ret
  910. NullParm:            ; was no nth parameter
  911.     mov    cx,0
  912.     mov    bx,si
  913.     ret
  914. NthParm EndP
  915.  
  916. ;==============================================================
  917.  
  918. ToUC        PROC    NEAR
  919. ;    converts char in AL to upper case
  920.     cmp    al,'a'
  921.     jb    FineAsIs
  922.     cmp    al,'z'
  923.     ja    FineAsIs
  924.     sub    al,20H        ; convert a to A
  925. FineAsIs:
  926.     ret
  927.  
  928. ToUc        ENDP
  929.  
  930. ;======================================
  931.  
  932. ;===============================================================
  933.  
  934. CODE    ends            ; end of code segment
  935.     end    Start
  936.