📄 vcpu.c
字号:
IA64FAULT vcpu_get_psr_masked(VCPU * vcpu, u64 * pval){ u64 psr = vcpu_get_psr(vcpu); *pval = psr & (MASK(0, 32) | MASK(35, 2)); return IA64_NO_FAULT;}BOOLEAN vcpu_get_psr_ic(VCPU * vcpu){ return !!PSCB(vcpu, interrupt_collection_enabled);}BOOLEAN vcpu_get_psr_i(VCPU * vcpu){ return !vcpu->vcpu_info->evtchn_upcall_mask;}/************************************************************************** VCPU interrupt control register access routines**************************************************************************/void vcpu_pend_unspecified_interrupt(VCPU * vcpu){ PSCB(vcpu, pending_interruption) = 1;}void vcpu_pend_interrupt(VCPU * vcpu, u64 vector){ if (vector & ~0xff) { printk("vcpu_pend_interrupt: bad vector\n"); return; } if (vcpu->arch.event_callback_ip) { printk("Deprecated interface. Move to new event based " "solution\n"); return; } if (VMX_DOMAIN(vcpu)) { set_bit(vector, VCPU(vcpu, irr)); } else { set_bit(vector, PSCBX(vcpu, irr)); PSCB(vcpu, pending_interruption) = 1; }}#define IA64_TPR_MMI 0x10000#define IA64_TPR_MIC 0x000f0/* checks to see if a VCPU has any unmasked pending interrupts * if so, returns the highest, else returns SPURIOUS_VECTOR *//* NOTE: Since this gets called from vcpu_get_ivr() and the * semantics of "mov rx=cr.ivr" ignore the setting of the psr.i bit, * this routine also ignores pscb.interrupt_delivery_enabled * and this must be checked independently; see vcpu_deliverable interrupts() */u64 vcpu_check_pending_interrupts(VCPU * vcpu){ u64 *p, *r, bits, bitnum, mask, i, vector; if (vcpu->arch.event_callback_ip) return SPURIOUS_VECTOR; /* Always check pending event, since guest may just ack the * event injection without handle. Later guest may throw out * the event itself. */ check_start: if (event_pending(vcpu) && !test_bit(vcpu->domain->shared_info->arch.evtchn_vector, &PSCBX(vcpu, insvc[0]))) vcpu_pend_interrupt(vcpu, vcpu->domain->shared_info->arch. evtchn_vector); p = &PSCBX(vcpu, irr[3]); r = &PSCBX(vcpu, insvc[3]); for (i = 3 ;; p--, r--, i--) { bits = *p; if (bits) break; // got a potential interrupt if (*r) { // nothing in this word which is pending+inservice // but there is one inservice which masks lower return SPURIOUS_VECTOR; } if (i == 0) { // checked all bits... nothing pending+inservice return SPURIOUS_VECTOR; } } // have a pending,deliverable interrupt... see if it is masked bitnum = ia64_fls(bits);//printk("XXXXXXX vcpu_check_pending_interrupts: got bitnum=%p...\n",bitnum); vector = bitnum + (i * 64); mask = 1L << bitnum; /* sanity check for guest timer interrupt */ if (vector == (PSCB(vcpu, itv) & 0xff)) { uint64_t now = ia64_get_itc(); if (now < PSCBX(vcpu, domain_itm)) {// printk("Ooops, pending guest timer before its due\n"); PSCBX(vcpu, irr[i]) &= ~mask; goto check_start; } }//printk("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...\n",vector); if (*r >= mask) { // masked by equal inservice//printk("but masked by equal inservice\n"); return SPURIOUS_VECTOR; } if (PSCB(vcpu, tpr) & IA64_TPR_MMI) { // tpr.mmi is set//printk("but masked by tpr.mmi\n"); return SPURIOUS_VECTOR; } if (((PSCB(vcpu, tpr) & IA64_TPR_MIC) + 15) >= vector) { //tpr.mic masks class//printk("but masked by tpr.mic\n"); return SPURIOUS_VECTOR; }//printk("returned to caller\n"); return vector;}u64 vcpu_deliverable_interrupts(VCPU * vcpu){ return (vcpu_get_psr_i(vcpu) && vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR);}u64 vcpu_deliverable_timer(VCPU * vcpu){ return (vcpu_get_psr_i(vcpu) && vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu, itv));}IA64FAULT vcpu_get_lid(VCPU * vcpu, u64 * pval){ /* Use EID=0, ID=vcpu_id. */ *pval = vcpu->vcpu_id << 24; return IA64_NO_FAULT;}IA64FAULT vcpu_get_ivr(VCPU * vcpu, u64 * pval){ int i; u64 vector, mask;#define HEARTBEAT_FREQ 16 // period in seconds#ifdef HEARTBEAT_FREQ#define N_DOMS 16 // period in seconds#if 0 static long count[N_DOMS] = { 0 };#endif static long nonclockcount[N_DOMS] = { 0 }; unsigned domid = vcpu->domain->domain_id;#endif#ifdef IRQ_DEBUG static char firstivr = 1; static char firsttime[256]; if (firstivr) { int i; for (i = 0; i < 256; i++) firsttime[i] = 1; firstivr = 0; }#endif vector = vcpu_check_pending_interrupts(vcpu); if (vector == SPURIOUS_VECTOR) { PSCB(vcpu, pending_interruption) = 0; *pval = vector; return IA64_NO_FAULT; }#ifdef HEARTBEAT_FREQ if (domid >= N_DOMS) domid = N_DOMS - 1;#if 0 if (vector == (PSCB(vcpu, itv) & 0xff)) { if (!(++count[domid] & ((HEARTBEAT_FREQ * 1024) - 1))) { printk("Dom%d heartbeat... ticks=%lx,nonticks=%lx\n", domid, count[domid], nonclockcount[domid]); //count[domid] = 0; //dump_runq(); } }#endif else nonclockcount[domid]++;#endif // now have an unmasked, pending, deliverable vector! // getting ivr has "side effects"#ifdef IRQ_DEBUG if (firsttime[vector]) { printk("*** First get_ivr on vector=%lu,itc=%lx\n", vector, ia64_get_itc()); firsttime[vector] = 0; }#endif /* if delivering a timer interrupt, remember domain_itm, which * needs to be done before clearing irr */ if (vector == (PSCB(vcpu, itv) & 0xff)) { PSCBX(vcpu, domain_itm_last) = PSCBX(vcpu, domain_itm); } i = vector >> 6; mask = 1L << (vector & 0x3f);//printk("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %lu\n",vector); PSCBX(vcpu, insvc[i]) |= mask; PSCBX(vcpu, irr[i]) &= ~mask; //PSCB(vcpu,pending_interruption)--; *pval = vector; return IA64_NO_FAULT;}IA64FAULT vcpu_get_tpr(VCPU * vcpu, u64 * pval){ *pval = PSCB(vcpu, tpr); return IA64_NO_FAULT;}IA64FAULT vcpu_get_eoi(VCPU * vcpu, u64 * pval){ *pval = 0L; // reads of eoi always return 0 return IA64_NO_FAULT;}IA64FAULT vcpu_get_irr0(VCPU * vcpu, u64 * pval){ *pval = PSCBX(vcpu, irr[0]); return IA64_NO_FAULT;}IA64FAULT vcpu_get_irr1(VCPU * vcpu, u64 * pval){ *pval = PSCBX(vcpu, irr[1]); return IA64_NO_FAULT;}IA64FAULT vcpu_get_irr2(VCPU * vcpu, u64 * pval){ *pval = PSCBX(vcpu, irr[2]); return IA64_NO_FAULT;}IA64FAULT vcpu_get_irr3(VCPU * vcpu, u64 * pval){ *pval = PSCBX(vcpu, irr[3]); return IA64_NO_FAULT;}IA64FAULT vcpu_get_itv(VCPU * vcpu, u64 * pval){ *pval = PSCB(vcpu, itv); return IA64_NO_FAULT;}IA64FAULT vcpu_get_pmv(VCPU * vcpu, u64 * pval){ *pval = PSCB(vcpu, pmv); return IA64_NO_FAULT;}IA64FAULT vcpu_get_cmcv(VCPU * vcpu, u64 * pval){ *pval = PSCB(vcpu, cmcv); return IA64_NO_FAULT;}IA64FAULT vcpu_get_lrr0(VCPU * vcpu, u64 * pval){ // fix this when setting values other than m-bit is supported gdprintk(XENLOG_DEBUG, "vcpu_get_lrr0: Unmasked interrupts unsupported\n"); *pval = (1L << 16); return IA64_NO_FAULT;}IA64FAULT vcpu_get_lrr1(VCPU * vcpu, u64 * pval){ // fix this when setting values other than m-bit is supported gdprintk(XENLOG_DEBUG, "vcpu_get_lrr1: Unmasked interrupts unsupported\n"); *pval = (1L << 16); return IA64_NO_FAULT;}IA64FAULT vcpu_set_lid(VCPU * vcpu, u64 val){ printk("vcpu_set_lid: Setting cr.lid is unsupported\n"); return IA64_ILLOP_FAULT;}IA64FAULT vcpu_set_tpr(VCPU * vcpu, u64 val){ if (val & 0xff00) return IA64_RSVDREG_FAULT; PSCB(vcpu, tpr) = val; /* This can unmask interrupts. */ if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) PSCB(vcpu, pending_interruption) = 1; return IA64_NO_FAULT;}IA64FAULT vcpu_set_eoi(VCPU * vcpu, u64 val){ u64 *p, bits, vec, bitnum; int i; p = &PSCBX(vcpu, insvc[3]); for (i = 3; (i >= 0) && !(bits = *p); i--, p--) ; if (i < 0) { printk("Trying to EOI interrupt when none are in-service.\n"); return IA64_NO_FAULT; } bitnum = ia64_fls(bits); vec = bitnum + (i * 64); /* clear the correct bit */ bits &= ~(1L << bitnum); *p = bits; /* clearing an eoi bit may unmask another pending interrupt... */ if (!vcpu->vcpu_info->evtchn_upcall_mask) { // but only if enabled... // worry about this later... Linux only calls eoi // with interrupts disabled printk("Trying to EOI interrupt with interrupts enabled\n"); } if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) PSCB(vcpu, pending_interruption) = 1;//printk("YYYYY vcpu_set_eoi: Successful\n"); return IA64_NO_FAULT;}IA64FAULT vcpu_set_lrr0(VCPU * vcpu, u64 val){ if (!(val & (1L << 16))) { printk("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); return IA64_ILLOP_FAULT; } // no place to save this state but nothing to do anyway return IA64_NO_FAULT;}IA64FAULT vcpu_set_lrr1(VCPU * vcpu, u64 val){ if (!(val & (1L << 16))) { printk("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); return IA64_ILLOP_FAULT; } // no place to save this state but nothing to do anyway return IA64_NO_FAULT;}IA64FAULT vcpu_set_itv(VCPU * vcpu, u64 val){ /* Check reserved fields. */ if (val & 0xef00) return IA64_ILLOP_FAULT; PSCB(vcpu, itv) = val; if (val & 0x10000) { /* Disable itm. */ PSCBX(vcpu, domain_itm) = 0; } else vcpu_set_next_timer(vcpu); return IA64_NO_FAULT;}IA64FAULT vcpu_set_pmv(VCPU * vcpu, u64 val){ if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT; PSCB(vcpu, pmv) = val; return IA64_NO_FAULT;}IA64FAULT vcpu_set_cmcv(VCPU * vcpu, u64 val){ if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT; PSCB(vcpu, cmcv) = val; return IA64_NO_FAULT;}/************************************************************************** VCPU temporary register access routines**************************************************************************/u64 vcpu_get_tmp(VCPU * vcpu, u64 index){ if (index > 7) return 0; return PSCB(vcpu, tmp[index]);}void vcpu_set_tmp(VCPU * vcpu, u64 index, u64 val){ if (index <= 7) PSCB(vcpu, tmp[index]) = val;}/**************************************************************************Interval timer routines**************************************************************************/BOOLEAN vcpu_timer_disabled(VCPU * vcpu){ u64 itv = PSCB(vcpu, itv); return (!itv || !!(itv & 0x10000));}BOOLEAN vcpu_timer_inservice(VCPU * vcpu){ u64 itv = PSCB(vcpu, itv); return test_bit(itv, PSCBX(vcpu, insvc));}BOOLEAN vcpu_timer_expired(VCPU * vcpu){ unsigned long domain_itm = PSCBX(vcpu, domain_itm); unsigned long now = ia64_get_itc(); if (!domain_itm) return FALSE; if (now < domain_itm) return FALSE; if (vcpu_timer_disabled(vcpu)) return FALSE; return TRUE;}void vcpu_safe_set_itm(unsigned long val){ unsigned long epsilon = 100; unsigned long flags; u64 now = ia64_get_itc(); local_irq_save(flags); while (1) {//printk("*** vcpu_safe_set_itm: Setting itm to %lx, itc=%lx\n",val,now); ia64_set_itm(val); if (val > (now = ia64_get_itc())) break; val = now + epsilon; epsilon <<= 1; } local_irq_restore(flags);}void vcpu_set_next_timer(VCPU * vcpu){ u64 d = PSCBX(vcpu, domain_itm); //u64 s = PSCBX(vcpu,xen_itm); u64 s = local_cpu_data->itm_next; u64 now = ia64_get_itc(); /* gloss over the wraparound problem for now... we know it exists * but it doesn't matter right now */ if (is_idle_domain(vcpu->domain)) {// printk("****** vcpu_set_next_timer called during idle!!\n"); vcpu_safe_set_itm(s); return; } //s = PSCBX(vcpu,xen_itm); if (d && (d > now) && (d < s)) { vcpu_safe_set_itm(d); //using_domain_as_itm++; } else { vcpu_safe_set_itm(s); //using_xen_as_itm++; }}IA64FAULT vcpu_set_itm(VCPU * vcpu, u64 val){ //UINT now = ia64_get_itc(); //if (val < now) val = now + 1000;//printk("*** vcpu_set_itm: called with %lx\n",val); PSCBX(vcpu, domain_itm) = val; vcpu_set_next_timer(vcpu); return IA64_NO_FAULT;}IA64FAULT vcpu_set_itc(VCPU * vcpu, u64 val){#define DISALLOW_SETTING_ITC_FOR_NOW#ifdef DISALLOW_SETTING_ITC_FOR_NOW static int did_print; if (!did_print) { printk("vcpu_set_itc: Setting ar.itc is currently disabled " "(this message is only displayed once)\n"); did_print = 1; }#else u64 oldnow = ia64_get_itc(); u64 olditm = PSCBX(vcpu, domain_itm); unsigned long d = olditm - oldnow; unsigned long x = local_cpu_data->itm_next - oldnow; u64 newnow = val, min_delta; local_irq_disable(); if (olditm) { printk("**** vcpu_set_itc(%lx): vitm changed to %lx\n", val, newnow + d); PSCBX(vcpu, domain_itm) = newnow + d; } local_cpu_data->itm_next = newnow + x; d = PSCBX(vcpu, domain_itm); x = local_cpu_data->itm_next; ia64_set_itc(newnow); if (d && (d > newnow) && (d < x)) { vcpu_safe_set_itm(d); //using_domain_as_itm++; } else { vcpu_safe_set_itm(x); //using_xen_as_itm++; } local_irq_enable();#endif return IA64_NO_FAULT;}IA64FAULT vcpu_get_itm(VCPU * vcpu, u64 * pval){ //FIXME: Implement this printk("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n"); return IA64_NO_FAULT; //return IA64_ILLOP_FAULT;}IA64FAULT vcpu_get_itc(VCPU * vcpu, u64 * pval){ //TODO: Implement this printk("vcpu_get_itc: Getting ar.itc is unsupported\n"); return IA64_ILLOP_FAULT;}void vcpu_pend_timer(VCPU * vcpu){ u64 itv = PSCB(vcpu, itv) & 0xff; if (vcpu_timer_disabled(vcpu)) return; //if (vcpu_timer_inservice(vcpu)) return; if (PSCBX(vcpu, domain_itm_last) == PSCBX(vcpu, domain_itm)) { // already delivered an interrupt for this so // don't deliver another return; } if (vcpu->arch.event_callback_ip) { /* A small window may occur when injecting vIRQ while related * handler has not been registered. Don't fire in such case. */ if (vcpu->virq_to_evtchn[VIRQ_ITC]) { send_guest_vcpu_virq(vcpu, VIRQ_ITC); PSCBX(vcpu, domain_itm_last) = PSCBX(vcpu, domain_itm); } } else vcpu_pend_interrupt(vcpu, itv);}// returns true if ready to deliver a timer interrupt too earlyu64 vcpu_timer_pending_early(VCPU * vcpu){ u64 now = ia64_get_itc(); u64 itm = PSCBX(vcpu, domain_itm); if (vcpu_timer_disabled(vcpu)) return 0; if (!itm) return 0; return (vcpu_deliverable_timer(vcpu) && (now < itm));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -