[comp.unix.wizards] Sun TOD clock problem in leap years

kre@munnari.oz (Robert Elz) (01/05/88)

There has been a discussion about a bug in SunOS 3.x (for versions
of x of 3 and 4 for certain, others possibly) in the TCP-IP mailing
list (aka comp.protocols.tcp-ip) which can cause problems on systems
which run time daemons (to keep clocks synchronised).

This problem has occurred because of 1988 being a leap year.

Stuart Levy of UMN posted a patch (source and binary) in that
list (see <880120627.AA19752@uc.msc.umn.edu>, which would correct
this problem.  His binary patch would need to be removed at the end
of the year, as it worked only in leap years.

I posted a alternate version of his patch which would work in any year.
I have since been unofficially asked by a friend at Sun if I could
give the binary patch wider distribution.

So, here's how its done (for SunOS 3.3 and 3.4, and others, perhaps)...

# adb -w -k /vmunix /dev/mem
resettodr+0xca?X
	(It should contain 0x536efff4, a subqw #1,a6@(-0xc) instruction.
	If you applied Stuart's patch it will contain 0x4e714e71, 2 nop's
	so put back the subw in both the kernel a.out, and memory.  This
	step is unnecessary if you haven't applied Stuart's fix).
.?W 536efff4
./W 536efff4
	(next, apply a slightly better fix)
resettodr+0xc0?i
	(it should contain "bnes resettodr+0xca", which we will change to be
	"bnes resettodr+0xce" and avoid the incorrect subw)
.?w 660c
	(now verify that its correct)
.?i
	(and assuming it is "bnes resettodr+0xca", change the running kernel)
./w 660c
$q

I can't verify that this actually fixes the reported problem, but it clearly
does fix a bug, and should have the same effect this year as Stuart's fix,
while not hurting next year.  I used SunOS 3.4 to do this, in case other
versions of SunOS deviate (3.3 is apparently the same), here is the original
section of binary ...

_resettodr+0xa6:              movw    a6@(-0x10),d0
_resettodr+0xaa:              moveq   #3,d1
_resettodr+0xac:              andw    d1,d0
_resettodr+0xae:              andl    #0xffff,d0
_resettodr+0xb4:              bnes    _resettodr+0xca
_resettodr+0xb6:              subqw   #1,a6@(-0xc)
_resettodr+0xba:              cmpw    #2,a6@(-0xc)
_resettodr+0xc0:              bnes    _resettodr+0xca	<<<< change this to
_resettodr+0xc2:              movl    #0x263b80,d0
_resettodr+0xc8:              bras    _resettodr+0xde
_resettodr+0xca:              subqw   #1,a6@(-0xc)
_resettodr+0xce:              moveq   #0,d0		<<<< branch to here
_resettodr+0xd0:              movw    a6@(-0xc),d0
_resettodr+0xd4:              lea     _monthsec:l,a0
_resettodr+0xda:              movl    a0@(-4,d0:l:4),d0
_resettodr+0xde:              addl    d0,d7

If you have Sun source, I think that you'll find the fix pretty trivial,
just move the "--mon" to outside (before) the call of the MONTHSEC,
leaving the arg to MONTHSEC as just "mon".

kre