Page 1 of 1

my keyboard interrupt not working when run with qemu

Posted: Thu Oct 20, 2022 12:09 am
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.

Re: my keyboard interrupt not working when run with qemu

Posted: Thu Oct 20, 2022 9:06 am
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); 
 }

Re: my keyboard interrupt not working when run with qemu

Posted: Thu Oct 20, 2022 10:09 am
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.

Re: my keyboard interrupt not working when run with qemu

Posted: Thu Oct 20, 2022 6:28 pm
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?

Re: my keyboard interrupt not working when run with qemu

Posted: Thu Oct 20, 2022 6:39 pm
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?

Re: my keyboard interrupt not working when run with qemu

Posted: Thu Oct 20, 2022 6:43 pm
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.