Page 1 of 1
problem with filling IDT
Posted: Sun Dec 13, 2009 2:42 pm
by alek
hi,
i am trying to fill IDT. Firstly I created c function to fill interrupt descriptor (based on brokenthorn.com tutorial)
Code: Select all
int i86_install_ir( uint32_t i, uint16_t flags, uint16_t selector, void (*irq)(void) )
{
uint32_t uiBase = (uint32_t)irq;
_idt[i].baseLo = (uint16_t)uiBase & 0xFFFF;
_idt[i].baseHi = (uint16_t) (uiBase >> 16) & 0xFFFF;
_idt[i].reserved = 0;
_idt[i].flags = (uint8_t)flags;
_idt[i].selector = selector;
return 0;
}
but it triple fault. So I made asembler code:
Code: Select all
GLOBAL idete
idete:
PUSH ebp
MOV ebp,esp ; making stack frame
PUSHA ; push all registers to the stack
MOV ecx,260 ; numer of loops (i did 4 more to be sure ;) )
MOV eax,[ebp+8] ; pointer to the array
petla:
MOV ebx,_idt_halt_handler ; pointer to the interrupt handler
MOV [eax],bx ; offset 0-15 of the base
ADD eax,2
MOV word [eax],0x8 ; segment selector (0x8 for code, ring0, 4gb)
ADD eax,2
MOV byte [eax],0x0 ; reserved, should be 0
ADD eax,1
MOV byte [eax],0x8E ; 10001110 interrupt, 32bit, ring 0, present
ADD eax,1
SHR ebx,16 ; get offset 16-31 of the base...
MOV [eax],bx ; ... and put it
ADD ebx,2
LOOP petla
POPA ; popping all registers
POP ebp ; deleting stack frame
RET
_idt_halt_handler:
HLT
IRET
c code:
Code: Select all
int i86_idt_initialize( uint16_t codeSel )
{
int i=0;
_idtr.base = (uint32_t)&_idt;
_idtr.limit = sizeof( struct idt_descriptor) * I86_MAX_INTERRUPTS - 1;
memoryset( (void*)&_idt[0], 0, sizeof( struct idt_descriptor)*I86_MAX_INTERRUPTS );
idete(&_idt[0]);
/*for( i=0; i<I86_MAX_INTERRUPTS;++i )
{
i86_install_ir( i, I86_IDT_DESC_PRESENT | I86_IDT_DESC_BIT32, codeSel, i86_halt_handler );
}*/
__asm__ __volatile__ ( "LIDT _idtr\n\t");
}
It triple fault when I try to call interrupt. It seems that it jumps to the wrong location in the memory but im not sure.
All of the code
Re: problem with filling IDT
Posted: Sun Dec 13, 2009 3:20 pm
by djsilence
I gues your error is there:
_idt.baseHi = (uint16_t) (uiBase >> 16) & 0xFFFF;
Maybe
_idt.baseHi = uint16_t((uiBase >> 16) & 0xffff);
will be better?
Re: problem with filling IDT
Posted: Sun Dec 13, 2009 3:22 pm
by djsilence
And if I can see in original code of that OS there is that:
uint64_t uiBase = (uint64_t)&(*irq);
Re: problem with filling IDT
Posted: Sun Dec 13, 2009 5:12 pm
by alek
ok, i even copied the orignal function and it looks like this:
Code: Select all
int i86_install_ir (uint32_t i, uint16_t flags, uint16_t sel, void (*irq)(void)) {
if (i>I86_MAX_INTERRUPTS)
return 0;
if (!irq)
return 0;
//! get base address of interrupt handler
uint64_t uiBase = (uint64_t)&(*irq);
//! store base address into idt
_idt[i].baseLo = uiBase & 0xffff;
_idt[i].baseHi = (uiBase >> 16) & 0xffff;
_idt[i].reserved = 0;
_idt[i].flags = flags;
_idt[i].selector = sel;
return 0;
}
int i86_idt_initialize( uint16_t codeSel )
{
int i=0;
_idtr.base = (uint32_t)&_idt;
_idtr.limit = sizeof( struct idt_descriptor) * I86_MAX_INTERRUPTS - 1;
memoryset( (void*)&_idt[0], 0, sizeof( struct idt_descriptor)*I86_MAX_INTERRUPTS );
//idete(&_idt[0]);
for( i=0; i<I86_MAX_INTERRUPTS;++i )
{
i86_install_ir( i, I86_IDT_DESC_PRESENT | I86_IDT_DESC_BIT32, codeSel, i86_halt_handler );
}
__asm__ __volatile__ ( "LIDT _idtr\n\t" "STI\n\t" "INT $0x21\n\t" );
}
void i86_halt_handler()
{
__asm__ __volatile__ ("HLT\n\t"
"LEAVE\n\t"
"IRET" );
}
fortunately it doesnt triple fault but doenst HALT too. Neither when I call the interrupt, nor because of the STI.
Re: problem with filling IDT
Posted: Sun Dec 13, 2009 9:32 pm
by neon
Hello,
1) Take the STI out. Dont use it until you remap the PIC.
2) Insure idt_descriptor and idtr structures are packed to 1 byte boundaries.
3) Be careful with using an IRQ handler as a C routine. This will not work on all compiliers without fixing the stack frame.
Please let us know if all 3 are good. I cannot tell with the code provided.
Re: problem with filling IDT
Posted: Mon Dec 14, 2009 2:50 am
by Combuster
neon wrote:3) Be careful with using an IRQ handler as a C routine. This will not work on all compiliers without fixing the stack frame.
3) Just don't use C routines for interrupt handlers. Even the one compiler that does support decent interrupt routines is unaware of various different stack formats, and your code will crash and burn when you try it with exceptions.
Re: problem with filling IDT
Posted: Mon Dec 14, 2009 7:06 am
by Andr3w
Hi,
Code: Select all
MOV ecx,260 ; numer of loops (i did 4 more to be sure ;) )
I don't think it's good to fill memory with 4 more IDT entries. You could corrupt something in memory.
So, I think that's enough to put 0xFF in
ecx.
-- Andrew
Re: problem with filling IDT
Posted: Mon Dec 14, 2009 7:10 pm
by alek
ok,
i discard filling the IDT in C, current procedure in asm:
Code: Select all
GLOBAL idete
idete:
PUSH ebp
MOV ebp,esp ; making stack frame
PUSHA ; push all registers to the stack
MOV ecx,0xFF ; numer of loops
MOV eax,[ebp+8] ; pointer to the array
petla:
MOV ebx,_idt_halt_handler ; pointer to the interrupt handler
MOV [eax],bl ; offset 0-15 of the base
INC eax
SHR ebx,8
MOV [eax],bl
INC eax
MOV word [eax],0x8 ; segment selector (0x8 for code, ring0, 4gb)
ADD eax,2
MOV byte [eax],0x0 ; reserved, should be 0
ADD eax,1
MOV byte [eax],0x8E ; 10001110 interrupt, 32bit, ring 0, present
INC eax
SHR ebx,8
MOV [eax],bl
INC eax
SHR ebx,8 ; get offset 16-31 of the base...
MOV [eax],bl ; ... and put it
INC eax
LOOP petla
POPA ; popping all registers
POP ebp ; deleting stack frame
RET
_idt_halt_handler:
PUSHA
MOV eax,0xB8000
MOV byte [eax],'X' ; write to the screen so I can see sth is happening
INC eax
MOV byte [eax],0x7
INC eax
MOV byte [eax],'X'
INC eax
MOV byte [eax],0x7
INC eax
MOV byte [eax],'X'
INC eax
MOV byte [eax],0x7
INC eax
MOV byte [eax],'X'
INC eax
MOV byte [eax],0x7
INC eax
POPA
IRETD
C code which calls this procedure:
Code: Select all
struct idt_descriptor
{
uint16_t baseLo;
uint16_t selector;
uint8_t reserved; // should be zero
uint8_t flags;
uint16_t baseHi;
};
struct idtr
{
uint16_t limit;
uint32_t base;
};
static struct idt_descriptor _idt[I86_MAX_INTERRUPTS];
static struct idtr _idtr;
extern void idete(struct idt_descriptor * a);
int i86_idt_initialize( uint16_t codeSel )
{
int i=0;
_idtr.base = (uint32_t)&_idt[0];
_idtr.limit = sizeof( struct idt_descriptor) * I86_MAX_INTERRUPTS - 1;
memoryset( (void*)&_idt[0], 0, sizeof( struct idt_descriptor)*I86_MAX_INTERRUPTS );
idete(&_idt[0]); // fill the table
__asm__ __volatile__ ( "LIDT _idtr\n\t" );
}
full code with colouring
ok, so when I boot this, nothing happens. but when I try to generate an interrupt:
__asm__ __volatile__ ( "INT $0x40\n\t" );
it crashes with triple fault. Seems I should use a debugger...
@neon i cant understand what do you mean in "Insure idt_descriptor and idtr structures are packed to 1 byte boundaries." (english is not my primary language
Can you please describe it?
Re: problem with filling IDT
Posted: Mon Dec 14, 2009 9:43 pm
by Wolf9466
Packed means that the compiler didn't add any extra filler to it, which almost always happens. Since you NEED it to be a certain size, in MSVC you can use #pragma pack(push, 1) at the beginning and #pragma pack(pop) at the end of whatever you want packed.
Re: problem with filling IDT
Posted: Mon Dec 14, 2009 10:34 pm
by djsilence
in MSVC you can use #pragma pack(push, 1) at the beginning and #pragma pack(pop) at the end of whatever you want packed.
If I remember MSVC doesn't add any extra byte. It is used just in GCC.
Re: problem with filling IDT
Posted: Tue Dec 15, 2009 12:10 am
by Combuster
djsilence wrote:If I remember MSVC doesn't add any extra byte. It is used just in GCC.
Wrong and wrong. MSVC does align members, and GCC doesn't use #pragma pack - it uses __attribute__(packed).