OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Oct 22, 2018 8:03 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 15 posts ] 
Author Message
 Post subject: [Solved] Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 3:27 am 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
Hi, I have a problem because my interrupts doesn't works. I set IDT and then divide by 0 to get interrupt. Unfortunately it gets triple fault instead. I run my OS on bochs. It's 32 bits OS. I use Nasm inline assembly by adding -masm=intel while compilation.

Here are the source files:

_____________________kernel.c________________________
Code:
#include "kernel.h"

void _start(void)
{
   term = New_TerminalB8000();
   T_Clear(term);
   idt_init();
   
   int a = 5;
   int b = 0;
   T_Print(term, "%d", a/b);
      
   for(;;);
}

_____________________idt.h________________________
Code:
#pragma once
#include "common.h"
#include "int_handlers.h"
#include "terminal.h"
#include "kernel.h"

struct IDTEntry
{
   uint16_t offset_0_15; // offset bits 0..15
   uint16_t selector; // a code segment selector in GDT or LDT
   uint8_t zero;      // unused, set to 0
   uint8_t flags; // type and attributes, see below
   uint16_t offset_16_31; // offset bits 16..31
}__attribute__((packed));

struct IDTR
{
   uint16_t limit;
   uint32_t base;
}__attribute__((packed));

typedef struct IDTEntry IDTEntry;
typedef struct IDTR IDTR;


void idt_init();

_____________________idt.c________________________
Code:
#include "idt.h"

#define SETIDTDESCR(d, offset) { \
   d.offset_0_15 = ((uint32_t)offset & 0xffff); \
   d.selector = 0x8; \
   d.zero = 0; \
   d.flags = 0x8E; \
   d.offset_16_31 = (((uint32_t)offset >> 16) & 0xffff); \
}

IDTEntry IDT[256];

void idt_init()
{
   for(int i=0; i<=32; i++)
      SETIDTDESCR(IDT[i], interrupt_handler);
   
   IDTR ptr = {
      (uint16_t)((256 * 8 ) - 1),
      (uint32_t)&IDT
   };
   
   __asm("lidt [0]" : : "m"(ptr));
}

_____________________int_handlers.h________________________
Code:
#pragma once
#include "common.h"
#include "kernel.h"

void interrupt_handler();

_____________________int_handlers.c________________________
Code:
#include "int_handlers.h"

void interrupt_handler()
{
   T_Print(term, "Interrupt");
   for(;;);
}


Please help me!


Last edited by Matt1223 on Wed Aug 01, 2018 2:42 am, edited 5 times in total.

Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 3:58 am 
Offline
Member
Member

Joined: Wed Jul 25, 2018 2:47 pm
Posts: 36
Location: Pizzaland, Southern Europe
You can use [ code ] tags to show your source listings so they are nicer to read. That being said, have you read this? You can't simply use a standard C function as an ISR, it does not have the correct cleanup/return procedure.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 4:01 am 
Offline

Joined: Sun Nov 23, 2008 5:56 am
Posts: 13
Location: Russia, Saint-Petersburg
Shouldn't
Code:
__asm("lidt [0]" : : "m"(ptr));
be
Code:
__asm("lidt [%0]" : : "m"(ptr));
instead?

Also, what error does Bochs print?


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 8:19 am 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
frabert wrote:
You can use [ code ] tags to show your source listings so they are nicer to read. That being said, have you read this? You can't simply use a standard C function as an ISR, it does not have the correct cleanup/return procedure.


Thanks for the tip with [ code ] :D !
I know that I can't use standard C function as an ISR, this is temporarily solution. I want to make IDT working and then I will make proper ISR.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 8:26 am 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
quirck wrote:
Shouldn't
Code:
__asm("lidt [0]" : : "m"(ptr));
be
Code:
__asm("lidt [%0]" : : "m"(ptr));
instead?

Also, what error does Bochs print?


Code:
__asm("lidt [%0]" : : "m"(ptr));
It doesn't work, while compiling I get this message:

C:\Users\Admin\AppData\Local\Temp\ccQPDoTR.s: Assembler messages:
C:\Users\Admin\AppData\Local\Temp\ccQPDoTR.s:44: Error: unsupported instruction `lidt'

Bochs doesn't show any message, it's just reseting. It's called Triple Fault. By the way, I use Nasm assembly by adding -masm=intel while compilation.


Last edited by Matt1223 on Mon Jul 30, 2018 10:15 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 8:50 am 
Offline
Member
Member

Joined: Wed Jul 25, 2018 2:47 pm
Posts: 36
Location: Pizzaland, Southern Europe
Add reset_on_triple_fault=0 to your cpu configuration in Bochs to keep it running after a triple fault. Also, run Bochs via a terminal so you can see its output.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 9:01 am 
Offline

Joined: Sun Nov 23, 2008 5:56 am
Posts: 13
Location: Russia, Saint-Petersburg
Matt1223 wrote:
Code:
__asm("lidt [0]" : : "m"(ptr));
It doesn't work, while compiling I get this message:

C:\Users\Admin\AppData\Local\Temp\ccQPDoTR.s: Assembler messages:
C:\Users\Admin\AppData\Local\Temp\ccQPDoTR.s:44: Error: unsupported instruction `lidt'


Hm, it's tricky to get gcc to work with lidt using intel syntax. I can't get rid of "QWORD PTR" in assembly, and lidt QWORD PTR ... is obviously wrong, hence the error.

Using AT&T syntax, it's
Code:
__asm("lidt %0" : : "m"(ptr));


With intel syntax, I managed to get the right output only using a register:
Code:
__asm("lidt [%0]" : : "r"(&ptr));


Anyway, "lidt [0]" tries to load the idtr from address 0, and ptr is not used at all.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 9:53 am 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
frabert wrote:
Add reset_on_triple_fault=0 to your cpu configuration in Bochs to keep it running after a triple fault. Also, run Bochs via a terminal so you can see its output.


I set it and it gives this message:
"exception(): 3rd (13) exception with no resolution"

There is nothing printed in terminal.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 9:58 am 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
quirck wrote:
Matt1223 wrote:
Code:
__asm("lidt [0]" : : "m"(ptr));
It doesn't work, while compiling I get this message:

C:\Users\Admin\AppData\Local\Temp\ccQPDoTR.s: Assembler messages:
C:\Users\Admin\AppData\Local\Temp\ccQPDoTR.s:44: Error: unsupported instruction `lidt'


Hm, it's tricky to get gcc to work with lidt using intel syntax. I can't get rid of "QWORD PTR" in assembly, and lidt QWORD PTR ... is obviously wrong, hence the error.

Using AT&T syntax, it's
Code:
__asm("lidt %0" : : "m"(ptr));


With intel syntax, I managed to get the right output only using a register:
Code:
__asm("lidt [%0]" : : "r"(&ptr));


Anyway, "lidt [0]" tries to load the idtr from address 0, and ptr is not used at all.


You're right. I check it in IDA and it was reffering to 0. I changed it to:
Code:
__asm("lidt [%0]" : : "r"(&ptr));
but it still doesn't work. From what I see in IDA it should. It's really weird!
IDA shows that:
mov eax, offset unk_402000
lidt fword ptr [eax]


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 10:27 am 
Offline

Joined: Sun Nov 23, 2008 5:56 am
Posts: 13
Location: Russia, Saint-Petersburg
Matt1223 wrote:
frabert wrote:
Add reset_on_triple_fault=0 to your cpu configuration in Bochs to keep it running after a triple fault. Also, run Bochs via a terminal so you can see its output.


I set it and it gives this message:
"exception(): 3rd (13) exception with no resolution"

There is nothing printed in terminal.


What is in bochs log? If you configured it, of course:
Code:
log: bochsout.txt


One more question: is the code loaded at the address it expects? For example, does this work?
Code:
asm volatile ( "call %0" : : "r"(interrupt_handler) );


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 10:48 am 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
quirck wrote:
Matt1223 wrote:
frabert wrote:
Add reset_on_triple_fault=0 to your cpu configuration in Bochs to keep it running after a triple fault. Also, run Bochs via a terminal so you can see its output.


I set it and it gives this message:
"exception(): 3rd (13) exception with no resolution"

There is nothing printed in terminal.


What is in bochs log? If you configured it, of course:
Code:
log: bochsout.txt


One more question: is the code loaded at the address it expects? For example, does this work?
Code:
asm volatile ( "call %0" : : "r"(interrupt_handler) );


It's really huge file so I can't send all of it. Tell me which part should I send.

Code:
asm volatile ( "call %0" : : "r"(interrupt_handler) );

This code works.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 10:54 am 
Offline

Joined: Sun Nov 23, 2008 5:56 am
Posts: 13
Location: Russia, Saint-Petersburg
Well, the lines around "3rd (13) exception with no resolution" :)
There should be the register dump, and usually there is some indication of what went wrong before it.

Take a look at this post for example.


One more idea: try using pack pragmas around structure definitions like:
Code:
#pragma pack(push,1)
struct IDTR
{
   uint16_t limit;
   uint32_t base;
};
#pragma pack(pop)
In other words, verify that their sizes are correct. GCC I'm using ignored the __attribute__((packed)) and padded the base field.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 12:06 pm 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
quirck wrote:
Well, the lines around "3rd (13) exception with no resolution" :)
There should be the register dump, and usually there is some indication of what went wrong before it.

Take a look at this post for example.


One more idea: try using pack pragmas around structure definitions like:
Code:
#pragma pack(push,1)
struct IDTR
{
   uint16_t limit;
   uint32_t base;
};
#pragma pack(pop)
In other words, verify that their sizes are correct. GCC I'm using ignored the __attribute__((packed)) and padded the base field.


Thank you very much! :D These pragmas worked! Do you have any idea why this attribute was ignored?
Anyway can I reward you somehow on this forum?


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 12:16 pm 
Offline

Joined: Sun Nov 23, 2008 5:56 am
Posts: 13
Location: Russia, Saint-Petersburg
As an alternative to the pragma, -mno-ms-bitfields switch can be used to make __attribute__((packed)) behave as expected. GCC documentation says it is done for windows compatibility.


Top
 Profile  
 
 Post subject: Re: Interrupt descriptor table problem
PostPosted: Mon Jul 30, 2018 12:20 pm 
Offline

Joined: Mon Jul 30, 2018 2:58 am
Posts: 8
quirck wrote:
As an alternative to the pragma, -mno-ms-bitfields switch can be used to make __attribute__((packed)) behave as expected. GCC documentation says it is done for windows compatibility.


Ok, thanks a lot! :D


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 14 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