IDT / interrrupts / Keyboard

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
skid
Posts: 11
Joined: Wed Dec 17, 2014 12:43 pm

IDT / interrrupts / Keyboard

Post by skid »

I cannot seem to wrap my head around this, the unhandled_int gets called but the keyboard handler causes a triple-fault.
Could anyone guide me to what goes wrong and why?

Code: Select all

[bits 16]			
[org 0x7c00]

;- flush segments + set stack
	cli	
	xor ax, ax
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov sp, 0x9c00

	jmp 0:start		

start:
;- init video
	mov ax, 0003h		; subroutine 00, mode 03
	int 10h
	
;-  quick enable a20 
enable_a20_fv:
	in al, 92h
	or al, 2
	out 92h, al
	
	cli
	lgdt [gdtr]
	lidt [idtr]

	mov eax, cr0
	or al, 1         ; enable paging / PE-bit
	mov cr0, eax

	jmp gdt.code:main

[bits 32]
main:
	mov eax, gdt.data
	mov ds, ax
	mov es, ax

	call pic_remap
	int 3h

	jmp $ 

; 	FUNCTIONS

read_keyboard:
	pusha 
	cli 
	in al,64h        ; read status
	test al,01h      ; 
    jz read_keyboard
    in al,60h        ; read scancode
    mov bx, ax
    mov al, [bx+keymap]
    ;mov [key], al
    mov [es:0xb8000], al
    mov al,0x20		; clear irq-buffer
	out 0x20, al
	sti
	popa
    iret 

unhandled_int:
	pusha
 	
    mov byte [es:0xb8000], '*'

 	popa
 	iret

pic_remap: 
    cli 
    
    mov  al,0x11			                  ; put both 8259s in init mode 
	out  0x20,al 
	out  0xA0,al 
 
	mov  al,0x20			                  ; remap pic irq0-irq7 -> int 0x20-27 
	out  0x21,al 
 
	mov  al,0x28 
	out  0xA1,al			                  ; remap pic irq8-irq15 -> int 0x28-30 
 
	mov  al,4                                         ; icw3 pic1(master) 
	out  0x21,al                                      ; bit 2=1: irq2 is the slave 
 
	mov  al,2                                         ; icw3 pic2 
	out  0xA1,al                                      ; bit 1=1: slave id is 2 
 
	mov  al,1                                         ; icw4 to both controllers 
	out  0x21,al                                      ; bit 0=1: 8086 mode 
	out  0xA1,al 
        
    cli 
    mov  al,255                                       ; mask all irqs 
    out  0xa1,al 
    out  0x21,al 
    ret 
 

; 	DATA SECTION

int_msg db 'unhandled interrrupt', 0

key 	db 0
keymap:
     	db    0, 0, '1','2','3','4','5','6','7','8','9','0','-','=',
     	db    0, 0, 'q','w','e','r','t','y','u','i','o','p','[',']',
     	db    0, 0, 'a','s','d','f','g','h','j','k','l',';',"'",'`',
        db    0,'/','z','x','c','v','b','n','m','7','8','9',',','.',
        db    0, '*'

; global descriptor tables
;--------------------------------------
gdt:
.null	equ $-gdt 		; 0x0 		
		dq 0
.code 	equ $-gdt 		; 0x8
		dw 0ffffh		; limit 4 Gib 
		dw 0000h   		; base 1-2
		db 0        	; base 3
		db 10011010b	; type
		db 11001111b	; flags
		db 0 			; base 4

.data 	equ $-gdt 	    ; 0x10
		dw 0ffffh   	; limit 4 Gib 
		dw 0000h		; base 1-2	 
		db 0        	; base 3
		db 10010010b	; type
		db 11001111b	; flags
		db 0 			; base 4
gdt_end:
gdtr: 
		dw gdt_end - gdt 	; size
		dd gdt              ; base address

idt:
; int 0 - divide error
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0

; int 1 - debug exception
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 2 - intel reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 3 - breakpoint
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 4 - overflow
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 5 - bounds check
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 6 - invalid opcode
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 7 - coprocessor not available
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 8 - double fault
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 9 - coprocessor segment overrun
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int A - invalid tss
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int B - segment not present
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int C - stack exception
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int D - triple fault
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int E - page fault
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int F - intel reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 10 - stack exception
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 11 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 12 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 13 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 14 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 15 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 16 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 17 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 18 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 19 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 20 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 21 - keyboard
		dw read_keyboard
		dw gdt.code
		db 0
		db 10001110b
		dw 0
idt_end:
idtr:
  		dw idt_end - idt - 1
  		dd idt

times  510 - ($-$$) db 0

bios_signature:
db 55h 
db 0AAh	
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: IDT / interrrupts / Keyboard

Post by iansjack »

At a quick glance:

1. You mask all hardware interrupts.
2. You never do a "sti".
3. You don't set SS.

I'm sure there are many more points of interest. So I don't see how any interrupts fire in the first place.

Whatever, a triple fault almost always means multiple page faults or general protection faults. I'd suggest that you write rudimentary handlers for these two exceptions which stop the processor and display some indication of which fault it is and perhaps the value of the instruction pointer. That way you know where to look. Mind, with an invalid stack, which seems to be the case, you are still going to get a triple fault.
freecrac
Member
Member
Posts: 69
Joined: Thu Sep 20, 2012 5:11 am
Location: germany hamburg

Re: IDT / interrrupts / Keyboard

Post by freecrac »

Hello.
Within a keyboard ISR the read status is not needed, because it only execute, if the keyboard have data in its output buffer and otherwise no interupt is generated:

Code: Select all

in al,64h ; read status
test al,01h
jz read_keyboard
Dirk
skid
Posts: 11
Joined: Wed Dec 17, 2014 12:43 pm

Re: IDT / interrrupts / Keyboard

Post by skid »

Tried to make some changes, if I understood you correct iansjack.
if I point any of int 0 - 19h to sys_talk (prints) or read_keyboard (doesnt seem to read or write, just blank) they fire, but 20h or above triggers the triple-fault. Is the problem in irq-remapping code? It's stolen so... As I said I can't really get my head around this.
How do you get debug-output to the console with qemu (linux)?

Code: Select all

[bits 16]				; real-mode
[org 0x7c00]

;- flush segments + set stack
	cli	
	xor ax, ax
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	;mov ss, ax
	;mov sp, 0x9c00

	jmp 0:start		

start:
;- init video
	mov ax, 0003h		; subroutine 00, mode 03
	int 10h
	
;-  quick enable a20 
enable_a20_fv:
	in al, 92h
	or al, 2
	out 92h, al
	
	cli
	lgdt [gdtr]
	lidt [idtr]

	mov eax, cr0
	or al, 1         ; enable paging / PE-bit
	mov cr0, eax

	jmp gdt.code:main

[bits 32]
main:
	mov eax, gdt.data
	mov ds, ax
	mov es, ax
	sti

        pic_remap
	int 21h

	jmp $ 

; 	FUNCTIONS

read_keyboard:
	pusha 
	cli 
	;in al,64h        ; read status
	;test al,01h      ; 
    ;jz read_keyboard
    in al,60h        ; read scancode
    mov bx, ax
    mov al, [bx+keymap]
    ;mov [key], al
    mov [es:0xb8000], al
    mov al,0x20		; clear irq-buffer
	out 0x20, al
	sti
	popa
    iret 

unhandled_int:
	pusha
 	
    mov byte [es:0xb8000], '*'
    hlt
 	popa
 	iret

sys_talk:
	pusha
 	
    mov byte [es:0xb8000], '!'
    hlt
 	popa
 	iret


triple_fault_handler:
	pusha
  	
    mov byte [es:0xb8000], 'T'
    hlt
 	popa
 	iret

page_fault_handler:
	pusha
  	
    mov byte [es:0xb8000], 'P'
    hlt
 	popa
 	iret

nmi_handler:
	pusha
  	
    mov byte [es:0xb8000], 'N'
    hlt
 	popa
 	iret

pic_remap: 
    cli 
    
    mov  al,0x11			                  ; put both 8259s in init mode 
	out  0x20,al 
	out  0xA0,al
 
	mov  al,0x20			                  ; remap pic irq0-irq7 -> int 0x20-27 
	out  0x21,al 
 
	;mov  al,0x28 
	;out  0xA1,al			                  ; remap pic irq8-irq15 -> int 0x28-30 
 
	mov  al,4                                         ; icw3 pic1(master) 
	out  0x21,al                                      ; bit 2=1: irq2 is the slave 
 
	mov  al,2                                         ; icw3 pic2 
	out  0xA1,al                                      ; bit 1=1: slave id is 2 
 
	mov  al,1                                         ; icw4 to both controllers 
	out  0x21,al                                      ; bit 0=1: 8086 mode 
	out  0xA1,al 
        
    mov  al,21  									; mask irqs 
    out  0xa1,al 
    out  0x21,al 
    sti
    ret 
 
; 	DATA SECTION
keymap:
     	db    0, 0, '1','2','3','4','5','6','7','8','9','0','-','=',
     	db    0, 0, 'q','w','e','r','t','y','u','i','o','p','[',']',
     	db    0, 0, 'a','s','d','f','g','h','j','k','l',';',"'",'`',
        db    0,'/','z','x','c','v','b','n','m','7','8','9',',','.',
        db    0, '*'

; global descriptor tables
;--------------------------------------
gdt:
.null	equ $-gdt 		; 0x0 		
		dq 0
.code 	equ $-gdt 		; 0x8
		dw 0ffffh		; limit 4 Gib 
		dw 0000h   		; base 1-2
		db 0        	; base 3
		db 10011010b	; type
		db 11001111b	; flags
		db 0 			; base 4

.data 	equ $-gdt 	    ; 0x10
		dw 0ffffh   	; limit 4 Gib 
		dw 0000h		; base 1-2	 
		db 0        	; base 3
		db 10010010b	; type
		db 11001111b	; flags
		db 0 			; base 4
gdt_end:
gdtr: 
		dw gdt_end - gdt -1	; size
		dd gdt              ; base address

idt:
; int 0 - divide error
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0

; int 1 - debug exception
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 2 - intel reserved
		dw nmi_handler
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 3 - breakpoint
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 4 - overflow
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 5 - bounds check
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 6 - invalid opcode
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 7 - coprocessor not available
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 8 - double fault
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 9 - coprocessor segment overrun
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int A - invalid tss
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int B - segment not present
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int C - stack exception
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int D - triple fault
		dw triple_fault_handler
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int E - page fault
		dw page_fault_handler
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int F - intel reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 10 - stack exception
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 11 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 12 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 13 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 14 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 15 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 16 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 17 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 18 - reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 19 - reserved
		dw sys_talk
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 20 / irq 0 -reserved
		dw unhandled_int
		dw gdt.code
		db 0
		db 10001110b
		dw 0
; int 21 / irq 1 - keyboard
		dw read_keyboard
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 22 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0

;int 23 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0
;int 24 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0
;int 25 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0
;int 26 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0
;int 28 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0
;int 29 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0
;int 30 /irq 2 - sys_talk
;		dw sys_talk
;		dw gdt.code
;		db 0
;		db 10001110b
;		dw 0

idt_end:
idtr:
  		dw idt_end - idt -1
  		dd idt

times  510 - ($-$$) db 0

bios_signature:
db 55h 
db 0AAh	
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: IDT / interrrupts / Keyboard

Post by iansjack »

Printing to the screen is fairly easy. Converting a hex number in a register is fairly easy. So it's not difficult to write a routine to print the contents of a register to the screen; you can incorporate that in an exception handler. But it won't help if the problem is a faulty stack as the exception handler will never get called.

I would suggest that you take this chance to learn how to use gdb in conjunction with qemu; then you can single-step through your code and/or set breakpoints to see exactly what is happening. Pay particular attention to the stack.

(Disclaimer: other debugging environments are available. Many like Bochs; my favourite for this sort of thing is SimNow.)
skid
Posts: 11
Joined: Wed Dec 17, 2014 12:43 pm

Re: IDT / interrrupts / Keyboard

Post by skid »

seems like the idtr doesn't get loaded properly (virtualbox logs ldtr={0000 base=00000000 limit=0000ffff flags=00000082}) and I don't a single clue why.

Code: Select all

[bits 16]
[org 0x1000]
	mov ax, cs
	mov ds, ax

	mov ax, 0xb800
	mov gs, ax

    mov di, 6
	mov byte [gs:di], "4"
	
	cli

	lgdt [gdtr]
	lidt [idtr]

	mov eax, cr0
	or al, 1
	mov cr0, eax

	jmp gdt.code:entry

[bits 32]
entry:
	mov eax, gdt.data
	mov ds, ax
	mov es, ax

	sti

	call pic_remap
	call unmask_irq

	mov byte [es:0xb8008], "5"

	int 21h
	jmp $	

idtr:
  		dw idt_end - idt -1 ; size
  		dd idt 				; base address
gdtr: 
		dw gdt_end - gdt -1	; size
		dd gdt              ; base address

%include "idt.inc"
%include "gdt.inc"
skid
Posts: 11
Joined: Wed Dec 17, 2014 12:43 pm

Re: IDT / interrrupts / Keyboard

Post by skid »

now irq7 fires instead of irq1 (keyboard), made a dummy handler for irq7 (read brendan's thread) but still

Code: Select all

pic_remap:
    mov al, 0x11        ; put both 8259s in init mode
    out 0x20, al
    out 0xA0, al
    mov al, 0x20        ; IRQ0-IRQ7 -> int 0x20-27
    out 0x21, al
    mov al, 0x28
    out 0xA1, al        ; IRQ8-IRQ15 -> int 0x28-30
    mov al, 4
    out 0x21, al
    mov al, 2
    out 0xA1, al
    mov al, 1
    out 0x21, al
    out 0xA1, al

; testing
unmask_irq: 
    mov al, 0xfd
    out 0x21, al
    mov al, 0xff
    out 0xa1, al
    
    sti 
    ret   

...

wtf: 
    iret

; int 21 / irq 1 - keyboard
		dw read_keyboard
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 22 /irq 2 
		dw sys_talk
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 23 /irq 3 
		dw sys_talk
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 24 /irq 4 
		dw sys_talk
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 25 /irq 5 
		dw sys_talk
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 26 /irq 6 
		dw sys_talk
		dw gdt.code
		db 0
		db 10001110b
		dw 0
;int 27 /irq 7 
		dw wtf
		dw gdt.code
		db 0
		db 10001110b
		dw 0

....

 
Post Reply