Page 1 of 1

OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 8:16 am
by obiwac
Whenever I press a key, instead of sending irq 1, it crashes my os with a triple fault. It does the same with the PIT, so I have disabled it for now. I have tried to do it manually with asm("int $1"), but it still crashes. I am compiling with gcc & nasm. Here are my codes:

irq.c:

Code: Select all


#include "irq.h"

void* irq_routines[16] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0
	
};

void irq_add_handler(int irq, void (*handler) (struct registers* r)) {
	irq_routines[irq] = handler;
	
}

void irq_remove_handler(int irq) {
	irq_routines[irq] = 0;
	
}

void irq_remap(void) {
	outportb(0x20, 0x11);
	outportb(0xA0, 0x11);
	
	outportb(0x21, 0x20);
	outportb(0xA1, 0x28);
	outportb(0x21, 0x04);
	outportb(0xA1, 0x02);
	outportb(0x21, 0x01);
	outportb(0xA1, 0x01);
	outportb(0x21, 0x0);
	outportb(0xA1, 0x0);
	
}

void irq_init(void) {
	irq_remap();
	
	set_idt_gate(32, (unsigned) irq0);
	set_idt_gate(33, (unsigned) irq1);
	set_idt_gate(34, (unsigned) irq2);
	set_idt_gate(35, (unsigned) irq3);
	set_idt_gate(36, (unsigned) irq4);
	set_idt_gate(37, (unsigned) irq5);
	set_idt_gate(38, (unsigned) irq6);
	set_idt_gate(39, (unsigned) irq7);
	set_idt_gate(40, (unsigned) irq8);
	set_idt_gate(41, (unsigned) irq9);
	set_idt_gate(42, (unsigned) irq10);
	set_idt_gate(43, (unsigned) irq11);
	set_idt_gate(44, (unsigned) irq12);
	set_idt_gate(45, (unsigned) irq13);
	set_idt_gate(46, (unsigned) irq14);
	set_idt_gate(47, (unsigned) irq15);
	
}

void irq_handler(struct registers* r) {
	void (*handler) (struct registers* r);
	handler = irq_routines[r->num - 32];
	
	if (handler) {
		handler(r);
		
	} if (r->num >= 40) {
		outportb(0xA0, 0x20);
		
	}
	
	outportb(0x20, 0x20);
	
}
I don't think irq.h is important. Its just some

Code: Select all

extern void irq ... ();
.

keyboard.c

Code: Select all


#include "keyboard_driver.h"

static uint8 press;
static uint8 release;

void keyboard_handler(struct registers* r) {
	uint8 scancode;
	scancode = inportb(0x60);
	
	println("Keypress", 0x07);
	
	if (scancode & 0x80) release = scancode;
	else press = scancode;
	
}

void keyboard_install(void) {
	while (inportb(0x64) & 0x1) {
		inportb(0x60);
		
	}
	
	outportb(0x64, 0xae);
	outportb(0x64, 0x20);
	
	uint8 status = (inportb(0x60) | 1) & ~0x10;
	
	outportb(0x64, 0x60);
	outportb(0x60, status);
	outportb(0x60, 0xf4);
	
	//irq_add_handler(33, keyboard_handler);
	irq_add_handler(1, keyboard_handler);
	
}

uint8 poll_key(void) {
	uint8 temp = press;
	press = 127;
	return temp;
	
}

uint8 poll_key_release(void) {
	uint8 temp = release;
	release = 127;
	return temp;
	
}
idt.c

Code: Select all


static uint8 flags = 0x8E;

void set_idt_gate(int n, uint32 handler) {
	idt[n].high_offset = high_16(handler);
	idt[n].low_offset = low_16(handler);
	idt[n].sel = KERNEL_CS;
	
	idt[n].always0 = 0;
	idt[n].flags = flags; 
	
}

void set_idt(void) {
	idt_reg.limit = (uint32) &idt;
	idt_reg.base = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
	__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));
	
}

void set_idt_flags(uint8 _flags) {
	flags = _flags;
	
}
and the assembly for interrupts:

Code: Select all

global irq0
continues up to...
global irq15

irq0:
	cli
	push byte 0
	push byte 32
	jmp irq_common

irq1:
	cli
	push byte 0
	push byte 33
	jmp irq_common .. and so on...

extern irq_handler
irq_common:
	pusha
	push ds
	push es
	push fs
	push gs
	
	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	mov eax, esp
	push eax
	mov eax, irq_handler
	call eax
	pop eax
	
	pop gs
	pop fs
	pop es
	pop ds
	popa
		
	add esp, 8
	iret
Thanks in advance!

Re: OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 8:20 am
by LtG
Did I read this wrong or did you mix these two up?

Code: Select all

   idt_reg.limit = (uint32) &idt;
   idt_reg.base = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
Also, would be useful if you'd do some troubleshooting first and tell us what you found, like single stepping with a debugger.. To some debuggers are intimidating but with OS dev you pretty much have to get used to it.

Re: OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 10:15 am
by obiwac
Thanks for your help!

Code: Select all

dbf event: Fatal error! (hyper)
.eax=00000000 .ebx=00000000 .ecx=00000000 .edx=00000000 .esi=00000000 .edi=00000000
.eip=00000000 .esp=ff920000 .ebp=00000000 .iopl=0 nv up di pl nz na pe nc
.cs=0000 .ds=0000 .es=0000 .fs=0000 .gs=0000 .ss=0000              .eflags=00000000
u: error: DBGCCmdHlpVarToDbgfAddr failed on '0000:00000000 L 0': VERR_SELECTOR_NOT_PRESENT
So I get this in the virtualbox debugger. I don't really know what this means though.

Re: OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 12:54 pm
by LtG
obiwac wrote:Thanks for your help!

Code: Select all

dbf event: Fatal error! (hyper)
.eax=00000000 .ebx=00000000 .ecx=00000000 .edx=00000000 .esi=00000000 .edi=00000000
.eip=00000000 .esp=ff920000 .ebp=00000000 .iopl=0 nv up di pl nz na pe nc
.cs=0000 .ds=0000 .es=0000 .fs=0000 .gs=0000 .ss=0000              .eflags=00000000
u: error: DBGCCmdHlpVarToDbgfAddr failed on '0000:00000000 L 0': VERR_SELECTOR_NOT_PRESENT
So I get this in the virtualbox debugger. I don't really know what this means though.
Don't know much about vbox, I prefer qemu and bochs. What exactly did you do and what happens?

Based on the error I would assume it's because your seg registers are all 0x0 (I'm assuming you're using protected mode):
.cs=0000 .ds=0000 .es=0000 .fs=0000 .gs=0000 .ss=0000 .eflags=00000000

You need use valid segment descriptors, not sure why they're all zero, did you set them all to zero?

Also, if this is your first go at osdev, I might recommend going thru the bare bones tutorial to get something working and then moving from there and when ever you get an issue you can easily roll back a couple of small changes getting back to working code and then figure out what exactly you did wrong. That is assuming you use version control, which you should =)

Re: OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 2:25 pm
by obiwac
But I do set them in the assembly irq_common label... And I don't set them to 0, I set them to ax which is set to 16.

Re: OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 3:11 pm
by Ankeraout
In irq_common :

Code: Select all

add esp, 8
iret
You forgot to send end of interrupt to the PIC before IRET !

I don't think this will solve the problem.
You should implement int0 - int31 handlers and display the called int number to the screen then sticks in an infinite loop to know what is the first called exception handler, which will tell you what goes wrong according to this page.

Re: OS crashes whenever I press a key

Posted: Wed Apr 05, 2017 6:00 pm
by obiwac
Thanks! I do have ints 0-31 , and so I get a General Protection fault, and then a triple fault, and then my os crashes.

Re: OS crashes whenever I press a key

Posted: Thu Apr 06, 2017 12:17 am
by FusT
Sounds to me like your IDT isn't set up properly.
Are you sure it's valid and loaded correctly? Could you post a dump (on bochs it's the 'info idt' debugger command)?

Re: OS crashes whenever I press a key

Posted: Thu Apr 06, 2017 1:26 am
by Ankeraout
A General Protection Fault may occur for various reasons. The most common are:
- Segment error (privilege, type, limit, read/write rights).
- Executing a privileged instruction while CPL != 0.
- Writing a 1 in a reserved register field.
--> Referencing or accessing a null-descriptor.
The saved instruction pointer points to the instruction which caused the exception.
As LtG said, all of your segment registers are pointing to the null gdt entry. This could be your problem.

Re: OS crashes whenever I press a key

Posted: Thu Apr 06, 2017 2:02 am
by BenLunt
obiwac wrote:

Code: Select all

void irq_handler(struct registers* r) {
	void (*handler) (struct registers* r);
	handler = irq_routines[r->num - 32];
I don't think irq.h is important. Its just some

Code: Select all

extern void irq ... ();
.
I think irq.h is important. It probably shows us the 'struct registers' definition.

In your code, the stack looks like:

Code: Select all

 push byte 0  [dword]
 push byte 32 [dword]
 pusha        [8 words]  (note, probably not dwords)
    ; should this be 'pushad'?
 push ds  [dword]
 push es  [dword]
 push fs  [dword]
 push gs  [dword]
 push eax [dword]
 call handler return value [dword]
You save the value in eax of the current stack location before calling the handler. The handler assumes the above format.
What does 'struct registers' look like?

Code: Select all

struct registers {
  dword gs;
  dword fs;
  dword es;
  dword ds;
  word  pusha[8];
  dword num;
  dword zero;
};
I am guessing that you have modified the 'struct registers' and/or the 'push'es in the .asm code and they no longer match.

Then, here is the error I believe you have:

Code: Select all

	handler = irq_routines[r->num - 32];
r->num = 0, so 'handler' above now has a value of 'undefined' since it grabs a value 32 dwords before the list of IRQ handlers you have.
i.e.:

Code: Select all

	handler = irq_routines[0 - 32];
is the same as

Code: Select all

	handler = irq_routines[-32];
which is in error...

Make sure your structure matches your pushes, and check whether the assembler is pushing words or dwords with the 'pusha' instruction. Then make sure your structure matches the pusha/pushad instruction.

Just my guess,
Ben
http://www.fysnet.net/osdesign_book_series.htm

Re: OS crashes whenever I press a key

Posted: Thu Apr 06, 2017 2:28 am
by obiwac
Thank you to everyone for having helped! I found out it was just a stupid little mistake. I was messing around once, and I remapped the keyboard interrupt to something else. Sorry for wasting your time! But maybe I should still look more in depth for the registers.

Code: Select all

struct __attribute__((packed)) registers {
	unsigned int gs, fs, es, ds;
	unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
	unsigned int num, err_code;
	unsigned int eip, cs, eflags, useresp, ss;
	
};