Page 1 of 1

[SOLVED] Weird PIT/PIC interrupt behaivor

Posted: Sat Mar 16, 2013 8:33 am
by HugeCode
Hi all. I have very interisting and weird problem.
I've mapped my IRQs to 0x20 using PIC. Then I set up an interrupt for IRQ(0) timer and also set up counter0 of PIT (+pit command word). When I run my OS, messages before and after interrupt setting are printed, but there is no IRQ0 handler message.
Because of this I decided to test if my IDT is correct by causing division by zero error. Division by zero exception works. Then I tried to print ISR and IRR of pit. In ISR output I can see that IRQ0 is acknowledged but it hasn't received EOI. Therefore I tried to debug handler, but I can see no handler call when debugging. I also tried to call interrupt manually (int 0x20) and it works. It works until it comes to iret instruction - when iret is executed, VM jumps to 0xfffffff0 (reboots?). And here the problem probably is. I found that SP(before_call) - SP(in_handler) = 4. Shouldn't it be 8 or 10 bytes? How can EFLAGS and EIP fit in four bytes?

So questions I have: is it only problem of manual interrupt (using int), or it's problem of my handler (it has Interrupt Trap Gate 32(0xE) flag set)?
Does anybody have any idea why the timer sets IRQ, but my interrupt is not called?
I'm posting here part of my PIT code:

Code: Select all

void pit_default_handler();

unsigned long long int _default_pit_ticks = 0;
void pit_init() {
	idt_register(IRQ0, (void*)&pit_default_handler, INTFLAG_MINRING_0+INTFLAG_TYPE_INTGATE32);
	pit_setcounter(0, 1000, PIT_MODE_RATEGEN+PIT_BINARY);
}
void pit_setcounter(unsigned char counter, unsigned int hzFreq, unsigned char flags) {
	unsigned short port = 0;

	if(counter > 2)
		return;

	hzFreq = 1193181 / hzFreq;
	if(counter==0)
		port = PIT_REG_COUNT0;
	else if(counter==1)
		port = PIT_REG_COUNT1;
	else port = PIT_REG_COUNT2;

	//writing OCW to 0x43
	outb(PIT_REG_CONTROL, flags | (counter << 6) | PIT_LOAD_LSBMSB);

	//writing COUNT to port
	outb(port, (unsigned char)hzFreq);
	outb(port, (unsigned char)(hzFreq >> 8));
}
void __declspec(naked) pit_default_handler() {
	cli();

	_default_pit_ticks++;
	if(_default_pit_ticks == 1000) {
		println("Second...");
		_default_pit_ticks = 0;
	}

	sti();
	hw_eoi(0);
	iret();
}
PS: I have also tested value of _default_pit_ticks, it's zero when performing manual call.

Re: Weird PIT/PIC interrupt behaivor

Posted: Sun Mar 17, 2013 12:54 am
by HugeCode
Any ideas?

Re: Weird PIT/PIC interrupt behaivor

Posted: Sun Mar 17, 2013 1:58 am
by Combuster
Read the FAQ, use bochs, and keep debugging?

Oh and, never ever use naked functions.

Re: Weird PIT/PIC interrupt behaivor

Posted: Sun Mar 17, 2013 6:28 am
by HugeCode
I finally solved the problem. There were two problems and first one was hiding the second. I've set up the exceptions. Then I found out that iret instruction was causing GPF, but not because stack was corrupted. It was in iret instruction. Visual Studio compiler takes it as 16bit so it loads segment:offset instead of loading selector:address from GDT. I had to use iretd.
The second problem was more interesting. I could see ISR with IRQ0 set, so processor knew that there's some interrupt which has to be called. I tried to send EOI to PIC, but it also didn't work. Then I found out that in my bootloader, interrupts are cleared before jumping to C code. So there wasn't error in C which I was checking and debugging several times. So "sti" solved the problem.

Re: Weird PIT/PIC interrupt behaivor

Posted: Sun Mar 17, 2013 6:22 pm
by Kazinsal
HugeCode wrote:Visual Studio compiler takes it as 16bit so it loads segment:offset instead of loading selector:address from GDT. I had to use iretd.
Odd. I use Visual Studio 2010 and don't have that issue. What version are you using?

EDIT: Actually, this issue doesn't make sense. iretd and iret are the same opcode in both modes.

Re: Weird PIT/PIC interrupt behaivor

Posted: Sun Mar 17, 2013 7:44 pm
by Owen
Blacklight wrote:EDIT: Actually, this issue doesn't make sense. iretd and iret are the same opcode in both modes.
Your x86-fu is weak...

iret word is CF in real mode/16-bit protected mode and 66 CF in 32-bit protected mode
iret dword is 66 CF in real mode/16-bit protected mode and 66 in 32-bit protected mode

Re: Weird PIT/PIC interrupt behaivor

Posted: Sun Mar 17, 2013 11:29 pm
by HugeCode
I have Visual Studio 2010. BTW why shouldn't I use naked functions?

Re: Weird PIT/PIC interrupt behaivor

Posted: Mon Mar 18, 2013 12:38 am
by Combuster
HugeCode wrote:I have Visual Studio 2010. BTW why shouldn't I use naked functions?
Because
a) You apparently have no idea how they work.
b) When you do know how they work you can't possibly construct an implementation that works forever.

That interrupt handler is broken like hell. Rewrite it in assembly, and use a sane reference on what it should actually be doing.

Re: Weird PIT/PIC interrupt behaivor

Posted: Mon Mar 18, 2013 1:21 am
by xenos
Owen wrote:iret dword is 66 CF in real mode/16-bit protected mode and 66 in 32-bit protected mode
I guess you mean CF in 32 bit pmode ;)