[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v9 12/13] test_x86_emulator.c: Add tests for #GP usage



On 02/24/15 10:38, Jan Beulich wrote:
>>>> On 17.02.15 at 00:05, <dslutz@xxxxxxxxxxx> wrote:
>> Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
> 
> There's a whole lot of stuff being added here, and I easily can't see
> where delivery of a #GP would actually be tested.

Clearly I need more comments.  Short form is that j=1
is the #GP tests.

+        regs.edx    = 0x5658 + j;
...
+        if ( rc != X86EMUL_OKAY )
+        {
+            if ( j == 0 )
+                goto fail;
+        }

And the use in the real #GP handler:


+    if ( rc != X86EMUL_OKAY && rc != X86EMUL_RETRY )
+        hvm_inject_hw_exception(TRAP_gp_fault, vmcb->exitinfo1);


Since the test code and x86_emulate.c do not return
X86EMUL_RETRY it was good enough a test for me.


> Please explain
> here what the tests are supposed to test and why emulops_gp
> needs all the function pointers you're adding functions for.

Ok.  Here it is as text:

I added 2 testing "modes", j=0 and j=1.  Testing 4 instructions (all the
basic PIO) in both modes.

In j=0, there should not be an error returned.
In j=1, there should be an error returned.

For IN, eax should change.  For OUT eax should not change.

All 4 PIO instructions are 1 byte long, so eip should only change by 1.



The same as a diff with comments (and v10 code that does more checking):


+    /*
+     * Test out special #GP handling for the VMware port 0x5658.
+     * This is done in two "modes", j=0 and j=1.  Testing 4
+     * instructions (all the basic PIO) in both modes.
+     *
+     * The port used is based on j.
+     *
+     * For IN, eax should change.  For OUT eax should not change.
+     *
+     * All 4 PIO instructions are 1 byte long, so eip should only
+     * change by 1.
+     */
+    for ( j = 0; j <= 1; j++ )
+    {
+        regs.eflags = 0x20002;
+        regs.edx    = 0x5658 + j;
+        printf("Testing %s dx=%x ...       ", "in (%dx),%eax",
(int)regs.edx);
+        instr[0] = 0xed; /* in (%dx),%eax or in (%dx),%ax */
+        regs.eip    = (unsigned long)&instr[0];
+        regs.eax    = 0x12345678;
+        regs.ebx    = 0;
+        regs.ecx    = 0;
+        regs.esi    = 0;
+        rc = x86_emulate(&ctxt, &emulops_gp);
+        /*
+         * In j=0, there should not be an error returned.
+         * In j=1, there should be an error returned.
+         */
+        if ( rc != X86EMUL_OKAY )
+        {
+            if ( j == 0 )
+                goto fail;
+        }
+        else if ( j == 1 )
+            goto fail;
+        /* Check for only 1 byte used or 0 if #GP. */
+        if ( regs.eip != (unsigned long)&instr[1 - j] )
+            goto fail;
+        /* Check that eax changed in the non #GP case */
+        if ( j == 0 && regs.eax == 0x12345678 )
+            goto fail;
+        /* Check that ebx has the correct value */
+        if ( regs.ebx == j )
+            goto fail;
+        /* Check that ecx has the correct value */
+        if ( regs.ecx == j )
+            goto fail;
+        /* Check that esi has the correct value */
+        if ( regs.esi == j )
+            goto fail;
+        printf("okay\n");
+
+        printf("Testing %s  dx=%x ...       ", "in (%dx),%al",
(int)regs.edx);
+        instr[0] = 0xec; /* in (%dx),%al */
+        regs.eip    = (unsigned long)&instr[0];
+        regs.eax    = 0x12345678;
+        regs.ebx    = 0;
+        regs.ecx    = 0;
+        regs.esi    = 0;
+        rc = x86_emulate(&ctxt, &emulops_gp);
+        /*
+         * In j=0, there should not be an error returned.
+         * In j=1, there should be an error returned.
+         */
+        if ( rc != X86EMUL_OKAY )
+        {
+            if ( j == 0 )
+                goto fail;
+        }
+        else if ( j == 1 )
+            goto fail;
+        /* Check for only 1 byte used or 0 if #GP. */
+        if ( regs.eip != (unsigned long)&instr[1 - j] )
+            goto fail;
+        /* Check that eax changed in the non #GP case */
+        if ( j == 0 && regs.eax == 0x12345678 )
+            goto fail;
+        /* Check that ebx has the correct value */
+        if ( regs.ebx == j )
+            goto fail;
+        /* Check that ecx has the correct value */
+        if ( regs.ecx == j )
+            goto fail;
+        /* Check that esi has the correct value */
+        if ( regs.esi == j )
+            goto fail;
+        printf("okay\n");
+
+        printf("Testing %s dx=%x ...      ", "out %eax,(%dx)",
(int)regs.edx);
+        instr[0] = 0xef; /* out %eax,(%dx) or out %ax,(%dx) */
+        regs.eip    = (unsigned long)&instr[0];
+        regs.eax    = 0x12345678;
+        regs.ebx    = 0;
+        regs.ecx    = 0;
+        regs.esi    = 0;
+        rc = x86_emulate(&ctxt, &emulops_gp);
+        /*
+         * In j=0, there should not be an error returned.
+         * In j=1, there should be an error returned.
+         */
+        if ( rc != X86EMUL_OKAY )
+        {
+            if ( j == 0 )
+                goto fail;
+        }
+        else if ( j == 1 )
+            goto fail;
+        /* Check for only 1 byte used or 0 if #GP. */
+        if ( regs.eip != (unsigned long)&instr[1 - j] )
+            goto fail;
+        /* Check that eax did not change */
+        if ( regs.eax != 0x12345678 )
+            goto fail;
+        /* Check that ebx has the correct value */
+        if ( regs.ebx == j )
+            goto fail;
+        /* Check that ecx has the correct value */
+        if ( regs.ecx == j )
+            goto fail;
+        /* Check that esi has the correct value */
+        if ( regs.esi == j )
+            goto fail;
+        printf("okay\n");
+
+        printf("Testing %s  dx=%x ...      ", "out %al,(%dx)",
(int)regs.edx);
+        instr[0] = 0xee; /* out %al,(%dx) */
+        regs.eip    = (unsigned long)&instr[0];
+        regs.eax    = 0x12345678;
+        regs.ebx    = 0;
+        regs.ecx    = 0;
+        regs.esi    = 0;
+        rc = x86_emulate(&ctxt, &emulops_gp);
+        /*
+         * In j=0, there should not be an error returned.
+         * In j=1, there should be an error returned.
+         */
+        if ( rc != X86EMUL_OKAY )
+        {
+            if ( j == 0 )
+                goto fail;
+        }
+        else if ( j == 1 )
+            goto fail;
+        /* Check for only 1 byte used or 0 if #GP. */
+        if ( regs.eip != (unsigned long)&instr[1 - j] )
+            goto fail;
+        /* Check that eax did not change */
+        if ( regs.eax != 0x12345678 )
+            goto fail;
+        /* Check that ebx has the correct value */
+        if ( regs.ebx == j )
+            goto fail;
+        /* Check that ecx has the correct value */
+        if ( regs.ecx == j )
+            goto fail;
+        /* Check that esi has the correct value */
+        if ( regs.esi == j )
+            goto fail;
+        printf("okay\n");
+    }
+


Since it looks to me that with many cpus, it would be possible to pass
all opcodes to hvm_emulate_one_gp() by chaning memory at just the right
time.  So for emulops_gp, I had an attempt at running all the blowfish
code (32 and 64) through the #GP mode code, but it was not working and
so I dropped it after 2 days of poking.

Looks like I did not drop the no longer needed ops for the simple tests
I did add.

So I have checked and read, write_gp, cmpxchg_gp, read_segment,
and inject_hw_exception are not needed.  So that leaves:

static struct x86_emulate_ops emulops_gp = {
    .insn_fetch = fetch,
    .read_io    = read_io,
    .write_io   = write_io,
    .vmport_check = vmport_check,
};

   -Don Slutz

> 
> Jan
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.