pushf causes irq0 in v86 mode

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
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

pushf causes irq0 in v86 mode

Post by Octacone »

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?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: pushf causes irq0 in v86 mode

Post by Octocontrabass »

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?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: pushf causes irq0 in v86 mode

Post by Octacone »

Octocontrabass wrote:Are you sure it's not a real IRQ0 triggered by the timer?
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: What are the values of CR4.VME and EFLAGS.IOPL?
Is this only happening in Bochs?
They are both zero. Nope, other emulators as well.

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
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: pushf causes irq0 in v86 mode

Post by Octocontrabass »

Octacone wrote:Still, an IRQ shouldn't interfere with anything, even doe it's interrupting a v86 thread?
As long as there are no bugs in your ISRs, an IRQ won't interfere with anything.
Octacone wrote:Also the GPF handler does get invoked but the parameters are all wrong (wrong segment offset pairs leading to bogus opcodes).
What's the value of EFLAGS on the stack? Maybe the #GP is not happening in V86 mode.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: pushf causes irq0 in v86 mode

Post by Octacone »

Octocontrabass wrote:
Octacone wrote:Still, an IRQ shouldn't interfere with anything, even doe it's interrupting a v86 thread?
As long as there are no bugs in your ISRs, an IRQ won't interfere with anything.
Octacone wrote:Also the GPF handler does get invoked but the parameters are all wrong (wrong segment offset pairs leading to bogus opcodes).
What's the value of EFLAGS on the stack? Maybe the #GP is not happening in V86 mode.
0x30202
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
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: pushf causes irq0 in v86 mode

Post by Octocontrabass »

Octacone wrote:pmode: some mov instruction
pmode: GPF
Sounds like a problem with your segments. What's the MOV instruction? What are the contents of the segment registers?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: pushf causes irq0 in v86 mode

Post by Octacone »

Octocontrabass wrote:
Octacone wrote:pmode: some mov instruction
pmode: GPF
Sounds like a problem with your segments. What's the MOV instruction? What are the contents of the segment registers?
mov eax, dword ptr ds:[eax]
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
rdos
Member
Member
Posts: 3296
Joined: Wed Oct 01, 2008 1:55 pm

Re: pushf causes irq0 in v86 mode

Post by rdos »

Octacone wrote:
Octocontrabass wrote:
Octacone wrote:pmode: some mov instruction
pmode: GPF
Sounds like a problem with your segments. What's the MOV instruction? What are the contents of the segment registers?
mov eax, dword ptr ds:[eax]
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.
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.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: pushf causes irq0 in v86 mode

Post by Octacone »

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.
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.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: pushf causes irq0 in v86 mode

Post by Octocontrabass »

Octacone wrote:They are all zero
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:a GPF happens in the middle of it, which means I cannot handle it properly
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:Even if I set them all to 0x10 it still fails.
How are you setting them? How does it fail?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

(solved) pushf causes irq0 in v86 mode

Post by Octacone »

Octocontrabass wrote:
Octacone wrote:They are all zero
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:a GPF happens in the middle of it, which means I cannot handle it properly
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:Even if I set them all to 0x10 it still fails.
How are you setting them? How does it fail?
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.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
rdos
Member
Member
Posts: 3296
Joined: Wed Oct 01, 2008 1:55 pm

Re: pushf causes irq0 in v86 mode

Post by rdos »

Octacone wrote:
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.
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.
I handle both invalid opcode & GPF with the same functions, so you might be correct.

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.
rdos
Member
Member
Posts: 3296
Joined: Wed Oct 01, 2008 1:55 pm

Re: (solved) pushf causes irq0 in v86 mode

Post by rdos »

Octacone wrote:
Octocontrabass wrote:
Octacone wrote:They are all zero
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.
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.
Octocontrabass wrote:
Octacone wrote:a GPF happens in the middle of it, which means I cannot handle it properly
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.
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.
Post Reply