my keyboard interrupt not working when run with qemu

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.
Post Reply
yyiu002
Posts: 3
Joined: Thu Oct 20, 2022 12:05 am

my keyboard interrupt not working when run with qemu

Post by yyiu002 »

I am learning to develop a small os, it now can initialise GDT, IDT, display some text at screen, I am now trying to get keyboard interrupt, the example code I got from 30days diy OS by OSASK on day6 harib03e works. But my implementation not working, source code is at https://github.com/Lewis-Liu-1/myos/tree/main/day6/daye.

From web search, I realise I only load GDT, IDT, load kernel, not configuring keyboard, to enable PS/2 interrupt somehow. But I don't know how to do that.
devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

Re: my keyboard interrupt not working when run with qemu

Post by devc1 »

I guess you have remapped the pic right ?
The wiki has the answers, however here is the code to unmask keyboard interrupts :

Code: Select all

#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 init_ps2_keyboard(){ 
         OutPortB(PIC1_DATA,0b11111000); 
         OutPortB(PIC2_DATA,0b11101111); 
 }
To handle the interrupt, you must first read the keypress value from the 0x60 port : "inb 0x60".

When you are about to return from the interrupt you must signal EOI to the pic (End of interrupt) to the master, call this function at the end :

Code: Select all

void pic_end_master(){ 
         OutPortB(PIC1_COMMAND,PIC_EOI); 
 }
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: my keyboard interrupt not working when run with qemu

Post by Octocontrabass »

yyiu002 wrote:From web search, I realise I only load GDT, IDT, load kernel, not configuring keyboard, to enable PS/2 interrupt somehow. But I don't know how to do that.
When you initialize the IDT, you also initialize the PIC. Initializing the PIC causes the PIC to lose any pending interrupts. If there is a pending PS/2 interrupt when you initialize the PIC, the PS/2 controller will be waiting for you to acknowledge the interrupt by reading port 0x60, but the PIC won't deliver the interrupt.

Try reading port 0x60 after you initialize the PIC.
devc1 wrote:When you are about to return from the interrupt you must signal EOI to the pic
The PIC has an auto-EOI mode.
yyiu002
Posts: 3
Joined: Thu Oct 20, 2022 12:05 am

Re: my keyboard interrupt not working when run with qemu

Post by yyiu002 »

Thanks all for your help.

I tried not initialise GDT, seems working, like following:

Code: Select all

#define ADR_IDT			0x0026f800
#define LIMIT_IDT		0x000007ff
#define ADR_GDT			0x00270000
#define LIMIT_GDT		0x0000ffff
#define ADR_BOTPAK		0x00280000
#define LIMIT_BOTPAK	0x0007ffff
#define AR_DATA32_RW	0x4092
#define AR_CODE32_ER	0x409a
#define AR_INTGATE32	0x008e

void init_gdt_idt(void)
{
	struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
	struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;
	int i;

#if 0
	for (i = 0; i <= LIMIT_GDT / 8; i++) {
		set_segmdesc(gdt + i, 0, 0, 0);
	}
	set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
	set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
	load_gdtr(LIMIT_GDT, ADR_GDT);
#endif
	/* IDT�̏����� */
	for (i = 0; i <= LIMIT_IDT / 8; i++) {
		set_gatedesc(idt + i, 0, 0, 0);
	}
	load_idtr2(LIMIT_IDT, ADR_IDT);

	set_gatedesc(idt + 0x21, (int) asm_inthandler21, 1 * 8, AR_INTGATE32);
	set_gatedesc(idt + 0x27, (int) asm_inthandler27, 1 * 8, AR_INTGATE32);
	set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 1 * 8, AR_INTGATE32);

	initialize_pic();
	io_sti(); 

}

initialise GDT will set code and data to new location, does it mean I have to move code to those location, before initialise IDT?

I also saw following code:

Code: Select all

	set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
	set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
	set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
previous pat is "1*8", this time selector is "2*8", why?
yyiu002
Posts: 3
Joined: Thu Oct 20, 2022 12:05 am

Re: my keyboard interrupt not working when run with qemu

Post by yyiu002 »

Continue my question.
at entry.S I have a called LGDT instruction, which loads GDT tables etc. Therefore at above function init_gdt_idt, initialise GDT is not necessary anymore.

Initialise GDT twice will cause issues, why?
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: my keyboard interrupt not working when run with qemu

Post by Octocontrabass »

yyiu002 wrote:initialise GDT will set code and data to new location, does it mean I have to move code to those location, before initialise IDT?
You should set the base to 0 and the limit to 0xFFFFFFFF for your code and data segments.
yyiu002 wrote:previous pat is "1*8", this time selector is "2*8", why?
That's the code segment selector. The correct selector depends on where you put the code segment in your GDT.
yyiu002 wrote:Initialise GDT twice will cause issues, why?
You didn't set the base to 0 and the limit to 0xFFFFFFFF.
Post Reply