Решил вынести это отдельной темой, так как вопрос важный, среди прочего озадачился сейчас этим.
Для измерения временных промежутков, хотя бы даже для реализации имеющихся в популярных ОС вызовов sleep/usleep, использование IRQ0, IRQ8 не подходит в виду небольшого разрешения таймера и часов РВ. Поэтому решил сделать реализацию на основе инструкции RDTSC.
Собственно запрос числа тактов процессора с момента включения
Код:
/*-----------------------------------------------------------------------------
/ void get_cpu_ticks(u64int* ticks)
/----------------------------------------------------------------------------*/
.global get_cpu_ticks
get_cpu_ticks:
mov 4(%esp), %ebx
rdtsc
mov %eax, (%ebx)
mov %edx, 4(%ebx)
ret
Для привязки к реальным временным единицам необходима тактовая частота CPU, которую я определяю в обработчике IRQ0, который выполняется с частотой BASE_FREQ = 1024 Гц
Код:
/*------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------*/
void timer_callback(registers_t regs)
{
timer_tick++;
if (tick_count == (BASE_FREQ >> 8 ))
{
tick_count = 0;
get_cpu_ticks(&cpu_ticks1);
dticks = (u32int) (cpu_ticks1 - cpu_ticks0);
cpu_ticks0 = cpu_ticks1;
cpu_freq = dticks << 8;
}
tick_count++;
msg_reset();
if (is_multitask())
{
task_switch();
}
}
/*------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------*/
u32int get_cpu_freq(void)
{
return cpu_freq;
}
Сама реализация sleep(...)
Код:
/*------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------*/
int sleep_msec(u32int msec)
{
u32int ticks = 0; /* Time interval in CPU ticks */
u64int cpu_ticks0 = 0; /* Initial CPU tick count */
u64int cpu_ticks1 = 0; /* Actual CPU tick count */
/* Get CPU ticks count */
get_cpu_ticks(&cpu_ticks0);
/* Calculate tick's count in 1 ms */
u32int scaled_cpu_freq = get_cpu_freq()/MSEC;
/* Tick's count in required time interval */
u32int eq_ticks = msec*scaled_cpu_freq;
do
{
/* Get CPU ticks count */
get_cpu_ticks(&cpu_ticks1);
/* Time interval in CPU ticks */
ticks = (u32int) (cpu_ticks1 - cpu_ticks0);
} while ( ticks < eq_ticks);
return 1;
}
На QEMU работает так
Счетчик обновляется раз в секунду - sleep(1000). Тактовая частота моего хост-процессора 3400 МГц, вроде ок
Что интересно - Bochs показывает частоту 50 МГц, видимо такая частота эмулируется там программно, но счетчик обновляется раз в секунду, то есть и тут вроде всё ок