Page 2 of 5

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:02 pm
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?

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:04 pm
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);

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:05 pm
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);
}

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:07 pm
by BrightLight
OK, well does it work now?

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:09 pm
by Octacone
omarrx024 wrote:OK, well does it work now?
Nope. I noticed that Keyboard_Handler never gets called. RIP

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:12 pm
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?

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:14 pm
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.

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:18 pm
by BrightLight
And what does that have to do with PIC_SendEOI()?

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:20 pm
by Octacone
omarrx024 wrote:And what does that have to do with PIC_SendEOI()?
:?: :?:
I followed wiki.

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 3:21 pm
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);
}


Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 4:03 pm
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);

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 4:12 pm
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).

Re: IRQ Firing Bug

Posted: Tue Jul 26, 2016 5:08 pm
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.

Re: IRQ Firing Bug

Posted: Wed Jul 27, 2016 4:59 am
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.

Re: IRQ Firing Bug

Posted: Wed Jul 27, 2016 5:08 am
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.