home *** CD-ROM | disk | FTP | other *** search
- PAGE 60,132
- NAME CMOSSAVE
- TITLE CMOSSave Save CMOS to a file on disk or floppy
- Comment |
- Version 2.2 1995 April 14 Roedy Green
- works with MASM 6.0 and Optasm
- This assembler code generates all three programs:
- CMOSSAVE.COM CMOSREST.COM and CMOSCHK.COM.
-
- See CMOS.TXT for details on use.
-
- USAGE:
-
- Examples:
- *********
-
- CMOSSave A:\MyCMOS.Sav
-
- CMOSRest A:\MyCMOS.Sav
-
- CMOSChk A:\ByCMOS.Sav
-
- Syntax errors or missing file trouble generates an ERRORLEVEL 4.
- CMOSChk generates an ERRORLEVEL 1 if the CMOS has changed since
- the CMOSSave was done.
-
- Version History
- ***************
-
- Version 1.0
- - released to BIX 91/09/07
-
- Version 1.1
- - released to BIX 91/09/18
- - added special check for small 64 character CMOSes.
-
- Version 1.2
- - fix spelling errors
- - use CMOS.SAV instead of MyCMOS.SAV in examples
-
- Version 1.3
- - now consider fewer bytes volatile, restore more stuff.
- - hints in docs about clearing CMOS.
-
- Version 1.4
- - now consider flags Status register C, offset 0C as volatile.
- fixes false alarms.
-
- Version 1.5 1994 June 1
- - change of address and phone number
- - address now appears in the banner.
-
- Version 1.6 1994 August 29
- - more information about how CMOS bits are used.
-
- Version 2.0 1994 October 1
- - easier configuration of CHKCMOS volatile bytes.
- - smarter bat files.
- - docs on different ways to use.
-
- Version 2.2 1995 April 16
- - docs on use before experimentation
-
- CMOS Usage - see also CMOS.OFS
-
- How to Assemble
- ***************
-
- Manually set the GENERATING equate embedded in this code, then:
-
- to assemble with MASM 6.0 use:
- ML.EXE /AT /c /Fl /VM /Zf /Zm CMOS.Asm
- LINK.EXE /TINY /MAP CMOS.Obj,CMOS.com,CMOS.map;
- copy cmos.com cmossave.com
-
- to assemble with OPTASM use:
- Optasm CMOS.Asm,CMOS.Obj,CMOS.Lst/L/N/G/S
- OLINK CMOS.Obj,CMOS.COM,/MAP/TINY;
- copy cmos.com cmossave.com
-
- Register Conventions
- ********************
-
- Subroutines may trash all registers except those explicity
- documented as input or output.
-
- | ; end of comment
-
-
- ; E Q U A T E S
-
- CMOSSAVE EQU 1
- CMOSREST EQU 2
- CMOSCHK EQU 3
-
- ; use /DGenerating#CMOSSAVE
- ; /DGenerating#CMOSREST
- ; /DGenerating#CMOSCHK
- ; on the assembler command line to select which version
- ; of the code to assemble.
- ; Or add code following of the form:
-
- ; GENERATING EQU CMOSSave
-
-
- If Generating eq CMOSSave
- %OUT Generating CMOSSave.Com
- Endif
-
- If Generating eq CMOSRest
- %OUT Generating CMOSRest.Com
- endif
-
- If Generating eq CMOSChk
- %OUT Generating CMOSChk.Com
- endif
- ;==============================================================
-
-
- stack segment stack ; keep MS link happy by providing null stack
- stack ends
-
- CODE SEGMENT PARA ; start off in code.
-
- ;==============================================================
-
- data segment byte ; provide a separate DATA segment
- ; actually all come after the code
- ;==============================================================
- ; V A R I A B L E S
-
-
- If Generating eq CMOSSave
-
- BannerMsg DB '░▒▓█ CMOSSave 2.2 █▓▒░',13d,10d
- DB 13d,10d
- DB 'Saves contents of CMOS to a file on hard disk or floppy.',13,10
- DB 'Copyright (c) 1991,1995 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
- DB '#601 - 1330 Burrard, Vancouver BC CANADA V6Z 2B8',13,10
- DB 'Shareware to freely distribute and use for any purpose except military.',13,10
- DB 13,10
- db '$'
-
- UsageMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Insert a formatted diskette.',13,10
- DB 'then try:',13,10
- DB 'CMOSSave A:\CMOS.Sav',13,10
- DB 'or if want to save on hard disk try:',13,10
- DB 'CMOSSave C:\CMOS.Sav',13,10
- DB 'Read CMOS.TXT to find how to use it properly.',13,10
- db '$'
-
- FileTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Cannot create the disk file.',13,10
- db '$'
-
- WorkedMsg DB 'CMOS successfully saved',13,10
- db '$'
-
- EndIf
-
-
- If Generating eq CMOSRest
- BannerMsg DB '░▒▓█ CMOSRest 2.2 █▓▒░',13d,10d
- DB 13d,10d
- DB 'Restores CMOS from a CMOSSave file on hard disk or floppy.',13,10
- DB 'Copyright (c) 1991,1995 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
- DB '#601 - 1330 Burrard, Vancouver BC CANADA V6Z 2B8',13,10
- DB 'Shareware to freely distribute and use for any purpose except military.',13,10
- DB 13,10
- db '$'
-
- UsageMsg DB '░▒▓█ Error █▓▒░',13,10
- DB 'Insert the diskette you used for CMOSSave.',13,10
- DB 'then try:',13,10
- DB 'CMOSRest A:\CMOS.Sav',13,10
- DB 'or if the file is on hard disk try:',13,10
- DB 'CMOSRest C:\CMOS.Sav',13,10
- DB 'Read CMOS.TXT to find how to use it properly.',13,10
- db '$'
-
- FileTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Cannot find/read the disk file.',13,10
- db '$'
-
- WorkedMsg DB 'CMOS successfully restored',13,10
- db '$'
-
- EndIf
-
- If Generating eq CMOSChk
- BannerMsg DB '░▒▓█ CMOSChk 2.2 █▓▒░',13d,10d
- DB 13d,10d
- DB 'Ensures CMOS not corrupted or changed.',13,10
- DB 'Copyright (c) 1991,1995 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
- DB '#601 - 1330 Burrard, Vancouver BC CANADA V6Z 2B8',13,10
- DB 'Shareware to freely distribute and use for any purpose except military.',13,10
- DB 13,10
- db '$'
-
- UsageMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Insert the diskette you used for CMOSSave.',13,10
- DB 'then try:',13,10
- DB 'CMOSChk A:\CMOS.Sav',13,10
- DB 'or if you have the file on hard disk try:',13,10
- DB 'CMOSChk C:\CMOS.Sav',13,10
- DB 'Read CMOS.TXT to find how to use it properly.',13,10
- db '$'
-
- FileTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Cannot find/read the disk file.',13,10
- db '$'
-
- MatchTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'CMOS has been corrupted! at hex offset:value:expected ',13,10
- db '$'
-
- ColonMsg db ':','$'
-
- NextTripleMsg db 13,10,'$'
-
-
- WorkedMsg DB 'CMOS is OK, i.e. unchanged since the last CMOSSave.',13,10
- db '$'
-
- EndIf
-
-
- FilenamePtr DW 0
- ; pointer to filename in command line
-
- CMOSSize DB 0
- ; size of cmos in bytes
-
- CMOSBuff db 0 ; dynamic buffer will grow to 128
- ; it hangs out past the end of the program
-
- data ends
-
- com group code,data ; force data segment to go at the end
-
- ASSUME CS:com,DS:com,ES:com,SS:com
- ; seg regs cover everything
- ORG 100H ; in Code segment
-
- ;==========================
-
- Main proc far
-
- ; M A I N L I N E R O U T I N E
- Start:
- lea dx,BannerMsg ; display the banner
- Call Say
- Call Parse ; get filename from command line
-
- If Generating eq CMOSSave
- call GetCMOS ; fetch CMOS to buffer
- call WriteCMOS ; write CMOS contents to file
- EndIf
-
- If Generating eq CMOSRest
- call ReadCMOS ; read CMOS contents from file
- call CalcCMOSSize ; it is 64 or 128 bytes long?
- call PutCMOS ; store buffer to CMOS
- EndIf
-
- If Generating eq CMOSChk
- call ReadCMOS ; read CMOS contents from file
- call CalcCMOSSize ; it is 64 or 128 bytes long?
- call CompareCMOS ; compare CMOS with buffer
- EndIf
-
- lea dx,WorkedMsg ; crow about success
- Call Say
- Done:
- mov ax,4c00h
- int 21h ;normal termination
-
- Main EndP
-
- ;===============================================================
-
- Trouble proc near
-
- FileTrouble:
- Lea dx,FileTroubleMsg ; display file trouble
- Call Say
- Jmp Abort
-
- abort:
- ; error exit
- mov ax, 4c04h ; ERRORLEVEL = 4
- int 21h ; DIE
-
- Trouble endp
-
- ;===============================================================
-
- MLeading PROC Near
-
- ; Remove leading blanks
- ; on entry BX is addr of string, CX its length
- ; trims off any leading blanks, leaving result in BX CX
- ; length may also be 0 or 1, but not -ve
- ; If the entire string is blank the result is the null string
- mov di,bx
- mov al,20H ; AL = blank -- the search char
- jcxz mleading2 ; jump if null string
- repe scasb ; scan ES:DI forwards till hit non blank
- ; DI points just after it (wrap ok)
- ; cx IS ONE TOO SMALL, OR 0 IF NONE FOUND
- je mleading1 ; jump if entire string was blank
- inc cx ; CX is length of remainder of string
- mleading1:
- dec di ; DI points to non-blank
- mleading2:
- mov bx,di ; put address back
- ret
-
- MLeading ENDP
-
- ;========================================
-
- MTrailing PROC Near
-
- ; Remove trailing blanks.
- ; on entry BX is addr of string, CX its length
- ; trims off any trailing blanks, leaving result in BX CX
- ; length may also be 0 or 1, but not -ve
- ; If the entire string is blank the result is the null string
- mov di,bx
- add di,cx ; calc addr last char in string
- dec di
- mov al,20H ; AL = blank -- the search char
- jcxz mtrailing1 ; jump if null string
- std
- repe scasb ; scan ES:DI backwards till hit non blank
- ; DI points just ahead of it (wrap ok)
- ; CX is one too small, or 0 if none found
- cld
- je mtrailing1 ; jump if whole string was blank
- inc cx
- mtrailing1:
- ret
-
- MTrailing ENDP
-
- ;========================================
-
- Parse PROC NEAR
- ; Parse the command line to remove lead/trail blanks from
- ; the single drive parameter and terminate it by 2 nulls.
- ; sample inputs
- ; CMOSRest A:\CMOS.SAV
- ; CMOSRest B:\MySub\MyCMOS.SAV
- ;
- ; When Done DS:BX points to start of string.
- ; String will be terminated by 2 nulls
- ; CX counts bytes in string exclusive of nulls
- ; counted string at HEX 80 PSP
- ; contains command line.
- ; Preceeded by unwanted spaces.
- ; possibly followed by unwanted spaces.
- ; currently missing a trailing null.
- xor ch,ch
- mov cl,ds:80H
- mov bx,81H
- call Mleading ; get rid of leading blanks
- call MTrailing ; get rid of trailing blanks
- mov di,bx ; calc addr of byte just past end
- add di,cx
- mov word ptr [di],0 ; plop in pair of nulls after string
- mov FileNamePtr,bx ; remember where filename was
- jcxz SyntaxTrouble ; missing parm.
- ret
-
- SyntaxTrouble:
- lea dx,UsageMsg ; display usage message
- Call Say
- Jmp Abort
-
- Parse ENDP
-
- ;======================================
-
- Say Proc
-
- ; on entry DX points to a string to display
- push ax
- MOV AH,9
- Int 21h
- pop ax
- ret
-
- Say EndP
-
- ;======================================
-
- If Generating eq CMOSSave
-
- GetCMOS Proc Near
-
- ; Get 128 byte contents of CMOS into a buffer.
-
- mov cx,128 ; count of times through loop
- lea bx,CMOSBuff ; where to put the contents
- sub al,al ; start offset in CMOS
- GetLoop:
- Call PeekCmos ; al=offset ah=contents
- mov byte ptr[bx],ah
- inc al
- inc bx
- loop GetLoop
- ret
-
- GetCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSRest
-
- PutCMOS Proc Near
-
- ; Put 128-byte contents of buffer into CMOS.
- ; do not touch the volatile bytes
-
- mov cx,128 ; count of times through loop
- lea bx,CMOSBuff ; where to put the contents
- sub al,al ; start offset in CMOS
- PutLoop:
- call Volatile ; test if this is a volatile byte
- ; test offset in al
- jc LeaveItAlone
- mov ah,byte ptr[bx]
- Call PokeCMOS ; al=offset ah=contents
-
- LeaveItAlone:
- inc bx
- inc al
- loop PutLoop
- ret
-
- PutCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSChk
-
- hexPAD DB '00$' ; where numeric output built by SayHexByte
-
- SayHexByte proc Near
- ; al contains hex byte to display:
-
- push ax ; preserve regs
- push bx
- push cx
- push dx
- mov dl,al ; save input
- ; Do first (leftmost digit)
- mov cl,4
- shr al,cl
- and al,0fh ; get first digit
- cmp al,9
- jg HexChar1
- add al,'0' ; convert digit to ASCII
- jmp StoreChar1
- HexChar1:
- add al,'A'-0AH ; convert to uppercase A..H
- StoreChar1:
- mov hexPad,al
-
- ; Do second (rightmost digit)
- mov al,dl
- and al,0fh ; get last digit
- cmp al,9
- jg HexChar2
- add al,'0' ; convert digit to ASCII
- jmp StoreChar2
- HexChar2:
- add al,'A'-0AH ; convert to uppercase A..H
- StoreChar2:
- mov hexPad+1,al
-
- ; Number is ready
- lea dx,Hexpad
- mov AH,09h ; BIOS put string terminated by $
- int 21h
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-
- SayHexByte ENDP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSChk
- CompareCMOS proc Near
-
- ; compares buffer version of CMOS with contents of actual CMOS
- ; ignores mismatches of volatile bytes.
- ; Aborts if finds a mismatch
-
- mov cx,128 ; count of times through loop
- lea bx,CMOSBuff ; where to find comparison set
- sub al,al ; start offset in CMOS
- push si
- sub si,si ; count of mismatches
- CompLoop:
- call Volatile ; test if this is a volatile byte
- ; test offset in al
- jc MatchedOk
- Call PeekCMOS ; al=offset ah=contents
- cmp ah,byte ptr[bx] ; compare CMOS with buffer
- je MatchedOk
-
- ; Mismatch
- test si,si ; only complain on first mismatch
- jnz AlreadyComplained
- lea dx,MatchTroubleMsg ; display CMOS mismatch
- call Say
- AlreadyComplained:
- push ax
- inc si ; count of how many mismatches found
- Call SayHexByte ; report offset
- lea dx,ColonMsg
- call Say
- mov al,ah ; report bad value in CMOS
- Call SayHexByte
- lea dx,ColonMsg
- call Say
- mov al,byte ptr[bx] ; report what value should be from file.
- call SayHexByte
- lea dx,NextTripleMsg
- call Say
- pop ax
-
- MatchedOk:
- inc bx
- inc al
- loop CompLoop
-
- test si,si
- jz NoMismatches
-
- mov ax, 4c01h ; ERRORLEVEL = 1
- int 21h ; DIE
-
- NoMisMatches:
- pop si
- ret
-
- CompareCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating ne CMOSSave
-
- ; Add to this list if you need more volatile bytes.
- ; Remember the trailing h.
-
- VolatileList db 0ch,032h
-
- VolatileCount equ $-VolatileList
-
-
- Volatile Proc near
-
- ; Is cmos offset in AL volatile? If so set carry.
- ; These bytes will be undisturbed.
- ; Preserves all registers.
- ; 00..09, 0C and 32 are volatile, rest are not.
- ; 0A 0B 0D 0E 0F used to be considered volatile, now are not.
- ; if cmos is small, all bytes past end are considered volatile
-
- cmp al,CMOSSize ; bytes past end are volatile
- jae IsVolatile
- cmp al,09h
- jbe IsVolatile ; early bytes are for timing
- push cx
- push di
- mov cx,VolatileCount
- lea di,VolatileList
- repne scasb ; search till find a match
- pop di
- pop cx
- je IsVolatile
-
- IsNotVolatile:
- clc ; clear carry
- ret
-
- IsVolatile:
- stc
- ret
-
- Volatile EndP
- EndIf
-
- ;===============================================================
-
- If Generating ne CMOSSave
-
- CalcCMOSSize Proc near
-
- ; Is CMOS 64 or 128 bytes long?
- ; It is 64 if bytes at 10..2F match those at 50..6F.
- ; Otherwise it is 128 bytes.
- ; Preserves all registers.
-
- push si
- push di
- push cx
- lea si,CMOSBuff+10h
- lea di,CMOSBuff+50h
- mov cx,02fh+1-10h
- repe cmpsb
- je IsCMOS64
-
- IsCMOS128:
- mov CMOSSize,128 ; differ, must be a big CMOS
- jmp CalcCMOSSizeDone
-
- IsCMOS64:
- mov CMOSSize,64 ; all same, small CMOS
-
- CalcCMOSSizeDone:
- pop cx
- pop di
- pop si
-
- ret
-
- CalcCMOSSize EndP
- EndIf
-
- ;===============================================================
-
- if Generating ne CMOSRest
-
- PeekCMOS proc near
-
- ; Reads one byte from cmos.
- ; on entry al has offset desired
- ; on exit ah has the contents of that byte.
- ; preserves all registers
-
- ; See page 5-81 IBM AT Tech ref BIOS listing for how to read CMOS
- ; We always enable the NMI with bit 7 on.
-
- push bx
- push ax
- cli ; disable interrupts
- or al,80h ; disable NMI
- out 70h,al ; output the byte address to CMOS
- jmp $+2 ; delay, safer than nop
- in al,71h ; read the CMOS byte
- jmp $+2 ; delay, safer than nop
- mov bl,al
- ; re-enable the NMI
- mov al,0dh ; point to battery status register
- out 70h,al ; leave pointing at a safe r/o register
- sti ; restore interrupts
- pop ax
- mov ah,bl
- pop bx
- ret
-
- PeekCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSRest
-
- PokeCMOS proc near
-
- ; Stuffs one byte into cmos.
- ; on entry al has offset desired, ah has the value to stuff.
- ; Preserves all registers.
-
- ; See page 5-81 IBM AT Tech ref BIOS listing for how to write CMOS
- ; We always enable the NMI with bit 7 on.
-
- push ax
- cli ; disable interrupts
- or al,80h ; disable NMI
- out 70h,al ; output the byte address to CMOS
- jmp $+2 ; delay, safer than nop
-
- mov al,ah ; get contents
- out 71h,al ; poke the CMOS byte
- jmp $+2 ; delay, safer than nop
- ; re-enable the NMI
- mov al,0dh ; point to battery status register
- out 70h,al ; leave pointing at a safe r/o register
- sti ; restore interrupts
- pop ax
- ret
-
- PokeCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating ne CMOSSave
-
- ReadCMOS Proc Near
-
- ; Open a file read the CMOS into a buffer
-
- mov dx,FileNamePtr ; DS:DX point to file
- xor al,al ; AL=0 is attribute read/only
- mov ah,03Dh ; DOS open function
- int 21h
- jc FileTrouble
- mov bx,ax ; save handle
- mov cx,128 ; read 128 bytes
- lea dx,CMOSBuff ; buffer address
- mov ah,3fH ; DOS read
- int 21h
- jc FileTrouble
- cmp ax,128
- jne FileTrouble
- mov ah,3eh ; DOS close
- int 21h
- jc FileTrouble
- ret
-
- ReadCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- if Generating eq CMOSSave
-
- WriteCMOS Proc Near
-
- ; Create a file write CMOS to it
-
- mov dx,FileNamePtr ; DS:DX point to file
- xor cx,cx ; CX=0 is attribute
- mov ah,03ch ; DOS create function
- int 21h
- jc FileTrouble
- mov bx,ax ; SAVE HANDLE
- MOV CX,128 ; write 128 bytes
- lea dx,CMOSBuff ; buffer address
- mov ah,40h ; DOS write
- int 21h
- jc FileTrouble
- cmp ax,128
- jne FileTrouble
- mov ah,3eh ; DOS close
- int 21h
- jc FileTrouble
- ret
-
- WriteCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- CODE ends ; end of code segment
- end Start
-