Приветствую сообщество osdev!
Мною был обнаружен баг в реализации таймера APIC-а в VmWare 8. Согласно документации Intel, при запуске APIC-а в режиме One Shot таймер APIC-а должен генерировать прерывание при достижении счетчиком нуля. Таким образом, после получения прерывания от этого таймера теоретически при прочтении регистра текущего значения счетчика мы ВСЕГДА должны получать значение ноль. По крайней мере я на это рассчитывал, и проверял это значение после получения прерывания, чтобы убедиться, что прерывание поступило именно от таймера, а не от криво настроенного PIC или IO APIC. На практике, при использовании виртуальной машины оказалось, что это предположение не всегда истинно и VmWare может запускать прерывание от таймера, до того как счетчик достигнет нуля. В частности, периодически, я получал значение 1. На реальном железе, я надеюсь, такое поведение не должно воспроизводиться.
Пример кода:
Код:
VOID ASMCODE HandleTimerRing(KrnControlBlock* CONST)
{
__asm
{
push ECX
xor EAX, EAX
mov EAX, DS:APIC_PAGE.currentCount.value
test EAX, EAX
jnz short SPURIOUS_RING
}
....
SPURIOUS_RING:
__asm pushad;
__asm mov ecx, DS:APIC_PAGE.currentCount.value;
__asm mov edx, 14;
__asm push 6;
__asm call PrintUlong;
__asm popad;
__asm pushad;
__asm mov ecx, eax;
__asm mov edx, 14;
__asm push 7;
__asm call PrintUlong;
__asm popad;
__asm pop ECX ; //
__asm jmp short EoiHandling; // 9
}
В результате выполнения этого кода обработчика прерывания таймера APIC в седьмой строке я получаю значение "00000001" а в шестой - "00000000". Заметьте, что в седьмую строку записывается значение EAX заполненное ранее из регистра Current Count APIC-а в начале обработчика. То есть APIC продолжает декрементировать значение регистра. В связи с этим, я полагаю, что current count регистр APIC может содержать любое относительно небольшое значение во время запуска прерывания.
Надеюсь, что данный пост поможет кому-нибудь сэкономить кучу времени, так как отладка планировщика - это то еще извращение.