X86: Fix the time keeping of the Local APIC timer.

This commit is contained in:
Gabe Black 2009-02-01 00:30:11 -08:00
parent 1c5b9773bd
commit 6b60a29706

View file

@ -344,10 +344,19 @@ X86ISA::Interrupts::readReg(ApicRegIndex reg)
break; break;
case APIC_CURRENT_COUNT: case APIC_CURRENT_COUNT:
{ {
assert(clock); if (apicTimerEvent.scheduled()) {
uint32_t val = regs[reg] - curTick / clock; assert(clock);
val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); // Compute how many m5 ticks happen per count.
return val; uint64_t ticksPerCount = clock *
divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
// Compute how many m5 ticks are left.
uint64_t val = apicTimerEvent.when() - curTick;
// Turn that into a count.
val = (val + ticksPerCount - 1) / ticksPerCount;
return val;
} else {
return 0;
}
} }
default: default:
break; break;
@ -441,19 +450,17 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
{ {
assert(clock); assert(clock);
newVal = bits(val, 31, 0); newVal = bits(val, 31, 0);
uint32_t newCount = newVal * // Compute how many timer ticks we're being programmed for.
(divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16); uint64_t newCount = newVal *
regs[APIC_CURRENT_COUNT] = newCount + curTick / clock; (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
// Find out how long a "tick" of the timer should take.
Tick timerTick = 16 * clock;
// Schedule on the edge of the next tick plus the new count. // Schedule on the edge of the next tick plus the new count.
Tick offset = curTick % timerTick; Tick offset = curTick % clock;
if (offset) { if (offset) {
reschedule(apicTimerEvent, reschedule(apicTimerEvent,
curTick + (newCount + 1) * timerTick - offset, true); curTick + (newCount + 1) * clock - offset, true);
} else { } else {
reschedule(apicTimerEvent, reschedule(apicTimerEvent,
curTick + newCount * timerTick, true); curTick + newCount * clock, true);
} }
} }
break; break;