I am currently using PIC and PIT to generate timer interrupts in my kernel. Now I want to switch to local APIC timer. I have tried few things but I am unable to get the APIC timer working. I had some discussion in this post - http://forum.osdev.org/viewtopic.php?f=1&t=25474 but I am starting a new post to explain what I have done after that post and where I am stuck Here is what I have done :
- compiled bochs with cpu_leve 6 to get the APIC enabled.
- I have checked that APIC is present and is enabled
Code: Select all
//check if APIC is present using CPUID
uint32 cpuHasAPIC()
{
uint32 eax , edx;
eax = 0x1;
uint32 CPU_FLAG_APIC = 0x200;
asm volatile("cpuid": "=d"(edx) :"a"(eax));
return edx & CPU_FLAG_APIC;
}
//check if apic is enabled and prints its base address
void checkAPICStatus()
{
uint32 APIC_ENABLE_FLAG = 0x800;
uint32 APIC_BASE_FLAG = 0xFFFFF000;
uint32 ecx = 0x1B; //<<<<<<<<<<<<<< APIC BASE MSR
uint32 eax, edx;
asm volatile("rdmsr":"=a"(eax), "=d"(edx):"c"(ecx));
uint32 apic_enabled = eax & APIC_ENABLE_FLAG;
if(apic_enabled)
{
print_str("\nAPIC IS ENABLED!!");
}else
{
print_str("\nAPIC IS DISABLED");
}
// Get APIC BASE address
uint32 apic_base = eax & APIC_BASE_FLAG;
print_str("\n APIC BASE ADDRESS IS ");
print_hex(apic_base);
}
- Added a page table entry for the APIC base - 0xFEE00000 which has the Cache Disable bit set.
I haven't mapped it to a physical page( even when I map it to a page it makes no difference). I have checked that the apic base address is correct by reading the APIC BASE MSR. (shown in code above)
- Added code from the wiki - http://wiki.osdev.org/APIC_timer to initialize APIC timer but it did not work.The timer interrupt didn't get triggered.
- After reading this post - http://forum.osdev.org/viewtopic.php?f= ... =APIC+init I made the timer code short and simple. Here is the code -
Code: Select all
uint32 apic = 0xFEE00000;
uint32 APIC_SPURIOUS = 0x0F0;
uint32 APIC_SW_ENABLE = 0x100;
uint32 APIC_DFR = 0x0E0;
uint32 APIC_TASKPRIOR = 0x80;
uint32 APIC_TMRDIV = 0x3E0;
uint32 APIC_LVT_TMR = 0x320;
uint32 TMR_PERIODIC = 0x20000;
uint32 APIC_TMRINITCNT = 0x380;
void apic_timer_init(){
//software enable apic timer
*(uint32*)(apic+APIC_SPURIOUS)=0xFF|APIC_SW_ENABLE;
//set DFR to flat mode
*(uint32*)(apic+APIC_DFR)=0xFFFFFFFF;
//set task priority to 0 to allow all
*(uint32*)(apic+APIC_TASKPRIOR)=0;
//set divider to 16
*(uint32*)(apic+APIC_TMRDIV)=0x03;
//map APIC timer to an interrupt enable it in periodic mode
*(uint32*)(apic+APIC_LVT_TMR)=32|TMR_PERIODIC;
//initialize intial count
*(uint32*)(apic+APIC_TMRINITCNT)=0x10000;
}
Please let me know if I am doing something wrong here. I am unable to figure out anything now.