diff mbox

[V2] tests/xen-access: Added vm_event emulation tests

Message ID 1492242328-22912-1-git-send-email-rcojocaru@bitdefender.com (mailing list archive)
State New, archived
Headers show

Commit Message

Razvan Cojocaru April 15, 2017, 7:45 a.m. UTC
This patch adds support for testing instruction emulation when
required by the vm_event reply sent for MEM_ACCESS events. To this
end, it adds the "emulate_write" and "emulate_exec" parameters
that behave like the old "write" and "exec" parameters, except
instead of allowing writes / executes for a hit page, they emulate
the trigger instruction. The new parameters don't mark all of the
guest's pages, instead they stop at the arbitrary low limit of
the first 1000 pages - otherwise the guest would slow to a crawl.
Since the emulator is still incomplete and has trouble with
emulating competing writes in SMP scenarios, the new tests are
only meant for debugging issues.

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>

---
Changes since V1:
 - Moved emulate_write and emulate_exec to the x86-only part of
   the code.
 - Stopped pointlessly setting after_first_access.
 - Added a comment explaining the 1000 pages limit.
---
 tools/tests/xen-access/xen-access.c | 52 ++++++++++++++++++++++++++++++-------
 1 file changed, 42 insertions(+), 10 deletions(-)

Comments

Tamas K Lengyel April 17, 2017, 10:24 p.m. UTC | #1
On Sat, Apr 15, 2017 at 1:45 AM, Razvan Cojocaru <rcojocaru@bitdefender.com>
wrote:

> This patch adds support for testing instruction emulation when
> required by the vm_event reply sent for MEM_ACCESS events. To this
> end, it adds the "emulate_write" and "emulate_exec" parameters
> that behave like the old "write" and "exec" parameters, except
> instead of allowing writes / executes for a hit page, they emulate
> the trigger instruction. The new parameters don't mark all of the
> guest's pages, instead they stop at the arbitrary low limit of
> the first 1000 pages - otherwise the guest would slow to a crawl.
> Since the emulator is still incomplete and has trouble with
> emulating competing writes in SMP scenarios, the new tests are
> only meant for debugging issues.
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>
>
Acked-by: Tamas K Lengyel <tamas@tklengyel.com>
diff mbox

Patch

diff --git a/tools/tests/xen-access/xen-access.c b/tools/tests/xen-access/xen-access.c
index ff4d289..0852ac5 100644
--- a/tools/tests/xen-access/xen-access.c
+++ b/tools/tests/xen-access/xen-access.c
@@ -337,7 +337,7 @@  void usage(char* progname)
 {
     fprintf(stderr, "Usage: %s [-m] <domain_id> write|exec", progname);
 #if defined(__i386__) || defined(__x86_64__)
-            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access");
+            fprintf(stderr, "|emulate_write|emulate_exec|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access");
 #elif defined(__arm__) || defined(__aarch64__)
             fprintf(stderr, "|privcall");
 #endif
@@ -369,6 +369,7 @@  int main(int argc, char *argv[])
     int debug = 0;
     int cpuid = 0;
     int desc_access = 0;
+    int emulate = 0;
     uint16_t altp2m_view_id = 0;
 
     char* progname = argv[0];
@@ -411,6 +412,18 @@  int main(int argc, char *argv[])
         memaccess = 1;
     }
 #if defined(__i386__) || defined(__x86_64__)
+    else if ( !strcmp(argv[0], "emulate_write") )
+    {
+        default_access = XENMEM_access_rx;
+        emulate = 1;
+        memaccess = 1;
+    }
+    else if ( !strcmp(argv[0], "emulate_exec") )
+    {
+        default_access = XENMEM_access_rw;
+        emulate = 1;
+        memaccess = 1;
+    }
     else if ( !strcmp(argv[0], "breakpoint") )
     {
         breakpoint = 1;
@@ -527,6 +540,21 @@  int main(int argc, char *argv[])
 
     if ( memaccess && !altp2m )
     {
+        uint32_t nr_pages = xenaccess->max_gpfn - START_PFN;
+
+        /*
+          The Xen emulator is not yet complete. Limiting ourselves to a small number
+          of pages from the first part of the guest's memory makes it less likely for
+          the guest to get stuck on an UNHANDLEABLE instruction (since that memory
+          tends to be used by simpler kernel code), and is less likely to have a heavy
+          impact on the guest (since emulating everything will take a heavy toll).
+          While it presents no guarantee that all the instructions will pass emulation,
+          using the first 1000 pages has proven useful in practice. The limit can be
+          changed in the future.
+        */
+        if ( emulate && nr_pages > 1000 )
+            nr_pages = 1000;
+
         /* Set the default access type and convert all pages to it */
         rc = xc_set_mem_access(xch, domain_id, default_access, ~0ull, 0);
         if ( rc < 0 )
@@ -535,8 +563,7 @@  int main(int argc, char *argv[])
             goto exit;
         }
 
-        rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN,
-                               (xenaccess->max_gpfn - START_PFN) );
+        rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN, nr_pages);
 
         if ( rc < 0 )
         {
@@ -702,15 +729,20 @@  int main(int argc, char *argv[])
                 }
                 else if ( default_access != after_first_access )
                 {
-                    rc = xc_set_mem_access(xch, domain_id, after_first_access,
-                                           req.u.mem_access.gfn, 1);
-                    if (rc < 0)
+                    if ( !emulate )
                     {
-                        ERROR("Error %d setting gfn to access_type %d\n", rc,
-                              after_first_access);
-                        interrupted = -1;
-                        continue;
+                        rc = xc_set_mem_access(xch, domain_id, after_first_access,
+                                               req.u.mem_access.gfn, 1);
+                        if (rc < 0)
+                        {
+                            ERROR("Error %d setting gfn to access_type %d\n", rc,
+                                  after_first_access);
+                            interrupted = -1;
+                            continue;
+                        }
                     }
+                    else
+                        rsp.flags |= VM_EVENT_FLAG_EMULATE;
                 }
 
                 rsp.u.mem_access = req.u.mem_access;