Crash with IDT Implementation

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
cmp
Posts: 14
Joined: Wed May 20, 2015 6:05 pm

Crash with IDT Implementation

Post by cmp »

Just starting with OS dev, but I have lots of previous experience with programming.
I've got a pretty basic kernel running thanks to the wiki, along with GDT. However now that I'm trying to implement the IDT, it isn't wanting to be friendly anymore.
I'm reusing code from James Molloy.

Here's what I've got with qemu:

Code: Select all

qemu: fatal: Trying to execute code outside RAM or ROM at 0x5e665b66

EAX=00006180 EBX=5b66ffff ECX=00000001 EDX=0a2b5d66
ESI=08c48366 EDI=00104fa8 EBP=00000014 ESP=000fffe8
EIP=5e665b66 EFL=00200087 [--S--PC] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00106020 00000027
IDT=     00106080 000007ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000050 CCD=ffffffb1 CCO=SUBL    
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
./qemu.sh: line 5: 14902 Aborted                 (core dumped) qemu-system-$(./target-triplet-to-arch.sh $HOST) -cdrom myos.iso
According to EIP, it happens when I pop ebx and esi...
I'm completely lost here. Not really sure how to debug something like this..

Here's the "isr common stub", it's probably the relevant code:

Code: Select all

  pusha             

   mov ax, ds              
   push eax              

   mov ax, 0x10  
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call isr_handler

   pop eax      
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   popa                    
   add esp, 8    
   sti
   iret         
I'd really appreciate any tips or help. Thanks a bunch guys.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Crash with IDT Implementation

Post by JAAman »

cmp wrote:

Code: Select all

qemu: fatal: Trying to execute code outside RAM or ROM at 0x5e665b66
According to EIP, it happens when I pop ebx and esi...
that message is saying that you are not executing memory at all... what are you using to determine that it is happening when you pop ebx/esi? because the address that qemu gives for EIP is invalid (outside of any memory) and does not evaluate to anything at all (no memory exists at that address, therefore that address contains nothing and nothing meaningful can come from executing it

your problem is likely the following:
Here's the "isr common stub", it's probably the relevant code:

Code: Select all

   add esp, 8    
   sti
   iret         
here you are modifying esp... this is effectively POPing more values off the stack that you didn't put on the stack... which of course causes your ESP to be wrong, so that IRET returns to the wrong address... and thus you get the CPU attempting to execute bogus memory

some exceptions will push an error code onto the stack, and in those specific cases (for those specific exception handlers, under those specific conditions) you need to remove the error code, but this is not for any other case, and thus the "add esp" is probably causing problems...



also:
you should (almost) never ever use STI... almost always when you think you want it, what you really want is to push/pop flags instead -- which will automatically happen when the CPU processes the interrupt
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Crash with IDT Implementation

Post by Octocontrabass »

cmp wrote:I'm reusing code from James Molloy.
That tutorial contains numerous bugs.

You're probably crashing because you've skipped the part of the tutorial that pushes two additional dwords to the stack before jumping to irq_common_stub. After you fix that, you will continue to have issues because irq_common_stub doesn't follow the ABI requirements. You also need to use a cross-compiler.
cmp
Posts: 14
Joined: Wed May 20, 2015 6:05 pm

Re: Crash with IDT Implementation

Post by cmp »

Well, I should revise my statement. I'm using the meaty code base from the wiki, and I understand all of it, however I used GDT and IDT code from Molloy.
The code in my kernel main is as follows:

Code: Select all

void kernel_main(void)
{
	printf("Hello kernel world!\n");
	asm volatile ("int $0x3");
	asm volatile ("int $0x4");
}
As expected, this crashes. And, as expected using int 0x8 doesn't, because that pushes an error code.. however it doesn't print my hello kernel world and doesn't go to my isr handler method. It just has the cursor in the top left. Also, it seems like anything above 0x10 or something around that doesn't cause a crash either, with the same results as described above. I'm really missing something here.

Thanks for the responses.

Edit: Success! It seems that the inline assembly was causing problems. However I'm now facing other problems.. If I dont use regs.int_no in my isr handler, it prints received interrupt a bunch of times.. or it crashes. Here's that code and my registers_t struct:

Code: Select all

void isr_handler(registers_t regs)
{
	printf("received interrupt: ");
	printf("%zu\n", regs.int_no);
}

typedef struct registers
{
   uint32_t ds;                  // Data segment selector
   uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
   uint32_t int_no, err_code;    // Interrupt number and error code (if applicable)
   uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
} registers_t;
It's the strangest thing... If I do use that in the printf statement without formatting (just printf(regs.int_no)) it works fine. Of course, it doesn't print the actual value correctly, but it prints received interrupt: [block thing]S [block thing]. So.. I guess formatting isn't working for me either, because with the formatting show above it just does the thing where the screen is empty minus the cursor.

Also, how would you suggest I go about choosing whether or not to add to esp?
Thanks guys, I really appreciate the help.
Hellbender
Member
Member
Posts: 63
Joined: Fri May 01, 2015 2:23 am
Libera.chat IRC: Hellbender

Re: Crash with IDT Implementation

Post by Hellbender »

Code: Select all

void isr_handler(registers_t regs)
There is your first problem. Instead, push address to regs, and do:

Code: Select all

void isr_handler(registers_t *regs)
GCC is free to modify the arguments that were passed in.
It does this especially when calling other functions to avoid copying arguments.

For example

Code: Select all

void test_1(int a, int b) {
  test_2(0, b);
}
void test_2(int zero, int b);
will cause GCC to set a=0 and jump to test_2.

So NEVER assume your stack parameters are left untouched.
Hellbender OS at github.
cmp
Posts: 14
Joined: Wed May 20, 2015 6:05 pm

Re: Crash with IDT Implementation

Post by cmp »

Well.. to be perfectly honest I don't know what I did.. But it works now.
Thanks for the suggestions guys.

On to ISR and other fun things!
madanra
Member
Member
Posts: 149
Joined: Mon Sep 07, 2009 12:01 pm

Re: Crash with IDT Implementation

Post by madanra »

Are you using a version control system, such as git? It's invaluable in these situations, as you can see exactly what you changed and work out which change(s) were responsible for fixing the problem.
Hellbender
Member
Member
Posts: 63
Joined: Fri May 01, 2015 2:23 am
Libera.chat IRC: Hellbender

Re: Crash with IDT Implementation

Post by Hellbender »

cmp wrote:Well.. to be perfectly honest I don't know what I did.. But it works now.
It's good that it works, but just remember that unless you fix it properly, it can randomly stop working as you change things that are somewhat related or change GCC optimization settings.

Other that kind of thing is inline assembler. I had some unnecessary trouble when GCC decided to allocate EBP as "r" register, and suddenly all those previously working mov instructions started using SS segment. Adding an extra "printf" made it work =)

--
- Tuomas
Hellbender OS at github.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re: Crash with IDT Implementation

Post by Candy »

Hellbender wrote:
cmp wrote:Well.. to be perfectly honest I don't know what I did.. But it works now.
It's good that it works, but just remember that unless you fix it properly, it can randomly stop working as you change things that are somewhat related or change GCC optimization settings.
As I love to put it, it stopped failing in the ways you looked at. You don't know if it actually works, you just know it doesn't fail in those ways.
Post Reply