~ubuntu-branches/ubuntu/trusty/xen/trusty

« back to all changes in this revision

Viewing changes to .pc/xsa45-4.2-05-set-info-guest-preemptible.patch/xen/common/domctl.c

  • Committer: Package Import Robot
  • Author(s): Stefan Bader
  • Date: 2013-06-14 10:01:32 UTC
  • mfrom: (40.1.2 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130614100132-ozzr5yioa5r1e797
Tags: 4.2.1-2ubuntu1
* Merge with Debian unstable. Dropping the following patches in favour
  of Debian ones:
  - xsa33-4.2-unstable.patch
  - xsa36-4.2.patch
  - xsa44-4.2.patch
  - xsa45-4.2-01-vcpu-destroy-pagetables-preemptible.patch
  - xsa45-4.2-02-new-guest-cr3-preemptible.patch
  - xsa45-4.2-03-new-user-base-preemptible.patch
  - xsa45-4.2-04-vcpu-reset-preemptible.patch
  - xsa45-4.2-05-set-info-guest-preemptible.patch
  - xsa45-4.2-06-unpin-preemptible.patch
  - xsa45-4.2-07-mm-error-paths-preemptible.patch
  - xsa46-4.2.patch
  - xsa47-4.2-unstable.patch
  - xsa49-4.2.patch
* Remaining changes:
  - debian/control: Depend on libssl-dev
  - Use dpkg-buildflags and strip the gcc prefix for getting LDFLAGS.
    This will again use the Ubuntu specific LDFLAGS (using some
    hardening options). Older releases would always pass those options
    in the environment but that changed.
  - Ressurrect qemu-dm for now (upstream qemu would not support
    migration, yet). Forward-port some patches from the old Debian
    package which still included qemu-dm:
    - qemu-prefix (modify LDFLAGS to point to lib dir for qemu-dm)
    - qemu-disable-blktap (this is not present in upstream)
    - ubuntu-qemu-disable-qemu-upstream (breaks build and also should
      be provided by qemu/kvm package)
* Remaining additional patches:
  - qemu-cve-2012-6075-1.patch / qemu-cve-2012-6075-2.patch
  - xsa34-4.2.patch
  - xsa35-4.2-with-xsa34.patch
  - xsa38.patch
  - xsa52-4.2-unstable.patch
  - xsa53-4.2.patch
  - xsa54.patch
  - xsa56.patch
  - qemu-fix-librt-test.patch
    Fix build regression caused by glibc not requiring to link against
    librt for the clock_gettime function. Patch picked from xen-devel
    mailing list.
  - tools-gdbsx-fix-build-failure-with-glibc-2.17.patch
    Add direct include to sys/types.h for xg_main.c which likely was
    indirectly done before. Needed to get ulong type definition.
  - tools-ocaml-fix-build: refresh and reenable (and fix the description
    of) this patch.  Without it the ocam native libraries (*.cmxa)
    build in /build local paths rather than appropriatly versioned
    library references.
  - APIC Register Virtualization (backported from Xen 4.3)
    - 0001-xen-enable-APIC-Register-Virtualization.patch
    - 0002-xen-enable-Virtual-interrupt-delivery.patch
    - 0003-xen-add-virtual-x2apic-support-for-apicv.patch
  - TSC Adjust Support (backported from Xen 4.3)
    - 0004-x86-Implement-TSC-adjust-feature-for-HVM-guest.patch
    - 0005-x86-Save-restore-TSC-adjust-during-HVM-guest-migrati.patch
    - 0006-x86-Expose-TSC-adjust-to-HVM-guest.patch
  - Fix FTBS on i386
    - 0007-x86-Fix-i386-virtual-apic.patch
  - Fix HVM regression when host supports SMEP
    - 0008-vmx-Simplify-cr0-update-handling-by-deferring-cr4-ch.patch
    - 0009-VMX-disable-SMEP-feature-when-guest-is-in-non-paging.patch
    - 0010-VMX-Always-disable-SMEP-when-guest-is-in-non-paging-.patch
  - silence-gcc-warnings.patch: Silence gcc warnings.
  - gcc48-ftbfs.patch
  - gcc48-ftbfs-2.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 * domctl.c
3
 
 * 
4
 
 * Domain management operations. For use by node control stack.
5
 
 * 
6
 
 * Copyright (c) 2002-2006, K A Fraser
7
 
 */
8
 
 
9
 
#include <xen/config.h>
10
 
#include <xen/types.h>
11
 
#include <xen/lib.h>
12
 
#include <xen/err.h>
13
 
#include <xen/mm.h>
14
 
#include <xen/sched.h>
15
 
#include <xen/sched-if.h>
16
 
#include <xen/domain.h>
17
 
#include <xen/event.h>
18
 
#include <xen/domain_page.h>
19
 
#include <xen/trace.h>
20
 
#include <xen/console.h>
21
 
#include <xen/iocap.h>
22
 
#include <xen/rcupdate.h>
23
 
#include <xen/guest_access.h>
24
 
#include <xen/bitmap.h>
25
 
#include <xen/paging.h>
26
 
#include <xen/hypercall.h>
27
 
#include <asm/current.h>
28
 
#include <asm/page.h>
29
 
#include <public/domctl.h>
30
 
#include <xsm/xsm.h>
31
 
 
32
 
static DEFINE_SPINLOCK(domctl_lock);
33
 
DEFINE_SPINLOCK(vcpu_alloc_lock);
34
 
 
35
 
int cpumask_to_xenctl_cpumap(
36
 
    struct xenctl_cpumap *xenctl_cpumap, const cpumask_t *cpumask)
37
 
{
38
 
    unsigned int guest_bytes, copy_bytes, i;
39
 
    uint8_t zero = 0;
40
 
    int err = 0;
41
 
    uint8_t *bytemap = xmalloc_array(uint8_t, (nr_cpu_ids + 7) / 8);
42
 
 
43
 
    if ( !bytemap )
44
 
        return -ENOMEM;
45
 
 
46
 
    guest_bytes = (xenctl_cpumap->nr_cpus + 7) / 8;
47
 
    copy_bytes  = min_t(unsigned int, guest_bytes, (nr_cpu_ids + 7) / 8);
48
 
 
49
 
    bitmap_long_to_byte(bytemap, cpumask_bits(cpumask), nr_cpu_ids);
50
 
 
51
 
    if ( copy_bytes != 0 )
52
 
        if ( copy_to_guest(xenctl_cpumap->bitmap, bytemap, copy_bytes) )
53
 
            err = -EFAULT;
54
 
 
55
 
    for ( i = copy_bytes; !err && i < guest_bytes; i++ )
56
 
        if ( copy_to_guest_offset(xenctl_cpumap->bitmap, i, &zero, 1) )
57
 
            err = -EFAULT;
58
 
 
59
 
    xfree(bytemap);
60
 
 
61
 
    return err;
62
 
}
63
 
 
64
 
int xenctl_cpumap_to_cpumask(
65
 
    cpumask_var_t *cpumask, const struct xenctl_cpumap *xenctl_cpumap)
66
 
{
67
 
    unsigned int guest_bytes, copy_bytes;
68
 
    int err = 0;
69
 
    uint8_t *bytemap = xzalloc_array(uint8_t, (nr_cpu_ids + 7) / 8);
70
 
 
71
 
    if ( !bytemap )
72
 
        return -ENOMEM;
73
 
 
74
 
    guest_bytes = (xenctl_cpumap->nr_cpus + 7) / 8;
75
 
    copy_bytes  = min_t(unsigned int, guest_bytes, (nr_cpu_ids + 7) / 8);
76
 
 
77
 
    if ( copy_bytes != 0 )
78
 
    {
79
 
        if ( copy_from_guest(bytemap, xenctl_cpumap->bitmap, copy_bytes) )
80
 
            err = -EFAULT;
81
 
        if ( (xenctl_cpumap->nr_cpus & 7) && (guest_bytes == copy_bytes) )
82
 
            bytemap[guest_bytes-1] &= ~(0xff << (xenctl_cpumap->nr_cpus & 7));
83
 
    }
84
 
 
85
 
    if ( err )
86
 
        /* nothing */;
87
 
    else if ( alloc_cpumask_var(cpumask) )
88
 
        bitmap_byte_to_long(cpumask_bits(*cpumask), bytemap, nr_cpu_ids);
89
 
    else
90
 
        err = -ENOMEM;
91
 
 
92
 
    xfree(bytemap);
93
 
 
94
 
    return err;
95
 
}
96
 
 
97
 
static inline int is_free_domid(domid_t dom)
98
 
{
99
 
    struct domain *d;
100
 
 
101
 
    if ( dom >= DOMID_FIRST_RESERVED )
102
 
        return 0;
103
 
 
104
 
    if ( (d = rcu_lock_domain_by_id(dom)) == NULL )
105
 
        return 1;
106
 
 
107
 
    rcu_unlock_domain(d);
108
 
    return 0;
109
 
}
110
 
 
111
 
void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
112
 
{
113
 
    struct vcpu *v;
114
 
    u64 cpu_time = 0;
115
 
    int flags = XEN_DOMINF_blocked;
116
 
    struct vcpu_runstate_info runstate;
117
 
    
118
 
    info->domain = d->domain_id;
119
 
    info->nr_online_vcpus = 0;
120
 
    info->ssidref = 0;
121
 
    
122
 
    /* 
123
 
     * - domain is marked as blocked only if all its vcpus are blocked
124
 
     * - domain is marked as running if any of its vcpus is running
125
 
     */
126
 
    for_each_vcpu ( d, v )
127
 
    {
128
 
        vcpu_runstate_get(v, &runstate);
129
 
        cpu_time += runstate.time[RUNSTATE_running];
130
 
        info->max_vcpu_id = v->vcpu_id;
131
 
        if ( !test_bit(_VPF_down, &v->pause_flags) )
132
 
        {
133
 
            if ( !(v->pause_flags & VPF_blocked) )
134
 
                flags &= ~XEN_DOMINF_blocked;
135
 
            if ( v->is_running )
136
 
                flags |= XEN_DOMINF_running;
137
 
            info->nr_online_vcpus++;
138
 
        }
139
 
    }
140
 
 
141
 
    info->cpu_time = cpu_time;
142
 
 
143
 
    info->flags = (info->nr_online_vcpus ? flags : 0) |
144
 
        ((d->is_dying == DOMDYING_dead) ? XEN_DOMINF_dying    : 0) |
145
 
        (d->is_shut_down                ? XEN_DOMINF_shutdown : 0) |
146
 
        (d->is_paused_by_controller     ? XEN_DOMINF_paused   : 0) |
147
 
        (d->debugger_attached           ? XEN_DOMINF_debugged : 0) |
148
 
        d->shutdown_code << XEN_DOMINF_shutdownshift;
149
 
 
150
 
    if ( is_hvm_domain(d) )
151
 
        info->flags |= XEN_DOMINF_hvm_guest;
152
 
 
153
 
    xsm_security_domaininfo(d, info);
154
 
 
155
 
    info->tot_pages         = d->tot_pages;
156
 
    info->max_pages         = d->max_pages;
157
 
    info->shr_pages         = atomic_read(&d->shr_pages);
158
 
    info->paged_pages       = atomic_read(&d->paged_pages);
159
 
    info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT);
160
 
    BUG_ON(SHARED_M2P(info->shared_info_frame));
161
 
 
162
 
    info->cpupool = d->cpupool ? d->cpupool->cpupool_id : CPUPOOLID_NONE;
163
 
 
164
 
    memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
165
 
}
166
 
 
167
 
static unsigned int default_vcpu0_location(cpumask_t *online)
168
 
{
169
 
    struct domain *d;
170
 
    struct vcpu   *v;
171
 
    unsigned int   i, cpu, nr_cpus, *cnt;
172
 
    cpumask_t      cpu_exclude_map;
173
 
 
174
 
    /* Do an initial CPU placement. Pick the least-populated CPU. */
175
 
    nr_cpus = cpumask_last(&cpu_online_map) + 1;
176
 
    cnt = xzalloc_array(unsigned int, nr_cpus);
177
 
    if ( cnt )
178
 
    {
179
 
        rcu_read_lock(&domlist_read_lock);
180
 
        for_each_domain ( d )
181
 
            for_each_vcpu ( d, v )
182
 
                if ( !test_bit(_VPF_down, &v->pause_flags)
183
 
                     && ((cpu = v->processor) < nr_cpus) )
184
 
                    cnt[cpu]++;
185
 
        rcu_read_unlock(&domlist_read_lock);
186
 
    }
187
 
 
188
 
    /*
189
 
     * If we're on a HT system, we only auto-allocate to a non-primary HT. We 
190
 
     * favour high numbered CPUs in the event of a tie.
191
 
     */
192
 
    cpumask_copy(&cpu_exclude_map, per_cpu(cpu_sibling_mask, 0));
193
 
    cpu = cpumask_first(&cpu_exclude_map);
194
 
    if ( cpumask_weight(&cpu_exclude_map) > 1 )
195
 
        cpu = cpumask_next(cpu, &cpu_exclude_map);
196
 
    ASSERT(cpu < nr_cpu_ids);
197
 
    for_each_cpu(i, online)
198
 
    {
199
 
        if ( cpumask_test_cpu(i, &cpu_exclude_map) )
200
 
            continue;
201
 
        if ( (i == cpumask_first(per_cpu(cpu_sibling_mask, i))) &&
202
 
             (cpumask_weight(per_cpu(cpu_sibling_mask, i)) > 1) )
203
 
            continue;
204
 
        cpumask_or(&cpu_exclude_map, &cpu_exclude_map,
205
 
                   per_cpu(cpu_sibling_mask, i));
206
 
        if ( !cnt || cnt[i] <= cnt[cpu] )
207
 
            cpu = i;
208
 
    }
209
 
 
210
 
    xfree(cnt);
211
 
 
212
 
    return cpu;
213
 
}
214
 
 
215
 
bool_t domctl_lock_acquire(void)
216
 
{
217
 
    /*
218
 
     * Caller may try to pause its own VCPUs. We must prevent deadlock
219
 
     * against other non-domctl routines which try to do the same.
220
 
     */
221
 
    if ( !spin_trylock(&current->domain->hypercall_deadlock_mutex) )
222
 
        return 0;
223
 
 
224
 
    /*
225
 
     * Trylock here is paranoia if we have multiple privileged domains. Then
226
 
     * we could have one domain trying to pause another which is spinning
227
 
     * on domctl_lock -- results in deadlock.
228
 
     */
229
 
    if ( spin_trylock(&domctl_lock) )
230
 
        return 1;
231
 
 
232
 
    spin_unlock(&current->domain->hypercall_deadlock_mutex);
233
 
    return 0;
234
 
}
235
 
 
236
 
void domctl_lock_release(void)
237
 
{
238
 
    spin_unlock(&domctl_lock);
239
 
    spin_unlock(&current->domain->hypercall_deadlock_mutex);
240
 
}
241
 
 
242
 
long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
243
 
{
244
 
    long ret = 0;
245
 
    struct xen_domctl curop, *op = &curop;
246
 
 
247
 
    if ( copy_from_guest(op, u_domctl, 1) )
248
 
        return -EFAULT;
249
 
 
250
 
    if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION )
251
 
        return -EACCES;
252
 
 
253
 
    switch ( op->cmd )
254
 
    {
255
 
    case XEN_DOMCTL_ioport_mapping:
256
 
    case XEN_DOMCTL_memory_mapping:
257
 
    case XEN_DOMCTL_bind_pt_irq:
258
 
    case XEN_DOMCTL_unbind_pt_irq: {
259
 
        struct domain *d;
260
 
        bool_t is_priv = IS_PRIV(current->domain);
261
 
        if ( !is_priv && ((d = rcu_lock_domain_by_id(op->domain)) != NULL) )
262
 
        {
263
 
            is_priv = IS_PRIV_FOR(current->domain, d);
264
 
            rcu_unlock_domain(d);
265
 
        }
266
 
        if ( !is_priv )
267
 
            return -EPERM;
268
 
        break;
269
 
    }
270
 
#ifdef XSM_ENABLE
271
 
    case XEN_DOMCTL_getdomaininfo:
272
 
        break;
273
 
#endif
274
 
    default:
275
 
        if ( !IS_PRIV(current->domain) )
276
 
            return -EPERM;
277
 
        break;
278
 
    }
279
 
 
280
 
    if ( !domctl_lock_acquire() )
281
 
        return hypercall_create_continuation(
282
 
            __HYPERVISOR_domctl, "h", u_domctl);
283
 
 
284
 
    switch ( op->cmd )
285
 
    {
286
 
 
287
 
    case XEN_DOMCTL_setvcpucontext:
288
 
    {
289
 
        struct domain *d = rcu_lock_domain_by_id(op->domain);
290
 
        vcpu_guest_context_u c = { .nat = NULL };
291
 
        unsigned int vcpu = op->u.vcpucontext.vcpu;
292
 
        struct vcpu *v;
293
 
 
294
 
        ret = -ESRCH;
295
 
        if ( d == NULL )
296
 
            break;
297
 
 
298
 
        ret = xsm_setvcpucontext(d);
299
 
        if ( ret )
300
 
            goto svc_out;
301
 
 
302
 
        ret = -EINVAL;
303
 
        if ( (d == current->domain) || /* no domain_pause() */
304
 
             (vcpu >= d->max_vcpus) || ((v = d->vcpu[vcpu]) == NULL) )
305
 
            goto svc_out;
306
 
 
307
 
        if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
308
 
        {
309
 
            ret = vcpu_reset(v);
310
 
            if ( ret == -EAGAIN )
311
 
                ret = hypercall_create_continuation(
312
 
                          __HYPERVISOR_domctl, "h", u_domctl);
313
 
            goto svc_out;
314
 
        }
315
 
 
316
 
#ifdef CONFIG_COMPAT
317
 
        BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
318
 
                     < sizeof(struct compat_vcpu_guest_context));
319
 
#endif
320
 
        ret = -ENOMEM;
321
 
        if ( (c.nat = alloc_vcpu_guest_context()) == NULL )
322
 
            goto svc_out;
323
 
 
324
 
#ifdef CONFIG_COMPAT
325
 
        if ( !is_pv_32on64_vcpu(v) )
326
 
            ret = copy_from_guest(c.nat, op->u.vcpucontext.ctxt, 1);
327
 
        else
328
 
            ret = copy_from_guest(c.cmp,
329
 
                                  guest_handle_cast(op->u.vcpucontext.ctxt,
330
 
                                                    void), 1);
331
 
#else
332
 
        ret = copy_from_guest(c.nat, op->u.vcpucontext.ctxt, 1);
333
 
#endif
334
 
        ret = ret ? -EFAULT : 0;
335
 
 
336
 
        if ( ret == 0 )
337
 
        {
338
 
            domain_pause(d);
339
 
            ret = arch_set_info_guest(v, c);
340
 
            domain_unpause(d);
341
 
        }
342
 
 
343
 
    svc_out:
344
 
        free_vcpu_guest_context(c.nat);
345
 
        rcu_unlock_domain(d);
346
 
    }
347
 
    break;
348
 
 
349
 
    case XEN_DOMCTL_pausedomain:
350
 
    {
351
 
        struct domain *d = rcu_lock_domain_by_id(op->domain);
352
 
        ret = -ESRCH;
353
 
        if ( d != NULL )
354
 
        {
355
 
            ret = xsm_pausedomain(d);
356
 
            if ( ret )
357
 
                goto pausedomain_out;
358
 
 
359
 
            ret = -EINVAL;
360
 
            if ( d != current->domain )
361
 
            {
362
 
                domain_pause_by_systemcontroller(d);
363
 
                ret = 0;
364
 
            }
365
 
        pausedomain_out:
366
 
            rcu_unlock_domain(d);
367
 
        }
368
 
    }
369
 
    break;
370
 
 
371
 
    case XEN_DOMCTL_unpausedomain:
372
 
    {
373
 
        struct domain *d = rcu_lock_domain_by_id(op->domain);
374
 
 
375
 
        ret = -ESRCH;
376
 
        if ( d == NULL )
377
 
            break;
378
 
 
379
 
        ret = xsm_unpausedomain(d);
380
 
        if ( ret )
381
 
        {
382
 
            rcu_unlock_domain(d);
383
 
            break;
384
 
        }
385
 
 
386
 
        domain_unpause_by_systemcontroller(d);
387
 
        rcu_unlock_domain(d);
388
 
        ret = 0;
389
 
    }
390
 
    break;
391
 
 
392
 
    case XEN_DOMCTL_resumedomain:
393
 
    {
394
 
        struct domain *d = rcu_lock_domain_by_id(op->domain);
395
 
 
396
 
        ret = -ESRCH;
397
 
        if ( d == NULL )
398
 
            break;
399
 
 
400
 
        ret = xsm_resumedomain(d);
401
 
        if ( ret )
402
 
        {
403
 
            rcu_unlock_domain(d);
404
 
            break;
405
 
        }
406
 
 
407
 
        domain_resume(d);
408
 
        rcu_unlock_domain(d);
409
 
        ret = 0;
410
 
    }
411
 
    break;
412
 
 
413
 
    case XEN_DOMCTL_createdomain:
414
 
    {
415
 
        struct domain *d;
416
 
        domid_t        dom;
417
 
        static domid_t rover = 0;
418
 
        unsigned int domcr_flags;
419
 
 
420
 
        ret = -EINVAL;
421
 
        if ( supervisor_mode_kernel ||
422
 
             (op->u.createdomain.flags &
423
 
             ~(XEN_DOMCTL_CDF_hvm_guest | XEN_DOMCTL_CDF_hap |
424
 
               XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off)) )
425
 
            break;
426
 
 
427
 
        dom = op->domain;
428
 
        if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
429
 
        {
430
 
            ret = -EINVAL;
431
 
            if ( !is_free_domid(dom) )
432
 
                break;
433
 
        }
434
 
        else
435
 
        {
436
 
            for ( dom = rover + 1; dom != rover; dom++ )
437
 
            {
438
 
                if ( dom == DOMID_FIRST_RESERVED )
439
 
                    dom = 0;
440
 
                if ( is_free_domid(dom) )
441
 
                    break;
442
 
            }
443
 
 
444
 
            ret = -ENOMEM;
445
 
            if ( dom == rover )
446
 
                break;
447
 
 
448
 
            rover = dom;
449
 
        }
450
 
 
451
 
        domcr_flags = 0;
452
 
        if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_hvm_guest )
453
 
            domcr_flags |= DOMCRF_hvm;
454
 
        if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_hap )
455
 
            domcr_flags |= DOMCRF_hap;
456
 
        if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_s3_integrity )
457
 
            domcr_flags |= DOMCRF_s3_integrity;
458
 
        if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_oos_off )
459
 
            domcr_flags |= DOMCRF_oos_off;
460
 
 
461
 
        d = domain_create(dom, domcr_flags, op->u.createdomain.ssidref);
462
 
        if ( IS_ERR(d) )
463
 
        {
464
 
            ret = PTR_ERR(d);
465
 
            break;
466
 
        }
467
 
 
468
 
        ret = 0;
469
 
 
470
 
        memcpy(d->handle, op->u.createdomain.handle,
471
 
               sizeof(xen_domain_handle_t));
472
 
 
473
 
        op->domain = d->domain_id;
474
 
        if ( copy_to_guest(u_domctl, op, 1) )
475
 
            ret = -EFAULT;
476
 
    }
477
 
    break;
478
 
 
479
 
    case XEN_DOMCTL_max_vcpus:
480
 
    {
481
 
        struct domain *d;
482
 
        unsigned int i, max = op->u.max_vcpus.max, cpu;
483
 
        cpumask_t *online;
484
 
 
485
 
        ret = -ESRCH;
486
 
        if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
487
 
            break;
488
 
 
489
 
        ret = -EINVAL;
490
 
        if ( (d == current->domain) || /* no domain_pause() */
491
 
             (max > MAX_VIRT_CPUS) ||
492
 
             (is_hvm_domain(d) && (max > MAX_HVM_VCPUS)) )
493
 
        {
494
 
            rcu_unlock_domain(d);
495
 
            break;
496
 
        }
497
 
 
498
 
        ret = xsm_max_vcpus(d);
499
 
        if ( ret )
500
 
        {
501
 
            rcu_unlock_domain(d);
502
 
            break;
503
 
        }
504
 
 
505
 
        /* Until Xenoprof can dynamically grow its vcpu-s array... */
506
 
        if ( d->xenoprof )
507
 
        {
508
 
            rcu_unlock_domain(d);
509
 
            ret = -EAGAIN;
510
 
            break;
511
 
        }
512
 
 
513
 
        /* Needed, for example, to ensure writable p.t. state is synced. */
514
 
        domain_pause(d);
515
 
 
516
 
        /*
517
 
         * Certain operations (e.g. CPU microcode updates) modify data which is
518
 
         * used during VCPU allocation/initialization
519
 
         */
520
 
        while ( !spin_trylock(&vcpu_alloc_lock) )
521
 
        {
522
 
            if ( hypercall_preempt_check() )
523
 
            {
524
 
                ret =  hypercall_create_continuation(
525
 
                    __HYPERVISOR_domctl, "h", u_domctl);
526
 
                goto maxvcpu_out_novcpulock;
527
 
            }
528
 
        }
529
 
 
530
 
        /* We cannot reduce maximum VCPUs. */
531
 
        ret = -EINVAL;
532
 
        if ( (max < d->max_vcpus) && (d->vcpu[max] != NULL) )
533
 
            goto maxvcpu_out;
534
 
 
535
 
        /*
536
 
         * For now don't allow increasing the vcpu count from a non-zero
537
 
         * value: This code and all readers of d->vcpu would otherwise need
538
 
         * to be converted to use RCU, but at present there's no tools side
539
 
         * code path that would issue such a request.
540
 
         */
541
 
        ret = -EBUSY;
542
 
        if ( (d->max_vcpus > 0) && (max > d->max_vcpus) )
543
 
            goto maxvcpu_out;
544
 
 
545
 
        ret = -ENOMEM;
546
 
        online = cpupool_online_cpumask(d->cpupool);
547
 
        if ( max > d->max_vcpus )
548
 
        {
549
 
            struct vcpu **vcpus;
550
 
 
551
 
            BUG_ON(d->vcpu != NULL);
552
 
            BUG_ON(d->max_vcpus != 0);
553
 
 
554
 
            if ( (vcpus = xzalloc_array(struct vcpu *, max)) == NULL )
555
 
                goto maxvcpu_out;
556
 
 
557
 
            /* Install vcpu array /then/ update max_vcpus. */
558
 
            d->vcpu = vcpus;
559
 
            wmb();
560
 
            d->max_vcpus = max;
561
 
        }
562
 
 
563
 
        for ( i = 0; i < max; i++ )
564
 
        {
565
 
            if ( d->vcpu[i] != NULL )
566
 
                continue;
567
 
 
568
 
            cpu = (i == 0) ?
569
 
                default_vcpu0_location(online) :
570
 
                cpumask_cycle(d->vcpu[i-1]->processor, online);
571
 
 
572
 
            if ( alloc_vcpu(d, i, cpu) == NULL )
573
 
                goto maxvcpu_out;
574
 
        }
575
 
 
576
 
        ret = 0;
577
 
 
578
 
    maxvcpu_out:
579
 
        spin_unlock(&vcpu_alloc_lock);
580
 
 
581
 
    maxvcpu_out_novcpulock:
582
 
        domain_unpause(d);
583
 
        rcu_unlock_domain(d);
584
 
    }
585
 
    break;
586
 
 
587
 
    case XEN_DOMCTL_destroydomain:
588
 
    {
589
 
        struct domain *d = rcu_lock_domain_by_id(op->domain);
590
 
        ret = -ESRCH;
591
 
        if ( d != NULL )
592
 
        {
593
 
            ret = xsm_destroydomain(d) ? : domain_kill(d);
594
 
            rcu_unlock_domain(d);
595
 
        }
596
 
    }
597
 
    break;
598
 
 
599
 
    case XEN_DOMCTL_setvcpuaffinity:
600
 
    case XEN_DOMCTL_getvcpuaffinity:
601
 
    {
602
 
        domid_t dom = op->domain;
603
 
        struct domain *d = rcu_lock_domain_by_id(dom);
604
 
        struct vcpu *v;
605
 
 
606
 
        ret = -ESRCH;
607
 
        if ( d == NULL )
608
 
            break;
609
 
 
610
 
        ret = xsm_vcpuaffinity(op->cmd, d);
611
 
        if ( ret )
612
 
            goto vcpuaffinity_out;
613
 
 
614
 
        ret = -EINVAL;
615
 
        if ( op->u.vcpuaffinity.vcpu >= d->max_vcpus )
616
 
            goto vcpuaffinity_out;
617
 
 
618
 
        ret = -ESRCH;
619
 
        if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
620
 
            goto vcpuaffinity_out;
621
 
 
622
 
        if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
623
 
        {
624
 
            cpumask_var_t new_affinity;
625
 
 
626
 
            ret = xenctl_cpumap_to_cpumask(
627
 
                &new_affinity, &op->u.vcpuaffinity.cpumap);
628
 
            if ( !ret )
629
 
            {
630
 
                ret = vcpu_set_affinity(v, new_affinity);
631
 
                free_cpumask_var(new_affinity);
632
 
            }
633
 
        }
634
 
        else
635
 
        {
636
 
            ret = cpumask_to_xenctl_cpumap(
637
 
                &op->u.vcpuaffinity.cpumap, v->cpu_affinity);
638
 
        }
639
 
 
640
 
    vcpuaffinity_out:
641
 
        rcu_unlock_domain(d);
642
 
    }
643
 
    break;
644
 
 
645
 
    case XEN_DOMCTL_scheduler_op:
646
 
    {
647
 
        struct domain *d;
648
 
 
649
 
        ret = -ESRCH;
650
 
        if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
651
 
            break;
652
 
 
653
 
        ret = xsm_scheduler(d);
654
 
        if ( ret )
655
 
            goto scheduler_op_out;
656
 
 
657
 
        ret = sched_adjust(d, &op->u.scheduler_op);
658
 
        if ( copy_to_guest(u_domctl, op, 1) )
659
 
            ret = -EFAULT;
660
 
 
661
 
    scheduler_op_out:
662
 
        rcu_unlock_domain(d);
663
 
    }
664
 
    break;
665
 
 
666
 
    case XEN_DOMCTL_getdomaininfo:
667
 
    { 
668
 
        struct domain *d;
669
 
        domid_t dom = op->domain;
670
 
 
671
 
        rcu_read_lock(&domlist_read_lock);
672
 
 
673
 
        for_each_domain ( d )
674
 
            if ( d->domain_id >= dom )
675
 
                break;
676
 
 
677
 
        if ( d == NULL )
678
 
        {
679
 
            rcu_read_unlock(&domlist_read_lock);
680
 
            ret = -ESRCH;
681
 
            break;
682
 
        }
683
 
 
684
 
        ret = xsm_getdomaininfo(d);
685
 
        if ( ret )
686
 
            goto getdomaininfo_out;
687
 
 
688
 
        getdomaininfo(d, &op->u.getdomaininfo);
689
 
 
690
 
        op->domain = op->u.getdomaininfo.domain;
691
 
        if ( copy_to_guest(u_domctl, op, 1) )
692
 
            ret = -EFAULT;
693
 
 
694
 
    getdomaininfo_out:
695
 
        rcu_read_unlock(&domlist_read_lock);
696
 
    }
697
 
    break;
698
 
 
699
 
    case XEN_DOMCTL_getvcpucontext:
700
 
    { 
701
 
        vcpu_guest_context_u c = { .nat = NULL };
702
 
        struct domain       *d;
703
 
        struct vcpu         *v;
704
 
 
705
 
        ret = -ESRCH;
706
 
        if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
707
 
            break;
708
 
 
709
 
        ret = xsm_getvcpucontext(d);
710
 
        if ( ret )
711
 
            goto getvcpucontext_out;
712
 
 
713
 
        ret = -EINVAL;
714
 
        if ( op->u.vcpucontext.vcpu >= d->max_vcpus )
715
 
            goto getvcpucontext_out;
716
 
 
717
 
        ret = -ESRCH;
718
 
        if ( (v = d->vcpu[op->u.vcpucontext.vcpu]) == NULL )
719
 
            goto getvcpucontext_out;
720
 
 
721
 
        ret = -ENODATA;
722
 
        if ( !v->is_initialised )
723
 
            goto getvcpucontext_out;
724
 
 
725
 
#ifdef CONFIG_COMPAT
726
 
        BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
727
 
                     < sizeof(struct compat_vcpu_guest_context));
728
 
#endif
729
 
        ret = -ENOMEM;
730
 
        if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
731
 
            goto getvcpucontext_out;
732
 
 
733
 
        if ( v != current )
734
 
            vcpu_pause(v);
735
 
 
736
 
        arch_get_info_guest(v, c);
737
 
        ret = 0;
738
 
 
739
 
        if ( v != current )
740
 
            vcpu_unpause(v);
741
 
 
742
 
#ifdef CONFIG_COMPAT
743
 
        if ( !is_pv_32on64_vcpu(v) )
744
 
            ret = copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1);
745
 
        else
746
 
            ret = copy_to_guest(guest_handle_cast(op->u.vcpucontext.ctxt,
747
 
                                                  void), c.cmp, 1);
748
 
#else
749
 
        ret = copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1);
750
 
#endif
751
 
 
752
 
        if ( copy_to_guest(u_domctl, op, 1) || ret )
753
 
            ret = -EFAULT;
754
 
 
755
 
    getvcpucontext_out:
756
 
        xfree(c.nat);
757
 
        rcu_unlock_domain(d);
758
 
    }
759
 
    break;
760
 
 
761
 
    case XEN_DOMCTL_getvcpuinfo:
762
 
    { 
763
 
        struct domain *d;
764
 
        struct vcpu   *v;
765
 
        struct vcpu_runstate_info runstate;
766
 
 
767
 
        ret = -ESRCH;
768
 
        if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
769
 
            break;
770
 
 
771
 
        ret = xsm_getvcpuinfo(d);
772
 
        if ( ret )
773
 
            goto getvcpuinfo_out;
774
 
 
775
 
        ret = -EINVAL;
776
 
        if ( op->u.getvcpuinfo.vcpu >= d->max_vcpus )
777
 
            goto getvcpuinfo_out;
778
 
 
779
 
        ret = -ESRCH;
780
 
        if ( (v = d->vcpu[op->u.getvcpuinfo.vcpu]) == NULL )
781
 
            goto getvcpuinfo_out;
782
 
 
783
 
        vcpu_runstate_get(v, &runstate);
784
 
 
785
 
        op->u.getvcpuinfo.online   = !test_bit(_VPF_down, &v->pause_flags);
786
 
        op->u.getvcpuinfo.blocked  = test_bit(_VPF_blocked, &v->pause_flags);
787
 
        op->u.getvcpuinfo.running  = v->is_running;
788
 
        op->u.getvcpuinfo.cpu_time = runstate.time[RUNSTATE_running];
789
 
        op->u.getvcpuinfo.cpu      = v->processor;
790
 
        ret = 0;
791
 
 
792
 
        if ( copy_to_guest(u_domctl, op, 1) )
793
 
            ret = -EFAULT;
794
 
 
795
 
    getvcpuinfo_out:
796
 
        rcu_unlock_domain(d);
797
 
    }
798
 
    break;
799
 
 
800
 
    case XEN_DOMCTL_max_mem:
801
 
    {
802
 
        struct domain *d;
803
 
        unsigned long new_max;
804
 
 
805
 
        ret = -ESRCH;
806
 
        d = rcu_lock_domain_by_id(op->domain);
807
 
        if ( d == NULL )
808
 
            break;
809
 
 
810
 
        ret = xsm_setdomainmaxmem(d);
811
 
        if ( ret )
812
 
            goto max_mem_out;
813
 
 
814
 
        ret = -EINVAL;
815
 
        new_max = op->u.max_mem.max_memkb >> (PAGE_SHIFT-10);
816
 
 
817
 
        spin_lock(&d->page_alloc_lock);
818
 
        /*
819
 
         * NB. We removed a check that new_max >= current tot_pages; this means
820
 
         * that the domain will now be allowed to "ratchet" down to new_max. In
821
 
         * the meantime, while tot > max, all new allocations are disallowed.
822
 
         */
823
 
        d->max_pages = new_max;
824
 
        ret = 0;
825
 
        spin_unlock(&d->page_alloc_lock);
826
 
 
827
 
    max_mem_out:
828
 
        rcu_unlock_domain(d);
829
 
    }
830
 
    break;
831
 
 
832
 
    case XEN_DOMCTL_setdomainhandle:
833
 
    {
834
 
        struct domain *d;
835
 
 
836
 
        ret = -ESRCH;
837
 
        d = rcu_lock_domain_by_id(op->domain);
838
 
        if ( d == NULL )
839
 
            break;
840
 
 
841
 
        ret = xsm_setdomainhandle(d);
842
 
        if ( ret )
843
 
        {
844
 
            rcu_unlock_domain(d);
845
 
            break;
846
 
        }
847
 
 
848
 
        memcpy(d->handle, op->u.setdomainhandle.handle,
849
 
               sizeof(xen_domain_handle_t));
850
 
        rcu_unlock_domain(d);
851
 
        ret = 0;
852
 
    }
853
 
    break;
854
 
 
855
 
    case XEN_DOMCTL_setdebugging:
856
 
    {
857
 
        struct domain *d;
858
 
 
859
 
        ret = -ESRCH;
860
 
        d = rcu_lock_domain_by_id(op->domain);
861
 
        if ( d == NULL )
862
 
            break;
863
 
 
864
 
        ret = -EINVAL;
865
 
        if ( d == current->domain ) /* no domain_pause() */
866
 
        {
867
 
            rcu_unlock_domain(d);
868
 
            break;
869
 
        }
870
 
 
871
 
        ret = xsm_setdebugging(d);
872
 
        if ( ret )
873
 
        {
874
 
            rcu_unlock_domain(d);
875
 
            break;
876
 
        }
877
 
 
878
 
        domain_pause(d);
879
 
        d->debugger_attached = !!op->u.setdebugging.enable;
880
 
        domain_unpause(d); /* causes guest to latch new status */
881
 
        rcu_unlock_domain(d);
882
 
        ret = 0;
883
 
    }
884
 
    break;
885
 
 
886
 
    case XEN_DOMCTL_irq_permission:
887
 
    {
888
 
        struct domain *d;
889
 
        unsigned int pirq = op->u.irq_permission.pirq;
890
 
        int allow = op->u.irq_permission.allow_access;
891
 
 
892
 
        ret = -ESRCH;
893
 
        d = rcu_lock_domain_by_id(op->domain);
894
 
        if ( d == NULL )
895
 
            break;
896
 
 
897
 
        if ( pirq >= d->nr_pirqs )
898
 
            ret = -EINVAL;
899
 
        else if ( xsm_irq_permission(d, pirq, allow) )
900
 
            ret = -EPERM;
901
 
        else if ( allow )
902
 
            ret = pirq_permit_access(d, pirq);
903
 
        else
904
 
            ret = pirq_deny_access(d, pirq);
905
 
 
906
 
        rcu_unlock_domain(d);
907
 
    }
908
 
    break;
909
 
 
910
 
    case XEN_DOMCTL_iomem_permission:
911
 
    {
912
 
        struct domain *d;
913
 
        unsigned long mfn = op->u.iomem_permission.first_mfn;
914
 
        unsigned long nr_mfns = op->u.iomem_permission.nr_mfns;
915
 
        int allow = op->u.iomem_permission.allow_access;
916
 
 
917
 
        ret = -EINVAL;
918
 
        if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
919
 
            break;
920
 
 
921
 
        ret = -ESRCH;
922
 
        d = rcu_lock_domain_by_id(op->domain);
923
 
        if ( d == NULL )
924
 
            break;
925
 
 
926
 
        if ( xsm_iomem_permission(d, mfn, mfn + nr_mfns - 1, allow) )
927
 
            ret = -EPERM;
928
 
        else if ( allow )
929
 
            ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
930
 
        else
931
 
            ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
932
 
 
933
 
        rcu_unlock_domain(d);
934
 
    }
935
 
    break;
936
 
 
937
 
    case XEN_DOMCTL_settimeoffset:
938
 
    {
939
 
        struct domain *d;
940
 
 
941
 
        ret = -ESRCH;
942
 
        d = rcu_lock_domain_by_id(op->domain);
943
 
        if ( d == NULL )
944
 
            break;
945
 
 
946
 
        ret = xsm_domain_settime(d);
947
 
        if ( ret )
948
 
        {
949
 
            rcu_unlock_domain(d);
950
 
            break;
951
 
        }
952
 
 
953
 
        domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds);
954
 
        rcu_unlock_domain(d);
955
 
        ret = 0;
956
 
    }
957
 
    break;
958
 
 
959
 
    case XEN_DOMCTL_set_target:
960
 
    {
961
 
        struct domain *d, *e;
962
 
 
963
 
        ret = -ESRCH;
964
 
        d = rcu_lock_domain_by_id(op->domain);
965
 
        if ( d == NULL )
966
 
            break;
967
 
 
968
 
        ret = -ESRCH;
969
 
        e = get_domain_by_id(op->u.set_target.target);
970
 
        if ( e == NULL )
971
 
            goto set_target_out;
972
 
 
973
 
        ret = -EINVAL;
974
 
        if ( (d == e) || (d->target != NULL) )
975
 
        {
976
 
            put_domain(e);
977
 
            goto set_target_out;
978
 
        }
979
 
 
980
 
        ret = xsm_set_target(d, e);
981
 
        if ( ret ) {
982
 
            put_domain(e);
983
 
            goto set_target_out;            
984
 
        }
985
 
 
986
 
        /* Hold reference on @e until we destroy @d. */
987
 
        d->target = e;
988
 
 
989
 
        ret = 0;
990
 
 
991
 
    set_target_out:
992
 
        rcu_unlock_domain(d);
993
 
    }
994
 
    break;
995
 
 
996
 
    case XEN_DOMCTL_subscribe:
997
 
    {
998
 
        struct domain *d;
999
 
 
1000
 
        ret = -ESRCH;
1001
 
        d = rcu_lock_domain_by_id(op->domain);
1002
 
        if ( d != NULL )
1003
 
        {
1004
 
            ret = xsm_domctl(d, op->cmd);
1005
 
            if ( !ret )
1006
 
                d->suspend_evtchn = op->u.subscribe.port;
1007
 
            rcu_unlock_domain(d);
1008
 
        }
1009
 
    }
1010
 
    break;
1011
 
 
1012
 
    case XEN_DOMCTL_disable_migrate:
1013
 
    {
1014
 
        struct domain *d;
1015
 
        ret = -ESRCH;
1016
 
        if ( (d = rcu_lock_domain_by_id(op->domain)) != NULL )
1017
 
        {
1018
 
            ret = xsm_domctl(d, op->cmd);
1019
 
            if ( !ret )
1020
 
                d->disable_migrate = op->u.disable_migrate.disable;
1021
 
            rcu_unlock_domain(d);
1022
 
        }
1023
 
    }
1024
 
    break;
1025
 
 
1026
 
    case XEN_DOMCTL_set_virq_handler:
1027
 
    {
1028
 
        struct domain *d;
1029
 
        uint32_t virq = op->u.set_virq_handler.virq;
1030
 
 
1031
 
        ret = -ESRCH;
1032
 
        d = rcu_lock_domain_by_id(op->domain);
1033
 
        if ( d != NULL )
1034
 
        {
1035
 
            ret = xsm_set_virq_handler(d, virq);
1036
 
            if ( !ret )
1037
 
                ret = set_global_virq_handler(d, virq);
1038
 
            rcu_unlock_domain(d);
1039
 
        }
1040
 
    }
1041
 
    break;
1042
 
 
1043
 
    default:
1044
 
        ret = arch_do_domctl(op, u_domctl);
1045
 
        break;
1046
 
    }
1047
 
 
1048
 
    domctl_lock_release();
1049
 
 
1050
 
    return ret;
1051
 
}
1052
 
 
1053
 
/*
1054
 
 * Local variables:
1055
 
 * mode: C
1056
 
 * c-set-style: "BSD"
1057
 
 * c-basic-offset: 4
1058
 
 * tab-width: 4
1059
 
 * indent-tabs-mode: nil
1060
 
 * End:
1061
 
 */