Bochs Keyboard Input

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
atilali
Posts: 9
Joined: Sun Feb 26, 2017 7:52 am

Bochs Keyboard Input

Post by atilali »

Hello, i am trying to program 8259A in bochs. But there are problems that i cant solve by myself so i'd like to ask them here. My question is when we map Master 8259's interrupt vectors to 0x20-0x27 range, does it mean that i need correct IVT entries between the physical addresses 0x80-A0 (i am in real mode and ivt sits at 0x000-0x400 so i thought interrupt numbers 0x20-0x27 would map to 0x80-0xA0 physical address range)?

If i call int 0x21(i think this is keyboard interrupt after mapping?) from assembly it works(a string printed on screen). But when i press any key it doesn't work. I'd appreciate any help which enlightens my misunderstandings on subject.

Code: Select all

cli
mov ax,0x7c0
mov ds,ax

mov ax,0x7000
mov sp,ax

xor ax,ax
mov es,ax
mov ax,0x84;0x21th interrupt address
mov di,ax

mov ax,[int_offset]
mov [es:di],ax
inc di
inc di

mov ax,[int_segment]
mov [es:di],ax

;ICW 1
mov	al, 0x11
out	0x20, al
out	0xA0, al
;ICW 2
mov	al, 0x20		
out	0x21, al
mov	al, 0x28		
out	0xA1, al
;ICW 3
mov	al, 0x4		
out	0x21, al
mov	al, 0x2		
out	0xA1, al	
;ICW 4
mov	al, 1		
out	0x21, al
out	0xA1, al

;OCW1 no mask
;mov	al, 0
;out	0x21, al
;out	0xa1, al

sti

int 0x21

end:
	jmp end

;prints string in [ds:si] to screen	
printStr:
	pusha;
	push di
	push es
	cld;inc si after lodsb
loadchr:
	lodsb;
	cmp al,0x00;
	je printStrFinish;
	cmp al,0x0A;
	je newline;
	mov ah,0x4e;
	mov di,[video_memory_index];
	mov es,[video_memory_base];
	mov [es:di],ax;
	inc di;
	inc di;
	mov [video_memory_index],di;
	jmp loadchr;
newline:
	push dx;
	push bx;
	push ax;
	mov bx,0x00A0;
	add [video_memory_index],bx;
	mov dx,0;
	mov ax,[video_memory_index];
	div bx;
	sub [video_memory_index],dx;
	pop ax;
	pop bx;
	pop dx;
	jmp loadchr;
printStrFinish:
	pop es
	pop di
	popa;
	ret;

video_memory_base dw 0xb800;
video_memory_index dw 0x0000;
disk_drive_number_str db 'DiskDriveNumber:',0x00;
int_offset dw 0x7d00
int_segment dw 0x0000
times 256-($-$$) db 0

mov ax,disk_drive_number_str;My interrupt handler which sits at 0x7d00
mov si,ax
call printStr
mov al, 0x20;send EOI
out 0x20, al
iret

times 510-($-$$) db 0
db 0x55
db 0xAA
User avatar
sleephacker
Member
Member
Posts: 97
Joined: Thu Aug 06, 2015 6:41 am
Location: Netherlands

Re: Bochs Keyboard Input

Post by sleephacker »

To get interrupts from the keyboard they first have to be enabled in the PS/2 controller configuration byte.
Also note that you should save and restore all registers you modify in an IRQ handler (in your case at least ax and si), because you don't know if the code that got interrupted was using any of those registers.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Bochs Keyboard Input

Post by BrightLight »

I haven't reviewed your code to see if the PIC is being configured correctly, but sleephacker is right: you need to configure the keyboard itself as well and not just the PIC, because the keyboard can also be used in polling mode instead of IRQs, and you have no real way of knowing how the BIOS configured the keyboard. After reading sleephacker's link to configure the PS/2 controller itself, you also need to configure the PS/2 keyboard. Read the Wiki article on PS/2 keyboards. Your homework for today will be figuring out which commands you need to send to tell the keyboard to send IRQs. :)

Hint: You'll need to reset the keyboard, configure the auto-repeat delay/speed, and enable IRQs as well.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Bochs Keyboard Input

Post by MichaelPetch »

Although I wouldn't structure your code the way you did, I'll just identify where I think things have gone wrong.You seem to have remapped both PICS to 0x20and 0x28. The problem is that the entire BIOS Interrupt Vector Table is pointing all of its routines to the old locations. If any external interrupt comes in other than the keyboard (which you have set up an interrupt service routine for) they will no longer be going to the original interrupt routines.

Since you have only dealt with the keyboard ISR after remapping you can disable all the external interrupts besides the keyboard by updating the masks with an instruction sequence like:

Code: Select all

;OCW1 no mask
mov   al, 0xFD
out   0x21, al
mov   al, 0xFF
out   0xa1, al
This should only enable the keyboard interrupt. One may ask why enabling the other interrupts will cause an issue. It is more than likely the BIOS originally installed default interrupt handlers for 0x20 to 0x2f. Usually it is to a BIOS function that simply does an IRET. The problem is that the default is almost certainly not sending an End of Interrupt (EOI) to the PICs. Effectively after the first timer tick occurs and IRET likely occurs without an EOI. Since IRQ0 is highest priority all future interrupts are effectively disabled so your system will appear to receive no further interrupts. This is why it is important to attach proper Interrupt service routines for any of the external interrupts that may be active.

As has been already mentioned your interrupt service routine clobbers registers. Your ISR should save and restore all the registers it will alter. This could easily be done with a `pusha` instruction at the beginning of your ISR and a `popa` before the `IRET`. PUSHA/POPA were only available on 80186 compatible processors and later. If you are targeting a real 8086 then you have to push each register individually and pop them individually.

On a side note. In real mode CS is the only general purpose (or segment) register that can be guaranteed to have a specific/known value when control is transferred to your ISR. This is because CS gets set to the value you placed into the Interrupt Vector Table for that ISR. You can't even rely on DS being what you expect.
Post Reply