Cannot enable keyboard IRQ in protected mode (bochs)

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
User avatar
micccy
Posts: 11
Joined: Sat Sep 05, 2015 2:10 am
Libera.chat IRC: micccy
Location: Italy

Cannot enable keyboard IRQ in protected mode (bochs)

Post by micccy »

(I'm writing this hoping that my english is good enough)

Hi all, I hope that someone can help me with a problem writing my little OS. (I personally like the idea to write the most of it in assembly. I'm working in text mode, accessing it by the video RAM, only for debug purposes.

The problem is that, after I switch into protected mode(the IDT is loaded whit all the "now unused" entries pointing to a IRETD instruction), I begin inizialising the PIT (I wrote a clock using IRQ0 (interrupt 20h) that works fine), and then I initialise the PS/2 controller and the keyboard.
Well, at the end of the initialising i enable IRQ1 on keyboard strike in the config byte, then I enable all the interrupts and perform a JMP $ instruction. I've not written a specific interrupt for the keyboard yet but I use a generic one that does nothing(Posted at the end of this post), only to verify if the keyboard is working: i set a breakpoint at 0x00001200 (where the generic interrupt is) using "lb 0x00001200", and then I strike a key to see if IRQ1 is raised (in this case bochs will break). During this process my PIT-based clock works, so I now that CPU is working and there isn't a problem whit the interrupts system. But interrupt 21h (corresponding to IRQ1) is never raised, and the PS/2 data buffer gets full. I've tried lots of changes but none work. Can You help me?
The code is(I will list all the functions used under the code):

Initialize the PS/2 controller:

Code: Select all

        CALL	K_W_I  				;Begin initializing
	MOV	AL,20h				;
	OUT	64h,AL				;Read config byte command
	CALL	K_W_O				;
 	IN	AL,60h				;Reading config byte
	AND	AL,10111100b			;Disable interrupt and translation
	MOV	BL,AL				        ;
	CALL	K_W_I				;
	MOV	AL,60h				;
	OUT	64h,AL				;Write config byte command
	CALL	K_W_I				;
	MOV	AL,BL				        ;
	OUT	60h,AL				;Ok
	CALL	K_W_I				;
 	MOV	AL,0AAh				;Controller TEST
	OUT	64h,AL				;
 	CALL	K_W_O				;
 	IN	AL,60h				;
	CMP	AL,55h				;
	JNZ	RESET				;Done
	CALL	K_W_I				;
	MOV	AL,0ABh				;First port test
	OUT	64h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,00h				;
	JNZ	RESET				;
	CALL	K_W_I				;
	MOV	AL,0A9h				;Second port test
	OUT	64h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,00h				;
	JNZ	RESET				;
	CALL	K_W_I				;
	MOV	AL,0AEh				;Enabling keyboard
	OUT	64h,AL				;
Keyboard initialize:

Code: Select all

RED0:	CALL	K_W_I				;Keyboard initialize
	MOV	AL,0F5h				;Stop key scanning
	OUT	60h,AL				;
	CALL	K_W_O				;
 	IN	AL,60h				;
 	CMP	AL,0FAh				;
	JNZ	RED0				        ;
RED1:	CALL	K_W_I				;Reset keyboard
	MOV	AL,0FFh				;
	OUT	60h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,0FAh				;
	JNZ	RED1				        ;
	CALL	K_W_O				;
	IN	AL,60h				;Ok
	CMP	AL,0AAh				;
	JNZ	RESET				;
RED3:	CALL	K_W_I				;Setting scan code set 2
	MOV	AL,0F0h				;
	OUT	60h,AL				;
	CALL	K_W_I				;
	MOV	AL,02h				;
	OUT	60h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,0FAh				;
	JNZ	RED3				        ;Ok
RED4:	CALL	K_W_I				;Setting typematic byte
	MOV	AL,0F3h				;
	OUT	60h,AL				;
	CALL	K_W_I				;
	MOV	AL,00h				;
	OUT	60h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,0FAh				;
	JNZ	RED4				        ;Ok
RED5:	CALL	K_W_I				;Setting LEDs
	MOV	AL,0EDh				;
	OUT	60h,AL				;
	CALL	K_W_I				;
	MOV	AL,02h				;
	OUT	60h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,0FAh				;
	JNZ	RED5				        ;Ok
RED6:	CALL	K_W_I				;Enabling key scanning
	MOV	AL,0F4h				;
	OUT	60h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	CMP	AL,0FAh				;
	JNZ	RED6				        ;Ok.

	CALL	K_W_I				;Enabling IRQ1 in the config byte
	MOV	AL,20h				;
	OUT	64h,AL				;
	CALL	K_W_O				;
	IN	AL,60h				;
	OR	AL,00000001b			;
	MOV	BL,AL				        ;
	CALL	K_W_I				;
	MOV	AL,60h				;
	OUT	64h,AL				;
	CALL	K_W_I				;
	MOV	AL,BL				        ;
	OUT	60h,AL				;
	JMP	COXI				       ;Ok

COXI: ...
Functions used:

Code: Select all

K_W_I:	IN      AL,64h				;Waiting until the command buffer is clear
	      AND	        AL,00000010b			;
          CMP    	AL,02h				;
          JZ      K_W_I				;
          RET					;Ok

K_W_O:	IN      AL,64h				;Waiting until there is something in the data buffer
	       AND	AL,00000001b			;
          CMP    	AL,01h				;
          JNZ     K_W_O				;
          RET					;Ok

RESET:      CALL K_W_I                ;
               MOV	AL,0FEh				;Perform a CPU reset
	       OUT	64h,AL				;Ok
If you want I can post a link to the complete source code (Interrupts,first bootloader,complete bootloader code...)

Bochs debug:

Code: Select all

01608908314i[BIOS  ] Booting from 0000:7c00
01681222589i[      ] Ctrl-C detected in signal handler.
Next at t=1681283171
(0) [0x0000000fe869] f000:e869 (unk. ctxt): cli                       ; fa
<bochs:2> lb 0x00001200
<bochs:3> c
01770989853i[KBD   ] keyboard: scan convert turned off
01770989928i[KBD   ] reset-disable command received
01770992023i[KBD   ] Switched to scancode set 2
01770993016i[KBD   ] setting typematic info
01770993024i[KBD   ] setting delay to 250 mS (unused)
01770993024i[KBD   ] setting repeat rate to 30,0 cps (unused)
27730184000i[KBD   ] internal keyboard buffer full, ignoring scancode.(a0)
35670360000i[KBD   ] internal keyboard buffer full, ignoring scancode.(1f)
35781548000i[KBD   ] internal keyboard buffer full, ignoring scancode.(9f)
Sorry for the ugly layout of the code, i don't now why it moved like that

EDIT: The generic interrupt that's at 0x00001200 is:

Code: Select all

RETY:   PUSHFD                     ;Here we are at 0x00001200
   PUSH   EDX         ;
   PUSH   ECX         ;
   PUSH   EBX         ;
   PUSH   EAX         ;
   JMP   EXIT         ;Done

.... other interrupts code

EXIT: MOV   AL,20h         ;Most interrupts jump here at their end
   OUT   0A0h,AL         ;
   OUT   20h,AL         ;
   POP   EAX            ;
   POP   EBX            ;
   POP   ECX            ;
   POP   EDX            ;
   POPFD            ;
   IRETD               ;Return
Last edited by micccy on Mon Sep 07, 2015 8:59 am, edited 3 times in total.
You learn more by a single triple fault than by reading the whole Intel specification...
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: Cannot enable IRQ1 in protected mode (bochs)

Post by SpyderTL »

In your interrupt handler, for any interrupts coming from the PIC, you need to let the PIC know that the interrupt has been handled, or else it won't send any more interrupts. A simple IRET won't do it.

Check out http://wiki.osdev.org/PIC#End_of_Interrupt
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
micccy
Posts: 11
Joined: Sat Sep 05, 2015 2:10 am
Libera.chat IRC: micccy
Location: Italy

Re: Cannot enable IRQ1 in protected mode (bochs)

Post by micccy »

SpyderTL wrote:In your interrupt handler, for any interrupts coming from the PIC, you need to let the PIC know that the interrupt has been handled, or else it won't send any more interrupts. A simple IRET won't do it.

Check out http://wiki.osdev.org/PIC#End_of_Interrupt
I'm sorry, I didn't wrote it but at 0x00001200 there isn't a simple IRETD, but a procedure that sends the EOI and performs the IRETD used by most of mine interrupts:

Code: Select all

RETY:	PUSHFD                     ;Here we are at 0x00001200
	PUSH	EDX			;
	PUSH	ECX			;
	PUSH	EBX			;
	PUSH	EAX			;
	JMP	EXIT			;Done

.... other interrupts code

EXIT: MOV	AL,20h			;
	OUT	0A0h,AL			;
	OUT	20h,AL			;
	POP	EAX				;
	POP	EBX				;
	POP	ECX				;
	POP	EDX				;
	POPFD				;
	IRETD					;Return

Most interrupts jump on "EXIT" at them end...

Post edited.

P.S. the CPU never jumps to 0x00001200, because i have a breakpoint to notify that. I think that the problem is that IRQ1 is never raised, but why if I've correctly enabled the PS/2 controller and the keyboard? Perhaps there's something wrong that i can't find. I've used the debugger to see if the IDT is correctly written, and it is. The other interrup based on IRQ0 works all the time, showing me a real-time clock in the under-left corner of the screen, so the PIC is working (IRQ0 correctly pointing on my clock interrupt 20h)
You learn more by a single triple fault than by reading the whole Intel specification...
User avatar
micccy
Posts: 11
Joined: Sat Sep 05, 2015 2:10 am
Libera.chat IRC: micccy
Location: Italy

Re: Cannot enable keyboard IRQ in protected mode (bochs)

Post by micccy »

I've tried to "poll" the keyboard checking if there is data in the buffer every time that the IRQ0 occurs (every 54ms), and using 0xE9 port hack to display in the bochs debugger if a key strike was detected. The keyboard seems to work correctly. I've also put the brakpoint on 0x00001201 because bochs seems to don't let you put a breakpoint on the first instruction of an interrupt. The question now is: If the PS/2 controller correctly receive the data from the keyboard, why doesn't generate an IRQ1?
You learn more by a single triple fault than by reading the whole Intel specification...
User avatar
micccy
Posts: 11
Joined: Sat Sep 05, 2015 2:10 am
Libera.chat IRC: micccy
Location: Italy

Re: Cannot enable keyboard IRQ in protected mode (bochs)

Post by micccy »

Problem solved. It was all my fault.
The PS/2 controller seems that doesn't receive any data if IRQ's are masked... waiting for when the IRQ's aren't masked to fill the internal buffer with the keyboard data. I don't know why, but when i flush the buffer just before enabling the interrupts(standard and NMI), after the interrupt enabling the buffer seemed to be always full (and none IRQ1 is raised). But if i flush the PS/2 controller buffer after the interrupt enabling, everything seems to work correctly. Someone knows why? It's perhaps a bug of my own code or it's a normal thing? (The code that flushes the buffer was exactly the same in the two cases)

Thank you for psicological support!

P.S. After receiving the reset command the keyboard seems to return an ACK response byte(0xFA), and THEN a test-passed byte (0xAA). "8042" PS/2 Controller page in the wiki seem to say that the keyboard will send 0xAA and then 0xFA. I don't fix it because I'm not 100% sure that's always like that, but I saw this on two computers and in bochs. It may be added to the PS2_Keyboard page
You learn more by a single triple fault than by reading the whole Intel specification...
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Cannot enable keyboard IRQ in protected mode (bochs)

Post by Octocontrabass »

GiacoMic wrote:I don't know why, but when i flush the buffer just before enabling the interrupts(standard and NMI), after the interrupt enabling the buffer seemed to be always full (and none IRQ1 is raised). But if i flush the PS/2 controller buffer after the interrupt enabling, everything seems to work correctly. Someone knows why?
That's a race condition. If you clear the buffer before enabling interrupts, the buffer has time to be filled again before the interrupts are enabled.
Post Reply