Page 1 of 1
[Solved] Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 3:27 am
by Matt1223
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: Select all
#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: Select all
#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: Select all
#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: Select all
#pragma once
#include "common.h"
#include "kernel.h"
void interrupt_handler();
_____________________int_handlers.c________________________
Code: Select all
#include "int_handlers.h"
void interrupt_handler()
{
T_Print(term, "Interrupt");
for(;;);
}
Please help me!
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 3:58 am
by frabert
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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 4:01 am
by quirck
Shouldn't
be
instead?
Also, what error does Bochs print?
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 8:19 am
by Matt1223
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 ]
!
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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 8:26 am
by Matt1223
quirck wrote:Shouldn't
be
instead?
Also, what error does Bochs print?
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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 8:50 am
by frabert
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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 9:01 am
by quirck
Matt1223 wrote: 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
With intel syntax, I managed to get the right output only using a register:
Anyway, "lidt [0]" tries to load the idtr from address 0, and ptr is not used at all.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 9:53 am
by Matt1223
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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 9:58 am
by Matt1223
quirck wrote:Matt1223 wrote: 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
With intel syntax, I managed to get the right output only using a register:
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:
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]
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 10:27 am
by quirck
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:
One more question: is the code loaded at the address it expects? For example, does this work?
Code: Select all
asm volatile ( "call %0" : : "r"(interrupt_handler) );
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 10:48 am
by Matt1223
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:
One more question: is the code loaded at the address it expects? For example, does this work?
Code: Select all
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: Select all
asm volatile ( "call %0" : : "r"(interrupt_handler) );
This code works.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 10:54 am
by quirck
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: Select all
#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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 12:06 pm
by Matt1223
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: Select all
#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!
These pragmas worked! Do you have any idea why this attribute was ignored?
Anyway can I reward you somehow on this forum?
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 12:16 pm
by quirck
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.
Re: Interrupt descriptor table problem
Posted: Mon Jul 30, 2018 12:20 pm
by Matt1223
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!