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

[Xen-devel] [PATCH 07 of 12] xenalyze: Handle MMIO records from different vmexits



handle_mmio() is called in Xen as a generic way to do emulation;
in VMX, this at least includes not only EXCEPTION_NMI (page faults
in shadow mode) and NPF (nested page fault in HAP mode), but also
APIC_ACCESS and sometimes even CR_ACCESS.

This patch allows xenalyze to process and summarize mmio records
for different vmexits separately.

The change that causes the biggest number of line changes is pulling
the MMIO information out of pf_xen_extra and in its own struct, which
is kept separate from the inflight union.

Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>

diff -r 910605f7ade3 -r c9f583c65e07 xenalyze.c
--- a/xenalyze.c        Mon Nov 28 16:16:23 2011 +0000
+++ b/xenalyze.c        Mon Nov 28 16:16:23 2011 +0000
@@ -1252,6 +1252,20 @@ char * pf_xen_name[PF_XEN_MAX] = {
 
 #define CORR_VA_INVALID (0ULL-1)
 
+enum {
+    NONPF_MMIO_APIC,
+    NONPF_MMIO_NPF,
+    NONPF_MMIO_UNKNOWN,
+    NONPF_MMIO_MAX
+};
+
+struct mmio_info {
+    unsigned long long gpa;
+    unsigned long long va; /* Filled only by shadow */
+    unsigned data;
+    unsigned data_valid:1, is_write:1;
+};
+
 struct pf_xen_extra {
     unsigned long long va;
     union {
@@ -1302,9 +1316,7 @@ struct pf_xen_extra {
     /* Flags */
     unsigned corr_valid:1,
         corr_is_kernel:1,
-        va_is_kernel:1,
-        mmio_data_valid:1,
-        mmio_is_write:1;
+        va_is_kernel:1;
 };
 
 struct pcpu_info;
@@ -1351,6 +1363,7 @@ struct hvm_data {
         struct event_cycle_summary cr3_write_resyncs[RESYNCS_MAX+1];
         struct event_cycle_summary vmcall[HYPERCALL_MAX+1];
         struct event_cycle_summary generic[HVM_EVENT_HANDLER_MAX];
+        struct event_cycle_summary mmio[NONPF_MMIO_MAX];
         struct hvm_gi_struct {
             int count;
             struct cycle_summary runtime[GUEST_INTERRUPT_CASE_MAX];
@@ -1367,33 +1380,37 @@ struct hvm_data {
     } summary;
 
     /* In-flight accumulation information */
-    union {
-        struct {
-            unsigned port:31,
-                is_write:1;
-            unsigned int val;
-        } io;
-        struct pf_xen_extra pf_xen;
-        struct {
-            unsigned cr;
-            unsigned long long val;
-            int repromote;
-        } cr_write;
-        struct {
-            unsigned addr;
-            unsigned long long val;
-        } msr;
-        struct {
-            unsigned int event;
-            uint32_t d[4];
-        } generic;
-        struct {
-            unsigned eax;
-        } vmcall;
-        struct {
-            unsigned vec;
-        } intr;
-    } inflight;
+    struct {
+        union {
+            struct {
+                unsigned port:31,
+                    is_write:1;
+                unsigned int val;
+            } io;
+            struct pf_xen_extra pf_xen;
+            struct {
+                unsigned cr;
+                unsigned long long val;
+                int repromote;
+            } cr_write;
+            struct {
+                unsigned addr;
+                unsigned long long val;
+            } msr;
+            struct {
+                unsigned int event;
+                uint32_t d[4];
+            } generic;
+            struct {
+                unsigned eax;
+            } vmcall;
+            struct {
+                unsigned vec;
+            } intr;
+        };
+        /* MMIO gets its separate area, since many exits may use it */
+        struct mmio_info mmio;
+    }inflight;
     int resyncs;
     void (*post_process)(struct hvm_data *);
     tsc_t exit_tsc, arc_cycles, entry_tsc;
@@ -3309,6 +3326,7 @@ void pf_preprocess(struct pf_xen_extra *
 
 void hvm_pf_xen_preprocess(unsigned event, struct hvm_data *h) {
     struct pf_xen_extra *e = &h->inflight.pf_xen;
+    struct mmio_info *m = &h->inflight.mmio;
     struct hvm_pf_xen_record *r = (typeof(r))h->d;
 
     if(event == TRC_HVM_PF_XEN64)
@@ -3325,7 +3343,7 @@ void hvm_pf_xen_preprocess(unsigned even
         e->error_code = r->x32.error_code;
     }
 
-    if(e->mmio_data_valid)
+    if(m->data_valid)
         e->pf_case = PF_XEN_MMIO;
     else
     {
@@ -3363,8 +3381,11 @@ void hvm_pf_xen_postprocess(struct hvm_d
     struct pf_xen_extra *e = &h->inflight.pf_xen;
 
     if(opt.summary_info) {
-        update_summary(&h->summary.pf_xen[e->pf_case],
-                       h->arc_cycles);
+        if(e->pf_case)
+            update_summary(&h->summary.pf_xen[e->pf_case],
+                           h->arc_cycles);
+        else
+            fprintf(warn, "Strange, pf_case 0!\n");
         switch(e->pf_case)
         {
         case PF_XEN_EMULATE:
@@ -3530,7 +3551,7 @@ struct outstanding_ipi *find_vec(struct 
 
 void hvm_vlapic_icr_handler(struct hvm_data *h)
 {
-    struct pf_xen_extra *e = &h->inflight.pf_xen;
+    struct mmio_info *m = &h->inflight.mmio;
     union {
         unsigned int val;
         struct {
@@ -3544,7 +3565,7 @@ void hvm_vlapic_icr_handler(struct hvm_d
                 _res2:2,
                 dest_shorthand:2;
         };
-    } icr = { .val = e->data };
+    } icr = { .val = m->data };
 
     void ipi_send(struct vcpu_data *ov, int vec)
     {
@@ -3590,7 +3611,7 @@ void hvm_vlapic_icr_handler(struct hvm_d
                    o->count);
     }
 
-    if(e->mmio_is_write) {
+    if(m->is_write) {
         if(opt.dump_all || opt.dump_cooked) {
             printf("              [vla] d%dv%d icr vec %d %s\n",
                    h->v->d->did, h->v->vid,
@@ -3657,9 +3678,9 @@ void hvm_vlapic_eoi_handler(struct hvm_d
 
 void hvm_vlapic_handler(struct hvm_data *h)
 {
-    struct pf_xen_extra *e = &h->inflight.pf_xen;
-
-    switch(e->gpa) {
+    struct mmio_info *m = &h->inflight.mmio;
+
+    switch(m->gpa) {
     case 0xfee00300:
         hvm_vlapic_icr_handler(h);
         break;
@@ -3673,14 +3694,56 @@ void hvm_vlapic_handler(struct hvm_data 
 /* Also called by shadow_mmio_postprocess */
 void enumerate_mmio(struct hvm_data *h)
 {
-    struct pf_xen_extra *e = &h->inflight.pf_xen;
-
-    if ( e->mmio_data_valid )
-        update_io_address(&h->summary.io.mmio, e->gpa, e->mmio_is_write, 
h->arc_cycles, e->va);
+    struct mmio_info *m = &h->inflight.mmio;
+
+    if ( m->data_valid )
+        update_io_address(&h->summary.io.mmio, m->gpa, m->is_write, 
h->arc_cycles, m->va);
+}
+
+void hvm_mmio_summary(struct hvm_data *h, void *data)
+{
+    int reason=(int)data;
+
+    PRINT_SUMMARY(h->summary.mmio[reason],
+                  "   mmio ");
 }
 
 void hvm_mmio_assist_postprocess(struct hvm_data *h)
 {
+    int reason;
+
+    switch(h->exit_reason)
+    {
+    case VMEXIT_NPF:
+    case EXIT_REASON_EPT_VIOLATION:
+        reason=NONPF_MMIO_NPF;
+        hvm_set_summary_handler(h, hvm_mmio_summary, (void *)reason);
+        break;
+    case EXIT_REASON_APIC_ACCESS:
+        reason=NONPF_MMIO_APIC;
+        hvm_set_summary_handler(h, hvm_mmio_summary, (void *)reason);
+        break;
+    default:
+    {
+        static int warned = 0;
+        if (!warned)
+        {
+            fprintf(stderr, "%s: Strange, MMIO with unexpected exit reason 
%d\n",
+                    __func__, h->exit_reason);
+            warned=1;
+        }
+        reason=NONPF_MMIO_UNKNOWN;
+        hvm_set_summary_handler(h, hvm_mmio_summary, (void *)reason);
+        break;
+    }
+    }
+
+    if(opt.summary_info)
+    {
+        update_summary(&h->summary.mmio[reason],
+                       h->arc_cycles);
+    }
+
     if ( opt.with_mmio_enumeration )
         enumerate_mmio(h);
 }
@@ -3688,8 +3751,7 @@ void hvm_mmio_assist_postprocess(struct 
 #define HVM_IO_ASSIST_WRITE 0x200
 void hvm_mmio_assist_process(struct record_info *ri, struct hvm_data *h)
 {
-    struct pf_xen_extra *e = &h->inflight.pf_xen;
-
+    struct mmio_info *m = &h->inflight.mmio;
     union {
         struct {
             unsigned int gpa;
@@ -3711,30 +3773,32 @@ void hvm_mmio_assist_process(struct reco
     } mevt = { .event = ri->event };
 
     if(mevt.x64) {
-        e->gpa = r->x64.gpa;
-        e->data = r->x64.data;
+        m->gpa = r->x64.gpa;
+        m->data = r->x64.data;
         if(ri->extra_words*(sizeof(unsigned int))==sizeof(r->x64))
-            e->mmio_data_valid=1;
+            m->data_valid=1;
     } else {
-        e->gpa = r->x32.gpa;
-        e->data = r->x32.data;
+        m->gpa = r->x32.gpa;
+        m->data = r->x32.data;
         if(ri->extra_words*(sizeof(unsigned int))==sizeof(r->x32))
-            e->mmio_data_valid=1;
-    }
-
-    e->mmio_is_write = mevt.write;
+            m->data_valid=1;
+    }
+
+    m->is_write = mevt.write;
 
     if(opt.dump_all)
     {
-        if(e->mmio_data_valid)
-            printf("]%s mmio_assist %c gpa %llx data %x\n", h->dump_header,
-                   mevt.write?'w':'r', e->gpa, e->data);
+        if(m->data_valid)
+            printf("]%s mmio_assist %c gpa %llx data %x\n",
+                   h->dump_header,
+                   mevt.write?'w':'r',
+                   m->gpa, m->data);
         else
             printf("]%s mmio_assist %c gpa %llx (no data)\n", h->dump_header,
-                   mevt.write?'w':'r', e->gpa);
-    }
-
-    if((e->gpa & 0xfffff000) == 0xfee00000)
+                   mevt.write?'w':'r', m->gpa);
+    }
+
+    if((m->gpa & 0xfffff000) == 0xfee00000)
         hvm_vlapic_handler(h);
 
     /* Catch MMIOs that don't go through the shadow code; tolerate
@@ -5857,6 +5921,7 @@ void shadow_emulate_other_process(struct
 
     e->gfn = r.gfn;
     e->va = r.va;
+    e->pf_case = sevt.minor;
 
     pf_preprocess(e, h->v->guest_paging_levels);
 
@@ -6035,10 +6100,15 @@ void shadow_fixup_process(struct record_
 void shadow_mmio_postprocess(struct hvm_data *h)
 {
     struct pf_xen_extra *e = &h->inflight.pf_xen;
+    struct mmio_info *m = &h->inflight.mmio;
 
     if ( opt.summary_info )
     {
-        update_summary(&h->summary.pf_xen[e->pf_case], h->arc_cycles);
+        if(e->pf_case)
+            update_summary(&h->summary.pf_xen[e->pf_case],
+                           h->arc_cycles);
+        else
+            fprintf(warn, "Strange, pf_case 0!\n");
 
         hvm_update_short_summary(h, HVM_SHORT_SUMMARY_MMIO);
     }
@@ -6048,23 +6118,23 @@ void shadow_mmio_postprocess(struct hvm_
 
     if ( opt.dump_cooked )
     {
-        if(e->mmio_data_valid)
+        if(m->data_valid)
             printf(" %s %smmio %s va %llx eip %llx%s gpa %llx data %x\n",
                    h->dump_header,
                    (e->pf_case==PF_XEN_FAST_MMIO)?"fast ":"",
-                   e->mmio_is_write?"write":"read",
+                   m->is_write?"write":"read",
                    e->va,
                    h->rip, find_symbol(h->rip),
-                   e->gpa,
-                   e->data);
+                   m->gpa,
+                   m->data);
         else
             printf(" %s %smmio %s va %llx eip %llx%s gpa %llx (no data)\n",
                    h->dump_header,
                    (e->pf_case==PF_XEN_FAST_MMIO)?"fast ":"",
-                   e->mmio_is_write?"write":"read",
-                   e->va,
+                   m->is_write?"write":"read",
+                   m->va,
                    h->rip, find_symbol(h->rip),
-                   e->gpa);
+                   m->gpa);
     }
 
 }
@@ -6072,6 +6142,7 @@ void shadow_mmio_postprocess(struct hvm_
 void shadow_mmio_process(struct record_info *ri, struct hvm_data *h)
 {
     struct pf_xen_extra *e = &h->inflight.pf_xen;
+    struct mmio_info *m = &h->inflight.mmio;
     union {
         /* for PAE, guest_l1e may be 64 while guest_va may be 32;
            so put it first for alignment sake. */
@@ -6104,7 +6175,7 @@ void shadow_mmio_process(struct record_i
             error(ERR_RECORD, ri);
             return;
         }
-        e->va = r->gpl2.va;
+        e->va = m->va = r->gpl2.va;
         break;
     case 4:
         if(sizeof(r->gpl4) != ri->extra_words * 4)
@@ -6115,7 +6186,7 @@ void shadow_mmio_process(struct record_i
             error(ERR_RECORD, ri);
             return;
         }
-        e->va = r->gpl4.va;
+        e->va = m->va = r->gpl4.va;
         break;
     }
 
@@ -6135,7 +6206,11 @@ void shadow_propagate_postprocess(struct
 
     if ( opt.summary_info )
     {
-        update_summary(&h->summary.pf_xen[e->pf_case], h->arc_cycles);
+        if(e->pf_case)
+            update_summary(&h->summary.pf_xen[e->pf_case],
+                           h->arc_cycles);
+        else
+            fprintf(warn, "Strange, pf_case 0!\n");
 
         hvm_update_short_summary(h, HVM_SHORT_SUMMARY_PROPAGATE);
     }
@@ -6255,20 +6330,20 @@ void shadow_fault_generic_dump(unsigned 
 
 void shadow_fault_generic_postprocess(struct hvm_data *h)
 {
-    union shadow_event sevt = { .event = h->inflight.generic.event };
+    struct pf_xen_extra *e = &h->inflight.pf_xen;
+    if ( e->pf_case < PF_XEN_NOT_SHADOW || e->pf_case > PF_XEN_LAST_FAULT )
+    {
+        fprintf(warn, "%s: Strange, unexpected case %d\n",
+                __func__, e->pf_case);
+        return;
+    }
+
     if(opt.summary_info) {
-        update_summary(&h->summary.pf_xen[sevt.minor],
-                       h->arc_cycles);
+        update_summary(&h->summary.pf_xen[e->pf_case],
+                           h->arc_cycles);
 
         hvm_update_short_summary(h, HVM_SHORT_SUMMARY_PROPAGATE);
     }
-
-    if(opt.dump_cooked)
-    {
-        shadow_fault_generic_dump(h->inflight.generic.event,
-                            h->inflight.generic.d,
-                            " ", h->dump_header);
-    }
 }
 
 void shadow_fault_generic_process(struct record_info *ri, struct hvm_data *h)

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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