[Solved] IRQ Firing Bug

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.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: IRQ Firing Bug

Post by BrightLight »

thehardcoreOS wrote:

Code: Select all

   if (r->int_no >= 40)
   {
      outportb(0xA0, 0x20);
   }
   outportb(0x20, 0x20);
   PIC_SendEOI(r->int_no);
In the code snippet from above, you seem to send EOI twice. What does PIC_SendEOI() do? And why do you need to pass the interrupt number to it?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

omarrx024 wrote:
thehardcoreOS wrote:

Code: Select all

   if (r->int_no >= 40)
   {
      outportb(0xA0, 0x20);
   }
   outportb(0x20, 0x20);
   PIC_SendEOI(r->int_no);
In the code snippet from above, you seem to send EOI twice. What does PIC_SendEOI() do? And why do you need to pass the interrupt number to it?
Oh I see, I removed this line PIC_SendEOI(1);
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

Here is what it does:

Code: Select all

void PIC_SendEOI(unsigned char irq)
{
	if(irq >= 8)
	{
		outportb(PIC2_COMMAND,PIC_EOI);
	}
	outportb(PIC1_COMMAND,PIC_EOI);
}
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: IRQ Firing Bug

Post by BrightLight »

OK, well does it work now?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

omarrx024 wrote:OK, well does it work now?
Nope. I noticed that Keyboard_Handler never gets called. RIP
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: IRQ Firing Bug

Post by BrightLight »

thehardcoreOS wrote:
omarrx024 wrote:OK, well does it work now?
Nope. I noticed that Keyboard_Handler never gets called. RIP
That's really odd. Can you make your keyboard handler just put a character on the screen and carefully follow the keyboard initialization code I gave you?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

omarrx024 wrote:
thehardcoreOS wrote:
omarrx024 wrote:OK, well does it work now?
Nope. I noticed that Keyboard_Handler never gets called. RIP
That's really odd. Can you make your keyboard handler just put a character on the screen and carefully follow the keyboard initialization code I gave you?
No I can not make my keyboard_handler do anything, because it never gets called when interrupt happens.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: IRQ Firing Bug

Post by BrightLight »

And what does that have to do with PIC_SendEOI()?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

omarrx024 wrote:And what does that have to do with PIC_SendEOI()?
:?: :?:
I followed wiki.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

Entire irq.c

Code: Select all

#include "../Include/irq.h"

#define ICW1_ICW4	             0x01		
#define ICW1_SINGLE	             0x02		
#define ICW1_INTERVAL4	0x04	
#define ICW1_LEVEL	             0x08		
#define ICW1_INIT	             0x10		
#define ICW4_8086	             0x01		
#define ICW4_AUTO	             0x02		
#define ICW4_BUF_SLAVE	0x08		
#define ICW4_BUF_MASTER	0x0C		
#define ICW4_SFNM	             0x10
#define PIC1		             0x20		
#define PIC2		             0xA0		
#define PIC1_COMMAND	PIC1
#define PIC1_DATA	             (PIC1+1)
#define PIC2_COMMAND	PIC2
#define PIC2_DATA	             (PIC2+1)
#define PIC_EOI		0x20			

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

struct regs
{
	unsigned int gs, fs, es, ds;      
	unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;  
	unsigned int int_no, err_code;   
	unsigned int eip, cs, eflags, useresp, ss;   
};

static volatile int sync_depth = 0;
#define SYNC_CLI() asm volatile("cli")
#define SYNC_STI() asm volatile("sti")

void Disable_Interrupts(void)
{
	uint32_t flags;
	asm volatile("pushf\n\t" "pop %%eax\n\t" "movl %%eax, %0\n\t" : "=r"(flags): : "%eax");
	SYNC_CLI();
	if (flags & (1 << 9)) 
	{
		sync_depth = 1;
	} 
	else 
	{
		sync_depth++;
	}
}

void Resume_Interrupts(void)
{
	if (sync_depth == 0 || sync_depth == 1) 
	{
		SYNC_STI();
	}
	 else 
	 {
		sync_depth--;
	}
}

void Enable_Interrupts(void)
{
	sync_depth = 0;
	SYNC_STI();
}

void IRQ_Uninstall_Handler(int irq)
{
	SYNC_CLI();
	irq_routines[irq] = 0;
	SYNC_STI();
}

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 InstallIRQS()
{
	IRQ_Remap();
	IDTSetGate(32, (unsigned)irq0, 0x08, 0x8E);
	IDTSetGate(33, (unsigned)irq1, 0x08, 0x8E);
	IDTSetGate(34, (unsigned)irq2, 0x08, 0x8E);
	IDTSetGate(35, (unsigned)irq3, 0x08, 0x8E);
	IDTSetGate(36, (unsigned)irq4, 0x08, 0x8E);
	IDTSetGate(37, (unsigned)irq5, 0x08, 0x8E);
	IDTSetGate(38, (unsigned)irq6, 0x08, 0x8E);
	IDTSetGate(39, (unsigned)irq7, 0x08, 0x8E);
	IDTSetGate(40, (unsigned)irq8, 0x08, 0x8E);
	IDTSetGate(41, (unsigned)irq9, 0x08, 0x8E);
	IDTSetGate(42, (unsigned)irq10, 0x08, 0x8E);
	IDTSetGate(43, (unsigned)irq11, 0x08, 0x8E);
	IDTSetGate(44, (unsigned)irq12, 0x08, 0x8E);
	IDTSetGate(45, (unsigned)irq13, 0x08, 0x8E);
	IDTSetGate(46, (unsigned)irq14, 0x08, 0x8E);
	IDTSetGate(47, (unsigned)irq15, 0x08, 0x8E);
	IRQSSucceeded();
}

void IRQSSucceeded()
{
	PrintString("\nIRQS Loaded!         ");
	PrintColoredString("[ Passed ]", 11, 0);
	ResetColors();
}

void IRQ_Set_Mask(unsigned char IRQline) 
{
    	uint16_t port;
    	uint8_t value;
    	if(IRQline < 8) 
    	{
       		 port = PIC1_DATA;
    	} 
    	else 
    	{
      		  port = PIC2_DATA;
      		  IRQline -= 8;
    	}
   	value = inportb(port) | (1 << IRQline);
    	outportb(port, value);        
}
 
void IRQ_Clear_Mask(unsigned char IRQline) 
{
    	uint16_t port;
    	uint8_t value;
    	if(IRQline < 8) 
    	{
        		port = PIC1_DATA;
    	} 
    	else 
    	{
        		port = PIC2_DATA;
        		IRQline -= 8;
   	}
    	value = inportb(port) & ~ (1 << IRQline);
   	outportb(port, value);        
}

void PIC_Remap(int offset1, int offset2)
{
	unsigned char a1, a2;
	a1 = inportb(PIC1_DATA);                
	a2 = inportb(PIC2_DATA);
	outportb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);  
	IO_Wait();
	outportb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
	IO_Wait();
	outportb(PIC1_DATA, offset1);        
	IO_Wait();
	outportb(PIC2_DATA, offset2);                
	IO_Wait();
	outportb(PIC1_DATA, 4);                      
	IO_Wait();
	outportb(PIC2_DATA, 2);                  
	IO_Wait();
	outportb(PIC1_DATA, ICW4_8086);
	IO_Wait();
	outportb(PIC2_DATA, ICW4_8086);
	IO_Wait();
	outportb(PIC1_DATA, a1);   
	outportb(PIC2_DATA, a2);
}

void PIC_SendEOI(unsigned char irq)
{
	if(irq >= 8)
	{
		outportb(PIC2_COMMAND,PIC_EOI);
	}
	outportb(PIC1_COMMAND,PIC_EOI);
}

void IRQ_Install_Handler(int irq, void (*handler)(struct regs *r))
{
	///SYNC_CLI();
	irq_routines[irq] = handler;
	//SYNC_STI(); //if I enable this line I get only one interrupt
	PrintString("IRQ install handler call for irq");
	PrintString(IntToString(irq));
}

void IRQ_Handler(struct regs *r)
{
	//Disable_Interrupts();
	void (*handler)(struct regs *r);
	handler = irq_routines[r->int_no - 32];
	if (handler)
	{
		handler(r);
		//Resume_Interrupts();
	}
	if (r->int_no >= 40)
	{
		outportb(0xA0, 0x20);
	}
	outportb(0x20, 0x20);
	PrintString("\nIRQ_Handler Called from asm with interupt number ");
	PrintString(IntToString(r->int_no));
}
entire keyboard.c

Code: Select all

#include "../Include/keyboard.h"

struct regs
{
	unsigned int gs, fs, es, ds;      
	unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;  
	unsigned int int_no, err_code;   
	unsigned int eip, cs, eflags, useresp, ss;   
};

unsigned char kbdus[128] =
{
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8',	/* 9 */
  '9', '0', '-', '=', '\b',	/* Backspace */
  '\t',			/* Tab */
  'q', 'w', 'e', 'r',	/* 19 */
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',	/* Enter key */
    0,			/* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',	/* 39 */
 '\'', '`',   0,		/* Left shift */
 '\\', 'z', 'x', 'c', 'v', 'b', 'n',			/* 49 */
  'm', ',', '.', '/',   0,				/* Right shift */
  '*',
    0,	/* Alt */
  ' ',	/* Space bar */
    0,	/* Caps lock */
    0,	/* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,	/* < ... F10 */
    0,	/* 69 - Num lock*/
    0,	/* Scroll Lock */
    0,	/* Home key */
    0,	/* Up Arrow */
    0,	/* Page Up */
  '-',
    0,	/* Left Arrow */
    0,
    0,	/* Right Arrow */
  '+',
    0,	/* 79 - End key*/
    0,	/* Down Arrow */
    0,	/* Page Down */
    0,	/* Insert Key */
    0,	/* Delete Key */
    0,   0,   0,
    0,	/* F11 Key */
    0,	/* F12 Key */
    0,	/* All other keys are undefined */
};		

void KeyboardSucceeded()
{
             PrintString("\nKeyboard Loaded!     ");
             PrintColoredString("[ Passed ]", 11, 0);
             ResetColors();
}

void Keyboard_Handler(struct regs *r)
{
       PrintString("Keyboard Handler Called");
	unsigned char scancode;
	scancode = inportb(0x60);
	if (scancode & 0x80)
    	{
        		//use this to see if user released any control keys aka shift ctrl alt altgr
    	}
    	else
    	{
		PrintString(kbdus[scancode]);
		WriteOutputToQemu(kbdus[scancode]);
    	}
       PIC_SendEOI(1);
}


uint8 PS2_Send(uint8 data)
{
      PS2_Wait_Write();
      outportb(0x60, data);
      PS2_Wait_Read();
      return inportb(0x60);
}

void InstallKeyboard()
{
       PS2_Send(0xFF);    
       PS2_Send(0xF3);     
       PS2_Send(0x20);    
       PS2_Send(0xF0);    
       PS2_Send(0x02);  
       PS2_Send(0xFA);      
       PS2_Send(0xF4);  
      	IRQ_Install_Handler(33, &Keyboard_Handler);
	KeyboardSucceeded();
}

void PS2_Wait_Write()
{
      while(inportb(0x64) & 2 == 0);
}

void PS2_Wait_Read()
{
      while(inportb(0x64) & 1 == 0);
}

OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: IRQ Firing Bug

Post by Ch4ozz »

This keyboard setup doesnt work for me on VBox.
Using simple PS2_Send(0xF4); only works fine for me on all emulators and machines (Qemu, Bochs, VBox, VMWare)

I didnt read your code but it looks like you copy and pasted some stuff and didnt completely understood how it works.
I suggest reading another tutorial in this case.

You should also empty your keyboard buffer like this:

Code: Select all

while (inb(0x64) & 0x1)
	inb(0x60);
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

Ch4ozz wrote:This keyboard setup doesnt work for me on VBox.
Using simple PS2_Send(0xF4); only works fine for me on all emulators and machines (Qemu, Bochs, VBox, VMWare)

I didnt read your code but it looks like you copy and pasted some stuff and didnt completely understood how it works.
I suggest reading another tutorial in this case.

You should also empty your keyboard buffer like this:

Code: Select all

while (inb(0x64) & 0x1)
	inb(0x60);
Okay, I added clear buffer code inside my keyboard handler. There is no point of making a proper keyboard driver if I can't get my IRQ to fire up my keyboard handler (in this case).
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: IRQ Firing Bug

Post by BrightLight »

Ch4ozz wrote:This keyboard setup doesnt work for me on VBox.
That's odd. My keyboard setup works on VBox, Bochs, QEMU, VMware and two real PCs.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: IRQ Firing Bug

Post by Octacone »

omarrx024 wrote:
Ch4ozz wrote:This keyboard setup doesnt work for me on VBox.
That's odd. My keyboard setup works on VBox, Bochs, QEMU, VMware and two real PCs.
So... is there a solution? I just can't fix this myself. Handlers get installed but never called again, only when I enable interrupts with sti they get called once and never again.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: IRQ Firing Bug

Post by iansjack »

Either you are not acknowledging the interrupt or you are not reading the character from the keyboard. A little simple debugging, single-stepping through the code, should tell you which.
Post Reply