Cannot get keyboard interrupt handler working

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.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Cannot get keyboard interrupt handler working

Post by xSlendiX »

Hello everyone! I succeeded into adding interrupts to my kernel but the interrupts are not working (followed the interrupts tutorial on the wiki).
My interrupt handling:

Code: Select all

void irq1_handler(void) {
        // TODO: Add a keyboard handler right here
        register int i;
        int keycode;

        printf("key pressed/released\n");

        keycode = inb(0x60);

        i = inb(0x61);
        outb(0x61, i|0x80);
        outb(0x61, i);

        send_eoi(i);
}
send_eoi:

Code: Select all

void send_eoi(int irq)
{
   if (irq > 7)
      outb(0xA0, 0x20);
   outb(0x20, 0x20);
}
What's wrong?
Hello world!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

Hello!

Code: Select all

        i = inb(0x61);
        outb(0x61, i|0x80);
        outb(0x61, i);

        send_eoi(i);
You should detele this and replace it with EOI (as in interrupt tutorial):

Code: Select all

//EOI
outb(0x20, 0x20);
Sending EOI by reading port 0x61 is wrong because it is port of PC SPEAKER.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Re: Cannot get keyboard interrupt handler working

Post by xSlendiX »

Klakap wrote:Hello!

Code: Select all

        i = inb(0x61);
        outb(0x61, i|0x80);
        outb(0x61, i);

        send_eoi(i);
You should detele this and replace it with EOI (as in interrupt tutorial):

Code: Select all

//EOI
outb(0x20, 0x20);
Sending EOI by reading port 0x61 is wrong because it is port of PC SPEAKER.
For some reason it still doesn't work...
Hello world!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

Hm. How you are set IDT for irq1(post code)? And how are you write assemblers methods? Is any other irq work? Try handle irq0, it is timer irq and it is firing forever. If it isnt fire, you make something wrong with setting interrupts.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Re: Cannot get keyboard interrupt handler working

Post by xSlendiX »

Klakap wrote:Hm. How you are set IDT for irq1(post code)? And how are you write assemblers methods? Is any other irq work? Try handle irq0, it is timer irq and it is firing forever. If it isnt fire, you make something wrong with setting interrupts.
It doesn't spam me at all...
Here is my kernel.c:

Code: Select all

#include <stdio.h>
#include <stdbool.h>
#include <interrupts.h>
#include <ioaccess.h>
#include <pic.h>

#include <kernel/tty.h>

#define PIC_MASTER_COMMAND 0x20
#define PIC_MASTER_DATA 0x21
#define PIC_MASTER_IMR 0x21
#define PIC_SLAVE_COMMAND 0xA0
#define PIC_SLAVE_DATA 0xA1
#define PIC_SLAVE_IMR 0xA1

#define EOI 0x20

void pic_remap(int interrupt_num) {
	char buffer[20];
	itoa(interrupt_num, buffer, 10);
	printf ("Interrupt number: %s\n", buffer);
	
	outb (PIC_MASTER_COMMAND, 0x11);
	outb (PIC_SLAVE_COMMAND, 0x11);
	
	outb (PIC_MASTER_DATA, interrupt_num);
	outb (PIC_SLAVE_DATA, interrupt_num + 8);
	
	outb (PIC_MASTER_DATA, 0x04);
	outb (PIC_SLAVE_DATA, 2);
	
	outb (PIC_MASTER_DATA, 0x01);
	outb (PIC_SLAVE_DATA, 0x01);
}

void pic_masc_irqs (uint16_t mask) {
	outb (PIC_MASTER_IMR, (uint8_t) mask);
	outb (PIC_SLAVE_IMR, (uint8_t) (mask >> 8));
}

void pic_send_eoi (int irq_num) {
	outb (PIC_MASTER_COMMAND, EOI);
	if (irq_num > 7) { // If the IRQs are over 7 years old, we must send an EOI both to the master and slave
		outb (PIC_SLAVE_COMMAND, EOI);
	}
}

// IDT Table

struct IDT_entry{
	unsigned short int offset_lowerbits;
	unsigned short int selector;
	unsigned char zero;
	unsigned char type_attr;
	unsigned short int offset_higherbits;
};

struct IDT_entry IDT[286];

// Im too lazy so stfu

void idt_init(void) {
        extern int load_idt();
        extern int irq0();
        extern int irq1();
        extern int irq2();
        extern int irq3();
        extern int irq4();
        extern int irq5();
        extern int irq6();
        extern int irq7();
        extern int irq8();
        extern int irq9();
        extern int irq10();
        extern int irq11();
        extern int irq12();
        extern int irq13();
        extern int irq14();
        extern int irq15();

	unsigned long irq0_address;
        unsigned long irq1_address;
        unsigned long irq2_address;
        unsigned long irq3_address;
        unsigned long irq4_address;
        unsigned long irq5_address;
        unsigned long irq6_address;
        unsigned long irq7_address;
        unsigned long irq8_address;
        unsigned long irq9_address;
        unsigned long irq10_address;
        unsigned long irq11_address;
        unsigned long irq12_address;
        unsigned long irq13_address;
        unsigned long irq14_address;
        unsigned long irq15_address;
	unsigned long idt_address;
	unsigned long idt_ptr[2];

        /* remapping the PIC */
	outb(0x20, 0x11);
        outb(0xA0, 0x11);
        outb(0x21, 0x20);
        outb(0xA1, 40);
        outb(0x21, 0x04);
        outb(0xA1, 0x02);
        outb(0x21, 0x01);
        outb(0xA1, 0x01);
        outb(0x21, 0x0);
        outb(0xA1, 0x0);

	irq0_address = (unsigned long)irq0; 
	IDT[32].offset_lowerbits = irq0_address & 0xffff;
	IDT[32].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[32].zero = 0;
	IDT[32].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[32].offset_higherbits = (irq0_address & 0xffff0000) >> 16;

	irq1_address = (unsigned long)irq1; 
	IDT[33].offset_lowerbits = irq1_address & 0xffff;
	IDT[33].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[33].zero = 0;
	IDT[33].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[33].offset_higherbits = (irq1_address & 0xffff0000) >> 16;

	irq2_address = (unsigned long)irq2; 
	IDT[34].offset_lowerbits = irq2_address & 0xffff;
	IDT[34].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[34].zero = 0;
	IDT[34].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[34].offset_higherbits = (irq2_address & 0xffff0000) >> 16;

	irq3_address = (unsigned long)irq3; 
	IDT[35].offset_lowerbits = irq3_address & 0xffff;
	IDT[35].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[35].zero = 0;
	IDT[35].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[35].offset_higherbits = (irq3_address & 0xffff0000) >> 16;

	irq4_address = (unsigned long)irq4; 
	IDT[36].offset_lowerbits = irq4_address & 0xffff;
	IDT[36].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[36].zero = 0;
	IDT[36].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[36].offset_higherbits = (irq4_address & 0xffff0000) >> 16;

	irq5_address = (unsigned long)irq5; 
	IDT[37].offset_lowerbits = irq5_address & 0xffff;
	IDT[37].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[37].zero = 0;
	IDT[37].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[37].offset_higherbits = (irq5_address & 0xffff0000) >> 16;

	irq6_address = (unsigned long)irq6; 
	IDT[38].offset_lowerbits = irq6_address & 0xffff;
	IDT[38].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[38].zero = 0;
	IDT[38].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[38].offset_higherbits = (irq6_address & 0xffff0000) >> 16;

	irq7_address = (unsigned long)irq7; 
	IDT[39].offset_lowerbits = irq7_address & 0xffff;
	IDT[39].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[39].zero = 0;
	IDT[39].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[39].offset_higherbits = (irq7_address & 0xffff0000) >> 16;

	irq8_address = (unsigned long)irq8; 
	IDT[40].offset_lowerbits = irq8_address & 0xffff;
	IDT[40].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[40].zero = 0;
	IDT[40].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[40].offset_higherbits = (irq8_address & 0xffff0000) >> 16;

	irq9_address = (unsigned long)irq9; 
	IDT[41].offset_lowerbits = irq9_address & 0xffff;
	IDT[41].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[41].zero = 0;
	IDT[41].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[41].offset_higherbits = (irq9_address & 0xffff0000) >> 16;

	irq10_address = (unsigned long)irq10; 
	IDT[42].offset_lowerbits = irq10_address & 0xffff;
	IDT[42].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[42].zero = 0;
	IDT[42].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[42].offset_higherbits = (irq10_address & 0xffff0000) >> 16;

	irq11_address = (unsigned long)irq11; 
	IDT[43].offset_lowerbits = irq11_address & 0xffff;
	IDT[43].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[43].zero = 0;
	IDT[43].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[43].offset_higherbits = (irq11_address & 0xffff0000) >> 16;

	irq12_address = (unsigned long)irq12; 
	IDT[44].offset_lowerbits = irq12_address & 0xffff;
	IDT[44].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[44].zero = 0;
	IDT[44].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[44].offset_higherbits = (irq12_address & 0xffff0000) >> 16;

	irq13_address = (unsigned long)irq13; 
	IDT[45].offset_lowerbits = irq13_address & 0xffff;
	IDT[45].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[45].zero = 0;
	IDT[45].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[45].offset_higherbits = (irq13_address & 0xffff0000) >> 16;

	irq14_address = (unsigned long)irq14; 
	IDT[46].offset_lowerbits = irq14_address & 0xffff;
	IDT[46].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[46].zero = 0;
	IDT[46].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[46].offset_higherbits = (irq14_address & 0xffff0000) >> 16;

        irq15_address = (unsigned long)irq15; 
	IDT[47].offset_lowerbits = irq15_address & 0xffff;
	IDT[47].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
	IDT[47].zero = 0;
	IDT[47].type_attr = 0x8e; /* INTERRUPT_GATE */
	IDT[47].offset_higherbits = (irq15_address & 0xffff0000) >> 16;

	/* fill the IDT descriptor */
	idt_address = (unsigned long)IDT ;
	idt_ptr[0] = (sizeof (struct IDT_entry) * 286) + ((idt_address & 0xffff) << 16);
	idt_ptr[1] = idt_address >> 16 ;

	load_idt(idt_ptr);
}

void kernel_main(void) {
	terminal_initialize();
	
	// outb('a', 0xE9);
	
	puts("Kernel joined the game.");
	
	// puts("Remapping PIC: IRQ=1 (Keyboard interrupt)");
	
	// pic_remap(1);
	
	puts("Remaping the PIC and initializing idt");
	
	idt_init();
	
	puts ("Checking if interrupts are enabled.");
	
	bool a = are_interrupts_enabled();
	
	if (a == true) {
		puts("Interrups are enabled");
	} else {
		puts("Interrupts are disabled");
	}
	
	puts ("Nothing left to do. The kernel is now sleeping.");
}
Hello world!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

You use method load_idt(). This method *must* be write in assembler, no in C. If you haven`t it, I think that it is error.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Re: Cannot get keyboard interrupt handler working

Post by xSlendiX »

Klakap wrote:You use method load_idt(). This method *must* be write in assembler, no in C. If you haven`t it, I think that it is error.
Why so? Interrupts are enabled properly.

https://imgur.com/a/MJ7jYpl
Hello world!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

How is your load_idt() method look? It should be:

Code: Select all

load_idt:
	mov edx, [esp + 4]    ;get IDT adress
	lidt [edx]    ;load IDT
	sti    ;enable interrupts
	ret    ;return
in assembler. No in C. I don`t now how your OS detecting whether is interrupts set, but load_idt() should look as I post.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Re: Cannot get keyboard interrupt handler working

Post by xSlendiX »

Klakap wrote:How is your load_idt() method look? It should be:

Code: Select all

load_idt:
	mov edx, [esp + 4]    ;get IDT adress
	lidt [edx]    ;load IDT
	sti    ;enable interrupts
	ret    ;return
in assembler. No in C. I don`t now how your OS detecting whether is interrupts set, but load_idt() should look as I post.
You can look at the project on github
Hello world!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

Please in which file is load_idt()? I cant found it.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Re: Cannot get keyboard interrupt handler working

Post by xSlendiX »

Klakap wrote:Please in which file is load_idt()? I cant found it.
https://github.com/xslendix/RaduOS/blob ... i386/irq.S
Hello world!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

Thank you.
See my comments:

_start:
movl $stack_top, %esp

;For get interrupts work in GRUB, you must load GDT. I recommended make it here. Look at interrupts tutorial in to part Interrupts in GRUB

# Call the global constructors.
call _init

# Transfer control to the main kernel.
call kernel_main

# Hang if kernel_main unexpectedly returns.
cli ;HERE IS PROBLEM This is disable interrupts!!! Delete it.
1: hlt ;You can`t use hlt if you are use interrupts. replace this with jmp $
jmp 1b
nullplan
Member
Member
Posts: 1801
Joined: Wed Aug 30, 2017 8:24 am

Re: Cannot get keyboard interrupt handler working

Post by nullplan »

Klakap wrote: # Hang if kernel_main unexpectedly returns.
cli ;HERE IS PROBLEM This is disable interrupts!!! Delete it.
1: hlt ;You can`t use hlt if you are use interrupts. replace this with jmp $
jmp 1b
Erm, no, this is the stuff after the kernel_main. That is, this is code that only runs if kernel_main returned, which it shouldn't.

Oh, so there's the problem. kernel_main() does return. And then you CLI and then you wait for interrupts. No wonder it isn't working. You either need an infinite loop in kernel_main() or you need to loose the CLI.

However, Klakap, hlt is perfectly usable with interrupts. It will disable the CPU until the next interrupt comes in. Just the CLI before that prevents the CPU from recognizing the interrupt.
Carpe diem!
Klakap
Member
Member
Posts: 299
Joined: Sat Mar 10, 2018 10:16 am

Re: Cannot get keyboard interrupt handler working

Post by Klakap »

nullplan wrote: However, Klakap, hlt is perfectly usable with interrupts. It will disable the CPU until the next interrupt comes in. Just the CLI before that prevents the CPU from recognizing the interrupt.
Yes? I have problem with hlt beacuse if I use it, after get irq, system was reboot. But I am agree, kernel_main() is return and it causes error.
xSlendiX
Posts: 20
Joined: Tue Jan 08, 2019 7:20 am

Re: Cannot get keyboard interrupt handler working

Post by xSlendiX »

nullplan wrote:
Klakap wrote: # Hang if kernel_main unexpectedly returns.
cli ;HERE IS PROBLEM This is disable interrupts!!! Delete it.
1: hlt ;You can`t use hlt if you are use interrupts. replace this with jmp $
jmp 1b
Erm, no, this is the stuff after the kernel_main. That is, this is code that only runs if kernel_main returned, which it shouldn't.

Oh, so there's the problem. kernel_main() does return. And then you CLI and then you wait for interrupts. No wonder it isn't working. You either need an infinite loop in kernel_main() or you need to loose the CLI.

However, Klakap, hlt is perfectly usable with interrupts. It will disable the CPU until the next interrupt comes in. Just the CLI before that prevents the CPU from recognizing the interrupt.
When I put a loop in kernel_main() i get exited from my OS back to GRUB, same thing when i remove the cli
Hello world!
Post Reply