pushf causes irq0 in v86 mode
pushf causes irq0 in v86 mode
Hi,
I'm writing a virtual 8068 monitor and I'm seeing some unexplained behavior.
As you know all privileged instructions are supposed to trigger a GPF when operating in v86 mode. That's happens but not with pushf which seems to trigger an interrupt request 0 handler for no reason whatsoever, after which the GPF happens.
Is there a secret mechanism that I'm not aware of? I couldn't find any similar behavior elsewhere on the internet.
I've checked all the related code and couldn't find anything obvious. The IDT looks intact except Bochs displays it in a weird way when operating in v86 mode, I guess that's by default.
Anything obvious that I'm missing?
I'm writing a virtual 8068 monitor and I'm seeing some unexplained behavior.
As you know all privileged instructions are supposed to trigger a GPF when operating in v86 mode. That's happens but not with pushf which seems to trigger an interrupt request 0 handler for no reason whatsoever, after which the GPF happens.
Is there a secret mechanism that I'm not aware of? I couldn't find any similar behavior elsewhere on the internet.
I've checked all the related code and couldn't find anything obvious. The IDT looks intact except Bochs displays it in a weird way when operating in v86 mode, I guess that's by default.
Anything obvious that I'm missing?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: pushf causes irq0 in v86 mode
Are you sure it's not a real IRQ0 triggered by the timer?
What are the values of CR4.VME and EFLAGS.IOPL?
Is this only happening in Bochs?
What are the values of CR4.VME and EFLAGS.IOPL?
Is this only happening in Bochs?
Re: pushf causes irq0 in v86 mode
Spot on! It looks like you're right. Even doe I disabled them, the IF bit was still set. I tried changing it manually and it worked.Octocontrabass wrote:Are you sure it's not a real IRQ0 triggered by the timer?
They are both zero. Nope, other emulators as well.Octocontrabass wrote: What are the values of CR4.VME and EFLAGS.IOPL?
Is this only happening in Bochs?
Still, an IRQ shouldn't interfere with anything, even doe it's interrupting a v86 thread? I guess there is a stack corruption at play, since the registers get all messed up. Also the GPF handler does get invoked but the parameters are all wrong (wrong segment offset pairs leading to bogus opcodes).
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: pushf causes irq0 in v86 mode
As long as there are no bugs in your ISRs, an IRQ won't interfere with anything.Octacone wrote:Still, an IRQ shouldn't interfere with anything, even doe it's interrupting a v86 thread?
What's the value of EFLAGS on the stack? Maybe the #GP is not happening in V86 mode.Octacone wrote:Also the GPF handler does get invoked but the parameters are all wrong (wrong segment offset pairs leading to bogus opcodes).
Re: pushf causes irq0 in v86 mode
0x30202Octocontrabass wrote:As long as there are no bugs in your ISRs, an IRQ won't interfere with anything.Octacone wrote:Still, an IRQ shouldn't interfere with anything, even doe it's interrupting a v86 thread?
What's the value of EFLAGS on the stack? Maybe the #GP is not happening in V86 mode.Octacone wrote:Also the GPF handler does get invoked but the parameters are all wrong (wrong segment offset pairs leading to bogus opcodes).
It depends, if interrupt are enabled then it happens like this:
v86: pushf
pmode: irq 0 handler
pmode: irq 0 handler still
pmode: some mov instruction
pmode: GPF
when they're disabled:
v86: pushf
pmode: GPF right after
I certainly won't be fun debugging over 100 instructions step by step... and checking the stack each step of the way.
Everything points towards a faulty IRQ handler, we'll see.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: pushf causes irq0 in v86 mode
Sounds like a problem with your segments. What's the MOV instruction? What are the contents of the segment registers?Octacone wrote:pmode: some mov instruction
pmode: GPF
Re: pushf causes irq0 in v86 mode
mov eax, dword ptr ds:[eax]Octocontrabass wrote:Sounds like a problem with your segments. What's the MOV instruction? What are the contents of the segment registers?Octacone wrote:pmode: some mov instruction
pmode: GPF
They are all zero, except CS (0x08) and SS(0x10).
As far as I can see, as soon as pushf executes, IRQ 0 fires and then a GPF happens in the middle of it, which means I cannot handle it properly since the stack is now all messed up.
Even if I set them all to 0x10 it still fails.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Re: pushf causes irq0 in v86 mode
I've written a V86 monitor, and pushf is part of the instructions that affect interrupt flag, and so causes faults so the monitor can emulate it. It doesn't cause interrupt 0. I think it causes int 6, which is the invalid opcode fault. Also note that int 6 does NOT push an error code, and so the stack frame is different from GPF. The way I handle this is to push zero on the stack at the start of the interrupt handler so the stack is the same as exceptions that push an error code.Octacone wrote:mov eax, dword ptr ds:[eax]Octocontrabass wrote:Sounds like a problem with your segments. What's the MOV instruction? What are the contents of the segment registers?Octacone wrote:pmode: some mov instruction
pmode: GPF
They are all zero, except CS (0x08) and SS(0x10).
As far as I can see, as soon as pushf executes, IRQ 0 fires and then a GPF happens in the middle of it, which means I cannot handle it properly since the stack is now all messed up.
Even if I set them all to 0x10 it still fails.
Re: pushf causes irq0 in v86 mode
It should only ever generate a GPF (14, 0xD) an nothing else, so you can trap it. It is accounted for in my ISR handler, a so called dummy error code.rdos wrote: I've written a V86 monitor, and pushf is part of the instructions that affect interrupt flag, and so causes faults so the monitor can emulate it. It doesn't cause interrupt 0. I think it causes int 6, which is the invalid opcode fault. Also note that int 6 does NOT push an error code, and so the stack frame is different from GPF. The way I handle this is to push zero on the stack at the start of the interrupt handler so the stack is the same as exceptions that push an error code.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: pushf causes irq0 in v86 mode
This is definitely the reason why the MOV instruction causes #GP. Your ISR entry code is not setting DS or ES to appropriate values. You shouldn't trust any ring 3 program to leave DS or ES set to values you can use in ring 0.Octacone wrote:They are all zero
The #GP that happens in the middle of your IRQ handler has nothing to do with V86 mode. You shouldn't try to handle it like a #GP in V86 mode because it's not happening in V86 mode.Octacone wrote:a GPF happens in the middle of it, which means I cannot handle it properly
How are you setting them? How does it fail?Octacone wrote:Even if I set them all to 0x10 it still fails.
(solved) pushf causes irq0 in v86 mode
That was the problem! I wasn't saving the segment registers, because people told me not to, "why would they change" etc... well they were wrong. I thought of it while debugging and tried to change them manually, but Bochs would just ignore my manually set values. They have to be set from code. Such a silly mistake. Thanks for helping.Octocontrabass wrote:This is definitely the reason why the MOV instruction causes #GP. Your ISR entry code is not setting DS or ES to appropriate values. You shouldn't trust any ring 3 program to leave DS or ES set to values you can use in ring 0.Octacone wrote:They are all zero
The #GP that happens in the middle of your IRQ handler has nothing to do with V86 mode. You shouldn't try to handle it like a #GP in V86 mode because it's not happening in V86 mode.Octacone wrote:a GPF happens in the middle of it, which means I cannot handle it properly
How are you setting them? How does it fail?Octacone wrote:Even if I set them all to 0x10 it still fails.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Re: pushf causes irq0 in v86 mode
I handle both invalid opcode & GPF with the same functions, so you might be correct.Octacone wrote:It should only ever generate a GPF (14, 0xD) an nothing else, so you can trap it. It is accounted for in my ISR handler, a so called dummy error code.rdos wrote: I've written a V86 monitor, and pushf is part of the instructions that affect interrupt flag, and so causes faults so the monitor can emulate it. It doesn't cause interrupt 0. I think it causes int 6, which is the invalid opcode fault. Also note that int 6 does NOT push an error code, and so the stack frame is different from GPF. The way I handle this is to push zero on the stack at the start of the interrupt handler so the stack is the same as exceptions that push an error code.
I know that my V86 pushf emulation works on real CPUs, so there is nothing wrong with the CPU implementation at least. Must be your handlers that are incorrect.
Re: (solved) pushf causes irq0 in v86 mode
Right. DS, ES, FS and GS are set to zero by the V86 exception handler. SS:ESP and CS:EIP are loaded from the current TSS & IDT. I guess he has a flat kernel and think his selectors are fixed, which might work within protected mode, but certainly doesn't work from V86 mode. The V86 segment registers are pushed on the kernel stack.Octacone wrote:Octocontrabass wrote:This is definitely the reason why the MOV instruction causes #GP. Your ISR entry code is not setting DS or ES to appropriate values. You shouldn't trust any ring 3 program to leave DS or ES set to values you can use in ring 0.Octacone wrote:They are all zero
The way to handle this correctly is that exception handlers must check if the VM flag is set in the flag image on the stack. If it is set, then the handler should assume the exception comes from V86 mode, and that the stack contains CS:EIP and SS:ESP that must be decoded as 8086 segments, and that the stack also contains DS, ES, FS and GS as 8086 segments.Octocontrabass wrote:The #GP that happens in the middle of your IRQ handler has nothing to do with V86 mode. You shouldn't try to handle it like a #GP in V86 mode because it's not happening in V86 mode.Octacone wrote:a GPF happens in the middle of it, which means I cannot handle it properly