ia64/xen-unstable

changeset 17459:e15be54059e4

x86, hvm: Clean up handling of APIC INIT and SIPI messages.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 15 15:47:53 2008 +0100 (2008-04-15)
parents 6691ae150d10
children 24f23a89f86c
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/vlapic.c xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/vcpu.h xen/include/asm-x86/hvm/vlapic.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Tue Apr 15 15:45:42 2008 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Tue Apr 15 15:47:53 2008 +0100
     1.3 @@ -688,24 +688,6 @@ void hvm_vcpu_destroy(struct vcpu *v)
     1.4      /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/
     1.5  }
     1.6  
     1.7 -
     1.8 -void hvm_vcpu_reset(struct vcpu *v)
     1.9 -{
    1.10 -    vcpu_pause(v);
    1.11 -
    1.12 -    vlapic_reset(vcpu_vlapic(v));
    1.13 -
    1.14 -    hvm_funcs.vcpu_initialise(v);
    1.15 -
    1.16 -    set_bit(_VPF_down, &v->pause_flags);
    1.17 -    clear_bit(_VPF_blocked, &v->pause_flags);
    1.18 -    v->fpu_initialised = 0;
    1.19 -    v->fpu_dirtied     = 0;
    1.20 -    v->is_initialised  = 0;
    1.21 -
    1.22 -    vcpu_unpause(v);
    1.23 -}
    1.24 -
    1.25  static void hvm_vcpu_down(void)
    1.26  {
    1.27      struct vcpu *v = current;
    1.28 @@ -1896,79 +1878,6 @@ void hvm_hypercall_page_initialise(struc
    1.29      hvm_funcs.init_hypercall_page(d, hypercall_page);
    1.30  }
    1.31  
    1.32 -int hvm_bringup_ap(int vcpuid, int trampoline_vector)
    1.33 -{
    1.34 -    struct domain *d = current->domain;
    1.35 -    struct vcpu *v;
    1.36 -    struct vcpu_guest_context *ctxt;
    1.37 -    struct segment_register reg;
    1.38 -
    1.39 -    ASSERT(is_hvm_domain(d));
    1.40 -
    1.41 -    if ( (v = d->vcpu[vcpuid]) == NULL )
    1.42 -        return -ENOENT;
    1.43 -
    1.44 -    v->fpu_initialised = 0;
    1.45 -    v->arch.flags |= TF_kernel_mode;
    1.46 -    v->is_initialised = 1;
    1.47 -
    1.48 -    ctxt = &v->arch.guest_context;
    1.49 -    memset(ctxt, 0, sizeof(*ctxt));
    1.50 -    ctxt->flags = VGCF_online;
    1.51 -    ctxt->user_regs.eflags = 2;
    1.52 -
    1.53 -    v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_ET;
    1.54 -    hvm_update_guest_cr(v, 0);
    1.55 -
    1.56 -    v->arch.hvm_vcpu.guest_cr[2] = 0;
    1.57 -    hvm_update_guest_cr(v, 2);
    1.58 -
    1.59 -    v->arch.hvm_vcpu.guest_cr[3] = 0;
    1.60 -    hvm_update_guest_cr(v, 3);
    1.61 -
    1.62 -    v->arch.hvm_vcpu.guest_cr[4] = 0;
    1.63 -    hvm_update_guest_cr(v, 4);
    1.64 -
    1.65 -    v->arch.hvm_vcpu.guest_efer = 0;
    1.66 -    hvm_update_guest_efer(v);
    1.67 -
    1.68 -    reg.sel = trampoline_vector << 8;
    1.69 -    reg.base = (uint32_t)reg.sel << 4;
    1.70 -    reg.limit = 0xffff;
    1.71 -    reg.attr.bytes = 0x89b;
    1.72 -    hvm_set_segment_register(v, x86_seg_cs, &reg);
    1.73 -
    1.74 -    reg.sel = reg.base = 0;
    1.75 -    reg.limit = 0xffff;
    1.76 -    reg.attr.bytes = 0x893;
    1.77 -    hvm_set_segment_register(v, x86_seg_ds, &reg);
    1.78 -    hvm_set_segment_register(v, x86_seg_es, &reg);
    1.79 -    hvm_set_segment_register(v, x86_seg_fs, &reg);
    1.80 -    hvm_set_segment_register(v, x86_seg_gs, &reg);
    1.81 -    hvm_set_segment_register(v, x86_seg_ss, &reg);
    1.82 -
    1.83 -    reg.attr.bytes = 0x82; /* LDT */
    1.84 -    hvm_set_segment_register(v, x86_seg_ldtr, &reg);
    1.85 -
    1.86 -    reg.attr.bytes = 0x8b; /* 32-bit TSS (busy) */
    1.87 -    hvm_set_segment_register(v, x86_seg_tr, &reg);
    1.88 -
    1.89 -    reg.attr.bytes = 0;
    1.90 -    hvm_set_segment_register(v, x86_seg_gdtr, &reg);
    1.91 -    hvm_set_segment_register(v, x86_seg_idtr, &reg);
    1.92 -
    1.93 -    /* Sync AP's TSC with BSP's. */
    1.94 -    v->arch.hvm_vcpu.cache_tsc_offset =
    1.95 -        v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset;
    1.96 -    hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
    1.97 -
    1.98 -    if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
    1.99 -        vcpu_wake(v);
   1.100 -
   1.101 -    gdprintk(XENLOG_INFO, "AP %d bringup succeeded.\n", vcpuid);
   1.102 -    return 0;
   1.103 -}
   1.104 -
   1.105  static int hvmop_set_pci_intx_level(
   1.106      XEN_GUEST_HANDLE(xen_hvm_set_pci_intx_level_t) uop)
   1.107  {
     2.1 --- a/xen/arch/x86/hvm/vlapic.c	Tue Apr 15 15:45:42 2008 +0100
     2.2 +++ b/xen/arch/x86/hvm/vlapic.c	Tue Apr 15 15:47:53 2008 +0100
     2.3 @@ -241,12 +241,146 @@ static int vlapic_match_dest(struct vcpu
     2.4      return result;
     2.5  }
     2.6  
     2.7 +static int vlapic_vcpu_pause_async(struct vcpu *v)
     2.8 +{
     2.9 +    vcpu_pause_nosync(v);
    2.10 +
    2.11 +    if ( v->is_running )
    2.12 +    {
    2.13 +        vcpu_unpause(v);
    2.14 +        return 0;
    2.15 +    }
    2.16 +
    2.17 +    sync_vcpu_execstate(v);
    2.18 +    return 1;
    2.19 +}
    2.20 +
    2.21 +static void vlapic_init_action(unsigned long _vcpu)
    2.22 +{
    2.23 +    struct vcpu *v = (struct vcpu *)_vcpu;
    2.24 +    struct domain *d = v->domain;
    2.25 +
    2.26 +    /* If the VCPU is not on its way down we have nothing to do. */
    2.27 +    if ( !test_bit(_VPF_down, &v->pause_flags) )
    2.28 +        return;
    2.29 +
    2.30 +    if ( !vlapic_vcpu_pause_async(v) )
    2.31 +    {
    2.32 +        tasklet_schedule(&vcpu_vlapic(v)->init_tasklet);
    2.33 +        return;
    2.34 +    }
    2.35 +
    2.36 +    domain_lock(d);
    2.37 +
    2.38 +    /* Paranoia makes us re-assert VPF_down under the domain lock. */
    2.39 +    set_bit(_VPF_down, &v->pause_flags);
    2.40 +    v->is_initialised = 0;
    2.41 +    clear_bit(_VPF_blocked, &v->pause_flags);
    2.42 +
    2.43 +    vlapic_reset(vcpu_vlapic(v));
    2.44 +
    2.45 +    domain_unlock(d);
    2.46 +
    2.47 +    vcpu_unpause(v);
    2.48 +}
    2.49 +
    2.50 +static int vlapic_accept_init(struct vcpu *v)
    2.51 +{
    2.52 +    /* Nothing to do if the VCPU is already reset. */
    2.53 +    if ( !v->is_initialised )
    2.54 +        return X86EMUL_OKAY;
    2.55 +
    2.56 +    /* Asynchronously take the VCPU down and schedule reset work. */
    2.57 +    set_bit(_VPF_down, &v->pause_flags);
    2.58 +    vcpu_sleep_nosync(v);
    2.59 +    tasklet_schedule(&vcpu_vlapic(v)->init_tasklet);
    2.60 +    return X86EMUL_RETRY;
    2.61 +}
    2.62 +
    2.63 +static int vlapic_accept_sipi(struct vcpu *v, int trampoline_vector)
    2.64 +{
    2.65 +    struct domain *d = current->domain;
    2.66 +    struct vcpu_guest_context *ctxt;
    2.67 +    struct segment_register reg;
    2.68 +
    2.69 +    /* If the VCPU is not on its way down we have nothing to do. */
    2.70 +    if ( !test_bit(_VPF_down, &v->pause_flags) )
    2.71 +        return X86EMUL_OKAY;
    2.72 +
    2.73 +    if ( !vlapic_vcpu_pause_async(v) )
    2.74 +        return X86EMUL_RETRY;
    2.75 +
    2.76 +    domain_lock(d);
    2.77 +
    2.78 +    if ( v->is_initialised )
    2.79 +        goto out;
    2.80 +
    2.81 +    ctxt = &v->arch.guest_context;
    2.82 +    memset(ctxt, 0, sizeof(*ctxt));
    2.83 +    ctxt->flags = VGCF_online;
    2.84 +    ctxt->user_regs.eflags = 2;
    2.85 +
    2.86 +    v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_ET;
    2.87 +    hvm_update_guest_cr(v, 0);
    2.88 +
    2.89 +    v->arch.hvm_vcpu.guest_cr[2] = 0;
    2.90 +    hvm_update_guest_cr(v, 2);
    2.91 +
    2.92 +    v->arch.hvm_vcpu.guest_cr[3] = 0;
    2.93 +    hvm_update_guest_cr(v, 3);
    2.94 +
    2.95 +    v->arch.hvm_vcpu.guest_cr[4] = 0;
    2.96 +    hvm_update_guest_cr(v, 4);
    2.97 +
    2.98 +    v->arch.hvm_vcpu.guest_efer = 0;
    2.99 +    hvm_update_guest_efer(v);
   2.100 +
   2.101 +    reg.sel = trampoline_vector << 8;
   2.102 +    reg.base = (uint32_t)reg.sel << 4;
   2.103 +    reg.limit = 0xffff;
   2.104 +    reg.attr.bytes = 0x89b;
   2.105 +    hvm_set_segment_register(v, x86_seg_cs, &reg);
   2.106 +
   2.107 +    reg.sel = reg.base = 0;
   2.108 +    reg.limit = 0xffff;
   2.109 +    reg.attr.bytes = 0x893;
   2.110 +    hvm_set_segment_register(v, x86_seg_ds, &reg);
   2.111 +    hvm_set_segment_register(v, x86_seg_es, &reg);
   2.112 +    hvm_set_segment_register(v, x86_seg_fs, &reg);
   2.113 +    hvm_set_segment_register(v, x86_seg_gs, &reg);
   2.114 +    hvm_set_segment_register(v, x86_seg_ss, &reg);
   2.115 +
   2.116 +    reg.attr.bytes = 0x82; /* LDT */
   2.117 +    hvm_set_segment_register(v, x86_seg_ldtr, &reg);
   2.118 +
   2.119 +    reg.attr.bytes = 0x8b; /* 32-bit TSS (busy) */
   2.120 +    hvm_set_segment_register(v, x86_seg_tr, &reg);
   2.121 +
   2.122 +    reg.attr.bytes = 0;
   2.123 +    hvm_set_segment_register(v, x86_seg_gdtr, &reg);
   2.124 +    hvm_set_segment_register(v, x86_seg_idtr, &reg);
   2.125 +
   2.126 +    /* Sync AP's TSC with BSP's. */
   2.127 +    v->arch.hvm_vcpu.cache_tsc_offset =
   2.128 +        v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset;
   2.129 +    hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
   2.130 +
   2.131 +    v->arch.flags |= TF_kernel_mode;
   2.132 +    v->is_initialised = 1;
   2.133 +    clear_bit(_VPF_down, &v->pause_flags);
   2.134 +
   2.135 + out:
   2.136 +    domain_unlock(d);
   2.137 +    vcpu_unpause(v);
   2.138 +    return X86EMUL_OKAY;
   2.139 +}
   2.140 +
   2.141  /* Add a pending IRQ into lapic. */
   2.142  static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
   2.143                               int vector, int level, int trig_mode)
   2.144  {
   2.145 -    int result = 0;
   2.146      struct vlapic *vlapic = vcpu_vlapic(v);
   2.147 +    int rc = X86EMUL_OKAY;
   2.148  
   2.149      switch ( delivery_mode )
   2.150      {
   2.151 @@ -271,8 +405,6 @@ static int vlapic_accept_irq(struct vcpu
   2.152          }
   2.153  
   2.154          vcpu_kick(v);
   2.155 -
   2.156 -        result = 1;
   2.157          break;
   2.158  
   2.159      case APIC_DM_REMRD:
   2.160 @@ -292,43 +424,20 @@ static int vlapic_accept_irq(struct vcpu
   2.161          /* No work on INIT de-assert for P4-type APIC. */
   2.162          if ( trig_mode && !(level & APIC_INT_ASSERT) )
   2.163              break;
   2.164 -        /* FIXME How to check the situation after vcpu reset? */
   2.165 -        if ( v->is_initialised )
   2.166 -            hvm_vcpu_reset(v);
   2.167 -        v->arch.hvm_vcpu.init_sipi_sipi_state =
   2.168 -            HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
   2.169 -        result = 1;
   2.170 +        rc = vlapic_accept_init(v);
   2.171          break;
   2.172  
   2.173      case APIC_DM_STARTUP:
   2.174 -        if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
   2.175 -             HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
   2.176 -            break;
   2.177 -
   2.178 -        v->arch.hvm_vcpu.init_sipi_sipi_state =
   2.179 -            HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
   2.180 -
   2.181 -        if ( v->is_initialised )
   2.182 -        {
   2.183 -            gdprintk(XENLOG_ERR, "SIPI for initialized vcpu %x\n", v->vcpu_id);
   2.184 -            goto exit_and_crash;
   2.185 -        }
   2.186 -
   2.187 -        if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
   2.188 -            result = 0;
   2.189 +        rc = vlapic_accept_sipi(v, vector);
   2.190          break;
   2.191  
   2.192      default:
   2.193          gdprintk(XENLOG_ERR, "TODO: unsupported delivery mode %x\n",
   2.194                   delivery_mode);
   2.195 -        goto exit_and_crash;
   2.196 +        domain_crash(v->domain);
   2.197      }
   2.198  
   2.199 -    return result;
   2.200 -
   2.201 - exit_and_crash:
   2.202 -    domain_crash(v->domain);
   2.203 -    return 0;
   2.204 +    return rc;
   2.205  }
   2.206  
   2.207  /* This function is used by both ioapic and lapic.The bitmap is for vcpu_id. */
   2.208 @@ -370,11 +479,9 @@ void vlapic_EOI_set(struct vlapic *vlapi
   2.209          vioapic_update_EOI(vlapic_domain(vlapic), vector);
   2.210  }
   2.211  
   2.212 -static void vlapic_ipi(struct vlapic *vlapic)
   2.213 +static int vlapic_ipi(
   2.214 +    struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
   2.215  {
   2.216 -    uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR);
   2.217 -    uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2);
   2.218 -
   2.219      unsigned int dest =         GET_APIC_DEST_FIELD(icr_high);
   2.220      unsigned int short_hand =   icr_low & APIC_SHORT_MASK;
   2.221      unsigned int trig_mode =    icr_low & APIC_INT_LEVELTRIG;
   2.222 @@ -386,6 +493,7 @@ static void vlapic_ipi(struct vlapic *vl
   2.223      struct vlapic *target;
   2.224      struct vcpu *v;
   2.225      uint32_t lpr_map = 0;
   2.226 +    int rc = X86EMUL_OKAY;
   2.227  
   2.228      HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
   2.229                  "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
   2.230 @@ -400,18 +508,23 @@ static void vlapic_ipi(struct vlapic *vl
   2.231              if ( delivery_mode == APIC_DM_LOWEST )
   2.232                  __set_bit(v->vcpu_id, &lpr_map);
   2.233              else
   2.234 -                vlapic_accept_irq(v, delivery_mode,
   2.235 -                                  vector, level, trig_mode);
   2.236 +                rc = vlapic_accept_irq(v, delivery_mode,
   2.237 +                                       vector, level, trig_mode);
   2.238          }
   2.239 +
   2.240 +        if ( rc != X86EMUL_OKAY )
   2.241 +            break;
   2.242      }
   2.243  
   2.244      if ( delivery_mode == APIC_DM_LOWEST )
   2.245      {
   2.246          target = apic_round_robin(vlapic_domain(v), vector, lpr_map);
   2.247          if ( target != NULL )
   2.248 -            vlapic_accept_irq(vlapic_vcpu(target), delivery_mode,
   2.249 -                              vector, level, trig_mode);
   2.250 +            rc = vlapic_accept_irq(vlapic_vcpu(target), delivery_mode,
   2.251 +                                   vector, level, trig_mode);
   2.252      }
   2.253 +
   2.254 +    return rc;
   2.255  }
   2.256  
   2.257  static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
   2.258 @@ -531,6 +644,7 @@ static int vlapic_write(struct vcpu *v, 
   2.259  {
   2.260      struct vlapic *vlapic = vcpu_vlapic(v);
   2.261      unsigned int offset = address - vlapic_base_address(vlapic);
   2.262 +    int rc = X86EMUL_OKAY;
   2.263  
   2.264      if ( offset != 0xb0 )
   2.265          HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
   2.266 @@ -621,9 +735,10 @@ static int vlapic_write(struct vcpu *v, 
   2.267          break;
   2.268  
   2.269      case APIC_ICR:
   2.270 -        /* No delay here, so we always clear the pending bit*/
   2.271 -        vlapic_set_reg(vlapic, APIC_ICR, val & ~(1 << 12));
   2.272 -        vlapic_ipi(vlapic);
   2.273 +        val &= ~(1 << 12); /* always clear the pending bit */
   2.274 +        rc = vlapic_ipi(vlapic, val, vlapic_get_reg(vlapic, APIC_ICR2));
   2.275 +        if ( rc == X86EMUL_OKAY )
   2.276 +            vlapic_set_reg(vlapic, APIC_ICR, val);
   2.277          break;
   2.278  
   2.279      case APIC_ICR2:
   2.280 @@ -673,14 +788,14 @@ static int vlapic_write(struct vcpu *v, 
   2.281          break;
   2.282      }
   2.283  
   2.284 -    return X86EMUL_OKAY;
   2.285 +    return rc;
   2.286  
   2.287   unaligned_exit_and_crash:
   2.288      gdprintk(XENLOG_ERR, "Unaligned LAPIC write len=0x%lx at offset=0x%x.\n",
   2.289               len, offset);
   2.290   exit_and_crash:
   2.291      domain_crash(v->domain);
   2.292 -    return X86EMUL_OKAY;
   2.293 +    return rc;
   2.294  }
   2.295  
   2.296  static int vlapic_range(struct vcpu *v, unsigned long addr)
   2.297 @@ -937,6 +1052,8 @@ int vlapic_init(struct vcpu *v)
   2.298      if ( v->vcpu_id == 0 )
   2.299          vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP;
   2.300  
   2.301 +    tasklet_init(&vlapic->init_tasklet, vlapic_init_action, (unsigned long)v);
   2.302 +
   2.303      return 0;
   2.304  }
   2.305  
   2.306 @@ -944,6 +1061,7 @@ void vlapic_destroy(struct vcpu *v)
   2.307  {
   2.308      struct vlapic *vlapic = vcpu_vlapic(v);
   2.309  
   2.310 +    tasklet_kill(&vlapic->init_tasklet);
   2.311      destroy_periodic_time(&vlapic->pt);
   2.312      unmap_domain_page_global(vlapic->regs);
   2.313      free_domheap_page(vlapic->regs_page);
     3.1 --- a/xen/include/asm-x86/hvm/hvm.h	Tue Apr 15 15:45:42 2008 +0100
     3.2 +++ b/xen/include/asm-x86/hvm/hvm.h	Tue Apr 15 15:47:53 2008 +0100
     3.3 @@ -138,7 +138,6 @@ void hvm_domain_destroy(struct domain *d
     3.4  
     3.5  int hvm_vcpu_initialise(struct vcpu *v);
     3.6  void hvm_vcpu_destroy(struct vcpu *v);
     3.7 -void hvm_vcpu_reset(struct vcpu *vcpu);
     3.8  
     3.9  void hvm_send_assist_req(struct vcpu *v);
    3.10  
    3.11 @@ -224,8 +223,6 @@ hvm_inject_exception(unsigned int trapnr
    3.12      hvm_funcs.inject_exception(trapnr, errcode, cr2);
    3.13  }
    3.14  
    3.15 -int hvm_bringup_ap(int vcpuid, int trampoline_vector);
    3.16 -
    3.17  static inline int hvm_event_pending(struct vcpu *v)
    3.18  {
    3.19      return hvm_funcs.event_pending(v);
     4.1 --- a/xen/include/asm-x86/hvm/vcpu.h	Tue Apr 15 15:45:42 2008 +0100
     4.2 +++ b/xen/include/asm-x86/hvm/vcpu.h	Tue Apr 15 15:47:53 2008 +0100
     4.3 @@ -26,9 +26,6 @@
     4.4  #include <asm/hvm/svm/vmcb.h>
     4.5  #include <asm/mtrr.h>
     4.6  
     4.7 -#define HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM          0
     4.8 -#define HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI     1
     4.9 -
    4.10  enum hvm_io_state {
    4.11      HVMIO_none = 0,
    4.12      HVMIO_dispatched,
    4.13 @@ -58,9 +55,6 @@ struct hvm_vcpu {
    4.14      spinlock_t          tm_lock;
    4.15      struct list_head    tm_list;
    4.16  
    4.17 -    /* For AP startup */
    4.18 -    unsigned long       init_sipi_sipi_state;
    4.19 -
    4.20      int                 xen_port;
    4.21  
    4.22      bool_t              flag_dr_dirty;
     5.1 --- a/xen/include/asm-x86/hvm/vlapic.h	Tue Apr 15 15:45:42 2008 +0100
     5.2 +++ b/xen/include/asm-x86/hvm/vlapic.h	Tue Apr 15 15:47:53 2008 +0100
     5.3 @@ -21,6 +21,7 @@
     5.4  #ifndef __ASM_X86_HVM_VLAPIC_H__
     5.5  #define __ASM_X86_HVM_VLAPIC_H__
     5.6  
     5.7 +#include <xen/softirq.h>
     5.8  #include <asm/msr.h>
     5.9  #include <public/hvm/ioreq.h>
    5.10  #include <asm/hvm/vpt.h>
    5.11 @@ -58,6 +59,7 @@ struct vlapic {
    5.12      struct periodic_time     pt;
    5.13      s_time_t                 timer_last_update;
    5.14      struct page_info         *regs_page;
    5.15 +    struct tasklet           init_tasklet;
    5.16  };
    5.17  
    5.18  static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg)