summaryrefslogblamecommitdiffstats
path: root/src/arch/i386/drivers/timer_bios.c
blob: f9caf8d9a4feba1bc7135041867359d1612a6b12 (plain) (tree)
























































                                                                          
/*
 * 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,
};