problem with filling IDT

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
alek
Posts: 5
Joined: Sat Dec 05, 2009 4:58 pm

problem with filling IDT

Post 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
User avatar
djsilence
Member
Member
Posts: 70
Joined: Wed Oct 01, 2008 11:18 am
Location: Ukraine, Kiev
Contact:

Re: problem with filling IDT

Post 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?
Don't think a ****, but in ukrainian schools English is TOO BAD!
User avatar
djsilence
Member
Member
Posts: 70
Joined: Wed Oct 01, 2008 11:18 am
Location: Ukraine, Kiev
Contact:

Re: problem with filling IDT

Post by djsilence »

And if I can see in original code of that OS there is that:

uint64_t uiBase = (uint64_t)&(*irq);
Don't think a ****, but in ukrainian schools English is TOO BAD!
alek
Posts: 5
Joined: Sat Dec 05, 2009 4:58 pm

Re: problem with filling IDT

Post 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.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: problem with filling IDT

Post 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.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: problem with filling IDT

Post 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.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Andr3w
Member
Member
Posts: 76
Joined: Tue Jun 09, 2009 4:09 am
Location: Somewhere

Re: problem with filling IDT

Post 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
alek
Posts: 5
Joined: Sat Dec 05, 2009 4:58 pm

Re: problem with filling IDT

Post 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?
Wolf9466
Posts: 12
Joined: Sun Jun 28, 2009 11:17 pm

Re: problem with filling IDT

Post 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.
User avatar
djsilence
Member
Member
Posts: 70
Joined: Wed Oct 01, 2008 11:18 am
Location: Ukraine, Kiev
Contact:

Re: problem with filling IDT

Post 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.
Don't think a ****, but in ukrainian schools English is TOO BAD!
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: problem with filling IDT

Post 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).
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply