Add test cases for I/O bitmaps, including corner cases.

Signed-off-by: Arthur Chunqi Li <yzt...@gmail.com>
---
 x86/vmx.h       |    6 +-
 x86/vmx_tests.c |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 3 deletions(-)

diff --git a/x86/vmx.h b/x86/vmx.h
index 18961f1..dba8b20 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -417,15 +417,15 @@ enum Ctrl1 {
        "popf\n\t"
 
 #define VMX_IO_SIZE_MASK               0x7
-#define _VMX_IO_BYTE                   1
-#define _VMX_IO_WORD                   2
+#define _VMX_IO_BYTE                   0
+#define _VMX_IO_WORD                   1
 #define _VMX_IO_LONG                   3
 #define VMX_IO_DIRECTION_MASK          (1ul << 3)
 #define VMX_IO_IN                      (1ul << 3)
 #define VMX_IO_OUT                     0
 #define VMX_IO_STRING                  (1ul << 4)
 #define VMX_IO_REP                     (1ul << 5)
-#define VMX_IO_OPRAND_DX               (1ul << 6)
+#define VMX_IO_OPRAND_IMM              (1ul << 6)
 #define VMX_IO_PORT_MASK               0xFFFF0000
 #define VMX_IO_PORT_SHIFT              16
 
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 44be3f4..ad28c4c 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -2,10 +2,13 @@
 #include "msr.h"
 #include "processor.h"
 #include "vm.h"
+#include "io.h"
 
 u64 ia32_pat;
 u64 ia32_efer;
 u32 stage;
+void *io_bitmap_a, *io_bitmap_b;
+u16 ioport;
 
 static inline void vmcall()
 {
@@ -473,6 +476,168 @@ static int cr_shadowing_exit_handler()
        return VMX_TEST_VMEXIT;
 }
 
+static void iobmp_init()
+{
+       u32 ctrl_cpu0;
+
+       io_bitmap_a = alloc_page();
+       io_bitmap_a = alloc_page();
+       memset(io_bitmap_a, 0x0, PAGE_SIZE);
+       memset(io_bitmap_b, 0x0, PAGE_SIZE);
+       ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0);
+       ctrl_cpu0 |= CPU_IO_BITMAP;
+       ctrl_cpu0 &= (~CPU_IO);
+       vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0);
+       vmcs_write(IO_BITMAP_A, (u64)io_bitmap_a);
+       vmcs_write(IO_BITMAP_B, (u64)io_bitmap_b);
+}
+
+static void iobmp_main()
+{
+/*
+       data = (u8 *)io_bitmap_b;
+       ioport = 0xffff;
+       data[(ioport - 0x8000) /8] |= (1 << (ioport % 8));
+       inb(ioport);
+       outb(0, ioport);
+*/
+       // stage 0, test IO pass
+       set_stage(0);
+       inb(0x5000);
+       outb(0x0, 0x5000);
+       if (stage != 0)
+               report("I/O bitmap - I/O pass", 0);
+       else
+               report("I/O bitmap - I/O pass", 1);
+       // test IO width, in/out
+       ((u8 *)io_bitmap_a)[0] = 0xFF;
+       set_stage(2);
+       inb(0x0);
+       if (stage != 3)
+               report("I/O bitmap - trap in", 0);
+       else
+               report("I/O bitmap - trap in", 1);
+       set_stage(3);
+       outw(0x0, 0x0);
+       if (stage != 4)
+               report("I/O bitmap - trap out", 0);
+       else
+               report("I/O bitmap - trap out", 1);
+       set_stage(4);
+       inl(0x0);
+       // test low/high IO port
+       set_stage(5);
+       ((u8 *)io_bitmap_a)[0x5000 / 8] = (1 << (0x5000 % 8));
+       inb(0x5000);
+       if (stage == 6)
+               report("I/O bitmap - I/O port, low part", 1);
+       else
+               report("I/O bitmap - I/O port, low part", 0);
+       set_stage(6);
+       ((u8 *)io_bitmap_b)[0x1000 / 8] = (1 << (0x1000 % 8));
+       inb(0x9000);
+       if (stage == 7)
+               report("I/O bitmap - I/O port, high part", 1);
+       else
+               report("I/O bitmap - I/O port, high part", 0);
+       // test partial pass
+       set_stage(7);
+       inl(0x4FFF);
+       if (stage == 8)
+               report("I/O bitmap - partial pass", 1);
+       else
+               report("I/O bitmap - partial pass", 0);
+       // test overrun
+       set_stage(8);
+       memset(io_bitmap_b, 0xFF, PAGE_SIZE);
+       inl(0xFFFF);
+       memset(io_bitmap_b, 0x0, PAGE_SIZE);
+       if (stage == 9)
+               report("I/O bitmap - overrun", 1);
+       else
+               report("I/O bitmap - overrun", 0);
+       
+       return;
+}
+
+static int iobmp_exit_handler()
+{
+       u64 guest_rip;
+       ulong reason, exit_qual;
+       u32 insn_len;
+       //u32 ctrl_cpu0;
+
+       guest_rip = vmcs_read(GUEST_RIP);
+       reason = vmcs_read(EXI_REASON) & 0xff;
+       exit_qual = vmcs_read(EXI_QUALIFICATION);
+       insn_len = vmcs_read(EXI_INST_LEN);
+       switch (reason) {
+       case VMX_IO:
+               switch (stage) {
+               case 2:
+                       if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_BYTE)
+                               report("I/O bitmap - I/O width, byte", 0);
+                       else
+                               report("I/O bitmap - I/O width, byte", 1);
+                       if (!(exit_qual & VMX_IO_IN))
+                               report("I/O bitmap - I/O direction, in", 0);
+                       else
+                               report("I/O bitmap - I/O direction, in", 1);
+                       set_stage(stage + 1);
+                       break;
+               case 3:
+                       if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_WORD)
+                               report("I/O bitmap - I/O width, word", 0);
+                       else
+                               report("I/O bitmap - I/O width, word", 1);
+                       if (!(exit_qual & VMX_IO_IN))
+                               report("I/O bitmap - I/O direction, out", 1);
+                       else
+                               report("I/O bitmap - I/O direction, out", 0);
+                       set_stage(stage + 1);
+                       break;
+               case 4:
+                       if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_LONG)
+                               report("I/O bitmap - I/O width, long", 0);
+                       else
+                               report("I/O bitmap - I/O width, long", 1);
+                       set_stage(stage + 1);
+                       break;
+               case 5:
+                       if (((exit_qual & VMX_IO_PORT_MASK) >> 
VMX_IO_PORT_SHIFT) == 0x5000)
+                               set_stage(stage + 1);
+                       break;
+               case 6:
+                       if (((exit_qual & VMX_IO_PORT_MASK) >> 
VMX_IO_PORT_SHIFT) == 0x9000)
+                               set_stage(stage + 1);
+                       break;
+               case 7:
+                       if (((exit_qual & VMX_IO_PORT_MASK) >> 
VMX_IO_PORT_SHIFT) == 0x4FFF)
+                               set_stage(stage + 1);
+                       //ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0);
+                       //ctrl_cpu0 &= (~CPU_IO_BITMAP);
+                       //vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0);
+                       break;
+               case 8:
+                       if (((exit_qual & VMX_IO_PORT_MASK) >> 
VMX_IO_PORT_SHIFT) == 0xFFFF)
+                               set_stage(stage + 1);
+                       break;
+               case 0:
+               case 1:
+                       set_stage(stage + 1);
+               default:
+                       break;
+               }
+               vmcs_write(GUEST_RIP, guest_rip + insn_len);
+               return VMX_TEST_RESUME;
+       default:
+               printf("guest_rip = 0x%llx\n", guest_rip);
+               printf("\tERROR : Undefined exit reason, reason = %d.\n", 
reason);
+               break;
+       }
+       return VMX_TEST_VMEXIT;
+}
+
 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs
    basic_* just implement some basic functions */
 struct vmx_test vmx_tests[] = {
@@ -486,5 +651,7 @@ struct vmx_test vmx_tests[] = {
                test_ctrl_efer_exit_handler, basic_syscall_handler, {0} },
        { "CR shadowing", basic_init, cr_shadowing_main,
                cr_shadowing_exit_handler, basic_syscall_handler, {0} },
+       { "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler,
+               basic_syscall_handler, {0} },
        { NULL, NULL, NULL, NULL, NULL, {0} },
 };
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to