[XEN] HVM: Clean up and simplify vlapic device-model code.

Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kfraser@localhost.localdomain committed 2006-10-30 13:53:09 +00:00
1 parent 30c8005e6e
commit f7c8af3a64
2 files changed
+223 -329

No files matched your search

+210 -225
View File
@@ -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
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];
vlapic_set_reg(vlapic, offset, val);
if ( !vlapic->vcpu->vcpu_id && (offset == APIC_LVT0) )
{
if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
val |= APIC_LVT_MASKED;
val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
vlapic_set_reg(vlapic, offset, val);
/* 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));
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 ( (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 ( !vlapic || !vlapic_enabled(vlapic) )
return -1;
if ( highest_irr != -1 &&
( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) )
{
if ( highest_irr < 0x10 )
{
uint32_t err_vector;
highest_irr = vlapic_find_highest_irr(vlapic);
if ( (highest_irr == -1) ||
((highest_irr & 0xF0) <= vlapic_get_reg(vlapic, APIC_PROCPRI)) )
return -1;
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);
vlapic_set_irr(err_vector, vlapic);
highest_irr = err_vector;
}
*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);
+13 -104
View File
@@ -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);
extern int vlapic_find_highest_irr(struct vlapic *vlapic);
void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode);
int cpu_has_apic_interrupt(struct vcpu* v);
int cpu_get_apic_interrupt(struct vcpu* v, int *mode);
int vlapic_find_highest_irr(struct vlapic *vlapic);
extern int vlapic_init(struct vcpu *vc);
int cpu_get_apic_interrupt(struct vcpu *v, int *mode);
extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
int vlapic_init(struct vcpu *vc);
extern uint32_t vlapic_update_ppr(struct vlapic *vlapic);
void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.