APIC timer not working

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,
 
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)
 
- 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.
 
- 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;
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;
  
}
 
 
Code for checking if APIC is present:
 
//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;
}
 
 
 
Code for checking if APIC is enabled and for getting APIC 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 APIC Base address
  print_str("\n APIC BASE ADDRESS IS ");
  print_hex(apic_base);
}
 
- Thanks
Vaibhav Jain
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux