- Subject: APIC timer not working
- From: Vaibhav Jain <vjoss197@xxxxxxxxx>
- Date: Sun, 24 Jun 2012 21:00:13 -0700
I am trying to write my own kernel but I am facing problems with timer interrupt.
I have been using PIC and PIT to generate timer interrupts and it has been working fine but now I want to switch to local APIC timer.
I am using bochs as emulator. I have made some changes but all in vain.
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 at the end)
- I have added code for disabling PIC. Now my code first remaps IRQs in PIC and then disables the PIC. If I don't remap the IRQs I sometimes get a double fault.
- 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. I have checked that the apic base address is correct by reading the APIC BASE MSR. (code at the end)
- Now I have reduced the code from the wiki to only a few lines (code below) but the interrupt is just not getting generated.
I checked bit 32 of the Interrupt Request register (0xFEE00390) and found it to be Set. But the interrupt handler is not getting called. The IDT and all the interrupt handlers are in place. If I switch back to the old code using PIC and PIT it works fine.
Please let me know if I am doing something wrong. I am unable to figure out anything.
Code for APIC timer :
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;
//software enable apic timer
//set DFR to flat mode
//set task priority to 0 to allow all
*(uint32*)(apic+APIC_TASKPRIOR) = 0;
//set divider to 16
//map APIC timer to an interrupt enable it in periodic mode
//initialize intial count
Code for checking if APIC is present:
//check if APIC is present using CPUID
uint32 eax , edx;
eax = 0x1;
uint32 CPU_FLAG_APIC = 0x200;
asm volatile("cpuid": "=d"(edx) :"a"(eax));
return edx & CPU_FLAG_APIC;
Code for checking if APIC is enabled and for getting APIC Base address :
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;
print_str("\nAPIC IS ENABLED!!");
print_str("\nAPIC IS DISABLED");
// Get APIC BASE address
uint32 apic_base = eax & APIC_BASE_FLAG;
// print APIC Base address
print_str("\n APIC BASE ADDRESS IS ");
Kernelnewbies mailing list
[Linux Kernel Development]