Page 1 of 2

Problem with software interrupts and IRQs

Posted: Fri Mar 28, 2014 11:24 am
by kubawal
Hi!

I know that on this wiki are a lot of articles about interrupts. But i read all of these.

I've got problem with Interrupts. When I write keyboard driver IRQ1 didn't work, so I write a test software interrupt 0x50 (what simply prints on screen 'INT50' - and it works, but not return.
I write exception handlers to get information about this error. And when I call

Code: Select all

int 0x50
I saw 'INT50' on the screen, but after that my exception handler gives me information about exception 13 (General Protection Fault)
IRQ don't work form beggining - it don't calls at all.

My interrupts API:

Code: Select all

#define _set_gate(gate_addr,type,dpl,addr) \
     __asm__ __volatile__("movw %%dx,%%ax\n\t" \
           "movw %0,%%dx\n\t" \
           "movl %%eax,%1\n\t" \
           "movl %%edx,%2\n\t" \
           : :"i"((short)(0x8000+(dpl<<13)+(type<<8))), \
             "o"(*((char *)(gate_addr))), \
             "o"(*(4+(char *)(gate_addr))), \
             "d"((char *)(addr)),"a"(0x00080000)) \
			 
#define PIC1		0x20		/* IO base address for master PIC */
#define PIC2		0xA0		/* IO base address for slave PIC */
#define PIC1_COMMAND	PIC1
#define PIC1_DATA	(PIC1+1)
#define PIC2_COMMAND	PIC2
#define PIC2_DATA	(PIC2+1)
#define PIC_EOI		0x20		/* End-of-interrupt command code */
 
			
void intSetGate(int n, void* p)
{
	_set_gate(&mosIDT[n], 14, 0, p); 
}

void intSetTrapGate(int n, void* p)
{
	_set_gate(&mosIDT[n], 15, 0, p);
}

void intSetSystemGate(int n, void* p)
{
	_set_gate(&mosIDT[n], 15, 3, p); 
}

static unsigned int cached_irq_mask = 0xffff; 
 
#define __byte(x,y)       (((unsigned char *)&(y))[x]) 
#define cached_21      (__byte(0,cached_irq_mask)) 
#define cached_A1      (__byte(1,cached_irq_mask)) 
 
void intDisableIRQ(unsigned int irq)  // disables IRQ
{ 
unsigned int mask = 1 << irq; 
cached_irq_mask |= mask; 
if (irq & 8) 
{ 
 outb(cached_A1,0xA1); 
} else { 
 outb(cached_21,0x21); 
} 
} 
 
void intEnableIRQ(unsigned int irq) // enables IRQ
{ 
unsigned int mask = ~(1 << irq); 
cached_irq_mask &= mask; 
if (irq & 8) { 
 mosWritePort(cached_A1,0xA1); 
} else { 
 mosWritePort(cached_21,0x21); 
} 
}

#define PIC1 0x20
#define PIC2 0xA0

#define ICW1 0x11
#define ICW4 0x01

void intInit(int pic1, int pic2) // initializes PIC (code from this wiki)
{
	/* send ICW1 */
	outb(PIC1, ICW1);
	outb(PIC2, ICW1);

	/* send ICW2 */
	outb(PIC1 + 1, pic1);	/* remap */
	outb(PIC2 + 1, pic2);	/*  pics */

	/* send ICW3 */
	outb(PIC1 + 1, 4);	/* IRQ2 -> connection to slave */
	outb(PIC2 + 1, 2);

	/* send ICW4 */
	outb(PIC1 + 1, ICW4);
	outb(PIC2 + 1, ICW4);

	/* disable all IRQs */
	outb(PIC1 + 1, 0xFF);
}

void intEOI(unsigned int irq) // send EOI to the PIC (code form this wiki)
{
	if(irq >= 8)
		outb(PIC2_COMMAND,PIC_EOI);
 
	outb(PIC1_COMMAND,PIC_EOI);
}
My interrupts code:

Code: Select all

; This is only wrappers

; IRQ 1 - keyboard interrupt
irq1: 
	 pushad
     call doIrq1
	 popad
	 iret
	 
	 
; int 0x50 - system test call
int50:
	 pushad
	 call doInt50
	 popad
	 iret

Code: Select all

#define ASMCALL extern "C"

ASMCALL void doInt50() // 0x50 - system test
{
	mosWriteString("INT50");
}

// call on system startup after intInit()
void sysintInit()
{
	intSetSystemGate(0x50, ASHANDLER(int50));
}

//...

// in  keyboard driver

ASMCALL void doIrq1() // keyboard interrupt
{
	//...
	mosWriteString("IRQ1");
	intEOI(1);
}
ASMCALL void irq1();

bool mosInitKbd() // call after intInit()
{

//...	
	
	intSetGate(0x21, (void*)irq1); // set interrupt handler into valid address
	intEnableIRQ(1);
	
	return true;
}

Re: Problem with software interrupts and IRQs

Posted: Fri Mar 28, 2014 3:25 pm
by Nable
Oh, it looks like you should learn about `enum`, `struct` and `union` - these keywords are very useful for getting rid of ugly defines.
Btw, I see `intInit` function but I don't see where it is called (and with what arguments).

Re: Problem with software interrupts and IRQs

Posted: Sat Mar 29, 2014 1:35 am
by Combuster
void intInit(int pic1, int pic2) // initializes PIC (code from this wiki)
Well, I have seen my fair share of problems with people copy-pasting code they don't know what it does, but actually messing up the copy... :lol:

(count the instructions to each of the PIC chips)

Re: Problem with software interrupts and IRQs

Posted: Sat Mar 29, 2014 11:36 am
by kubawal
Nable wrote:Btw, I see `intInit` function but I don't see where it is called (and with what arguments).
This is fragment of my function that initializes system:

Code: Select all

intInit(0x20, 0x28); // init PIC
	
	sysintInit(); // init system interrupts (INT 0x50)
	excInit(); // init exceptions (EXC0 - EXC14)

// ...

mosInitKbd(); // initializes kbd (IRQ 1)
Nable wrote:Oh, it looks like you should learn about `enum`, `struct` and `union` - these keywords are very useful for getting rid of ugly defines.
I'm not a begginer in c++. I didn't name this topic 'HELP MY SYSTEM DONT WORK HELP! HELP! HELP!!!!'. I know what is structs, classes, unions, bit enums etc.
I write this topic because i try all ways to fix it (but I must **** up something because otherwise it should works ;) )

PS. I run it into VirtualBox, with GRUB.
PPS. I tested code from tutorial (http://haxite.org/article/view/85-Kurs+ ... B%C4%87+I/), what I using before and it also has not working IRQs
PPPS. in my startup code IDT have definition like this:

Code: Select all

;...
lidt [idt_descr]
;...

; IDT
idt_descr: ; header
dw 256*8-1 
dd mosIDT
GLOBAL mosIDT
mosIDT:
times 256 dd 0,0

Re: Problem with software interrupts and IRQs

Posted: Sun Mar 30, 2014 11:58 am
by kubawal
I find another ISR template:

Code: Select all

pusha
push	eax
push	ds
push	es
push	fs
push	gs

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

// do something

pop	gs
pop	fs
pop	es
pop	ds
pop	eax
popa
iret
What is the difference between this code and my code from first post?

Re: Problem with software interrupts and IRQs

Posted: Sun Mar 30, 2014 12:12 pm
by Combuster
kubawal wrote:What is the difference between this code and my code from first post?
- popa/popad (16 or 32 bit push depending on assembler vs always 32-bit push)
- reloading of segment registers - which is a good idea in case userspace broke something.

Re: Problem with software interrupts and IRQs

Posted: Sun Mar 30, 2014 12:32 pm
by kubawal
But it also not works :)

PS. I try to don't use asm wrappers and use BLACK MAGIC, but VirtualBox machine crashes and I've got MessageBox with Buddy Meditation about error ](*,)

Re: Problem with software interrupts and IRQs

Posted: Sun Mar 30, 2014 12:40 pm
by Combuster
That's because you asked the wrong question.

Considering you appear to be a novice when it comes to debugging, VirtualBox is a bad help. Run your code in Bochs - most likely you'll get detailed messages regarding how you screwed up. You can even compile bochs with debugger enabled for detailed inspection.

Re: Problem with software interrupts and IRQs

Posted: Tue Apr 01, 2014 3:50 am
by kubawal
I completly rewrite my startup code and GDT + IDT support with Bran's tutorial.
Manually called interrupts works, but IRQ's not.
Because keyboard interrupt not works (does it need to set First Port Interrupt in Configuration Byte?) I try to use PIT and IRQ 0. It should simply change character in left-top corner of the console - but it also not works ](*,)
My new code:

Code: Select all

#define PACKED __attribute__((packed))
struct idtEntry
{
    unsigned short baseLow;
    unsigned short sel;  	// selektor jadra      
    unsigned char always0;  // zawsze 0
    unsigned char flags;      
    unsigned short baseHigh;
} PACKED;

struct idtLoad
{
    unsigned short limit;
    unsigned int base;
} PACKED;

idtEntry IDT[256]; // IDT
idtLoad IDTl; // IDT load struct

void intSetEntry(unsigned char num, unsigned long base, unsigned short sel = 0x08, unsigned char flags = 0x8E) // default: kernel code segment, ring 0
{
    /* The interrupt routine's base address */
    IDT[num].baseLow = (base & 0xFFFF);
    IDT[num].baseHigh = (base >> 16) & 0xFFFF;

    IDT[num].sel = sel;
    IDT[num].always0 = 0;
    IDT[num].flags = flags;
}		 
 
void intEnableIRQ(unsigned char IRQline) { // enables IRQ (probably it not works) (code form this wiki)
    WORD port;
    BYTE value;
 
    if(IRQline < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        IRQline -= 8;
    }
    value = inb(port) | (1 << IRQline);
    outb(port, value);        
}
 
void intDisableIRQ(unsigned char IRQline) {
    WORD port;
    BYTE value;
 
    if(IRQline < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        IRQline -= 8;
    }
    value = inb(port) & ~(1 << IRQline);
    outb(port, value);        
}

void intInit(int pic1, int pic2) // initialozes interrupts
{
	// set IDT load struct params
    IDTl.limit = (sizeof(idtEntry) * 256) - 1;
    IDTl.base = reinterpret_cast<unsigned int>(IDT);
	
	// remap PIC
	
	/* send ICW1 */
	outb(PIC1, ICW1);
	outb(PIC2, ICW1);

	/* send ICW2 */
	outb(PIC1 + 1, pic1);	/* remap */
	outb(PIC2 + 1, pic2);	/*  pics */

	/* send ICW3 */
	outb(PIC1 + 1, 4);	/* IRQ2 -> connection to slave */
	outb(PIC2 + 1, 2);

	/* send ICW4 */
	outb(PIC1 + 1, ICW4);
	outb(PIC2 + 1, ICW4);

	/* disable all IRQs */
	outb(PIC1 + 1, 0xFF);
	
	// zero IDT
	mosSetMemory<idtEntry>(IDT, 256, brute_cast<idtEntry>(0x0000));
	
	// load IDT	
       idtFlush();
}

ASMCALL void idtFlush(); // asm("lidt [IDTl]")

// PIT driver

int taskNum = 0;
typedef void (*pitTask)();
pitTask tasks[10]; // task list to do

DEFWRAP(irq, 0);

DEFHANDLER(Irq, 0)
{
	for(int i = 0; i < taskNum; i++)
		tasks[i]();
	intEOI(0);
}

void numbers() // increments character in left-top
{
	volatile WORD* mem = (WORD*)0xB8000;
	*mem++;
}

void pitInit(unsigned long freq)
{
	taskNum = 0;

// set PIT freq
	freq = 1193180 / freq;
	outb(0x36, 0x43);
	outb(freq&0xff, 0x40);
	outb((freq>>8)&0xff, 0x40);
	
	intSetGate(0x20, ASHANDLER(irq0));
	intEnableIRQ(0);
	
	pitAddTask(numbers);
}

void pitAddTask(pitTask task)
{
	if(taskNum == 10)
		return; // can't add new task
	tasks[taskNum++] = task;
}

Re: Problem with software interrupts and IRQs

Posted: Tue Apr 01, 2014 7:32 am
by Combuster
I don't buy your "complete rewrite" as the first bug I mentioned is still present in this code.

Re: Problem with software interrupts and IRQs

Posted: Wed Apr 02, 2014 6:27 am
by kubawal
Combuster wrote:the first bug I mentioned is still present in this code
Is that what you mean?
Combuster wrote:(count the instructions to each of the PIC chips)
I don't understand what do you mean. In this code I send messgaes to both PICs...

I try to use another code for PIC remap ( http://www.osdever.net/tutorials/view/b ... t-tutorial ) but it also not works.

Re: Problem with software interrupts and IRQs

Posted: Fri Apr 04, 2014 12:12 pm
by kubawal
Can someone to explain this?

Re: Problem with software interrupts and IRQs

Posted: Fri Apr 04, 2014 12:54 pm
by Combuster
I also said you were bad at copy-pasting.
count the instructions to each of the PIC chips
Did you do this for the original version and your version yet?

Re: Problem with software interrupts and IRQs

Posted: Sat Apr 05, 2014 2:56 am
by kubawal
Combuster wrote:I also said you were bad at copy-pasting.
No, I'm simply not very good in english :)
What do you mean in 'count the instructions'?

Re: Problem with software interrupts and IRQs

Posted: Mon Apr 07, 2014 8:41 am
by kubawal
kubawal wrote:Can someone to explain this?