Page 1 of 1

Very strange behaviour with IDT under long pure 64-bit mode

Posted: Sat Jul 13, 2013 7:39 am
by JohnXiba
Hi everyone,

I'm facing this very strange behaviour trying to setup an IDT under long IA-32e mode. I followed the Intel manuals instructions and yet something's bugging me desperately for the past 4-5 hours now. Here's the setup, then I'll describe the problem:

Code: Select all

[bits 64]
__setupIDT:

	; RBX|RAX = IDT entry (trap-gate, 32 bits), pointing to __interruptProcedure
	mov		rax, 0x8F00_0000_0000
	mov		rbx, CODE64_SEL
	shl		rbx, 16
	or		rax, rbx
	mov		rbx, qword __interruptProcedure
	and		rbx, 0xFFFF0000
	shl		rbx, 32
	or		rax, rbx
	mov		rbx, qword __interruptProcedure
	and		rbx, 0xFFFF
	or		rax, rbx
	mov		rbx, qword __interruptProcedure
	shr		rbx, 32
	
	mov		rdi, qword IDT
	mov		cx, 256

__setupIDT_NextIDTStore:
	mov		[rdi], rax
	mov		[rdi+8], rbx
	add		rdi, 16
	dec		cx
	jnz		__setupIDT_NextIDTStore
	
	mov		rax, qword IDTR
	lidt	[rax]
	;sti
	lea		rbx, [rip]
        ;int            32
	call	__interruptProcedure
	ret

align 16
__interruptProcedure:
	mov		rax, [rsp]
	hlt
	iretq

align 16
IDTR:
	idt_limit			dw	(256 * 16 - 1)
	idt_base			dq	IDT

align 16
IDT:
	times 256 ddq 0x00000000_00000000_0000_0000_0000_0000	; set-up by code
CODE64_SEL is 0x08 and in my GDT table that entry has the value 0x002F9A000000FFFF, which is 64-bit pure mode, execute/read, present, base 0, limit 0xFF[...], but base and limit don't matter. Now, this is the funny thing that's happening. When executing the instruction "call __interruptProcedure" you would expect the CPU to PUSH on the stack the RIP (which points to "RET"). That happens precisely so with the given code (by looking at RAX after HLT-ing in __interruptProcedure, I know it's ok). But IF I UNCOMMENT the "STI" instruction, what is being pushed on the stack instead is the address of the "IRETQ" instruction inside __interruptProcedure. If I comment the "CALL __interruptProcedure", keep "STI" uncommented and uncomment "INT 32" as well, the same RIP is pushed on the stack => pointing to "IRETQ". If, in this situation, I also remove the HLT instruction inside __interruptProcedure, QEMU simply resets (probably because IRETQ returns to itself??).

Thank you very much in advance for your suggestions,
John X.

P.S.: Other notes - The assembler I use is YASM (an extension of NASM which uses basically the same syntax), running the code using QEMU. I was able to see the values of the registers by using QEMU's Monitor feature. The execution stops inside __interruptProcedure at the HLT instruction; when that happens, RAX should be loaded with the RIP pushed on the stack (mov rax, [rsp]). In QEMU Monitor I'm running the command "x /1i $eax" to see the instruction pointed by the RIP on the stack; this results in "RET" when STI is commented out and in "IRETQ" when it's uncommented. See details on the bottom of this page http://en.wikibooks.org/wiki/QEMU/Monitor regarding the QEMU Monitor command "x /1i $eax". Also, I've set-up the paging tables for long mode and everything is working properly regarding that. Each IDT entry is set-up to point to __interruptProcedure and to be a trap-gate, running under ring 0, present and to use the 0x08 code selector I've mentioned earlier. The IST for each IDT entry is set to be 0.

Re: Very strange behaviour with IDT under long pure 64-bit m

Posted: Sat Jul 13, 2013 8:09 am
by Gigasoft
A second call to __interruptProcedure comes from the timer interrupt while executing the "hlt" instruction. Since the interrupt is not cleared, no further interrupts happen. If you remove the "hlt" (and the call), execution eventually reaches "ret".

Re: Very strange behaviour with IDT under long pure 64-bit m

Posted: Sat Jul 13, 2013 8:24 am
by JohnXiba
By following your suggestions and I left __interruptProcedure only with the IRETQ; What follows after LIDT [RAX] is:

Code: Select all

        sti
	int		32
	mov		eax, 'RZIZ'
	mov		[0xB8000], eax
	cli
	hlt
        ret
Unfortunately, QEMU behaves the same and the virtual machine resets.

Re: Very strange behaviour with IDT under long pure 64-bit m

Posted: Sat Jul 13, 2013 5:38 pm
by JohnXiba
I have thoroughly read the Intel manual vol. 3A chapters 6 (Interrupt and Exception Handling) and 10 (Advanced Programmable Interrupt Controller (APIC)) and now everything is crystal-clear. I should do this more often but unfortunately I'm working on a tight time-frame here and I didn't know if I could afford some reading time :)

Everything works perfectly now, cheers