diff options
-rw-r--r-- | xen/arch/x86/hvm/vlapic.c | 431 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vlapic.h | 117 |
2 files changed, 221 insertions, 327 deletions
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 2cdb4644d5..2c7f163fda 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -29,13 +29,15 @@ #include <asm/hvm/hvm.h> #include <asm/hvm/io.h> #include <asm/hvm/support.h> - #include <xen/lib.h> #include <xen/sched.h> #include <asm/current.h> #include <public/hvm/ioreq.h> #include <public/hvm/params.h> +#define VLAPIC_VERSION 0x00050014 +#define VLAPIC_LVT_NUM 6 + /* XXX remove this definition after GFW enabled */ #define VLAPIC_NO_BIOS @@ -43,6 +45,13 @@ extern u32 get_apic_bus_cycle(void); #define APIC_BUS_CYCLE_NS (((s_time_t)get_apic_bus_cycle()) / 1000) +#define LVT_MASK \ + APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK + +#define LINT_MASK \ + LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\ + APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER + static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] = { /* LVTT */ @@ -57,9 +66,70 @@ static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] = LVT_MASK }; -int hvm_apic_support(struct domain *d) +/* Following could belong in apicdef.h */ +#define APIC_SHORT_MASK 0xc0000 +#define APIC_DEST_NOSHORT 0x0 +#define APIC_DEST_MASK 0x800 + +#define vlapic_lvt_enabled(vlapic, lvt_type) \ + (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED)) + +#define vlapic_lvt_vector(vlapic, lvt_type) \ + (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK) + +#define vlapic_lvt_dm(vlapic, lvt_type) \ + (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK) + +#define vlapic_lvtt_period(vlapic) \ + (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC) + +/* + * Generic APIC bitmap vector update & search routines. + */ + +#define VEC_POS(v) ((v)%32) +#define REG_POS(v) (((v)/32)* 0x10) +#define vlapic_test_and_set_vector(vec, bitmap) \ + test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) +#define vlapic_test_and_clear_vector(vec, bitmap) \ + test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) +#define vlapic_set_vector(vec, bitmap) \ + set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) +#define vlapic_clear_vector(vec, bitmap) \ + clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) + +static int vlapic_find_highest_vector(u32 *bitmap) { - return d->arch.hvm_domain.params[HVM_PARAM_APIC_ENABLED]; + int word_offset = MAX_VECTOR / 32; + + /* Work backwards through the bitmap (first 32-bit word in every four). */ + while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) ) + continue; + + return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32); +} + + +/* + * IRR-specific bitmap update & search routines. + */ + +static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic) +{ + vlapic->flush_tpr_threshold = 1; + return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR); +} + +static void vlapic_set_irr(int vector, struct vlapic *vlapic) +{ + vlapic->flush_tpr_threshold = 1; + vlapic_set_vector(vector, vlapic->regs + APIC_IRR); +} + +static void vlapic_clear_irr(int vector, struct vlapic *vlapic) +{ + vlapic->flush_tpr_threshold = 1; + vlapic_clear_vector(vector, vlapic->regs + APIC_IRR); } int vlapic_find_highest_irr(struct vlapic *vlapic) @@ -72,6 +142,24 @@ int vlapic_find_highest_irr(struct vlapic *vlapic) return result; } + +int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig) +{ + int ret; + + ret = vlapic_test_and_set_irr(vec, vlapic); + if ( trig ) + vlapic_set_vector(vec, vlapic->regs + APIC_TMR); + + /* We may need to wake up target vcpu, besides set pending bit here */ + return ret; +} + +int hvm_apic_support(struct domain *d) +{ + return d->arch.hvm_domain.params[HVM_PARAM_APIC_ENABLED]; +} + s_time_t get_apictime_scheduled(struct vcpu *v) { struct vlapic *vlapic = VLAPIC(v); @@ -139,11 +227,13 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source, (delivery_mode != APIC_DM_NMI)) ) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, " - "delivery_mode 0x%x, dest 0x%x.\n", v, delivery_mode, dest); + "delivery_mode 0x%x, dest 0x%x.\n", + v, delivery_mode, dest); return result; } - switch ( short_hand ) { + switch ( short_hand ) + { case APIC_DEST_NOSHORT: /* no shorthand */ if ( !dest_mode ) /* Physical */ { @@ -159,7 +249,7 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source, ldr = vlapic_get_reg(target, APIC_LDR); /* Flat mode */ - if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT) + if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT ) { result = GET_APIC_LOGICAL_ID(ldr) & dest; } @@ -173,8 +263,8 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source, "delivery mode\n"); domain_crash_synchronous(); } - result = (GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ? - (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0; + result = ((GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ? + (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0); } } break; @@ -220,14 +310,14 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode, if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode ) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, - "level trig mode repeatedly for vector %d\n", vector); + "level trig mode repeatedly for vector %d\n", vector); break; } if ( trig_mode ) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, - "level trig mode for vector %d\n", vector); + "level trig mode for vector %d\n", vector); vlapic_set_vector(vector, vlapic->regs + APIC_TMR); } @@ -247,29 +337,27 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode, break; case APIC_DM_INIT: - if ( trig_mode && !(level & APIC_INT_ASSERT) ) //Deassert - printk("This hvm_vlapic is for P4, no work for De-assert init\n"); - else + /* No work on INIT de-assert for P4-type APIC. */ + if ( trig_mode && !(level & APIC_INT_ASSERT) ) + break; + /* FIXME How to check the situation after vcpu reset? */ + if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) ) { - /* FIXME How to check the situation after vcpu reset? */ - if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) ) - { - printk("Reset hvm vcpu not supported yet\n"); - domain_crash_synchronous(); - } - v->arch.hvm_vcpu.init_sipi_sipi_state = - HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI; - result = 1; + gdprintk(XENLOG_ERR, "Reset hvm vcpu not supported yet\n"); + domain_crash_synchronous(); } + v->arch.hvm_vcpu.init_sipi_sipi_state = + HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI; + result = 1; break; case APIC_DM_STARTUP: if ( v->arch.hvm_vcpu.init_sipi_sipi_state == - HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM ) + HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM ) break; v->arch.hvm_vcpu.init_sipi_sipi_state = - HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM; + HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM; if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) { @@ -302,7 +390,7 @@ struct vlapic *apic_round_robin(struct domain *d, int next, old; struct vlapic* target = NULL; - if ( dest_mode == 0 ) //Physical mode + if ( dest_mode == 0 ) /* Physical mode */ { printk("<apic_round_robin> lowest priority for physical mode.\n"); return NULL; @@ -362,21 +450,6 @@ void vlapic_EOI_set(struct vlapic *vlapic) ioapic_update_EOI(vlapic->domain, vector); } -static int vlapic_check_vector(struct vlapic *vlapic, - uint32_t dm, uint32_t vector) -{ - if ( (dm == APIC_DM_FIXED) && (vector < 16) ) - { - vlapic->err_status |= 0x40; - vlapic_accept_irq(vlapic->vcpu, APIC_DM_FIXED, - vlapic_lvt_vector(vlapic, APIC_LVTERR), 0, 0); - printk("<vlapic_check_vector>: check failed " - " dm %x vector %x\n", dm, vector); - return 0; - } - return 1; -} - static void vlapic_ipi(struct vlapic *vlapic) { uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR); @@ -450,7 +523,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic) if ( unlikely(!vlapic_lvtt_period(vlapic)) ) { tmcct = 0; - // FIXME: should we add interrupt here? + /* FIXME: should we add interrupt here? */ } else { @@ -490,15 +563,10 @@ static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset, printk("access local APIC ARBPRI register which is for P6\n"); break; - case APIC_TMCCT: //Timer CCR + case APIC_TMCCT: /* Timer CCR */ *result = vlapic_get_tmcct(vlapic); break; - case APIC_ESR: - vlapic->err_write_count = 0; - *result = vlapic_get_reg(vlapic, offset); - break; - default: *result = vlapic_get_reg(vlapic, offset); break; @@ -565,31 +633,31 @@ static void vlapic_write(struct vcpu *v, unsigned long address, offset, len, val); /* - * According to IA 32 Manual, all resgiters should be accessed with - * 32 bits alignment. + * According to the IA32 Manual, all accesses should be 32 bits. + * Some OSes do 8- or 16-byte accesses, however. */ if ( len != 4 ) { unsigned int tmp; unsigned char alignment; - /* Some kernels do will access with byte/word alignment */ - printk("Notice: Local APIC write with len = %lx\n",len); + gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len); + alignment = offset & 0x3; tmp = vlapic_read(v, offset & ~0x3, 4); - switch ( len ) { + + switch ( len ) + { case 1: - /* XXX the saddr is a tmp variable from caller, so should be ok - But we should still change the following ref to val to - local variable later */ val = (tmp & ~(0xff << (8*alignment))) | ((val & 0xff) << (8*alignment)); break; case 2: - if ( alignment != 0x0 && alignment != 0x2 ) + if ( alignment & 1 ) { - printk("alignment error for vlapic with len == 2\n"); + gdprintk(XENLOG_ERR, "Uneven alignment error for " + "2-byte vlapic access\n"); domain_crash_synchronous(); } @@ -597,14 +665,9 @@ static void vlapic_write(struct vcpu *v, unsigned long address, ((val & 0xffff) << (8*alignment)); break; - case 3: - /* will it happen? */ - printk("vlapic_write with len = 3 !!!\n"); - domain_crash_synchronous(); - break; - default: - printk("Local APIC write with len = %lx, should be 4 instead\n", len); + gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, " + "should be 4 instead\n", len); domain_crash_synchronous(); break; } @@ -612,7 +675,8 @@ static void vlapic_write(struct vcpu *v, unsigned long address, offset &= 0xff0; - switch ( offset ) { + switch ( offset ) + { case APIC_ID: /* Local APIC ID */ vlapic_set_reg(vlapic, APIC_ID, val); break; @@ -638,7 +702,7 @@ static void vlapic_write(struct vcpu *v, unsigned long address, case APIC_SPIV: vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff); - if ( !( val & APIC_SPIV_APIC_ENABLED) ) + if ( !(val & APIC_SPIV_APIC_ENABLED) ) { int i; uint32_t lvt_val; @@ -666,9 +730,7 @@ static void vlapic_write(struct vcpu *v, unsigned long address, break; case APIC_ESR: - vlapic->err_write_count = !vlapic->err_write_count; - if ( !vlapic->err_write_count ) - vlapic->err_status = 0; + /* Nothing to do. */ break; case APIC_ICR: @@ -681,78 +743,72 @@ static void vlapic_write(struct vcpu *v, unsigned long address, vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000); break; - case APIC_LVTT: // LVT Timer Reg - case APIC_LVTTHMR: // LVT Thermal Monitor - case APIC_LVTPC: // LVT Performance Counter - case APIC_LVT0: // LVT LINT0 Reg - case APIC_LVT1: // LVT Lint1 Reg - case APIC_LVTERR: // LVT Error Reg - { - if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK ) - val |= APIC_LVT_MASKED; - - val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4]; + case APIC_LVTT: /* LVT Timer Reg */ + case APIC_LVTTHMR: /* LVT Thermal Monitor */ + case APIC_LVTPC: /* LVT Performance Counter */ + case APIC_LVT0: /* LVT LINT0 Reg */ + case APIC_LVT1: /* LVT Lint1 Reg */ + case APIC_LVTERR: /* LVT Error Reg */ + { + if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK ) + val |= APIC_LVT_MASKED; - vlapic_set_reg(vlapic, offset, val); + val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4]; - /* On hardware, when write vector less than 0x20 will error */ - if ( !(val & APIC_LVT_MASKED) ) - vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic, offset), - vlapic_lvt_vector(vlapic, offset)); + vlapic_set_reg(vlapic, offset, val); - if ( !vlapic->vcpu_id && (offset == APIC_LVT0) ) - { - if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT ) - if ( val & APIC_LVT_MASKED) - clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); - else - set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); - else + if ( !vlapic->vcpu->vcpu_id && (offset == APIC_LVT0) ) + { + if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT ) + if ( val & APIC_LVT_MASKED) clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); - } - + else + set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); + else + clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); } - break; + } + break; case APIC_TMICT: - { - s_time_t now = NOW(), offset; + { + s_time_t now = NOW(), offset; - stop_timer(&vlapic->vlapic_timer); + stop_timer(&vlapic->vlapic_timer); - vlapic_set_reg(vlapic, APIC_TMICT, val); - vlapic_set_reg(vlapic, APIC_TMCCT, val); - vlapic->timer_last_update = now; + vlapic_set_reg(vlapic, APIC_TMICT, val); + vlapic_set_reg(vlapic, APIC_TMCCT, val); + vlapic->timer_last_update = now; - offset = APIC_BUS_CYCLE_NS * - vlapic->timer_divide_count * val; + offset = APIC_BUS_CYCLE_NS * + vlapic->timer_divide_count * val; - set_timer(&vlapic->vlapic_timer, now + offset); + set_timer(&vlapic->vlapic_timer, now + offset); - HVM_DBG_LOG(DBG_LEVEL_VLAPIC, - "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", " - "timer initial count 0x%x, offset 0x%016"PRIx64", " - "expire @ 0x%016"PRIx64".", - APIC_BUS_CYCLE_NS, now, - vlapic_get_reg(vlapic, APIC_TMICT), - offset, now + offset); - } - break; + HVM_DBG_LOG(DBG_LEVEL_VLAPIC, + "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", " + "timer initial count 0x%x, offset 0x%016"PRIx64", " + "expire @ 0x%016"PRIx64".", + APIC_BUS_CYCLE_NS, now, + vlapic_get_reg(vlapic, APIC_TMICT), + offset, now + offset); + } + break; case APIC_TDCR: - { - unsigned int tmp1, tmp2; + { + unsigned int tmp1, tmp2; - tmp1 = val & 0xf; - tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; - vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7); + tmp1 = val & 0xf; + tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; + vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7); - vlapic_set_reg(vlapic, APIC_TDCR, val); + vlapic_set_reg(vlapic, APIC_TDCR, val); - HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x", - vlapic->timer_divide_count); - } - break; + HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x", + vlapic->timer_divide_count); + } + break; default: printk("Local APIC Write to read-only register\n"); @@ -764,12 +820,9 @@ static int vlapic_range(struct vcpu *v, unsigned long addr) { struct vlapic *vlapic = VLAPIC(v); - if ( vlapic_global_enabled(vlapic) && - (addr >= vlapic->base_address) && - (addr < vlapic->base_address + VLOCAL_APIC_MEM_LENGTH) ) - return 1; - - return 0; + return (vlapic_global_enabled(vlapic) && + (addr >= vlapic->base_address) && + (addr < vlapic->base_address + PAGE_SIZE)); } struct hvm_mmio_handler vlapic_mmio_handler = { @@ -780,18 +833,15 @@ struct hvm_mmio_handler vlapic_mmio_handler = { void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) { - /* When apic disabled */ if ( vlapic == NULL ) return; - if ( vlapic->vcpu_id ) + if ( vlapic->vcpu->vcpu_id ) value &= ~MSR_IA32_APICBASE_BSP; vlapic->apic_base_msr = value; - vlapic->base_address = vlapic->apic_base_msr & - MSR_IA32_APICBASE_BASE; + vlapic->base_address = vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE; - /* with FSB delivery interrupt, we can restart APIC functionality */ if ( !(value & MSR_IA32_APICBASE_ENABLE) ) set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status ); else @@ -820,7 +870,7 @@ void vlapic_timer_fn(void *data) vlapic->timer_last_update = now; if ( vlapic_test_and_set_irr(timer_vector, vlapic) ) - vlapic->intr_pending_count[timer_vector]++; + vlapic->timer_pending_count++; if ( vlapic_lvtt_period(vlapic) ) { @@ -837,13 +887,6 @@ void vlapic_timer_fn(void *data) else vlapic_set_reg(vlapic, APIC_TMCCT, 0); -#if 0 - if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) - { - /* TODO: add guest time handling here */ - } -#endif - HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", " "timer initial count 0x%x, timer current count 0x%x.", @@ -852,22 +895,6 @@ void vlapic_timer_fn(void *data) vlapic_get_reg(vlapic, APIC_TMCCT)); } -#if 0 -static int -vlapic_check_direct_intr(struct vcpu *v, int * mode) -{ - struct vlapic *vlapic = VLAPIC(v); - int type; - - type = fls(vlapic->direct_intr.deliver_mode) - 1; - if ( type == -1 ) - return -1; - - *mode = type; - return 0; -} -#endif - int vlapic_accept_pic_intr(struct vcpu *v) { struct vlapic *vlapic = VLAPIC(v); @@ -878,60 +905,33 @@ int vlapic_accept_pic_intr(struct vcpu *v) int cpu_get_apic_interrupt(struct vcpu *v, int *mode) { struct vlapic *vlapic = VLAPIC(v); + int highest_irr; - if ( vlapic && vlapic_enabled(vlapic) ) - { - int highest_irr = vlapic_find_highest_irr(vlapic); - - if ( highest_irr != -1 && - ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) ) - { - if ( highest_irr < 0x10 ) - { - uint32_t err_vector; - - vlapic->err_status |= 0x20; - err_vector = vlapic_lvt_vector(vlapic, APIC_LVTERR); - - HVM_DBG_LOG(DBG_LEVEL_VLAPIC, - "Sending an illegal vector 0x%x.", highest_irr); + if ( !vlapic || !vlapic_enabled(vlapic) ) + return -1; - vlapic_set_irr(err_vector, vlapic); - highest_irr = err_vector; - } + highest_irr = vlapic_find_highest_irr(vlapic); + if ( (highest_irr == -1) || + ((highest_irr & 0xF0) <= vlapic_get_reg(vlapic, APIC_PROCPRI)) ) + return -1; - *mode = APIC_DM_FIXED; - return highest_irr; - } - } - return -1; -} - -int cpu_has_apic_interrupt(struct vcpu* v) -{ - struct vlapic *vlapic = VLAPIC(v); - - if (vlapic && vlapic_enabled(vlapic)) { - int highest_irr = vlapic_find_highest_irr(vlapic); - - if ( highest_irr != -1 && - ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) ) { - return 1; - } - } - return 0; + *mode = APIC_DM_FIXED; + return highest_irr; } /* check to see if there is pending interrupt */ int cpu_has_pending_irq(struct vcpu *v) { struct hvm_domain *plat = &v->domain->arch.hvm_domain; + int dummy; /* APIC */ - if ( cpu_has_apic_interrupt(v) ) return 1; - + if ( cpu_get_apic_interrupt(v, &dummy) != -1 ) + return 1; + /* PIC */ - if ( !vlapic_accept_pic_intr(v) ) return 0; + if ( !vlapic_accept_pic_intr(v) ) + return 0; return plat->interrupt_request; } @@ -943,20 +943,18 @@ void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) if ( unlikely(vlapic == NULL) ) return; - switch ( deliver_mode ) { + switch ( deliver_mode ) + { case APIC_DM_FIXED: case APIC_DM_LOWEST: vlapic_set_vector(vector, vlapic->regs + APIC_ISR); vlapic_clear_irr(vector, vlapic); vlapic_update_ppr(vlapic); - - if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) ) + if ( (vector == vlapic_lvt_vector(vlapic, APIC_LVTT)) && + (vlapic->timer_pending_count != 0) ) { - if ( vlapic->intr_pending_count[vector] > 0 ) - { - vlapic->intr_pending_count[vector]--; - vlapic_set_irr(vector, vlapic); - } + vlapic->timer_pending_count--; + vlapic_set_irr(vector, vlapic); } break; @@ -969,7 +967,6 @@ void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) case APIC_DM_NMI: case APIC_DM_INIT: case APIC_DM_STARTUP: - vlapic->direct_intr.deliver_mode &= (1 << (deliver_mode >> 8)); break; default: @@ -980,19 +977,11 @@ void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) static int vlapic_reset(struct vlapic *vlapic) { - struct vcpu *v; + struct vcpu *v = vlapic->vcpu; int i; - ASSERT( vlapic != NULL ); - - v = vlapic->vcpu; - - ASSERT( v != NULL ); - vlapic->domain = v->domain; - vlapic->vcpu_id = v->vcpu_id; - vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24); vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION); @@ -1045,8 +1034,6 @@ int vlapic_init(struct vcpu *v) { struct vlapic *vlapic = NULL; - ASSERT( v != NULL ); - HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id); vlapic = xmalloc_bytes(sizeof(struct vlapic)); @@ -1067,11 +1054,9 @@ int vlapic_init(struct vcpu *v) } vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page)); - memset(vlapic->regs, 0, PAGE_SIZE); VLAPIC(v) = vlapic; - vlapic->vcpu = v; vlapic_reset(vlapic); diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index b57d213775..4478b71ac2 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -25,56 +25,11 @@ #define MAX_VECTOR 256 -#define VEC_POS(v) ((v)%32) -#define REG_POS(v) (((v)/32)* 0x10) -#define vlapic_test_and_set_vector(vec, bitmap) \ - test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) -#define vlapic_test_and_clear_vector(vec, bitmap) \ - test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) -#define vlapic_set_vector(vec, bitmap) \ - set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) -#define vlapic_clear_vector(vec, bitmap) \ - clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)) - -static inline int vlapic_find_highest_vector(u32 *bitmap) -{ - int word_offset = MAX_VECTOR / 32; - - /* Work backwards through the bitmap (first 32-bit word in every four). */ - while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) ) - continue; - - return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32); -} - #define VLAPIC(v) (v->arch.hvm_vcpu.vlapic) -#define VLAPIC_VERSION 0x00050014 - -#define VLOCAL_APIC_MEM_LENGTH (1 << 12) - -#define VLAPIC_LVT_NUM 6 - #define VLAPIC_ID(vlapic) \ (GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID))) -/* followed define is not in apicdef.h */ -#define APIC_SHORT_MASK 0xc0000 -#define APIC_DEST_NOSHORT 0x0 -#define APIC_DEST_MASK 0x800 - -#define vlapic_lvt_enabled(vlapic, lvt_type) \ - (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED)) - -#define vlapic_lvt_vector(vlapic, lvt_type) \ - (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK) - -#define vlapic_lvt_dm(vlapic, lvt_type) \ - (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK) - -#define vlapic_lvtt_period(vlapic) \ - (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC) - #define _VLAPIC_GLOB_DISABLE 0x0 #define VLAPIC_GLOB_DISABLE_MASK 0x1 #define VLAPIC_SOFTWARE_DISABLE_MASK 0x2 @@ -87,96 +42,50 @@ static inline int vlapic_find_highest_vector(u32 *bitmap) #define vlapic_global_enabled(vlapic) \ (!(test_bit(_VLAPIC_GLOB_DISABLE, &(vlapic)->status))) -#define LVT_MASK \ - APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK - -#define LINT_MASK \ - LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\ - APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER - -typedef struct direct_intr_info { - int deliver_mode; - int source[6]; -} direct_intr_info_t; - struct vlapic { uint32_t status; - uint32_t vcpu_id; uint64_t apic_base_msr; unsigned long base_address; uint32_t timer_divide_count; struct timer vlapic_timer; - int intr_pending_count[MAX_VECTOR]; + int timer_pending_count; int flush_tpr_threshold; s_time_t timer_last_update; - direct_intr_info_t direct_intr; - uint32_t err_status; - uint32_t err_write_count; struct vcpu *vcpu; struct domain *domain; struct page_info *regs_page; void *regs; }; -static inline int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic) -{ - vlapic->flush_tpr_threshold = 1; - return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR); -} - -static inline void vlapic_set_irr(int vector, struct vlapic *vlapic) -{ - vlapic->flush_tpr_threshold = 1; - vlapic_set_vector(vector, vlapic->regs + APIC_IRR); -} - -static inline void vlapic_clear_irr(int vector, struct vlapic *vlapic) -{ - vlapic->flush_tpr_threshold = 1; - vlapic_clear_vector(vector, vlapic->regs + APIC_IRR); -} - -static inline int vlapic_set_irq(struct vlapic *vlapic, - uint8_t vec, uint8_t trig) -{ - int ret; - - ret = vlapic_test_and_set_irr(vec, vlapic); - if ( trig ) - vlapic_set_vector(vec, vlapic->regs + APIC_TMR); - - /* We may need to wake up target vcpu, besides set pending bit here */ - return ret; -} - static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg) { - return *( (uint32_t *)(vlapic->regs + reg)); + return *((uint32_t *)(vlapic->regs + reg)); } -static inline void vlapic_set_reg(struct vlapic *vlapic, - uint32_t reg, uint32_t val) +static inline void vlapic_set_reg( + struct vlapic *vlapic, uint32_t reg, uint32_t val) { *((uint32_t *)(vlapic->regs + reg)) = val; } -void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode); +int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig); + +void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode); -extern int vlapic_find_highest_irr(struct vlapic *vlapic); +int vlapic_find_highest_irr(struct vlapic *vlapic); -int cpu_has_apic_interrupt(struct vcpu* v); -int cpu_get_apic_interrupt(struct vcpu* v, int *mode); +int cpu_get_apic_interrupt(struct vcpu *v, int *mode); -extern int vlapic_init(struct vcpu *vc); +int vlapic_init(struct vcpu *vc); -extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); +void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); -extern uint32_t vlapic_update_ppr(struct vlapic *vlapic); +uint32_t vlapic_update_ppr(struct vlapic *vlapic); int vlapic_accept_pic_intr(struct vcpu *v); -struct vlapic* apic_round_robin(struct domain *d, +struct vlapic *apic_round_robin(struct domain *d, uint8_t dest_mode, uint8_t vector, uint32_t bitmap); |