diff options
Diffstat (limited to 'src/arch/i386/drivers/timer_bios.c')
| -rw-r--r-- | src/arch/i386/drivers/timer_bios.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/arch/i386/drivers/timer_bios.c b/src/arch/i386/drivers/timer_bios.c new file mode 100644 index 000000000..f9caf8d9a --- /dev/null +++ b/src/arch/i386/drivers/timer_bios.c @@ -0,0 +1,57 @@ +/* + * Etherboot routines for PCBIOS firmware. + * + * Body of routines taken from old pcbios.S + */ + +#include <gpxe/init.h> +#include <gpxe/timer.h> +#include <stdio.h> +#include <realmode.h> +#include <bios.h> +#include <bits/timer2.h> + +/* A bit faster actually, but we don't care. */ +#define TIMER2_TICKS_PER_SEC 18 + +/* + * Use direct memory access to BIOS variables, longword 0040:006C (ticks + * today) and byte 0040:0070 (midnight crossover flag) instead of calling + * timeofday BIOS interrupt. + */ + +static tick_t bios_currticks ( void ) { + static int days = 0; + uint32_t ticks; + uint8_t midnight; + + /* Re-enable interrupts so that the timer interrupt can occur */ + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ) : : ); + + get_real ( ticks, BDA_SEG, 0x006c ); + get_real ( midnight, BDA_SEG, 0x0070 ); + + if ( midnight ) { + midnight = 0; + put_real ( midnight, BDA_SEG, 0x0070 ); + days += 0x1800b0; + } + + return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) ); +} + +static int bios_ts_init(void) +{ + DBG("BIOS timer installed\n"); + return 0; +} + +struct timer bios_ts __timer ( 02 ) = { + .init = bios_ts_init, + .udelay = i386_timer2_udelay, + .currticks = bios_currticks, +}; + |
