Trying to make my Kernel an Executable

If you are new to OS Development, plan on spending some time here first before going into the other forums.

Moderator:Moderators

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am
Re: Trying to make my Kernel an Executable

Post by oib111 » Wed Sep 02, 2009 11:18 pm

Wouldn't all my problems just be solved if I stuck all the declarations into gdt.h and idt.h and then included them in main.c?

EDIT:

And they did ... except something's a bit wrong here lol...

Image

For one thing the cursor is at the totally wrong location? Not sure why. I checked all my screen functions and as far as I can tell they are all taking care of updating the cursor position correctly. And the second problem....segment limit 0x-1000 lol? I think a problem with itoa_s and itoa perhaps?

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: Trying to make my Kernel an Executable

Post by Mike » Thu Sep 03, 2009 5:05 am

oib111 wrote:And the second problem....segment limit 0x-1000 lol? I think a problem with itoa_s and itoa perhaps?
Hello,

That is (technically) the correct values. If the sign bit is set, the current functions will treat it as an signed integer rather then an unsigned integer which is why you are getting those values.
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Thu Sep 03, 2009 5:15 am

Oh ok, fixed it. Also, whenever I try generating an interrupt Bochs triple faults?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Fri Sep 04, 2009 9:37 am

that means you have not set up the IDT correctly, or that your interrupt handlers are broken. Do you mind posting any relevent code please?
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Fri Sep 04, 2009 6:36 pm

Ok, but it'll be a lot of code...

Code: Select all

//Exception messages
char *exception_messages[32] = {
	"Division by Zero",
	"Debug",
	"Non Maskable Interrupt",
	"Breakpoint",
	"Info Detected Overflow",
	"Out of Bounds",
	"Invalid Opcode",
	"No Coprocessor",
	"Double Fault",
	"Coprocessor Segment Overrun",
	"Bad TSS",
	"Segment Not Present",
	"Stack Fault",
	"General Protection Fault",
	"Page Fault",
	"Unknown Interrupt",
	"Coprocessor Fault",
	"Alignment Check",
	"Machine Code",
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
	"Reserved", 
};

//ISR (interrupt service routine definitions
//they all jump to our common stub which then passes the stack
//(represented by the regs structure) as a parameter to the 
//fault_handler function
//remember, we push dummy error codes to keep the stack frame uniform

void isr0() {
	_asm {
		cli
		push 0
		push 0
		jmp isr_common_stub
	}
}

void isr1() {
	_asm {
		cli
		push 0
		push 1
		jmp isr_common_stub
	}
}

void isr2() {
	_asm {
		cli
		push 0
		push 2
		jmp isr_common_stub
	}
}

void isr3() {
	_asm {
		cli
		push 0
		push 3
		jmp isr_common_stub
	}
}

void isr4() {
	_asm {
		cli
		push 0
		push 4
		jmp isr_common_stub
	}
}

void isr5() {
	_asm {
		cli
		push 0
		push 5
		jmp isr_common_stub
	}
}

void isr6() {
	_asm {
		cli
		push 0
		push 6
		jmp isr_common_stub
	}
}

void isr7() {
	_asm {
		cli
		push 0
		push 7
		jmp isr_common_stub
	}
}

void isr8() {
	_asm {
		cli
		push 8
		jmp isr_common_stub
	}
}

void isr9() {
	_asm {
		cli
		push 0
		push 9
		jmp isr_common_stub
	}
}

void isr10() {
	_asm {
		cli
		push 10
		jmp isr_common_stub
	}
}

void isr11() {
	_asm {
		cli
		push 11
		jmp isr_common_stub
	}
}

void isr12() {
	_asm {
		cli
		push 12
		jmp isr_common_stub
	}
}

void isr13() {
	_asm {
		cli
		push 13
		jmp isr_common_stub
	}
}

void isr14() {
	_asm {
		cli
		push 14
		jmp isr_common_stub
	}
}

void isr15() {
	_asm {
		cli
		push 0
		push 15
		jmp isr_common_stub
	}
}

void isr16() {
	_asm {
		cli
		push 0
		push 16
		jmp isr_common_stub
	}
}

void isr17() {
	_asm {
		cli
		push 0
		push 17
		jmp isr_common_stub
	}
}

void isr18() {
	_asm {
		cli
		push 0
		push 18
		jmp isr_common_stub
	}
}

void isr19() {
	_asm {
		cli
		push 0
		push 19
		jmp isr_common_stub
	}
}

void isr20() {
	_asm {
		cli
		push 0
		push 20
		jmp isr_common_stub
	}
}

void isr21() {
	_asm {
		cli
		push 0
		push 21
		jmp isr_common_stub
	}
}

void isr22() {
	_asm {
		cli
		push 0
		push 22
		jmp isr_common_stub
	}
}

void isr23() {
	_asm {
		cli
		push 0
		push 23
		jmp isr_common_stub
	}
}

void isr24() {
	_asm {
		cli
		push 0
		push 24
		jmp isr_common_stub
	}
}

void isr25() {
	_asm {
		cli
		push 0
		push 25
		jmp isr_common_stub
	}
}

void isr26() {
	_asm {
		cli
		push 0
		push 26
		jmp isr_common_stub
	}
}

void isr27() {
	_asm {
		cli
		push 0
		push 27
		jmp isr_common_stub
	}
}

void isr28() {
	_asm {
		cli
		push 0
		push 28
		jmp isr_common_stub
	}
}

void isr29() {
	_asm {
		cli
		push 0
		push 29
		jmp isr_common_stub
	}
}

void isr30() {
	_asm {
		cli
		push 0
		push 30
		jmp isr_common_stub
	}
}

void isr31() {
	_asm {
		cli
		push 0
		push 31
		jmp isr_common_stub
	}
}

void isr_common_stub() {
	_asm {
		pusha
		push ds
		push es
		push fs
		push gs
		mov ax, 10h
		mov ds, ax
		mov es, ax
		mov fs, ax
		mov gs, ax
		mov eax, esp
		push eax
		call fault_handler
		pop eax
		pop gs
		pop fs
		pop es
		pop ds
		popa
		add esp, 8				; Cleans up the stack
		iret
	}
	return;
}

void fault_handler(struct regs *stack) {
	setattrib(4, 15);
	clrscr();
	if(stack->int_no < 32) {
		printf("fault_handler: Exception occurred: %s\n", exception_messages[stack->int_no]);
	}
	else {
		printf("fault_handler: Unhandled exception occurred\n");
	}
}

void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags) {
	idt[num].base_lo = (base & 0xFFFF);
	idt[num].base_hi = (base >> 16) & 0xFFFF;
	
	idt[num].sel = sel;
	idt[num].always0 = 0;
	idt[num].flags = flags;
}

void install_idt() {
	idtp.limit = (sizeof(struct idt_entry)*256)-1;
	idtp.base = &idt;

	// blank out the IDT entries

	memset(idt, 0, (sizeof(struct idt_entry)*256)-1);

	// install all of our ISRs

	idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
	idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
	idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
	idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E);
	idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E);
	idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E);
	idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E);
	idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E);
	idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E);
	idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E);
	idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E);
	idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E);
	idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E);
	idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E);
	idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E);
	idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E);
	idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E);
	idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E);
	idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E);
	idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E);
	idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E);
	idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E);
	idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E);
	idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E);
	idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E);
	idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E);
	idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E);
	idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E);
	idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E);
	idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
	idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
	idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);

	// load our IDT

	idt_load();
}
That was all the relevant things in idt.c (well things I thought were relevant), and here's the declaration of the regs structure in idt.h

Code: Select all

// What the stack looks like after an ISR was run
struct regs
{
    unsigned int gs, fs, es, ds;      // pushed the segs last
    unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;  // pushed by 'pusha'
    unsigned int int_no, err_code;    // our 'push #' and ecodes do this
    int eip, cs, eflags, useresp, ss;   // pushed by the processor automatically
};

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Sat Sep 05, 2009 10:45 am

That would be your problem.

You are not cleaning the stack up properly.

as a start, all the

Code: Select all

void isr<num>() {
   _asm {
      cli
      push 0
      push 0
      jmp isr_common_stub
   }
}
functions need to be declared as __declspec(naked) so there is no prolog or epilog code.

also, you need to use the "iretd" opcode rather than the "iret" one as you are in a 32bit code segment.

With any luck, that should stop the stack problems.


However, can you please explain why you are doing these things in the common_stub function?

Code: Select all

void isr_common_stub() {
   _asm {
      pusha
      push ds
      push es
      push fs
      push gs
      mov ax, 10h
      mov ds, ax
      mov es, ax
      mov fs, ax
      mov gs, ax
      mov eax, esp
      push eax
      call fault_handler
      pop eax
      pop gs
      pop fs
      pop es
      pop ds
      popa
      add esp, 8            ; Cleans up the stack
      iret
   }
   return;
}
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Sat Sep 05, 2009 5:10 pm

So that my function's don't change the previous registers. Also it'd be helpful for debugging purposes.

EDIT:

Adding _declspec(naked) and using iretd didn't help. :?

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: Trying to make my Kernel an Executable

Post by Mike » Sat Sep 05, 2009 5:39 pm

Hello,

isr_common_stub should also have __declspec (naked). Also insure you remove the add esp, 8 instruction when you do this as it will not be needed and will cause problems.
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Sat Sep 05, 2009 5:53 pm

Still triple faulting :|

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: Trying to make my Kernel an Executable

Post by Mike » Sat Sep 05, 2009 8:06 pm

Hello,

Are you sure the IRQ handlers are being executed properly without crashing? That is, put a CLI and HLT in your IRQ handlers to test if they properly halt the system or still triple fault.
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Sat Sep 05, 2009 11:40 pm

After a long discussion with Andy we fixed the problem! Woot haha.

Post Reply