home *** CD-ROM | disk | FTP | other *** search
/ Windows 95 Secrets (4th Edition) / Windows95Secrets4thEdition.iso / utility / configur / cmossave / cmos.asm < prev    next >
Encoding:
Assembly Source File  |  1995-05-11  |  17.3 KB  |  779 lines

  1.     PAGE    60,132
  2. NAME    CMOSSAVE
  3.     TITLE    CMOSSave Save CMOS to a file on disk or floppy
  4. Comment |
  5.     Version 2.2 1995 April 14 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. See CMOS.TXT for details on use.
  11.  
  12.   USAGE:
  13.  
  14. Examples:
  15. *********
  16.  
  17. CMOSSave A:\MyCMOS.Sav
  18.  
  19. CMOSRest A:\MyCMOS.Sav
  20.  
  21. CMOSChk  A:\ByCMOS.Sav
  22.  
  23. Syntax errors or missing file trouble generates an ERRORLEVEL 4.
  24. CMOSChk generates an ERRORLEVEL 1 if the CMOS has changed since
  25. the CMOSSave was done.
  26.  
  27. Version History
  28. ***************
  29.  
  30. Version 1.0
  31. - released to BIX 91/09/07
  32.  
  33. Version 1.1
  34. - released to BIX 91/09/18
  35. - added special check for small 64 character CMOSes.
  36.  
  37. Version 1.2
  38. - fix spelling errors
  39. - use CMOS.SAV instead of MyCMOS.SAV in examples
  40.  
  41. Version 1.3
  42. - now consider fewer bytes volatile, restore more stuff.
  43. - hints in docs about clearing CMOS.
  44.  
  45. Version 1.4
  46. - now consider flags Status register C, offset 0C as volatile.
  47.   fixes false alarms.
  48.  
  49. Version 1.5 1994 June 1
  50. - change of address and phone number
  51. - address now appears in the banner.
  52.  
  53. Version 1.6 1994 August 29
  54. - more information about how CMOS bits are used.
  55.  
  56. Version 2.0 1994 October 1
  57. - easier configuration of CHKCMOS volatile bytes.
  58. - smarter bat files.
  59. - docs on different ways to use.
  60.  
  61. Version 2.2 1995 April 16
  62. - docs on use before experimentation
  63.  
  64. CMOS Usage - see also CMOS.OFS
  65.  
  66. How to Assemble
  67. ***************
  68.  
  69. Manually set the GENERATING equate embedded in this code, then:
  70.  
  71. to assemble with MASM 6.0 use:
  72. ML.EXE /AT /c /Fl /VM /Zf /Zm CMOS.Asm
  73. LINK.EXE /TINY /MAP CMOS.Obj,CMOS.com,CMOS.map;
  74. copy cmos.com cmossave.com
  75.  
  76. to assemble with OPTASM use:
  77. Optasm     CMOS.Asm,CMOS.Obj,CMOS.Lst/L/N/G/S
  78. OLINK     CMOS.Obj,CMOS.COM,/MAP/TINY;
  79. copy cmos.com cmossave.com
  80.  
  81. Register Conventions
  82. ********************
  83.  
  84. Subroutines may trash all registers except those explicity
  85. documented as input or output.
  86.  
  87. | ; end of comment
  88.  
  89.  
  90. ;    E Q U A T E S
  91.  
  92. CMOSSAVE    EQU    1
  93. CMOSREST    EQU    2
  94. CMOSCHK     EQU    3
  95.  
  96. ; use /DGenerating#CMOSSAVE
  97. ;     /DGenerating#CMOSREST
  98. ;     /DGenerating#CMOSCHK
  99. ; on the assembler command line to select which version
  100. ; of the code to assemble.
  101. ;    Or add code following of the form:
  102.  
  103. ; GENERATING EQU CMOSSave
  104.  
  105.  
  106.     If    Generating eq CMOSSave
  107. %OUT Generating CMOSSave.Com
  108.     Endif
  109.  
  110.     If    Generating eq CMOSRest
  111. %OUT Generating CMOSRest.Com
  112.     endif
  113.  
  114.     If    Generating eq CMOSChk
  115. %OUT Generating CMOSChk.Com
  116.     endif
  117. ;==============================================================
  118.  
  119.  
  120. stack    segment stack        ; keep MS link happy by providing null stack
  121. stack    ends
  122.  
  123. CODE    SEGMENT PARA        ; start off in code.
  124.  
  125. ;==============================================================
  126.  
  127. data    segment byte        ; provide a separate DATA segment
  128.                 ; actually all come after the code
  129. ;==============================================================
  130. ;  V A R I A B L E S
  131.  
  132.  
  133.     If    Generating eq CMOSSave
  134.  
  135. BannerMsg    DB '░▒▓█ CMOSSave 2.2 █▓▒░',13d,10d
  136.         DB 13d,10d
  137.         DB 'Saves contents of CMOS to a file on hard disk or floppy.',13,10
  138.         DB 'Copyright (c) 1991,1995 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
  139.         DB '#601 - 1330 Burrard, Vancouver BC CANADA  V6Z 2B8',13,10
  140.         DB 'Shareware to freely distribute and use for any purpose except military.',13,10
  141.         DB 13,10
  142.         db '$'
  143.  
  144. UsageMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  145.         DB 'Insert a formatted diskette.',13,10
  146.         DB 'then try:',13,10
  147.         DB 'CMOSSave A:\CMOS.Sav',13,10
  148.         DB 'or if want to save on hard disk try:',13,10
  149.         DB 'CMOSSave C:\CMOS.Sav',13,10
  150.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  151.         db '$'
  152.  
  153. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  154.         DB 'Cannot create the disk file.',13,10
  155.         db '$'
  156.  
  157. WorkedMsg    DB 'CMOS successfully saved',13,10
  158.         db '$'
  159.  
  160.     EndIf
  161.  
  162.  
  163.     If    Generating eq CMOSRest
  164. BannerMsg    DB '░▒▓█ CMOSRest 2.2 █▓▒░',13d,10d
  165.         DB 13d,10d
  166.         DB 'Restores CMOS from a CMOSSave file on hard disk or floppy.',13,10
  167.         DB 'Copyright (c) 1991,1995 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
  168.         DB '#601 - 1330 Burrard, Vancouver BC CANADA  V6Z 2B8',13,10
  169.         DB 'Shareware to freely distribute and use for any purpose except military.',13,10
  170.         DB 13,10
  171.         db '$'
  172.  
  173. UsageMsg    DB '░▒▓█ Error █▓▒░',13,10
  174.         DB 'Insert the diskette you used for CMOSSave.',13,10
  175.         DB 'then try:',13,10
  176.         DB 'CMOSRest A:\CMOS.Sav',13,10
  177.         DB 'or if the file is on hard disk try:',13,10
  178.         DB 'CMOSRest C:\CMOS.Sav',13,10
  179.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  180.         db '$'
  181.  
  182. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  183.         DB 'Cannot find/read the disk file.',13,10
  184.         db '$'
  185.  
  186. WorkedMsg    DB 'CMOS successfully restored',13,10
  187.         db '$'
  188.  
  189.     EndIf
  190.  
  191.     If    Generating eq CMOSChk
  192. BannerMsg    DB '░▒▓█ CMOSChk 2.2 █▓▒░',13d,10d
  193.         DB 13d,10d
  194.         DB 'Ensures CMOS not corrupted or changed.',13,10
  195.         DB 'Copyright (c) 1991,1995 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
  196.         DB '#601 - 1330 Burrard, Vancouver BC CANADA  V6Z 2B8',13,10
  197.         DB 'Shareware to freely distribute and use for any purpose except military.',13,10
  198.         DB 13,10
  199.         db '$'
  200.  
  201. UsageMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  202.         DB 'Insert the diskette you used for CMOSSave.',13,10
  203.         DB 'then try:',13,10
  204.         DB 'CMOSChk A:\CMOS.Sav',13,10
  205.         DB 'or if you have the file on hard disk try:',13,10
  206.         DB 'CMOSChk C:\CMOS.Sav',13,10
  207.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  208.         db '$'
  209.  
  210. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  211.         DB 'Cannot find/read the disk file.',13,10
  212.         db '$'
  213.  
  214. MatchTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
  215.         DB 'CMOS has been corrupted! at hex offset:value:expected ',13,10
  216.         db '$'
  217.  
  218. ColonMsg    db ':','$'
  219.  
  220. NextTripleMsg    db 13,10,'$'
  221.  
  222.  
  223. WorkedMsg    DB 'CMOS is OK, i.e. unchanged since the last CMOSSave.',13,10
  224.         db '$'
  225.  
  226.     EndIf
  227.  
  228.  
  229. FilenamePtr    DW    0
  230.             ; pointer to filename in command line
  231.  
  232. CMOSSize    DB    0
  233.             ; size of cmos in bytes
  234.  
  235. CMOSBuff    db 0    ; dynamic buffer will grow to 128
  236.             ; it hangs out past the end of the program
  237.  
  238. data        ends
  239.  
  240. com    group    code,data    ; force data segment to go at the end
  241.  
  242.     ASSUME    CS:com,DS:com,ES:com,SS:com
  243.                 ; seg regs cover everything
  244.     ORG    100H        ; in Code segment
  245.  
  246. ;==========================
  247.  
  248. Main    proc    far
  249.  
  250. ;    M A I N L I N E   R O U T I N E
  251. Start:
  252.     lea    dx,BannerMsg    ; display the banner
  253.     Call    Say
  254.     Call    Parse        ; get filename from command line
  255.  
  256.     If    Generating eq CMOSSave
  257.     call    GetCMOS     ; fetch CMOS to buffer
  258.     call    WriteCMOS    ; write CMOS contents to file
  259.     EndIf
  260.  
  261.     If    Generating eq CMOSRest
  262.     call    ReadCMOS    ; read CMOS contents from file
  263.     call    CalcCMOSSize    ; it is 64 or 128 bytes long?
  264.     call    PutCMOS     ; store buffer to CMOS
  265.     EndIf
  266.  
  267.     If    Generating eq CMOSChk
  268.     call    ReadCMOS    ; read CMOS contents from file
  269.     call    CalcCMOSSize    ; it is 64 or 128 bytes long?
  270.     call    CompareCMOS    ; compare CMOS with buffer
  271.     EndIf
  272.  
  273.     lea    dx,WorkedMsg    ; crow about success
  274.     Call    Say
  275. Done:
  276.     mov    ax,4c00h
  277.     int    21h        ;normal termination
  278.  
  279. Main    EndP
  280.  
  281. ;===============================================================
  282.  
  283. Trouble proc    near
  284.  
  285. FileTrouble:
  286.     Lea    dx,FileTroubleMsg    ; display file trouble
  287.     Call    Say
  288.     Jmp    Abort
  289.  
  290. abort:
  291.                 ; error exit
  292.     mov    ax, 4c04h    ; ERRORLEVEL = 4
  293.     int    21h        ; DIE
  294.  
  295. Trouble endp
  296.  
  297. ;===============================================================
  298.  
  299. MLeading    PROC    Near
  300.  
  301. ;    Remove leading blanks
  302. ;    on entry BX is addr of string, CX its length
  303. ;    trims off any leading blanks, leaving result in BX CX
  304. ;    length may also be 0 or 1, but not -ve
  305. ;    If the entire string is blank the result is the null string
  306.     mov    di,bx
  307.     mov    al,20H        ; AL = blank  -- the search char
  308.     jcxz    mleading2    ; jump if null string
  309.     repe    scasb        ; scan ES:DI forwards till hit non blank
  310.                 ; DI points just after it (wrap ok)
  311.                 ; cx IS ONE TOO SMALL, OR 0 IF NONE FOUND
  312.     je    mleading1    ; jump if entire string was blank
  313.     inc    cx        ; CX is length of remainder of string
  314. mleading1:
  315.     dec    di        ; DI points to non-blank
  316. mleading2:
  317.     mov    bx,di        ; put address back
  318.     ret
  319.  
  320. MLeading    ENDP
  321.  
  322. ;========================================
  323.  
  324. MTrailing    PROC    Near
  325.  
  326. ;    Remove trailing blanks.
  327. ;    on entry BX is addr of string, CX its length
  328. ;    trims off any trailing blanks, leaving result in BX CX
  329. ;    length may also be 0 or 1, but not -ve
  330. ;    If the entire string is blank the result is the null string
  331.     mov    di,bx
  332.     add    di,cx        ; calc addr last char in string
  333.     dec    di
  334.     mov    al,20H        ; AL = blank  -- the search char
  335.     jcxz    mtrailing1    ; jump if null string
  336.     std
  337.     repe    scasb        ; scan ES:DI backwards till hit non blank
  338.                 ; DI points just ahead of it (wrap ok)
  339.                 ; CX is one too small, or 0 if none found
  340.     cld
  341.     je    mtrailing1    ; jump if whole string was blank
  342.     inc    cx
  343. mtrailing1:
  344.     ret
  345.  
  346. MTrailing    ENDP
  347.  
  348. ;========================================
  349.  
  350. Parse        PROC    NEAR
  351. ;    Parse the command line to remove lead/trail blanks from
  352. ;    the single drive parameter and terminate it by 2 nulls.
  353. ;    sample inputs
  354. ;    CMOSRest A:\CMOS.SAV
  355. ;    CMOSRest    B:\MySub\MyCMOS.SAV
  356. ;
  357. ;    When Done DS:BX points to start of string.
  358. ;    String will be terminated by 2 nulls
  359. ;    CX counts bytes in string exclusive of nulls
  360.                 ; counted string at HEX 80 PSP
  361.                 ; contains command line.
  362.                 ; Preceeded by unwanted spaces.
  363.                 ; possibly followed by unwanted spaces.
  364.                 ; currently missing a trailing null.
  365.     xor    ch,ch
  366.     mov    cl,ds:80H
  367.     mov    bx,81H
  368.     call    Mleading    ; get rid of leading blanks
  369.     call    MTrailing    ; get rid of trailing blanks
  370.     mov    di,bx        ; calc addr of byte just past end
  371.     add    di,cx
  372.     mov    word ptr [di],0 ; plop in pair of nulls after string
  373.     mov    FileNamePtr,bx    ; remember where filename was
  374.     jcxz    SyntaxTrouble    ; missing parm.
  375.     ret
  376.  
  377. SyntaxTrouble:
  378.     lea    dx,UsageMsg        ; display usage message
  379.     Call    Say
  380.     Jmp    Abort
  381.  
  382. Parse        ENDP
  383.  
  384. ;======================================
  385.  
  386. Say    Proc
  387.  
  388. ;    on entry DX points to a string to display
  389.     push    ax
  390.     MOV    AH,9
  391.     Int    21h
  392.     pop    ax
  393.     ret
  394.  
  395. Say    EndP
  396.  
  397. ;======================================
  398.  
  399.     If    Generating eq CMOSSave
  400.  
  401. GetCMOS Proc    Near
  402.  
  403. ;    Get 128 byte contents of CMOS into a buffer.
  404.  
  405.     mov    cx,128        ; count of times through loop
  406.     lea    bx,CMOSBuff    ; where to put the contents
  407.     sub    al,al        ; start offset in CMOS
  408. GetLoop:
  409.     Call    PeekCmos    ; al=offset ah=contents
  410.     mov    byte ptr[bx],ah
  411.     inc    al
  412.     inc    bx
  413.     loop    GetLoop
  414.     ret
  415.  
  416. GetCMOS EndP
  417.  
  418.     EndIf
  419.  
  420. ;===============================================================
  421.  
  422.     If    Generating eq CMOSRest
  423.  
  424. PutCMOS Proc    Near
  425.  
  426. ;    Put 128-byte contents of buffer into CMOS.
  427. ;    do not touch the volatile bytes
  428.  
  429.     mov    cx,128        ; count of times through loop
  430.     lea    bx,CMOSBuff    ; where to put the contents
  431.     sub    al,al        ; start offset in CMOS
  432. PutLoop:
  433.     call    Volatile    ; test if this is a volatile byte
  434.                 ; test offset in al
  435.     jc    LeaveItAlone
  436.     mov    ah,byte ptr[bx]
  437.     Call    PokeCMOS    ; al=offset ah=contents
  438.  
  439. LeaveItAlone:
  440.     inc    bx
  441.     inc    al
  442.     loop    PutLoop
  443.     ret
  444.  
  445. PutCMOS EndP
  446.  
  447.     EndIf
  448.  
  449. ;===============================================================
  450.  
  451.     If    Generating eq CMOSChk
  452.  
  453. hexPAD    DB    '00$'    ; where numeric output built by SayHexByte
  454.  
  455. SayHexByte    proc    Near
  456.     ;    al contains hex byte to display:
  457.  
  458.     push    ax        ; preserve regs
  459.     push    bx
  460.     push    cx
  461.     push    dx
  462.     mov    dl,al        ; save input
  463. ;    Do first (leftmost digit)
  464.     mov    cl,4
  465.     shr    al,cl
  466.     and    al,0fh        ; get first digit
  467.     cmp    al,9
  468.     jg    HexChar1
  469.     add    al,'0'        ; convert digit to ASCII
  470.     jmp    StoreChar1
  471. HexChar1:
  472.     add    al,'A'-0AH    ; convert to uppercase A..H
  473. StoreChar1:
  474.     mov    hexPad,al
  475.  
  476. ;    Do second (rightmost digit)
  477.     mov    al,dl
  478.     and    al,0fh        ; get last digit
  479.     cmp    al,9
  480.     jg    HexChar2
  481.     add    al,'0'        ; convert digit to ASCII
  482.     jmp    StoreChar2
  483. HexChar2:
  484.     add    al,'A'-0AH    ; convert to uppercase A..H
  485. StoreChar2:
  486.     mov    hexPad+1,al
  487.  
  488. ;    Number is ready
  489.     lea    dx,Hexpad
  490.     mov    AH,09h        ; BIOS put string terminated by $
  491.     int    21h
  492.     pop    dx
  493.     pop    cx
  494.     pop    bx
  495.     pop    ax
  496.     ret
  497.  
  498. SayHexByte    ENDP
  499.  
  500.     EndIf
  501.  
  502. ;===============================================================
  503.  
  504.     If    Generating eq CMOSChk
  505. CompareCMOS    proc    Near
  506.  
  507. ;    compares buffer version of CMOS with contents of actual CMOS
  508. ;    ignores mismatches of volatile bytes.
  509. ;    Aborts if finds a mismatch
  510.  
  511.     mov    cx,128        ; count of times through loop
  512.     lea    bx,CMOSBuff    ; where to find comparison set
  513.     sub    al,al        ; start offset in CMOS
  514.     push    si
  515.     sub    si,si        ; count of mismatches
  516. CompLoop:
  517.     call    Volatile    ; test if this is a volatile byte
  518.                 ; test offset in al
  519.     jc    MatchedOk
  520.     Call    PeekCMOS    ; al=offset ah=contents
  521.     cmp    ah,byte ptr[bx] ; compare CMOS with buffer
  522.     je    MatchedOk
  523.  
  524. ;    Mismatch
  525.     test    si,si            ; only complain on first mismatch
  526.     jnz    AlreadyComplained
  527.     lea    dx,MatchTroubleMsg    ; display CMOS mismatch
  528.     call    Say
  529. AlreadyComplained:
  530.     push    ax
  531.     inc    si        ; count of how many mismatches found
  532.     Call    SayHexByte    ; report offset
  533.     lea    dx,ColonMsg
  534.     call    Say
  535.     mov    al,ah        ; report bad value in CMOS
  536.     Call    SayHexByte
  537.     lea    dx,ColonMsg
  538.     call    Say
  539.     mov    al,byte ptr[bx] ; report what value should be from file.
  540.     call    SayHexByte
  541.     lea    dx,NextTripleMsg
  542.     call    Say
  543.     pop    ax
  544.  
  545. MatchedOk:
  546.     inc    bx
  547.     inc    al
  548.     loop    CompLoop
  549.  
  550.     test    si,si
  551.     jz    NoMismatches
  552.  
  553.     mov    ax, 4c01h        ; ERRORLEVEL = 1
  554.     int    21h            ; DIE
  555.  
  556. NoMisMatches:
  557.     pop    si
  558.     ret
  559.  
  560. CompareCMOS    EndP
  561.  
  562.     EndIf
  563.  
  564. ;===============================================================
  565.  
  566.     If    Generating ne CMOSSave
  567.  
  568. ;    Add to this list if you need more volatile bytes.
  569. ;    Remember the trailing h.
  570.  
  571. VolatileList    db    0ch,032h
  572.  
  573. VolatileCount    equ    $-VolatileList
  574.  
  575.  
  576. Volatile    Proc    near
  577.  
  578. ;    Is cmos offset in AL volatile?    If so set carry.
  579. ;    These bytes will be undisturbed.
  580. ;    Preserves all registers.
  581. ;    00..09, 0C and 32 are volatile, rest are not.
  582. ;    0A 0B 0D 0E 0F used to be considered volatile, now are not.
  583. ;    if cmos is small, all bytes past end are considered volatile
  584.  
  585.     cmp    al,CMOSSize        ; bytes past end are volatile
  586.     jae    IsVolatile
  587.     cmp    al,09h
  588.     jbe    IsVolatile        ; early bytes are for timing
  589.     push    cx
  590.     push    di
  591.     mov    cx,VolatileCount
  592.     lea    di,VolatileList
  593.     repne    scasb            ; search till find a match
  594.     pop    di
  595.     pop    cx
  596.     je    IsVolatile
  597.  
  598. IsNotVolatile:
  599.     clc                ; clear carry
  600.     ret
  601.  
  602. IsVolatile:
  603.     stc
  604.     ret
  605.  
  606. Volatile    EndP
  607.     EndIf
  608.  
  609. ;===============================================================
  610.  
  611.     If    Generating ne CMOSSave
  612.  
  613. CalcCMOSSize    Proc    near
  614.  
  615. ;    Is CMOS 64 or 128 bytes long?
  616. ;    It is 64 if bytes at 10..2F match those at 50..6F.
  617. ;    Otherwise it is 128 bytes.
  618. ;    Preserves all registers.
  619.  
  620.     push    si
  621.     push    di
  622.     push    cx
  623.     lea    si,CMOSBuff+10h
  624.     lea    di,CMOSBuff+50h
  625.     mov    cx,02fh+1-10h
  626.     repe    cmpsb
  627.     je    IsCMOS64
  628.  
  629. IsCMOS128:
  630.     mov    CMOSSize,128    ; differ, must be a big CMOS
  631.     jmp    CalcCMOSSizeDone
  632.  
  633. IsCMOS64:
  634.     mov    CMOSSize,64    ; all same, small CMOS
  635.  
  636. CalcCMOSSizeDone:
  637.     pop    cx
  638.     pop    di
  639.     pop    si
  640.  
  641.     ret
  642.  
  643. CalcCMOSSize    EndP
  644.     EndIf
  645.  
  646. ;===============================================================
  647.  
  648.     if    Generating ne CMOSRest
  649.  
  650. PeekCMOS    proc    near
  651.  
  652. ;    Reads one byte from cmos.
  653. ;    on entry al has offset desired
  654. ;    on exit ah has the contents of that byte.
  655. ;    preserves all registers
  656.  
  657. ;    See page 5-81 IBM AT Tech ref BIOS listing for how to read CMOS
  658. ;    We always enable the NMI with bit 7 on.
  659.  
  660.     push    bx
  661.     push    ax
  662.     cli                ; disable interrupts
  663.     or    al,80h            ; disable NMI
  664.     out    70h,al            ; output the byte address to CMOS
  665.     jmp    $+2            ; delay, safer than nop
  666.     in    al,71h            ; read the CMOS byte
  667.     jmp    $+2            ; delay, safer than nop
  668.     mov    bl,al
  669.                     ; re-enable the NMI
  670.     mov    al,0dh            ; point to battery status register
  671.     out    70h,al            ; leave pointing at a safe r/o register
  672.     sti                ; restore interrupts
  673.     pop    ax
  674.     mov    ah,bl
  675.     pop    bx
  676.     ret
  677.  
  678. PeekCMOS    EndP
  679.  
  680.     EndIf
  681.  
  682. ;===============================================================
  683.  
  684.     If    Generating eq CMOSRest
  685.  
  686. PokeCMOS    proc    near
  687.  
  688. ;    Stuffs one byte into cmos.
  689. ;    on entry al has offset desired, ah has the value to stuff.
  690. ;    Preserves all registers.
  691.  
  692. ;    See page 5-81 IBM AT Tech ref BIOS listing for how to write CMOS
  693. ;    We always enable the NMI with bit 7 on.
  694.  
  695.     push    ax
  696.     cli                ; disable interrupts
  697.     or    al,80h            ; disable NMI
  698.     out    70h,al            ; output the byte address to CMOS
  699.     jmp    $+2            ; delay, safer than nop
  700.  
  701.     mov    al,ah            ; get contents
  702.     out    71h,al            ; poke the CMOS byte
  703.     jmp    $+2            ; delay, safer than nop
  704.                     ; re-enable the NMI
  705.     mov    al,0dh            ; point to battery status register
  706.     out    70h,al            ; leave pointing at a safe r/o register
  707.     sti                ; restore interrupts
  708.     pop    ax
  709.     ret
  710.  
  711. PokeCMOS    EndP
  712.  
  713.     EndIf
  714.  
  715. ;===============================================================
  716.  
  717.     If    Generating ne CMOSSave
  718.  
  719. ReadCMOS    Proc    Near
  720.  
  721. ;    Open a file read the CMOS into a buffer
  722.  
  723.     mov    dx,FileNamePtr    ; DS:DX point to file
  724.     xor    al,al        ; AL=0 is attribute read/only
  725.     mov    ah,03Dh     ; DOS open function
  726.     int    21h
  727.     jc    FileTrouble
  728.     mov    bx,ax        ; save handle
  729.     mov    cx,128        ; read 128 bytes
  730.     lea    dx,CMOSBuff    ; buffer address
  731.     mov    ah,3fH        ; DOS read
  732.     int    21h
  733.     jc    FileTrouble
  734.     cmp    ax,128
  735.     jne    FileTrouble
  736.     mov    ah,3eh        ; DOS close
  737.     int    21h
  738.     jc    FileTrouble
  739.     ret
  740.  
  741. ReadCMOS    EndP
  742.  
  743.     EndIf
  744.  
  745. ;===============================================================
  746.  
  747.     if    Generating eq CMOSSave
  748.  
  749. WriteCMOS    Proc    Near
  750.  
  751. ;    Create a file write CMOS to it
  752.  
  753.     mov    dx,FileNamePtr    ; DS:DX point to file
  754.     xor    cx,cx        ; CX=0 is attribute
  755.     mov    ah,03ch     ; DOS create function
  756.     int    21h
  757.     jc    FileTrouble
  758.     mov    bx,ax        ; SAVE HANDLE
  759.     MOV    CX,128        ; write 128 bytes
  760.     lea    dx,CMOSBuff    ; buffer address
  761.     mov    ah,40h        ; DOS write
  762.     int    21h
  763.     jc    FileTrouble
  764.     cmp    ax,128
  765.     jne    FileTrouble
  766.     mov    ah,3eh        ; DOS close
  767.     int    21h
  768.     jc    FileTrouble
  769.     ret
  770.  
  771. WriteCMOS    EndP
  772.  
  773.     EndIf
  774.  
  775. ;===============================================================
  776.  
  777. CODE    ends            ; end of code segment
  778.     end    Start
  779.