Introduce the new timer subsystem.
[people/mdeck/gpxe.git] / src / arch / i386 / drivers / timer_bios.c
1 /*
2  * Etherboot routines for PCBIOS firmware.
3  *
4  * Body of routines taken from old pcbios.S
5  */
6
7 #include <gpxe/init.h>
8 #include <gpxe/timer.h>
9 #include <stdio.h>
10 #include <realmode.h>
11 #include <bios.h>
12 #include <bits/timer2.h>
13
14 /* A bit faster actually, but we don't care. */
15 #define TIMER2_TICKS_PER_SEC    18
16
17 /*
18  * Use direct memory access to BIOS variables, longword 0040:006C (ticks
19  * today) and byte 0040:0070 (midnight crossover flag) instead of calling
20  * timeofday BIOS interrupt.
21  */
22
23 static tick_t bios_currticks ( void ) {
24         static int days = 0;
25         uint32_t ticks;
26         uint8_t midnight;
27
28         /* Re-enable interrupts so that the timer interrupt can occur */
29         __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
30                                            "nop\n\t"
31                                            "nop\n\t"
32                                            "cli\n\t" ) : : );
33
34         get_real ( ticks, BDA_SEG, 0x006c );
35         get_real ( midnight, BDA_SEG, 0x0070 );
36
37         if ( midnight ) {
38                 midnight = 0;
39                 put_real ( midnight, BDA_SEG, 0x0070 );
40                 days += 0x1800b0;
41         }
42
43         return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) );
44 }
45
46 static int bios_ts_init(void)
47 {
48         DBG("BIOS timer installed\n");
49         return 0;
50 }
51
52 struct timer bios_ts __timer ( 02 ) = {
53         .init = bios_ts_init,
54         .udelay = i386_timer2_udelay,
55         .currticks = bios_currticks,
56 };
57