Page 2 of 2
Re: General Protection Fault
Posted: Mon Mar 16, 2009 10:37 am
by Schol-R-LEA
As you say, with an IPS equivalent to 1 MHz (sort of), and a PIT frequency of 20 kHz, you are only giving the ISR a window of 50 cycles between the interrupts, meaning that most of the simulated PIT yanks are getting dropped on the floor. Even so, if the ISR is blocking, that shouldn't present a problem - they should just be ignored. It does seem to be part of the problem from your description, though, so perhaps we're still overlooking something.
Re: General Protection Fault
Posted: Mon Mar 16, 2009 11:44 am
by mangaluve
Im out of ideas
I guess I could post some more code but I guess it wouldn't be fun to look through for anyone
Now I get an exception immediatly on the first IRQ..it's strange. Is the initialization code for the PIT correct?
Code: Select all
void init_timer(u32int frequency)
{
// Firstly, register our timer callback.
register_interrupt_handler(0x20, &timer_callback);
u32int divisor = 1193180 / frequency;
// Send the command byte.
outb(0x43, 0x36);
// Divisor has to be sent byte-wise, so split here into upper/lower bytes.
u8int l = (u8int)(divisor & 0xFF);
u8int h = (u8int)( (divisor>>8) & 0xFF );
// Send the frequency divisor.
outb(0x40, l);
outb(0x40, h);
}
if I change outb(0x43, 0x36) to outb(0x43, 0x34), I still get an exception but not immediatly.
Re: General Protection Fault
Posted: Mon Mar 16, 2009 10:07 pm
by neon
Get the return cs:eip from the stack inside of the gpf handler and compare it with the functions inside of your linker script to see what function is throwing the #gpf. Its alot better then guessing...
The return cs:eip is on the stack along with the error code when the #gpf exception is executed.
As far as I can see, your PIT initialization code should be fine.
if I change outb(0x43, 0x36) to outb(0x43, 0x34), I still get an exception but not immediatly.
Hm... That enables the interrupt on terminal count mode of the PIT which basically tells the PIT to count down until the counter reaches 0. It does not reset (Its a one shot timer.)
Makes me think the problem is somewhere else in the code...
Re: General Protection Fault
Posted: Tue Mar 17, 2009 2:36 am
by mangaluve
Thanks! I can print the EIP/ESP/Error code in my Exception Handler, but how do I use the linker script to determine what function that EIP corresponds to?
It's weird, because adding one putchar in my ISR makes the exception occur. So if I have two putchars, I get an exception, but not if I only have one. Something else must be really wrong.
Secondly, I dont get any logs from Bochs. In my bochsrc I have
Code: Select all
log: bochsout.txt
panic: action=report
error: action=report
info: action=report
debug: action=ignore
but no bochsout.txt is created...
Re: General Protection Fault
Posted: Tue Mar 17, 2009 5:25 am
by neon
Thanks! I can print the EIP/ESP/Error code in my Exception Handler, but how do I use the linker script to determine what function that EIP corresponds to?
My mistake-I meant
linker map not linker script
but no bochsout.txt is created...
That should work so long as you are using bochsrc. bochsout.txt should be in the same directory as bochs. If you have verified that both these statements are true, then I would personally grab another copy of bochs.
Re: General Protection Fault
Posted: Tue Mar 17, 2009 5:39 am
by mangaluve
Thanks I'll try with another version then. Can I get it to report exceptions and that kind of stuff (even though I got exception handlers)?
Edit: I dont get the strange behavior in Bochs 2.0.2. (there the logging works). All the problems, but with my kernel and logging happens in 2.3.7.
Edit: Another question, some posts ago people asked if I disabled interrupts the first thing I do in my ISR and then enable them before IRET. I do, but doesn't an interrupt gate do this automatically (and I only need CLI/STI for trap gates)?
Re: General Protection Fault
Posted: Wed Mar 18, 2009 3:28 pm
by JAAman
mangaluve wrote:
Edit: Another question, some posts ago people asked if I disabled interrupts the first thing I do in my ISR and then enable them before IRET. I do, but doesn't an interrupt gate do this automatically (and I only need CLI/STI for trap gates)?
yes, you definitely shouldnt be doing CLI/STI with interrupt gates -- in fact, doing so can cause problems since you are enabling interupts before leaving the ISR... leading to an unlikely, but potential stack overflow...
Re: General Protection Fault
Posted: Thu Mar 19, 2009 3:33 am
by mangaluve
I set the "flags" of my entries in the IDT to 0x8E. That means interrupt gate, right? So then it's wrong to have CLI/STI? I followed JamesM tutorial pretty much, and it seems to be done that way there? Is CLI automatically set with interrupt gates in the beginning of the ISR? And upon IRET, the value of the interrupt flag is restored as it was before the interrupt occured?
Secondly, when should I use trap gates and when interrupt gates?
Re: General Protection Fault
Posted: Thu Mar 19, 2009 4:29 am
by xenos
The main difference between interrupt gates and trap gates is that the IF (interrupt flag) is cleared (i.e., interrupts are disabled) when a handler is called through an interrupt gate, but remains untouched when it is called through a trap. In any case, the IF is restored at the end of the handler, as iret pops the saved flags from the stack.
So, it is true that an interrupt gate disables interrupt when the handler is called this way, by clearing the IF. But if you use STI in your handler, it sets the IF and interrupts are re-enabled. This may cause another interrupt to happen while you are still serving the first one. If this happens to often, lots of return addresses are pushed onto the stack and never popped off again - until the end of the stack is reached.
Therefore you should never use STI within an interrupt handler, and all hardware interrupts should be handled through interrupt gates. Trap gates should be used for software-triggered exception handlers, which can safely be interrupted by hardware interrupts. If you need parts of an exception handler to be uninterruptible (for example, if you mess with page tables or other kernel data structures, you certainly want to block the timer interrupt to avoid a thread switch), just guard your critical sectio with CLI and STI.
Re: General Protection Fault
Posted: Thu Mar 19, 2009 5:30 am
by mangaluve
Thanks! I got a little confused though..
First of all, isn't it true that STI doesn't enable interrupts until the next instruction? So if I have STI followed by IRET, the IRET instruction will run before the interrupt flag is set?
Secondly, you said that I shouldnt have STI in my handler? But that I should guard critical sections with CLI/STI? I just got a little confused.
Re: General Protection Fault
Posted: Thu Mar 19, 2009 6:34 am
by xenos
mangaluve wrote:First of all, isn't it true that STI doesn't enable interrupts until the next instruction? So if I have STI followed by IRET, the IRET instruction will run before the interrupt flag is set?
That's true, as of part 2B of the Intel manuals:
If protected-mode virtual interrupts are not enabled, STI sets the interrupt flag (IF) in the EFLAGS register. After the IF flag is set, the processor begins responding to external, maskable interrupts after the next instruction is executed. The delayed effect of this instruction is provided to allow interrupts to be enabled just before returning from a procedure (or subroutine). For instance, if an STI instruction is followed by an RET instruction, the RET instruction is allowed to execute before external interrupts are recognized1. If the STI instruction is followed by a CLI instruction (which clears the IF flag), the effect of the STI instruction is negated.
Though, having STI immediately befor IRET does not make much sense because the IRET instuctions pops the EFLAGS from the stack, so IF is overwritten with the saved value on the stack.
Secondly, you said that I shouldnt have STI in my handler? But that I should guard critical sections with CLI/STI? I just got a little confused.
You can use CLI / STI to guard (short) critical sections in an
exception handler, or for software triggered interrupts (i.e. with the int xx instruction), which are handled through a trap gate, protecting the current thread from beeing preempted. (This is not a general advice for protecting critical sections - depending on whether you support multiple processors or not, you might need more complicated mechanisms.)
But you shouldn't use STI in an
interrupt handler, i.e. when you handle a hardware interrupt through a call gate, so you disable new hardware interrupts until you are finished handling the current interrupt. In this case, since interrupts are disabled anyway, there is no need to guard critical sections using CLI / STI, because timer interrupts and thus thread switches are disabled.