OSDev.org
https://forum.osdev.org/

[Solved] Interrupt descriptor table problem
https://forum.osdev.org/viewtopic.php?f=1&t=33091
Page 1 of 1

Author:  Matt1223 [ Mon Jul 30, 2018 3:27 am ]
Post subject:  [Solved] Interrupt descriptor table problem

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!

Author:  frabert [ Mon Jul 30, 2018 3:58 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  quirck [ Mon Jul 30, 2018 4:01 am ]
Post subject:  Re: Interrupt descriptor table problem

Shouldn't
Code:
__asm("lidt [0]" : : "m"(ptr));
be
Code:
__asm("lidt [%0]" : : "m"(ptr));
instead?

Also, what error does Bochs print?

Author:  Matt1223 [ Mon Jul 30, 2018 8:19 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  Matt1223 [ Mon Jul 30, 2018 8:26 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  frabert [ Mon Jul 30, 2018 8:50 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  quirck [ Mon Jul 30, 2018 9:01 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  Matt1223 [ Mon Jul 30, 2018 9:53 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  Matt1223 [ Mon Jul 30, 2018 9:58 am ]
Post subject:  Re: Interrupt descriptor table problem

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]

Author:  quirck [ Mon Jul 30, 2018 10:27 am ]
Post subject:  Re: Interrupt descriptor table problem

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

Author:  Matt1223 [ Mon Jul 30, 2018 10:48 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  quirck [ Mon Jul 30, 2018 10:54 am ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  Matt1223 [ Mon Jul 30, 2018 12:06 pm ]
Post subject:  Re: Interrupt descriptor table problem

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?

Author:  quirck [ Mon Jul 30, 2018 12:16 pm ]
Post subject:  Re: Interrupt descriptor table problem

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.

Author:  Matt1223 [ Mon Jul 30, 2018 12:20 pm ]
Post subject:  Re: Interrupt descriptor table problem

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

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/