ia64/xen-unstable

changeset 15182:98cf6c05c32a

Implement VCPUOP_register_vcpu_info
This change implements the VCPUOP_register_vcpu_info vcpu_op. This
allows a guest to choose where each VCPU's vcpu_info structure is
placed within its address space, allowing it to put it somewhere which
is easily accessible via some per-cpu data access mechanism.

Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
author Jeremy Fitzhardinge <jeremy@xensource.com>
date Tue May 22 14:48:56 2007 +0100 (2007-05-22)
parents c702d9a2781f
children f6928d636999
files xen/arch/x86/domain.c xen/common/domain.c xen/include/xen/sched.h
line diff
     1.1 --- a/xen/arch/x86/domain.c	Tue May 22 06:43:05 2007 +0100
     1.2 +++ b/xen/arch/x86/domain.c	Tue May 22 14:48:56 2007 +0100
     1.3 @@ -49,6 +49,8 @@
     1.4  DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
     1.5  DEFINE_PER_CPU(__u64, efer);
     1.6  
     1.7 +static void unmap_vcpu_info(struct vcpu *v);
     1.8 +
     1.9  static void paravirt_ctxt_switch_from(struct vcpu *v);
    1.10  static void paravirt_ctxt_switch_to(struct vcpu *v);
    1.11  
    1.12 @@ -728,11 +730,116 @@ int arch_set_info_guest(
    1.13  
    1.14  int arch_vcpu_reset(struct vcpu *v)
    1.15  {
    1.16 +    unmap_vcpu_info(v);
    1.17      destroy_gdt(v);
    1.18      vcpu_destroy_pagetables(v);
    1.19      return 0;
    1.20  }
    1.21  
    1.22 +/*
    1.23 + * Copy from an old vcpu to a new one, being careful that events don't
    1.24 + * get lost.  The new vcpu_info is marked as having pending events;
    1.25 + * this may cause a spurious upcall into the guest, but that's better
    1.26 + * than losing events altogether.
    1.27 + *
    1.28 + * The caller should restore the event mask state once the new vcpu_info
    1.29 + * has been installed.
    1.30 + */
    1.31 +static unsigned char
    1.32 +transfer_vcpu_info(const vcpu_info_t *old, vcpu_info_t *new)
    1.33 +{
    1.34 +    unsigned char mask = old->evtchn_upcall_mask;
    1.35 +
    1.36 +    memcpy(new, old, sizeof(*new));
    1.37 +
    1.38 +    new->evtchn_upcall_mask = 1;
    1.39 +    new->evtchn_upcall_pending = 1;
    1.40 +    new->evtchn_pending_sel = ~0;
    1.41 +
    1.42 +    return mask;
    1.43 +}
    1.44 +
    1.45 +/*
    1.46 + * Unmap a mapped guest page, if any, and use the standard shared_info
    1.47 + * vcpu_info location.
    1.48 + */
    1.49 +static void
    1.50 +unmap_vcpu_info(struct vcpu *v)
    1.51 +{
    1.52 +    struct domain *d = v->domain;
    1.53 +    unsigned long mfn;
    1.54 +    vcpu_info_t *sh_vcpu_info;
    1.55 +    vcpu_info_t *old_vcpu_info;
    1.56 +    unsigned char mask;
    1.57 +
    1.58 +    sh_vcpu_info = shared_info_addr(d, vcpu_info[v->vcpu_id]);
    1.59 +
    1.60 +    if (v->vcpu_info == sh_vcpu_info) {
    1.61 +        ASSERT(v->vcpu_info_mfn == INVALID_MFN);
    1.62 +        return;
    1.63 +    }
    1.64 +
    1.65 +    mfn = v->vcpu_info_mfn;
    1.66 +
    1.67 +    ASSERT(mfn != INVALID_MFN);
    1.68 +
    1.69 +    mask = transfer_vcpu_info(v->vcpu_info, sh_vcpu_info);
    1.70 +
    1.71 +    old_vcpu_info = v->vcpu_info;
    1.72 +
    1.73 +    v->vcpu_info = sh_vcpu_info;
    1.74 +    v->vcpu_info_mfn = INVALID_MFN;
    1.75 +    wmb();                      /* update pointers before unmapping */
    1.76 +
    1.77 +    put_page_and_type(mfn_to_page(mfn));
    1.78 +    unmap_domain_page_global(old_vcpu_info);
    1.79 +
    1.80 +    sh_vcpu_info->evtchn_upcall_mask = mask;
    1.81 +
    1.82 +    update_vcpu_system_time(v);
    1.83 +}
    1.84 +
    1.85 +/* 
    1.86 + * Map a guest page in and point the vcpu_info pointer at it.  This
    1.87 + * makes sure that the vcpu_info is always pointing at a valid piece
    1.88 + * of memory, and it sets a pending event to make sure that a pending
    1.89 + * event doesn't get missed.
    1.90 + */
    1.91 +static int
    1.92 +map_vcpu_info(struct vcpu *v, unsigned long mfn, unsigned offset)
    1.93 +{
    1.94 +    struct domain *d = v->domain;
    1.95 +    unsigned char mask;
    1.96 +    void *mapping;
    1.97 +    struct vcpu_info *new_info;
    1.98 +
    1.99 +    if (offset > (PAGE_SIZE - sizeof(vcpu_info_t)))
   1.100 +        return -EINVAL;
   1.101 +
   1.102 +    mfn = gmfn_to_mfn(d, mfn);
   1.103 +    if ( !mfn_valid(mfn) ||
   1.104 +         !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
   1.105 +        return -EINVAL;
   1.106 +
   1.107 +    mapping = map_domain_page_global(mfn);
   1.108 +    new_info = (vcpu_info_t *)(mapping + offset);
   1.109 +
   1.110 +    mask = transfer_vcpu_info(v->vcpu_info, new_info);
   1.111 +    wmb();
   1.112 +
   1.113 +    unmap_vcpu_info(v);
   1.114 +
   1.115 +    v->vcpu_info = new_info;
   1.116 +    v->vcpu_info_mfn = mfn;
   1.117 +
   1.118 +    wmb();
   1.119 +    new_info->evtchn_upcall_mask = mask;
   1.120 +
   1.121 +    update_vcpu_system_time(v);
   1.122 +
   1.123 +    return 0;
   1.124 +}
   1.125 +
   1.126  long
   1.127  arch_do_vcpu_op(
   1.128      int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg)
   1.129 @@ -769,6 +876,26 @@ arch_do_vcpu_op(
   1.130          break;
   1.131      }
   1.132  
   1.133 +    case VCPUOP_register_vcpu_info:
   1.134 +    {
   1.135 +        struct domain *d = v->domain;
   1.136 +        struct vcpu_register_vcpu_info info;
   1.137 +
   1.138 +        rc = -EFAULT;
   1.139 +        if ( copy_from_guest(&info, arg, 1) )
   1.140 +            break;
   1.141 +
   1.142 +        LOCK_BIGLOCK(d);
   1.143 +        if (info.mfn == INVALID_MFN) {
   1.144 +            unmap_vcpu_info(v);
   1.145 +            rc = 0;
   1.146 +        } else
   1.147 +            rc = map_vcpu_info(v, info.mfn, info.offset);
   1.148 +        UNLOCK_BIGLOCK(d);
   1.149 +
   1.150 +        break;
   1.151 +    }
   1.152 +
   1.153      default:
   1.154          rc = -ENOSYS;
   1.155          break;
     2.1 --- a/xen/common/domain.c	Tue May 22 06:43:05 2007 +0100
     2.2 +++ b/xen/common/domain.c	Tue May 22 14:48:56 2007 +0100
     2.3 @@ -136,6 +136,7 @@ struct vcpu *alloc_vcpu(
     2.4  
     2.5      v->domain = d;
     2.6      v->vcpu_id = vcpu_id;
     2.7 +    v->vcpu_info_mfn = INVALID_MFN;
     2.8  
     2.9      v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
    2.10      v->runstate.state_entry_time = NOW();
     3.1 --- a/xen/include/xen/sched.h	Tue May 22 06:43:05 2007 +0100
     3.2 +++ b/xen/include/xen/sched.h	Tue May 22 14:48:56 2007 +0100
     3.3 @@ -75,6 +75,7 @@ struct vcpu
     3.4      int              processor;
     3.5  
     3.6      vcpu_info_t     *vcpu_info;
     3.7 +    unsigned long    vcpu_info_mfn;
     3.8  
     3.9      struct domain   *domain;
    3.10