Subject: port-sparc64/18452: microtime has possibility that time steps backwards
To: None <gnats-bugs@gnats.netbsd.org>
From: None <t-nkyma@tcp-ip.or.jp>
List: netbsd-bugs
Date: 09/29/2002 04:04:41
>Number:         18452
>Category:       port-sparc64
>Synopsis:       microtime has possibility that time steps backwards
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    port-sparc64-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Sep 28 12:05:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Takeshi Nakayama
>Release:        NetBSD 1.6
>Organization:
Private
>Environment:
System: NetBSD nyx 1.6 NetBSD 1.6 (NYX32) #39: Fri Sep 27 18:42:10 JST 2002
 takeshi@nyx:/usr/src/sys/arch/sparc64/compile/NYX32 sparc64
Architecture: sparc
Machine: sparc64
>Description:
	The sparc64 machines without counter-timer uses %tick to
	calculate microtime() in locare.s. This code assumes %tick
	is synchronized with time (struct timeval time), however,
	that is not right in practice.
>How-To-Repeat:
	ps(1) shows minus time value (per PR port-sparc64/15677).
	ntpd(8) adjusts time frequently.
>Fix:
	Just to use the delta of %tick for calculation of microtime,
	without taking assumption that tick synchronizes with time.

	The next patches are an ugly sample of this method. OpenBSD
	uses similar code but written in C.

Index: clock.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sparc64/sparc64/clock.c,v
retrieving revision 1.50
diff -c -d -r1.50 clock.c
*** clock.c	2002/06/11 23:33:27	1.50
--- clock.c	2002/09/16 06:01:45
***************
*** 810,820 ****
--- 810,828 ----
  	void *cap;
  {
  	int s;
+ 	long tick, *tickp;
  
  #if	NKBD	> 0
  	extern int cnrom __P((void));
  	extern int rom_console_input;
  #endif
+ 
+ 	s = splhigh();
+ 	__asm __volatile("sethi %%hi(saved_tick), %1; "
+ 			 "rdpr %%tick, %0; "
+ 			 "stx %0, [%1 + %%lo(saved_tick)]"
+ 			 : "=&r" (tick), "=r" (tickp));
+ 	splx(s);
  
  	hardclock((struct clockframe *)cap);
  	if (poll_console)
Index: locore.s
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sparc64/sparc64/locore.s,v
retrieving revision 1.158
diff -c -d -r1.158 locore.s
*** locore.s	2002/07/18 11:59:07	1.158
--- locore.s	2002/09/16 06:01:51
***************
*** 11572,11577 ****
--- 11572,11580 ----
  	.xword	200000000
  	!! Here we'll store cpu_clockrate/1000000 so we can calculate usecs
  	.xword	0
+ 	.globl	saved_tick
+ saved_tick:
+ 	.xword	0
  	.text
  
  ENTRY(microtime)
***************
*** 11669,11684 ****
  	stx	%g1, [%o1 + %lo(_C_LABEL(cpu_clockrate) + 8)]	! Save it so we don't need to divide again
  1:
  
! 	STPTR	%o2, [%o0]					! Store seconds.
  	udivx	%o4, %g1, %o4					! Scale it: ticks / MHz = usec
  
! 	udivx	%o4, %o5, %o2					! Now %o2 has seconds
  
! 	mulx	%o2, %o5, %o5					! Now calculate usecs -- damn no remainder insn
! 	sub	%o4, %o5, %o1					! %o1 has the remainder
  
  	retl
! 	 STPTR	%o1, [%o0+PTRSZ]				! Save time_t low word
  #endif
  
  /*
--- 11672,11698 ----
  	stx	%g1, [%o1 + %lo(_C_LABEL(cpu_clockrate) + 8)]	! Save it so we don't need to divide again
  1:
  
! 	sethi	%hi(saved_tick), %g5
! 	ldx	[%g5 + %lo(saved_tick)], %o1
! 	sub	%o4, %o1, %o4					! %o4 has delta ticks
  	udivx	%o4, %g1, %o4					! Scale it: ticks / MHz = usec
  
! 	udivx	%o4, %o5, %o1					! Now %o1 has delta seconds
! 	add	%o2, %o1, %o2
  
! 	mulx	%o1, %o5, %o1					! Now calculate usecs -- damn no remainder insn
! 	sub	%o4, %o1, %o1					! %o1 has the delta remainder
! 	add	%o3, %o1, %o3
  
+ 	sub	%o3, %o5, %o5					! Did we overflow?
+ 	brlz,pn	%o5, 4f
+ 	 nop
+ 	add	%o2, 1, %o2					! overflow
+ 	mov	%o5, %o3
+ 4:
+ 	STPTR	%o2, [%o0]					! Store seconds.
  	retl
! 	 STPTR	%o3, [%o0+PTRSZ]				! Save time_t low word
  #endif
  
  /*
>Release-Note:
>Audit-Trail:
>Unformatted: