gpf after receiving irq

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
pompon
Posts: 15
Joined: Fri Mar 13, 2009 11:04 am

gpf after receiving irq

Post by pompon »

Hi,
I've got a problem with idt in pmode: after receiving any irq, the cpu reports general protection fault.
The error code refers to the idt of received irq. List of steps I'm doing after setting gdt and entering pmode:
1. set all segment registers
2. remap irqs
3. load idt
4. enable interrupts
5. jump to the furher code (not involving OS at all)
The thing is that after first gpf, cpu seems to ignore next irqs - I obtain only a single error message.
The code is being emulated with QEMU PC emulator version 0.10.0.
Below the listing of 32 bit code (execution starts at start_system32):

Code: Select all

[bits 32]

extern _Z3runv

global outb
global inb
global start_system32
global handle_master

outb:
.DATA equ 6
.PORT equ 4
	mov dx, [esp+.PORT]
	mov al, [esp+.DATA]
	out dx, al
	ret
	
inb:
.PORT equ 4
	mov dx, [esp+.PORT]
	in al, dx
	ret

PIC_M_COMM equ 0x20
PIC_M_DATA equ 0x21
PIC_S_COMM equ 0xA0
PIC_S_DATA equ 0xA1

PIC_EOI equ 0x20
ICW1_INIT equ 0x10 ; initialization sequence
ICW1_ICW4 equ 0x1 ; ICW4 will be provided
ICW3_M_IRQ2 equ 0x4 ; slave at IRQ2
ICW3_S_ID2 equ 0x2 ; slave ID = 2
ICW4_8086 equ 0x1 ; 8086/8080 mode

%macro IN 1 ; [port]
	in		al, %1
%endmacro

%macro OUT 2 ; [port] [code]
	mov		al, %2
	out		%1, al
%endmacro

extern irq_handler

handle_master:
	pushad
	call	irq_handler
	OUT PIC_M_COMM, PIC_EOI
	popad
	iretd

handle_slave:
	pushad
	call	irq_handler
	OUT PIC_S_COMM, PIC_EOI
	OUT PIC_M_COMM, PIC_EOI
	popad
	iretd

PIC_M_OFFSET equ 0x20
PIC_S_OFFSET equ 0x28

init_PIC:
	;master
	OUT PIC_M_COMM, ICW1_INIT | ICW1_ICW4
	OUT PIC_M_DATA, PIC_M_OFFSET
	OUT PIC_M_DATA, ICW3_M_IRQ2
	OUT PIC_M_DATA, ICW4_8086
	OUT PIC_M_DATA, 0
	
	;slave
	OUT PIC_S_COMM, ICW1_INIT | ICW1_ICW4
	OUT PIC_S_DATA, PIC_S_OFFSET
	OUT PIC_S_DATA, ICW3_S_ID2
	OUT PIC_S_DATA, ICW4_8086
	OUT PIC_S_DATA, 0
	
	ret

;	offset	= handler
;	segment = 0x8 (CODE)
;
;	offset-- -------- P DPL 0 D 110 000 reserved 
;	???????? ???????? 1 00  0 1 110 000 ?????
;
;	segment- -------- offset-- --------
;	00000000 00001000 ???????? ????????

IDT times 256 dw 0x0, 0x0008, 0x8e00, 0x0
IDT_size equ ($-IDT)-1

IDTR dw IDT_size	; size
	 dd IDT			; offset

extern exception_handler

handler:
	pushad
	popad
	iretd

%macro handler_standard 2 ; [handler name] [interrupt index]
%1:
	pushad
	push	long %2
	call	exception_handler
	pop		eax
	popad
	iretd
%endmacro

%macro handler_code 2 ; [handler name] [interrupt_index]
%1:
.ERROR_CODE equ 0x20
	pushad
	push	long [esp+.ERROR_CODE]
	push	long %2
	call	exception_handler
	pop		eax
	pop		eax
	popad
	add		esp, 4
	iretd
%endmacro

%macro fill_specific 2 ; [handler name] [interrupt index]
	mov		eax, %1
	mov		ebx, eax
	shr		ebx, 16
	mov		edx, IDT
	mov		[edx+8*%2], ax
	mov		[edx+8*%2+6], bx
%endmacro

handler_code h8, 8
handler_code h10, 10
handler_code h11, 11
handler_code h12, 12
handler_code h13, 13
handler_code h14, 14
handler_standard h0, 0
handler_standard h1, 1
handler_standard h2, 2
handler_standard h3, 3
handler_standard h4, 4
handler_standard h5, 5
handler_standard h6, 6
handler_standard h7, 7
handler_standard h9, 9
handler_standard h15, 15
handler_standard h16, 16
handler_standard h17, 17
handler_standard h18, 18
handler_standard h19, 19

set_IDTR:
	mov		eax, handler
	mov		ebx, eax
	shr		ebx, 16
	mov		edx, IDT
	mov		ecx, 256
.fill:	
	mov		[edx], ax
	mov		[edx+6], bx
	add		edx, 8
	loop	.fill

	fill_specific h0, 0
	fill_specific h1, 1
	fill_specific h2, 2
	fill_specific h3, 3
	fill_specific h4, 4
	fill_specific h5, 5
	fill_specific h6, 6
	fill_specific h7, 7
	fill_specific h8, 8
	fill_specific h9, 9
	fill_specific h10, 10
	fill_specific h11, 11
	fill_specific h12, 12
	fill_specific h13, 13
	fill_specific h14, 14
	fill_specific h15, 15
	fill_specific h16, 16
	fill_specific h17, 17
	fill_specific h18, 18
	fill_specific h19, 19
	fill_specific handle_master, PIC_M_OFFSET+0
	fill_specific handle_master, PIC_M_OFFSET+1
	fill_specific handle_master, PIC_M_OFFSET+2
	fill_specific handle_master, PIC_M_OFFSET+3
	fill_specific handle_master, PIC_M_OFFSET+4
	fill_specific handle_master, PIC_M_OFFSET+5
	fill_specific handle_master, PIC_M_OFFSET+6
	fill_specific handle_master, PIC_M_OFFSET+7
	fill_specific handle_slave, PIC_S_OFFSET+0
	fill_specific handle_slave, PIC_S_OFFSET+1
	fill_specific handle_slave, PIC_S_OFFSET+2
	fill_specific handle_slave, PIC_S_OFFSET+3
	fill_specific handle_slave, PIC_S_OFFSET+4
	fill_specific handle_slave, PIC_S_OFFSET+5
	fill_specific handle_slave, PIC_S_OFFSET+6
	fill_specific handle_slave, PIC_S_OFFSET+7

	lidt	[IDTR]
	ret

start_system32:
	mov		ax, 0x10
	mov		ds, ax
	mov 	ss, ax
	mov		es, ax
	mov		fs, ax
	mov		gs, ax
	call	init_PIC
	call	set_IDTR
	sti
	jmp		_Z3runv
do you have any suggestions what I'm doing wrong?,
thank you in advance,
pompon
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: gpf after receiving irq

Post by Tosi »

Are you setting the PIC interrupt masks after remapping? If you don't set the masks and don't have a timer IRQ installed every time the timer ticks it will start running from 0x000000000 which is probably contains remnants of the real mode IVT and is not valid code, causing a GPF.
pompon
Posts: 15
Joined: Fri Mar 13, 2009 11:04 am

Re: gpf after receiving irq

Post by pompon »

Code: Select all

init_PIC:
   ;master
   OUT PIC_M_COMM, ICW1_INIT | ICW1_ICW4
   OUT PIC_M_DATA, PIC_M_OFFSET
   OUT PIC_M_DATA, ICW3_M_IRQ2
   OUT PIC_M_DATA, ICW4_8086
   OUT PIC_M_DATA, 0
   
   ;slave
   OUT PIC_S_COMM, ICW1_INIT | ICW1_ICW4
   OUT PIC_S_DATA, PIC_S_OFFSET
   OUT PIC_S_DATA, ICW3_S_ID2
   OUT PIC_S_DATA, ICW4_8086
   OUT PIC_S_DATA, 0
   
   ret
I'm initiating both PICs and setting their masks to 0, if that is what you were asking for,
pompon
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: gpf after receiving irq

Post by xenos »

Setting the PIC mask to 0x00 unmasks all interrupts, i.e., they are enabled. To mask / disable all interrupts, you need to set the PIC mask to 0xff.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
pompon
Posts: 15
Joined: Fri Mar 13, 2009 11:04 am

Re: gpf after receiving irq

Post by pompon »

XenOS wrote:Setting the PIC mask to 0x00 unmasks all interrupts, i.e., they are enabled. To mask / disable all interrupts, you need to set the PIC mask to 0xff.
Indeed, I want to enable them. The problem is that I get gpf instead of handler execution.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: gpf after receiving irq

Post by Combuster »

Have you checked the source location and error value for the GPF? Is there a specific line causing your error, or is it a random line meaning it gives an exception when it tries to enter the interrupt handler?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pompon
Posts: 15
Joined: Fri Mar 13, 2009 11:04 am

Re: gpf after receiving irq

Post by pompon »

Combuster wrote:Have you checked the source location and error value for the GPF? Is there a specific line causing your error, or is it a random line meaning it gives an exception when it tries to enter the interrupt handler?
error code: 0x102 (IDT 0x20 - that's where I've mapped irq0)
return eip: the place where I'm setting infinite loop or write hlt instruction
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: gpf after receiving irq

Post by Combuster »

Then please post the code that you use to initialize all the other fields of the IDT - you are only showing how you set
the offset bits, but not the segment and other fields.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pompon
Posts: 15
Joined: Fri Mar 13, 2009 11:04 am

Re: gpf after receiving irq

Post by pompon »

Code: Select all

;   offset   = handler
;   segment = 0x8 (CODE)
;
;   offset-- -------- P DPL 0 D 110 000 reserved
;   ???????? ???????? 1 00  0 1 110 000 ?????
;
;   segment- -------- offset-- --------
;   00000000 00001000 ???????? ????????

IDT times 256 dw 0x0, 0x0008, 0x8e00, 0x0
IDT_size equ ($-IDT)-1

IDTR dw IDT_size   ; size
    dd IDT         ; offset
For all interrupts the selector is set to 0x8 (my code segment) and the type is set to 0x8e.
Only offset is being set at runtime.
pompon
Posts: 15
Joined: Fri Mar 13, 2009 11:04 am

Re: gpf after receiving irq

Post by pompon »

I've solved the problem. It was all about the mov instruction here:

Code: Select all

   mov      edx, IDT
   mov      [edx+8*%2], ax
   mov      [edx+8*%2+6], bx
It appears that the constant offset (here: 8*%2) cannot exceed 255. After replacing it with:

Code: Select all

	mov		edx, %2
	shl		edx, 3
	add		edx, IDT
	mov		[edx], ax
	mov		[edx+6], bx
The code works just fine. Thanks to Combuster, XenOS and Tosi for contribution.
Post Reply