Page 1 of 1

Another IRQ Question... WITH CODE!

Posted: Wed Jan 08, 2003 2:55 pm
by Simrook
I've been lurking here for the past week reading this and that, and i have my own IRQ question now.. I've read lots of different material, and am getting to understand what I'm doing (I think). I followed and implemented many thigns that have been discussed on the five page thread a while ago about setting up the IDT. Here's my code, and it doesn't work. I get a "3rd (13) exception with no resolution" error in bochs (v 2.0).

I also boot from Grub, and have had no problems with it really. Everything is complied in gcc, and i can post the linker script/makefile if requested.

There is probably some really dumb mistake in here that someone will be able to tell me right away, but alas... my code:

void create_idt( unsigned long num, void (*handler)(void) );
void init_idt( void );
void keyboard_handler( void );
void default_func( void );

typedef struct {
unsigned short offset_low;
unsigned short selector;
unsigned char param_count;
unsigned char access;
unsigned short offset_high;
} __attribute__ ((packed)) idt_entry;

typedef struct {
unsigned short size;
unsigned long base;
} __attribute__ ((packed)) gate;

gate idtr;
idt_entry IDT[256];

void KernelMain( void ) {
char *prompt;

__clear_screen();
printf( "Adam's OS\n" );
printf( "version 0.01b\t\t\tBuild 1100\n" );
printf( "Jan 03 Development\n" );
printf( "Initlizing \"kernel\" services...\n" );
printf( "Disabling interrupts...\n" );
cli();

init_idt();

while(1) {
/*printf( "] " );
prompt = getline();
printf( "\n" );

if( strcmp( prompt, "exit" ) == 0 ) {
printf( "We cannot reboot right now, sorry!\n" );
*/
}
}

void create_idt( unsigned long num, void (*handler)(void) ) {
idt_entry *idt_temp;

idt_temp = (idt_entry *)(idtr.base + (num *8));
idt_temp->offset_low = (unsigned short) (((unsigned long)handler & 0xFFFF));
idt_temp->selector = (unsigned short)0x10;
idt_temp->access = (unsigned char) 0x8E;
idt_temp->param_count = (unsigned char)0;
idt_temp->offset_high = (unsigned short)(((unsigned long)handler >> 16));

}

void init_idt( void ) {
int n;

idtr.size = 256*8-1;
idtr.base = 0x00001000;

printf( "Creating IDT's...\n" );
for( n = 0; n < 256; n++ ) {
create_idt(n, &default_func);
}

printf( "Creating keyboard IDT...\n" );
create_idt(32, &keyboard_handler);

printf( "LIDT idtr\n" );
asm volatile ( "LIDT idtr");
printf( "STI" );
asm( "STI" );
printf( "init_idt() complete.\n" );
}

void default_func( void ) {
//_printc( "x" );
asm( "popl %eax" );
asm( "popl %eax" );
asm( "cli" );
asm( "hlt" );
}

void keyboard_handler( void ) {
printf( "key\n" );
outportb( 0x20, 0x20 );
asm( "MOV %ebp, %esp" );
asm( "POP %ebp" );
asm( "IRET" );
}

------------
There's a lot more in the kernel of course, printf and getline, etc... but none of that should matter.

Oh, and the tripple fault happens when I "STI". The message "init_idt complete." never appears.

Thanks for your help!

- Simrook

Re:Another IRQ Question... WITH CODE!

Posted: Wed Jan 08, 2003 3:58 pm
by Curufir
Well my C knowledge is quite...actually let's be honest and say extremely...limited. 2 things I noticed though.

How can you be sure that the IDT base is actually 0x1000 linear? I see where you set up the structure, but are you sure it's doing what you think it is. Guess one of the C gurus, or you, could answer that in a microsecond.

Have you remapped the PICS? If so have you unmasked IRQ0? Because not handling the timer interrupt properly might explain why the error occurs immediately after STI.

Aside from that it's the standard questions of is your GDT setup right, are you trashing the stack etc.

One of the C gurus will be able to give better advice on the actual code, I just wanted to mention the IRQ0 thing because that's what the STI followed by triple fault error felt like (At least I've done that myself in the past :-[).

Re:Another IRQ Question... WITH CODE!

Posted: Wed Jan 08, 2003 4:20 pm
by whyme_t

Code: Select all

00000020 <_keyboard_handler>:
  20:???55                   ???push   %ebp
  21:???89 e5                ???mov    %esp,%ebp
  23:???83 ec 08             ???sub    $0x8,%esp
  26:???83 ec 0c             ???sub    $0xc,%esp
  29:???68 1b 00 00 00       ???push   $0x1b
  2e:???e8 e3 ff ff ff       ???call   16 <_printf>
  33:???83 c4 10             ???add    $0x10,%esp
  36:???83 ec 08             ???sub    $0x8,%esp
  39:???6a 20                ???push   $0x20
  3b:???6a 20                ???push   $0x20
  3d:???e8 be ff ff ff       ???call   0 <_outportb>
  42:???83 c4 10             ???add    $0x10,%esp
  45:???89 ec                ???mov    %ebp,%esp
  47:???5d                   ???pop    %ebp
  48:???cf                   ???iret
  49:???c9                   ???leave  
  4a:???c3                   ???ret    
I'm no guru :) but i'll try to help. This is your code disassembled. Note that ebp was pushed onto the stack at the start, and is not popped back off at the end of your function, resulting in unexpected results. When you iret, the code the compiler adds to take care of this is not reached (49: leave), so ebp is not popped. Although you could inline leave before you iret I strongly recommend you write asm wrapper functions for your ISR's which take care of the nitty gritty details of interrupt handlers (dropping error codes, restoring registers, etc).

EDIT - shouldn't your idtr.base = (unsigned long int) IDT ;

Re:Another IRQ Question... WITH CODE!

Posted: Wed Jan 08, 2003 8:25 pm
by Simrook
Well, I have implemented a wrapper handler in asm, and have remapped the PIC.

I'm still getting a tripple fault however. I've figured out now that Bochs has a nice little debugger built into it, and have found that it is not faulting on the STI asm routine. Here is what the code is being executed to execute STI in a c function enable_sti:

push ebp
mov ebp, esp
sti
leave
ret_near

Thanks to Bochs, i've figured out that it is 3xFaulting on the execution of ret_near.

The question now is, why? Do I need to add something to my compile command line perhaps? If so, what?

In responce to curufir, I tell the complier to put the IDT structures at 0xWhatever. I'm pretty sure that I've unmasked IRQ0, and being now that I'm sure the 3xFault does not occure right after the STI, I'm more confident I have. I lifted the code for my pic remapping from the FAQ. And hopefully Grub did setup the GDT right.

Thanks for your help so far... any idea nows?

- Simrook

Re:Another IRQ Question... WITH CODE!

Posted: Thu Jan 09, 2003 3:42 am
by Pype.Clicker
* you must exit your interrupt/exception handler using IRET, not ret_near ...
* you must pusha/popa registers (and possibly do the same with segment registers) around your ISR. If you don't do it, your "normal" code may see its registers changing randomly and it will surely crash as soon as pointers will be involved.

Re:Another IRQ Question... WITH CODE!

Posted: Thu Jan 09, 2003 12:08 pm
by jrfritz
yea...pype is right...I had to do the same...