APIC timer not working

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
vjain20
Member
Member
Posts: 73
Joined: Wed Apr 04, 2012 9:12 pm

APIC timer not working

Post by vjain20 »

Hi,

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);
}

- 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( 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;
 	
}
However still the timer interrupt is not getting generated and 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 here. I am unable to figure out anything now.
- Thanks
Vaibhav jain
User avatar
turdus
Member
Member
Posts: 496
Joined: Tue Feb 08, 2011 1:58 pm

Re: APIC timer not working

Post by turdus »

If I don't remap the IRQs I sometimes get a double fault.
I assume it's because of spurios interrupt. If you don't remap irqs, an exception handler will be called, which is not good.
I haven't mapped it to a physical page( even when I map it to a page it makes no difference).
You have to map it, since it's a physical address, and you're referring to a linear. It can be identical map, but must be mapped.

Code: Select all

uint32 apic = 0xFEE00000;
This should be a linear address where you've mapped the physical frame returned by rdmsr in checkAPICStatus.

Finally, you seem to forget to enable LAPIC in apic_timer_init (or at least you haven't posted the code for that). Read wiki carefully:
Enabling APIC Timer

* First you have to enable the Local APIC hardware by writing it's MSR.
* After that, you have to specify a spurious interrupt and software enable the APIC (this step is necessary).
* Finally, you specify APIC timer interrupt number and operation mode.
You can read how to enable LAPIC here: http://wiki.osdev.org/Apic

Good luck!
vjain20
Member
Member
Posts: 73
Joined: Wed Apr 04, 2012 9:12 pm

Re: APIC timer not working

Post by vjain20 »

@turdus : I can't thank you enough!!
Finally got it working! I was mistaken in thinking that 0xFEE00000 is the linear address.
I did not code for enabling the APIC because a comment in the wiki says that it is should be
enabled by writing to MSR if it is not already enabled. I checked that it is automatically enabled. So I was just writing to the Spurious interrupt register and not to the MSR global enable bit. So just by mapping to the correct physical address I got it to work. Thanks a lot!!
- Thanks
Vaibhav jain
User avatar
turdus
Member
Member
Posts: 496
Joined: Tue Feb 08, 2011 1:58 pm

Re: APIC timer not working

Post by turdus »

Not at all. Good luck for the rest!
Post Reply