#define IDLE_DOMAIN 32767
#define DEFAULT_DOMAIN 32768
+#define MAX_VLAPIC_LIST 8
struct vlapic_struct {
- int outstanding_ipis;
- tsc_t first_ipi_tsc;
- int ipi_virq_injected;
+ struct {
+ struct outstanding_ipi {
+ tsc_t first_tsc;
+ int vec, count;
+ int injected, valid;
+ } list[MAX_VLAPIC_LIST];
+ } outstanding;
};
struct vcpu_data {
"dest_field", "self", "all-inc", "all-exc"
};
-void clear_vlapic(struct vlapic_struct *vla) {
- vla->outstanding_ipis = 0;
- vla->first_ipi_tsc = 0;
- vla->ipi_virq_injected = 0;
+void hvm_vlapic_vmentry_cleanup(struct vcpu_data *v, tsc_t tsc)
+{
+ int i;
+
+ struct vlapic_struct *vla = &v->vlapic;
+
+ for(i=0; i<MAX_VLAPIC_LIST; i++)
+ {
+ unsigned long long lat=0;
+ struct outstanding_ipi *o = vla->outstanding.list + i;
+
+ if(!(o->valid && o->injected))
+ continue;
+
+ if(tsc >= o->first_tsc)
+ lat = tsc - o->first_tsc;
+ else
+ fprintf(warn, "Strange, vec %d first_tsc %lld > ri->tsc %lld!\n",
+ o->vec, o->first_tsc, tsc);
+
+ if(opt.dump_ipi_latency
+ || (opt.dump_all && o->count > 1)) {
+ struct time_struct t;
+ cycles_to_time(lat, &t);
+ printf(" [vla] d%dv%d vec %d ipis %d, latency %lld (%lu.%09lu s)\n",
+ v->d->did, v->vid, o->vec, o->count, lat,
+ t.s, t.ns);
+ }
+
+#if 0
+ /* FIXME: make general somehow */
+ if(opt.summary_info)
+ {
+ update_summary(&h->summary.ipi_latency, lat);
+ h->summary.ipi_count[vla->outstanding_ipis]++;
+ }
+#endif
+
+ o->vec = o->count = o->injected = o->valid = o->first_tsc = 0;
+ }
+}
+
+void hvm_vlapic_clear(struct vlapic_struct *vla)
+{
+ bzero(vla, sizeof(*vla));
+}
+
+struct outstanding_ipi *find_vec(struct vlapic_struct *vla, int vec)
+{
+ struct outstanding_ipi *o = NULL;
+ int i;
+
+ /* Find the entry for this vector, or the first empty one. */
+ for(i=0; i<MAX_VLAPIC_LIST; i++)
+ {
+ if(vla->outstanding.list[i].valid && vla->outstanding.list[i].vec == vec)
+ {
+ o = vla->outstanding.list + i;
+ break;
+ } else if(!vla->outstanding.list[i].valid && !o)
+ o = vla->outstanding.list + i;
+ }
+
+ if(!o->valid) {
+ o->vec = vec;
+ o->valid = 1;
+ }
+
+ return o;
}
void hvm_vlapic_icr_handler(struct hvm_data *h)
};
} icr = { .val = e->data };
+ void ipi_send(struct vcpu_data *ov, int vec)
+ {
+ struct vlapic_struct *vla;
+ struct outstanding_ipi *o = NULL;
+
+ if(ov->runstate.state == RUNSTATE_LOST) {
+ if(opt.dump_all)
+ fprintf(warn, "%s: v%d in state RUNSTATE_LOST, not counting ipi\n",
+ __func__, ov->vid);
+ return;
+ }
+
+ vla = &ov->vlapic;
+
+ o = find_vec(vla, vec);
+
+ if(!o)
+ {
+ fprintf(warn, "%s: Couldn't find an open slot!\n",
+ __func__);
+ return;
+ }
+
+ if(!o->first_tsc)
+ o->first_tsc = P.now;
+
+ if(opt.dump_all && o->count == 0 && o->injected)
+ printf(" [vla] Pre-injection\n");
+
+ o->count++;
+
+ if((opt.dump_all || opt.dump_cooked)
+#if 0
+ && (ov->runstate.state != RUNSTATE_RUNNING
+ || ov->hvm.vmexit_valid)
+#endif
+ )
+ printf(" [vla] d%dv%d vec %d state %s (outstanding ipis %d)\n",
+ ov->d->did, ov->vid,
+ o->vec,
+ runstate_name[ov->runstate.state],
+ o->count);
+ }
+
if(e->mmio_is_write) {
if(opt.dump_all || opt.dump_cooked) {
- printf(" vlapic icr vec %d %s\n",
+ printf(" [vla] d%dv%d icr vec %d %s\n",
+ h->v->d->did, h->v->vid,
icr.vec,
hvm_vlapic_icr_dest_shorthand_name[icr.dest_shorthand]);
}
- if(icr.dest_shorthand == 3 && icr.vec == 0xd1)
+ if(icr.dest_shorthand == 3)
{
struct vcpu_data *ov, *v = h->v;
- struct vlapic_struct *vla;
struct domain_data *d = v->d;
int i;
if(!ov || ov == v)
continue;
- if(ov->runstate.state == RUNSTATE_LOST) {
- if(opt.dump_all)
- fprintf(warn, "%s: v%d in state RUNSTATE_LOST, not counting ipi\n",
- __func__, ov->vid);
- continue;
- }
-
- vla = &ov->vlapic;
+ ipi_send(ov, icr.vec);
- if(!vla->first_ipi_tsc)
- {
- struct record_info *ri;
- ri = &v->p->ri;
- vla->first_ipi_tsc = ri->tsc;
- }
-
- vla->outstanding_ipis++;
-
- if((opt.dump_all || opt.dump_cooked) &&
- (ov->runstate.state != RUNSTATE_RUNNING))
- printf(" v%d in state %s (outstanding ipis %d)\n",
- ov->vid, runstate_name[ov->runstate.state],
- vla->outstanding_ipis);
}
+ } else if(icr.dest_shorthand != 1) {
+ fprintf(warn, "Strange, vlapic icr %s vec %d!\n",
+ hvm_vlapic_icr_dest_shorthand_name[icr.dest_shorthand],
+ icr.vec);
}
} else {
/* Read */
if(opt.dump_all || opt.dump_cooked) {
- printf(" vlapic icr status %s\n",
+ printf(" [vla] d%dv%d icr status %s\n",
+ h->v->d->did, h->v->vid,
icr.delivery_status?"pending":"idle");
}
}
}
+void hvm_vlapic_inject(struct vcpu_data *v, int vec)
+{
+ struct vlapic_struct *vla = &v->vlapic;
+ struct outstanding_ipi *o = NULL;
+
+ o = find_vec(vla, vec);
+
+ if(o) {
+ if(opt.dump_all)
+ printf(" [vla] d%dv%d vec %d injecting\n",
+ v->d->did, v->vid, vec);
+ o->injected=1;
+ } else {
+ fprintf(stderr, "%s: Couldn't find an open ipi slot!\n",
+ __func__);
+ }
+}
+
void hvm_vlapic_eoi_handler(struct hvm_data *h) {
if(opt.dump_all || opt.dump_cooked)
- printf(" vlapic eoi\n");
+ printf(" [vla] d%dv%d eoi\n",
+ h->v->d->did, h->v->vid);
}
void hvm_vlapic_handler(struct hvm_data *h)
}
}
-
- /* Vista bug */
- if(r->vector == 0xd1 && h->v->vlapic.outstanding_ipis)
- h->v->vlapic.ipi_virq_injected = 1;
+ hvm_vlapic_inject(h->v, r->vector);
}
/* I/O Handling */
/* Vista bug
* This has to be done here because irqs are injected on the path out
* to vmexit. */
- if(h->v->vlapic.ipi_virq_injected)
- {
- struct vcpu_data *v = h->v;
- struct vlapic_struct *vla = &v->vlapic;
- unsigned long long lat=0;
-
- if(ri->tsc > vla->first_ipi_tsc)
- lat = ri->tsc - vla->first_ipi_tsc;
- else
- fprintf(stderr, "Strange, first_ipi_tsc %lld > ri->tsc %lld!\n",
- vla->first_ipi_tsc, ri->tsc);
-
- if((opt.dump_all || opt.dump_cooked) && vla->outstanding_ipis > 1)
- {
- struct time_struct t;
- cycles_to_time(lat, &t);
- printf(" d%dv%d received %d ipis, latency %lld (%lu.%09lu s)\n",
- v->d->did, v->vid, vla->outstanding_ipis, lat,
- t.s, t.ns);
- }
-
- if(opt.summary_info)
- {
- update_summary(&h->summary.ipi_latency, lat);
- h->summary.ipi_count[vla->outstanding_ipis]++;
-
- }
-
- if(opt.dump_cooked || opt.dump_ipi_latency) {
- struct time_struct t;
- abs_cycles_to_time(ri->tsc, &t);
- printf("Ipis: %d latency: %lld (time %lu.%09lu s)\n",
- vla->outstanding_ipis, lat, t.s, t.ns);
- }
-
- clear_vlapic(vla);
- }
+ hvm_vlapic_vmentry_cleanup(h->v, ri->tsc);
if(h->w2h.waking && opt.dump_all)
printf(" [w2h] d%dv%d Finishing waking\n",
if(v->data_type == VCPU_DATA_HVM)
v->hvm.vmexit_valid=0;
runstate_update(v, RUNSTATE_LOST, tsc);
- clear_vlapic(&v->vlapic);
+ hvm_vlapic_clear(&v->vlapic);
if(v->data_type == VCPU_DATA_HVM) {
int i;
if ( p->current ) {
- clear_vlapic(&p->current->vlapic);
+ hvm_vlapic_clear(&p->current->vlapic);
if(p->current->data_type == VCPU_DATA_HVM) {
p->current->hvm.vmexit_valid=0;
cr3_switch(0, &p->current->hvm);