svn commit: r195860 - in stable/7/sys: . boot/i386/libi386 contrib/pf

Ed Maste emaste at FreeBSD.org
Sat Jul 25 02:22:11 UTC 2009


Author: emaste
Date: Sat Jul 25 02:22:10 2009
New Revision: 195860
URL: http://svn.freebsd.org/changeset/base/195860

Log:
  MFC r179825 by olli:
  
    Implement a workaround for a long-standing problem in
    libi386's time(), caused by a qemu bug.  The bug might
    be present in other BIOSes, too.
  
    qemu either does not simulate the AT RTC correctly or
    has a broken BIOS 1A/02 implementation, and will return
    an incorrect value if the RTC is read while it is being
    updated.
  
    The effect is worsened by the fact that qemu's INT 15/86
    function ("wait" a.k.a. usleep) is non-implmeneted or
    broken and returns immediately, causing beastie.4th to
    spin in a tight loop calling the "read RTC" function
    millions of times, triggering the problem quickly.
  
    Therefore, we keep reading the BIOS value until we get
    the same result twice.  This change fixes beastie.4th's
    countdown under qemu.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/boot/i386/libi386/time.c
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/boot/i386/libi386/time.c
==============================================================================
--- stable/7/sys/boot/i386/libi386/time.c	Fri Jul 24 21:42:10 2009	(r195859)
+++ stable/7/sys/boot/i386/libi386/time.c	Sat Jul 25 02:22:10 2009	(r195860)
@@ -32,18 +32,16 @@ __FBSDID("$FreeBSD$");
 #include "bootstrap.h"
 #include "libi386.h"
 
+static int	bios_seconds(void);
+
 /*
- * Return the time in seconds since the beginning of the day.
- *
- * If we pass midnight, don't wrap back to 0.
+ * Return the BIOS time-of-day value.
  *
  * XXX uses undocumented BCD support from libstand.
  */
-
-time_t
-time(time_t *t)
+static int
+bios_seconds(void)
 {
-    static time_t	lasttime, now;
     int			hr, minute, sec;
     
     v86.ctl = 0;
@@ -55,7 +53,33 @@ time(time_t *t)
     minute = bcd2bin(v86.ecx & 0xff);		/* minute in %cl */
     sec = bcd2bin((v86.edx & 0xff00) >> 8);	/* second in %dh */
     
-    now = hr * 3600 + minute * 60 + sec;
+    return (hr * 3600 + minute * 60 + sec);
+}
+
+/*
+ * Return the time in seconds since the beginning of the day.
+ *
+ * Some BIOSes (notably qemu) don't correctly read the RTC
+ * registers in an atomic way, sometimes returning bogus values.
+ * Therefore we "debounce" the reading by accepting it only when
+ * we got two identical values in succession.
+ *
+ * If we pass midnight, don't wrap back to 0.
+ */
+time_t
+time(time_t *t)
+{
+    static time_t lasttime;
+    time_t now, check;
+    int try;
+
+    try = 0;
+    check = bios_seconds();
+    do {
+	now = check;
+	check = bios_seconds();
+    } while (now != check && ++try < 1000);
+
     if (now < lasttime)
 	now += 24 * 3600;
     lasttime = now;


More information about the svn-src-stable mailing list