PIT on EFI

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
SanderR
Member
Member
Posts: 70
Joined: Tue Aug 30, 2016 1:31 pm
Libera.chat IRC: SDR

PIT on EFI

Post by SanderR »

Hello everyone,

I test me operating system on 4 devices, where 3 of them have EFI and on two virtual machines: QEMU and VBox
I have two methods for loading the operating system: via EFI and via Grub2.

If I boot the operatingsystem via Grub2, the PIT does send interrupts but if I boot the operating system via EFI the interrupt is not fired.

This is how I initialise the interrupts:

Code: Select all

void initialise_interrupts(){
  uint8_t oldpic1 = inportb(PIC1_DATA);
  uint8_t oldpic2 = inportb(PIC2_DATA);
  outportb(PIC1, 0x11);
  outportb(PIC2, 0x11);
  outportb(PIC1_DATA, PIC_OFFSET);
  outportb(PIC2_DATA, PIC_OFFSET + 8);
  outportb(PIC1_DATA, ICW1_INTERVAL4);
  outportb(PIC2_DATA, ICW1_SINGLE);
  outportb(PIC1_DATA, ICW1_ICW4);
  outportb(PIC2_DATA, ICW1_ICW4);
  outportb(PIC1_DATA, 0x0);
  outportb(PIC2_DATA, 0x0);
  outportb(PIC1_DATA,oldpic1);
  outportb(PIC2_DATA,oldpic2);

  idtr.Offset = (uintptr_t)&idt[0];
  idtr.Limit = (uint16_t)sizeof(IDTDescEntry) * IDT_MAX_DESCRIPTORS - 1;

  IDTDescEntry *idtentries = (IDTDescEntry*) idtr.Offset;
  for(uint16_t i = 0 ; i < idtr.Limit ; i++){
      setRawInterrupt(i,NakedInterruptHandler);
  }
  for(uint16_t i = 0 ; i < PIC_OFFSET ; i++){
      setRawInterrupt(i,GeneralFault_Handler);
  }
  asm volatile ("lidt %0" : : "m"(idtr));
  asm volatile ("sti");
}
These are the setInterrupt functions:

Code: Select all

void interrupt_set_offset(IDTDescEntry* int_PageFault,uint64_t offset){
  int_PageFault->offset0 = (uint16_t)(offset & 0x000000000000ffff);
  int_PageFault->offset1 = (uint16_t)((offset & 0x00000000ffff0000) >> 16);
  int_PageFault->offset2 = (uint32_t)((offset & 0xffffffff00000000) >> 32);
}

void setInterrupt(int offset,void *fun){
  IDTDescEntry* int_PageFault = (IDTDescEntry*)(idtr.Offset + ((offset+PIC_OFFSET) * sizeof(IDTDescEntry)));
  interrupt_set_offset(int_PageFault,(uint64_t)fun);
  int_PageFault->type_attr = IDT_TA_InterruptGate;
  int_PageFault->selector = GDT_CODE_SEGMENT;
  IRQ_clear_mask(offset + PIC_OFFSET);
}

void setRawInterrupt(int offset,void *fun){
  IDTDescEntry* int_PageFault = (IDTDescEntry*)(idtr.Offset + ((offset) * sizeof(IDTDescEntry)));
  interrupt_set_offset(int_PageFault,(uint64_t)fun);
  int_PageFault->type_attr = IDT_TA_TrapGate;
  int_PageFault->selector = GDT_CODE_SEGMENT;
}
And this is the initialisation function for the PIT:

Code: Select all

void initialise_timer(){
  int divisor = 1193180 / 100;       /* Calculate our divisor */
	outportb(0x43, 0x36);             /* Set our command byte 0x36 */
	outportb(0x40, divisor & 0xFF);   /* Set low byte of divisor */
	outportb(0x40, divisor >> 8);     /* Set high byte of divisor */
  setInterrupt (0, timer_int);
  outportb(0xA0,0x20);
	outportb(0x20,0x20);
}
Can someone point me in the right direction please?
Octocontrabass
Member
Member
Posts: 5487
Joined: Mon Mar 25, 2013 7:01 pm

Re: PIT on EFI

Post by Octocontrabass »

SanderR wrote: Sat Sep 28, 2024 8:55 am

Code: Select all

  outportb(PIC1_DATA, 0x0);
  outportb(PIC2_DATA, 0x0);
  outportb(PIC1_DATA,oldpic1);
  outportb(PIC2_DATA,oldpic2);
Clearing the mask register is a bad idea when you don't know which interrupts might arrive. Restoring the previous value of the mask register is also a bad idea when you don't know which interrupts might arrive. You should probably mask every interrupt line (except the cascade "IRQ2" line).
SanderR wrote: Sat Sep 28, 2024 8:55 am

Code: Select all

  for(uint16_t i = 0 ; i < idtr.Limit ; i++){
It looks like you're corrupting a bunch of memory here.
SanderR wrote: Sat Sep 28, 2024 8:55 am

Code: Select all

void interrupt_set_offset(IDTDescEntry* int_PageFault,uint64_t offset){
Why is it called "PageFault"?
SanderR wrote: Sat Sep 28, 2024 8:55 am

Code: Select all

  IRQ_clear_mask(offset + PIC_OFFSET);
Does this actually clear the correct mask bit?
SanderR wrote: Sat Sep 28, 2024 8:55 am

Code: Select all

  outportb(0xA0,0x20);
	outportb(0x20,0x20);
Why are you sending two EOIs in your timer initialization code?
Post Reply