xref: /dragonfly/stand/boot/pc32/libi386/time.c (revision 479ab7f0)
1*479ab7f0SSascha Wildner /*-
2*479ab7f0SSascha Wildner  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3*479ab7f0SSascha Wildner  * All rights reserved.
4*479ab7f0SSascha Wildner  *
5*479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6*479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
7*479ab7f0SSascha Wildner  * are met:
8*479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10*479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12*479ab7f0SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13*479ab7f0SSascha Wildner  *
14*479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*479ab7f0SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*479ab7f0SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*479ab7f0SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*479ab7f0SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*479ab7f0SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*479ab7f0SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*479ab7f0SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*479ab7f0SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*479ab7f0SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*479ab7f0SSascha Wildner  * SUCH DAMAGE.
25*479ab7f0SSascha Wildner  *
26*479ab7f0SSascha Wildner  * $FreeBSD: src/sys/boot/i386/libi386/time.c,v 1.5 2003/08/25 23:28:31 obrien Exp $
27*479ab7f0SSascha Wildner  * $DragonFly: src/sys/boot/pc32/libi386/time.c,v 1.3 2003/11/10 06:08:36 dillon Exp $
28*479ab7f0SSascha Wildner  */
29*479ab7f0SSascha Wildner #include <stand.h>
30*479ab7f0SSascha Wildner #include <btxv86.h>
31*479ab7f0SSascha Wildner #include "bootstrap.h"
32*479ab7f0SSascha Wildner #include "libi386.h"
33*479ab7f0SSascha Wildner 
34*479ab7f0SSascha Wildner /*
35*479ab7f0SSascha Wildner  * Return the time in seconds since the beginning of the day.
36*479ab7f0SSascha Wildner  *
37*479ab7f0SSascha Wildner  * If we pass midnight, don't wrap back to 0.
38*479ab7f0SSascha Wildner  *
39*479ab7f0SSascha Wildner  * XXX uses undocumented BCD support from libstand.
40*479ab7f0SSascha Wildner  */
41*479ab7f0SSascha Wildner static int
bios_seconds(void)42*479ab7f0SSascha Wildner bios_seconds(void)
43*479ab7f0SSascha Wildner {
44*479ab7f0SSascha Wildner     time_t now;
45*479ab7f0SSascha Wildner     int sec;
46*479ab7f0SSascha Wildner     int minute;
47*479ab7f0SSascha Wildner     int	hr;
48*479ab7f0SSascha Wildner 
49*479ab7f0SSascha Wildner     v86.ctl = 0;
50*479ab7f0SSascha Wildner     v86.addr = 0x1a;		/* int 0x1a, function 2 */
51*479ab7f0SSascha Wildner     v86.eax = 0x0200;
52*479ab7f0SSascha Wildner     v86int();
53*479ab7f0SSascha Wildner 
54*479ab7f0SSascha Wildner     hr = bcd2bin((v86.ecx & 0xff00) >> 8);	/* hour in %ch */
55*479ab7f0SSascha Wildner     minute = bcd2bin(v86.ecx & 0xff);		/* minute in %cl */
56*479ab7f0SSascha Wildner     sec = bcd2bin((v86.edx & 0xff00) >> 8);	/* second in %dh */
57*479ab7f0SSascha Wildner     now = hr * 3600 + minute * 60 + sec;
58*479ab7f0SSascha Wildner 
59*479ab7f0SSascha Wildner     return (now);
60*479ab7f0SSascha Wildner }
61*479ab7f0SSascha Wildner 
62*479ab7f0SSascha Wildner /*
63*479ab7f0SSascha Wildner  * Some BIOSes (notably qemu) don't correctly read the RTC
64*479ab7f0SSascha Wildner  * registers in an atomic way, sometimes returning bogus values.
65*479ab7f0SSascha Wildner  * Therefore we "debounce" the reading by accepting it only when
66*479ab7f0SSascha Wildner  * we got 8 identical values in succession.
67*479ab7f0SSascha Wildner  *
68*479ab7f0SSascha Wildner  * If we pass midnight, don't wrap back to 0.
69*479ab7f0SSascha Wildner  */
70*479ab7f0SSascha Wildner time_t
time(time_t * t)71*479ab7f0SSascha Wildner time(time_t *t)
72*479ab7f0SSascha Wildner {
73*479ab7f0SSascha Wildner     static time_t lasttime;
74*479ab7f0SSascha Wildner     time_t now, check;
75*479ab7f0SSascha Wildner     int same, try;
76*479ab7f0SSascha Wildner 
77*479ab7f0SSascha Wildner     try = same = 0;
78*479ab7f0SSascha Wildner     check = bios_seconds();
79*479ab7f0SSascha Wildner     do {
80*479ab7f0SSascha Wildner 	now = check;
81*479ab7f0SSascha Wildner 	check = bios_seconds();
82*479ab7f0SSascha Wildner 	if (check != now)
83*479ab7f0SSascha Wildner 	    same = 0;
84*479ab7f0SSascha Wildner     } while (++same < 8 && ++try < 1000);
85*479ab7f0SSascha Wildner 
86*479ab7f0SSascha Wildner     if (now < lasttime)
87*479ab7f0SSascha Wildner 	now += 24 * 3600;
88*479ab7f0SSascha Wildner     lasttime = now;
89*479ab7f0SSascha Wildner 
90*479ab7f0SSascha Wildner     if (t != NULL)
91*479ab7f0SSascha Wildner 	*t = now;
92*479ab7f0SSascha Wildner     return(now);
93*479ab7f0SSascha Wildner }
94*479ab7f0SSascha Wildner 
95*479ab7f0SSascha Wildner /*
96*479ab7f0SSascha Wildner  * Use the BIOS Wait function to pause for (period) microseconds.
97*479ab7f0SSascha Wildner  *
98*479ab7f0SSascha Wildner  * Resolution of this function is variable, but typically around
99*479ab7f0SSascha Wildner  * 1ms.
100*479ab7f0SSascha Wildner  */
101*479ab7f0SSascha Wildner void
delay(int period)102*479ab7f0SSascha Wildner delay(int period)
103*479ab7f0SSascha Wildner {
104*479ab7f0SSascha Wildner     v86.ctl = 0;
105*479ab7f0SSascha Wildner     v86.addr = 0x15;		/* int 0x15, function 0x86 */
106*479ab7f0SSascha Wildner     v86.eax = 0x8600;
107*479ab7f0SSascha Wildner     v86.ecx = period >> 16;
108*479ab7f0SSascha Wildner     v86.edx = period & 0xffff;
109*479ab7f0SSascha Wildner     v86int();
110*479ab7f0SSascha Wildner }
111