Page 1 of 1

Returning to execution after handling invalid instruction

Posted: Tue Jun 03, 2014 5:59 pm
by smeezekitty
Ok. Here is the thing. I am working on a Windows driver that is designed
to emulate Pentium (+MMX?) on 486 class CPUs to allow you to run newer software

I successfully was able to catch the illegal instructions, but cannot figure out how to return to normal execution

Code: Select all

__declspec(naked) void illegal_operand_handler (void) {
    __asm{
        push    ebp
        mov     ebp, esp
        pushad
        pushfd
        push    ds
        mov     ds, ax
        mov     esi, [ebp+4]
        cld
        lods    byte ptr [esi]
       cmp     al, 0xf 
      je      handle_0xf
GoPrevTrap01:
        pop     ds
        popfd
        popad
        pop     ebp 
        jmp     dword ptr [prevIllegalOpHandler]
       
handle_0xf:
      lods   byte ptr [esi] //Find out what the faulting instruction is
      cmp      al, 0xA2
        jne      not_cpuid    
      add     dword ptr [ebp+3], 4
        pop     ds
        popfd
        popad
        pop     ebp
        iretd      
not_cpuid:
      jmp short GoPrevTrap01
    };
} 
Keeping it simple, I am trying to just skip the "cpuid" instruction. But the program either crashes or the whole OS BSoDs

Anybody help please?

Re: Returning to execution after handling invalid instructio

Posted: Tue Jun 03, 2014 11:55 pm
by Combuster
mov ds, ax
Uninitialized variable?

Re: Returning to execution after handling invalid instructio

Posted: Wed Jun 04, 2014 12:33 pm
by smeezekitty
Uninitialized variable?
Yeah I did that when I was trying different things to make it work. But as far as I can tell, DS isn't even used in that code

I guess I am confused on the stack layout. What is on the stack at the time of an invalid instruction interrupt and what needs to be on the stack
to get back to normal execution.
I tried to look for a document that shows the CPU state after an illegal instruction but couldn't find one

Re: Returning to execution after handling invalid instructio

Posted: Wed Jun 04, 2014 12:36 pm
by sortie
You will want to read the Intel CPU documentation. The state after an invalid instruction is pretty much just like a normal exception (because it is that). The processor pushes a few things, the usual osdev interrupt tutorials will cover that stuff.

Re: Returning to execution after handling invalid instructio

Posted: Thu Jun 05, 2014 12:10 am
by bluemoon
smeezekitty wrote:
Uninitialized variable?
Yeah I did that when I was trying different things to make it work. But as far as I can tell, DS isn't even used in that code
How about these:

Code: Select all

mov     esi, [ebp+4]
lods    byte ptr [esi]
smeezekitty wrote:I guess I am confused on the stack layout. What is on the stack at the time of an invalid instruction interrupt and what needs to be on the stack to get back to normal execution.
According the to manual, #UD has no error code, so the usual interrupt handler's stack layout.
You inspect the return address to figure out what instruction was causing fault, and
1. emulate it, adjust return address, and return (skip it)
2. terminate the process by other mechanism
3. or signal it like windows SEP.

Re: Returning to execution after handling invalid instructio

Posted: Thu Jun 05, 2014 1:36 am
by Brendan
Hi,
smeezekitty wrote:

Code: Select all

      add     dword ptr [ebp+3], 4
If this instruction had a comment, someone would have been able to compare the comment (the intended purpose of the instruction) to the code (the actual implementation of that intended purpose) and may have realised there's a mismatch between intent and implementation.

Basically, the main bug is a lack of comments (which makes it harder to find less important bugs).


Cheers,

Brendan

Re: Returning to execution after handling invalid instructio

Posted: Thu Jun 05, 2014 2:42 pm
by smeezekitty
Ok you guys nailed it with the uninitialized (E)AX
I re-added mov eax, [ebp+8]
I was messing around and somehow removed it

It works now. I will later probably need some hlep emulating specific instructions but for now I got it skipping CPUID successfully.
But I will be leaving tomorrow and won't be able to get back to it for several days
add dword ptr [ebp+3], 4
ebp+3 is wrong. ebp+4 is correct

The point is to increment the return address so it doesn't jump back to the faulting instruction

Some resources that helped me understand the stack a little better
http://www.acm.uiuc.edu/sigops/roll_you ... 6/idt.html
http://pdos.csail.mit.edu/6.828/2005/le ... slides.pdf