OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 1:13 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Can't get IDT working :/
PostPosted: Sun Oct 31, 2021 10:32 am 
Offline
Member
Member

Joined: Sat Oct 23, 2021 5:36 am
Posts: 26
I tried setting up a long mode IDT without much success (constant triple faulting). I can't figure out what's wrong..

Code:
struct idt_entry;

struct idt_desc {
   word_t            Size;
   struct idt_entry *Entries;
} __packed;

struct idt_entry {
   word_t  Offset0;
   word_t  Selector;
   byte_t  Ist;
   byte_t  TypeAttr;
   word_t  Offset1;
   dword_t Offset2;
   dword_t Zero;
} __packed;


Code:
static struct idt_desc Idt = {0};
static struct idt_entry IdtEntries[0x10] = {0};

void
SetupIDT(void) {
   InterruptDisable(); //cli

   Idt.Size = sizeof(IdtEntries) - 1;
   Idt.Entries = IdtEntries;
   for(int i = 0; i < 0x10; ++i) {
      const qword_t Offset = (qword_t)InterruptHandler;
      IdtEntries[i].Offset0 = (word_t)(Offset & 0xffff);
      IdtEntries[i].Offset1 = (word_t)((Offset >> 16) & 0xffff);
      IdtEntries[i].Offset2 = (dword_t)((Offset >> 32) & 0xffffffff);
      IdtEntries[i].Ist = 0;
      IdtEntries[i].Zero = 0;
      IdtEntries[i].Selector = 8;
      IdtEntries[i].TypeAttr = 0b10001000;
   }
   LoadInterruptTable(&Idt); //lidt [rdi]
   InterruptEnable(); //"sti"

}


Code:
InterruptHandler:
   iretq


Top
 Profile  
 
 Post subject: Re: Can't get IDT working :/
PostPosted: Sun Oct 31, 2021 12:41 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
Well, this simply can't work. For one, you are initializing only the first sixteen entries. That is not even enough to cover the exception range. For two, you make no distinction between exceptions with and without error code (you cannot simply iret from exceptions with error code, you have to remove the error code first). And finally, you enable interrupts not having initialized any interrupt controllers. So what is going to happen? Very quickly some sort of timer interrupt will fire on some unknown vector that is likely beyond the size of the IDT. This will invoke the double fault interrupt, which luckily you have, but you immediately iret from it. Leaving aside that there is probably an error code (not quite sure on that off the cuff), the processor manual states that you cannot trust the RIP portion of the interrupt frame to point to anything sensible for a double fault (since DF is an Abort type exception). If you look at, say, Linux, you will see that it handles double fault by testing for one known case where they can happen (but then the RIP can be set to something well known), and in all other cases, they will just panic.

So, putting it all together: You must initialize all 256 IDT entries to something slightly more comprehensive that "iret", and you must not "sti" until you have discovered and initialized all interrupt controllers, because otherwise you will not know what an interrupt means.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Can't get IDT working :/
PostPosted: Sun Oct 31, 2021 1:14 pm 
Offline
Member
Member

Joined: Sat Oct 23, 2021 5:36 am
Posts: 26
nullplan wrote:
Well, this simply can't work. For one, you are initializing only the first sixteen entries. That is not even enough to cover the exception range. For two, you make no distinction between exceptions with and without error code (you cannot simply iret from exceptions with error code, you have to remove the error code first). And finally, you enable interrupts not having initialized any interrupt controllers. So what is going to happen? Very quickly some sort of timer interrupt will fire on some unknown vector that is likely beyond the size of the IDT. This will invoke the double fault interrupt, which luckily you have, but you immediately iret from it. Leaving aside that there is probably an error code (not quite sure on that off the cuff), the processor manual states that you cannot trust the RIP portion of the interrupt frame to point to anything sensible for a double fault (since DF is an Abort type exception). If you look at, say, Linux, you will see that it handles double fault by testing for one known case where they can happen (but then the RIP can be set to something well known), and in all other cases, they will just panic.

So, putting it all together: You must initialize all 256 IDT entries to something slightly more comprehensive that "iret", and you must not "sti" until you have discovered and initialized all interrupt controllers, because otherwise you will not know what an interrupt means.


For testing purposes, can I not use "sti", but invoke #PF via accessing an address outside of range I've previously mapped (first 1MB)?
Also, should I change idt_entry#TypeAttr field per entry, does it ever differ (I wasn't really sure what to set it to and I figured out this value might be appropriate looking at other people's reference code)?

And finally, how big is the error code? - Found the answer myself.

Sorry if I'm asking trivial questions. I just found the interrupt tutorial very confusing in many ways. :|

Thanks :D


Top
 Profile  
 
 Post subject: Re: Can't get IDT working :/
PostPosted: Sun Oct 31, 2021 1:59 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
angods wrote:
Also, should I change idt_entry#TypeAttr field per entry, does it ever differ (I wasn't really sure what to set it to and I figured out this value might be appropriate looking at other people's reference code)?

You may set it to either an interrupt gate or a trap gate. The only difference between the two is that interrupt gates guarantee interrupts are disabled when the handler is called. If you're not sure, just use interrupt gates for now. You can always go back and change it later. (Where exactly did you see someone using 0x88? That's not a valid descriptor type.)


Top
 Profile  
 
 Post subject: Re: Can't get IDT working :/
PostPosted: Sun Oct 31, 2021 2:58 pm 
Offline
Member
Member

Joined: Sat Oct 23, 2021 5:36 am
Posts: 26
Octocontrabass wrote:
angods wrote:
Also, should I change idt_entry#TypeAttr field per entry, does it ever differ (I wasn't really sure what to set it to and I figured out this value might be appropriate looking at other people's reference code)?

You may set it to either an interrupt gate or a trap gate. The only difference between the two is that interrupt gates guarantee interrupts are disabled when the handler is called. If you're not sure, just use interrupt gates for now. You can always go back and change it later. (Where exactly did you see someone using 0x88? That's not a valid descriptor type.)


I can't remember where I saw someone using it, but I was just experimenting.. I forgot to change it to 'normal' (0x8e) before sending the code.


Last edited by angods on Sun Oct 31, 2021 3:39 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Can't get IDT working :/
PostPosted: Sun Oct 31, 2021 3:35 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
angods wrote:
Do I miss something?

In 64-bit mode, everything pushed to the stack is padded to 64 bits (8 bytes).


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 63 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group