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