Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/vm_event.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * vm_event.c
3
 *
4
 * VM event support.
5
 *
6
 * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
23
#include <xen/sched.h>
24
#include <xen/event.h>
25
#include <xen/wait.h>
26
#include <xen/vm_event.h>
27
#include <xen/mem_access.h>
28
#include <asm/p2m.h>
29
#include <asm/monitor.h>
30
#include <asm/vm_event.h>
31
#include <xsm/xsm.h>
32
33
/* for public/io/ring.h macros */
34
#define xen_mb()   smp_mb()
35
#define xen_rmb()  smp_rmb()
36
0
#define xen_wmb()  smp_wmb()
37
38
0
#define vm_event_ring_lock_init(_ved)  spin_lock_init(&(_ved)->ring_lock)
39
0
#define vm_event_ring_lock(_ved)       spin_lock(&(_ved)->ring_lock)
40
0
#define vm_event_ring_unlock(_ved)     spin_unlock(&(_ved)->ring_lock)
41
42
static int vm_event_enable(
43
    struct domain *d,
44
    struct xen_domctl_vm_event_op *vec,
45
    struct vm_event_domain **ved,
46
    int pause_flag,
47
    int param,
48
    xen_event_channel_notification_t notification_fn)
49
0
{
50
0
    int rc;
51
0
    unsigned long ring_gfn = d->arch.hvm_domain.params[param];
52
0
53
0
    if ( !*ved )
54
0
        *ved = xzalloc(struct vm_event_domain);
55
0
    if ( !*ved )
56
0
        return -ENOMEM;
57
0
58
0
    /* Only one helper at a time. If the helper crashed,
59
0
     * the ring is in an undefined state and so is the guest.
60
0
     */
61
0
    if ( (*ved)->ring_page )
62
0
        return -EBUSY;;
63
0
64
0
    /* The parameter defaults to zero, and it should be
65
0
     * set to something */
66
0
    if ( ring_gfn == 0 )
67
0
        return -ENOSYS;
68
0
69
0
    vm_event_ring_lock_init(*ved);
70
0
    vm_event_ring_lock(*ved);
71
0
72
0
    rc = vm_event_init_domain(d);
73
0
74
0
    if ( rc < 0 )
75
0
        goto err;
76
0
77
0
    rc = prepare_ring_for_helper(d, ring_gfn, &(*ved)->ring_pg_struct,
78
0
                                 &(*ved)->ring_page);
79
0
    if ( rc < 0 )
80
0
        goto err;
81
0
82
0
    /* Set the number of currently blocked vCPUs to 0. */
83
0
    (*ved)->blocked = 0;
84
0
85
0
    /* Allocate event channel */
86
0
    rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id,
87
0
                                         notification_fn);
88
0
    if ( rc < 0 )
89
0
        goto err;
90
0
91
0
    (*ved)->xen_port = vec->port = rc;
92
0
93
0
    /* Prepare ring buffer */
94
0
    FRONT_RING_INIT(&(*ved)->front_ring,
95
0
                    (vm_event_sring_t *)(*ved)->ring_page,
96
0
                    PAGE_SIZE);
97
0
98
0
    /* Save the pause flag for this particular ring. */
99
0
    (*ved)->pause_flag = pause_flag;
100
0
101
0
    /* Initialize the last-chance wait queue. */
102
0
    init_waitqueue_head(&(*ved)->wq);
103
0
104
0
    vm_event_ring_unlock(*ved);
105
0
    return 0;
106
0
107
0
 err:
108
0
    destroy_ring_for_helper(&(*ved)->ring_page,
109
0
                            (*ved)->ring_pg_struct);
110
0
    vm_event_ring_unlock(*ved);
111
0
    xfree(*ved);
112
0
    *ved = NULL;
113
0
114
0
    return rc;
115
0
}
116
117
static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
118
0
{
119
0
    int avail_req = RING_FREE_REQUESTS(&ved->front_ring);
120
0
    avail_req -= ved->target_producers;
121
0
    avail_req -= ved->foreign_producers;
122
0
123
0
    BUG_ON(avail_req < 0);
124
0
125
0
    return avail_req;
126
0
}
127
128
/*
129
 * vm_event_wake_blocked() will wakeup vcpus waiting for room in the
130
 * ring. These vCPUs were paused on their way out after placing an event,
131
 * but need to be resumed where the ring is capable of processing at least
132
 * one event from them.
133
 */
134
static void vm_event_wake_blocked(struct domain *d, struct vm_event_domain *ved)
135
0
{
136
0
    struct vcpu *v;
137
0
    unsigned int avail_req = vm_event_ring_available(ved);
138
0
139
0
    if ( avail_req == 0 || ved->blocked == 0 )
140
0
        return;
141
0
142
0
    /* We remember which vcpu last woke up to avoid scanning always linearly
143
0
     * from zero and starving higher-numbered vcpus under high load */
144
0
    if ( d->vcpu )
145
0
    {
146
0
        int i, j, k;
147
0
148
0
        for (i = ved->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, j++)
149
0
        {
150
0
            k = i % d->max_vcpus;
151
0
            v = d->vcpu[k];
152
0
            if ( !v )
153
0
                continue;
154
0
155
0
            if ( !(ved->blocked) || avail_req == 0 )
156
0
               break;
157
0
158
0
            if ( test_and_clear_bit(ved->pause_flag, &v->pause_flags) )
159
0
            {
160
0
                vcpu_unpause(v);
161
0
                avail_req--;
162
0
                ved->blocked--;
163
0
                ved->last_vcpu_wake_up = k;
164
0
            }
165
0
        }
166
0
    }
167
0
}
168
169
/*
170
 * In the event that a vCPU attempted to place an event in the ring and
171
 * was unable to do so, it is queued on a wait queue.  These are woken as
172
 * needed, and take precedence over the blocked vCPUs.
173
 */
174
static void vm_event_wake_queued(struct domain *d, struct vm_event_domain *ved)
175
0
{
176
0
    unsigned int avail_req = vm_event_ring_available(ved);
177
0
178
0
    if ( avail_req > 0 )
179
0
        wake_up_nr(&ved->wq, avail_req);
180
0
}
181
182
/*
183
 * vm_event_wake() will wakeup all vcpus waiting for the ring to
184
 * become available.  If we have queued vCPUs, they get top priority. We
185
 * are guaranteed that they will go through code paths that will eventually
186
 * call vm_event_wake() again, ensuring that any blocked vCPUs will get
187
 * unpaused once all the queued vCPUs have made it through.
188
 */
189
void vm_event_wake(struct domain *d, struct vm_event_domain *ved)
190
0
{
191
0
    if (!list_empty(&ved->wq.list))
192
0
        vm_event_wake_queued(d, ved);
193
0
    else
194
0
        vm_event_wake_blocked(d, ved);
195
0
}
196
197
static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
198
0
{
199
0
    if ( vm_event_check_ring(*ved) )
200
0
    {
201
0
        struct vcpu *v;
202
0
203
0
        vm_event_ring_lock(*ved);
204
0
205
0
        if ( !list_empty(&(*ved)->wq.list) )
206
0
        {
207
0
            vm_event_ring_unlock(*ved);
208
0
            return -EBUSY;
209
0
        }
210
0
211
0
        /* Free domU's event channel and leave the other one unbound */
212
0
        free_xen_event_channel(d, (*ved)->xen_port);
213
0
214
0
        /* Unblock all vCPUs */
215
0
        for_each_vcpu ( d, v )
216
0
        {
217
0
            if ( test_and_clear_bit((*ved)->pause_flag, &v->pause_flags) )
218
0
            {
219
0
                vcpu_unpause(v);
220
0
                (*ved)->blocked--;
221
0
            }
222
0
        }
223
0
224
0
        destroy_ring_for_helper(&(*ved)->ring_page,
225
0
                                (*ved)->ring_pg_struct);
226
0
227
0
        vm_event_cleanup_domain(d);
228
0
229
0
        vm_event_ring_unlock(*ved);
230
0
    }
231
0
232
0
    xfree(*ved);
233
0
    *ved = NULL;
234
0
235
0
    return 0;
236
0
}
237
238
static inline void vm_event_release_slot(struct domain *d,
239
                                         struct vm_event_domain *ved)
240
0
{
241
0
    /* Update the accounting */
242
0
    if ( current->domain == d )
243
0
        ved->target_producers--;
244
0
    else
245
0
        ved->foreign_producers--;
246
0
247
0
    /* Kick any waiters */
248
0
    vm_event_wake(d, ved);
249
0
}
250
251
/*
252
 * vm_event_mark_and_pause() tags vcpu and put it to sleep.
253
 * The vcpu will resume execution in vm_event_wake_blocked().
254
 */
255
void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
256
0
{
257
0
    if ( !test_and_set_bit(ved->pause_flag, &v->pause_flags) )
258
0
    {
259
0
        vcpu_pause_nosync(v);
260
0
        ved->blocked++;
261
0
    }
262
0
}
263
264
/*
265
 * This must be preceded by a call to claim_slot(), and is guaranteed to
266
 * succeed.  As a side-effect however, the vCPU may be paused if the ring is
267
 * overly full and its continued execution would cause stalling and excessive
268
 * waiting.  The vCPU will be automatically unpaused when the ring clears.
269
 */
270
void vm_event_put_request(struct domain *d,
271
                          struct vm_event_domain *ved,
272
                          vm_event_request_t *req)
273
0
{
274
0
    vm_event_front_ring_t *front_ring;
275
0
    int free_req;
276
0
    unsigned int avail_req;
277
0
    RING_IDX req_prod;
278
0
    struct vcpu *curr = current;
279
0
280
0
    if( !vm_event_check_ring(ved))
281
0
        return;
282
0
283
0
    if ( curr->domain != d )
284
0
    {
285
0
        req->flags |= VM_EVENT_FLAG_FOREIGN;
286
0
#ifndef NDEBUG
287
0
        if ( !(req->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
288
0
            gdprintk(XENLOG_G_WARNING, "d%dv%d was not paused.\n",
289
0
                     d->domain_id, req->vcpu_id);
290
0
#endif
291
0
    }
292
0
293
0
    req->version = VM_EVENT_INTERFACE_VERSION;
294
0
295
0
    vm_event_ring_lock(ved);
296
0
297
0
    /* Due to the reservations, this step must succeed. */
298
0
    front_ring = &ved->front_ring;
299
0
    free_req = RING_FREE_REQUESTS(front_ring);
300
0
    ASSERT(free_req > 0);
301
0
302
0
    /* Copy request */
303
0
    req_prod = front_ring->req_prod_pvt;
304
0
    memcpy(RING_GET_REQUEST(front_ring, req_prod), req, sizeof(*req));
305
0
    req_prod++;
306
0
307
0
    /* Update ring */
308
0
    front_ring->req_prod_pvt = req_prod;
309
0
    RING_PUSH_REQUESTS(front_ring);
310
0
311
0
    /* We've actually *used* our reservation, so release the slot. */
312
0
    vm_event_release_slot(d, ved);
313
0
314
0
    /* Give this vCPU a black eye if necessary, on the way out.
315
0
     * See the comments above wake_blocked() for more information
316
0
     * on how this mechanism works to avoid waiting. */
317
0
    avail_req = vm_event_ring_available(ved);
318
0
    if( curr->domain == d && avail_req < d->max_vcpus &&
319
0
        !atomic_read(&curr->vm_event_pause_count) )
320
0
        vm_event_mark_and_pause(curr, ved);
321
0
322
0
    vm_event_ring_unlock(ved);
323
0
324
0
    notify_via_xen_event_channel(d, ved->xen_port);
325
0
}
326
327
int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
328
                          vm_event_response_t *rsp)
329
0
{
330
0
    vm_event_front_ring_t *front_ring;
331
0
    RING_IDX rsp_cons;
332
0
333
0
    vm_event_ring_lock(ved);
334
0
335
0
    front_ring = &ved->front_ring;
336
0
    rsp_cons = front_ring->rsp_cons;
337
0
338
0
    if ( !RING_HAS_UNCONSUMED_RESPONSES(front_ring) )
339
0
    {
340
0
        vm_event_ring_unlock(ved);
341
0
        return 0;
342
0
    }
343
0
344
0
    /* Copy response */
345
0
    memcpy(rsp, RING_GET_RESPONSE(front_ring, rsp_cons), sizeof(*rsp));
346
0
    rsp_cons++;
347
0
348
0
    /* Update ring */
349
0
    front_ring->rsp_cons = rsp_cons;
350
0
    front_ring->sring->rsp_event = rsp_cons + 1;
351
0
352
0
    /* Kick any waiters -- since we've just consumed an event,
353
0
     * there may be additional space available in the ring. */
354
0
    vm_event_wake(d, ved);
355
0
356
0
    vm_event_ring_unlock(ved);
357
0
358
0
    return 1;
359
0
}
360
361
/*
362
 * Pull all responses from the given ring and unpause the corresponding vCPU
363
 * if required. Based on the response type, here we can also call custom
364
 * handlers.
365
 *
366
 * Note: responses are handled the same way regardless of which ring they
367
 * arrive on.
368
 */
369
void vm_event_resume(struct domain *d, struct vm_event_domain *ved)
370
0
{
371
0
    vm_event_response_t rsp;
372
0
373
0
    /*
374
0
     * vm_event_resume() runs in either XEN_DOMCTL_VM_EVENT_OP_*, or
375
0
     * EVTCHN_send context from the introspection consumer. Both contexts
376
0
     * are guaranteed not to be the subject of vm_event responses.
377
0
     * While we could ASSERT(v != current) for each VCPU in d in the loop
378
0
     * below, this covers the case where we would need to iterate over all
379
0
     * of them more succintly.
380
0
     */
381
0
    ASSERT(d != current->domain);
382
0
383
0
    /* Pull all responses off the ring. */
384
0
    while ( vm_event_get_response(d, ved, &rsp) )
385
0
    {
386
0
        struct vcpu *v;
387
0
388
0
        if ( rsp.version != VM_EVENT_INTERFACE_VERSION )
389
0
        {
390
0
            printk(XENLOG_G_WARNING "vm_event interface version mismatch\n");
391
0
            continue;
392
0
        }
393
0
394
0
        /* Validate the vcpu_id in the response. */
395
0
        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
396
0
            continue;
397
0
398
0
        v = d->vcpu[rsp.vcpu_id];
399
0
400
0
        /*
401
0
         * In some cases the response type needs extra handling, so here
402
0
         * we call the appropriate handlers.
403
0
         */
404
0
405
0
        /* Check flags which apply only when the vCPU is paused */
406
0
        if ( atomic_read(&v->vm_event_pause_count) )
407
0
        {
408
0
#ifdef CONFIG_HAS_MEM_PAGING
409
0
            if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING )
410
0
                p2m_mem_paging_resume(d, &rsp);
411
0
#endif
412
0
413
0
            /*
414
0
             * Check emulation flags in the arch-specific handler only, as it
415
0
             * has to set arch-specific flags when supported, and to avoid
416
0
             * bitmask overhead when it isn't supported.
417
0
             */
418
0
            vm_event_emulate_check(v, &rsp);
419
0
420
0
            /*
421
0
             * Check in arch-specific handler to avoid bitmask overhead when
422
0
             * not supported.
423
0
             */
424
0
            vm_event_register_write_resume(v, &rsp);
425
0
426
0
            /*
427
0
             * Check in arch-specific handler to avoid bitmask overhead when
428
0
             * not supported.
429
0
             */
430
0
            vm_event_toggle_singlestep(d, v, &rsp);
431
0
432
0
            /* Check for altp2m switch */
433
0
            if ( rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
434
0
                p2m_altp2m_check(v, rsp.altp2m_idx);
435
0
436
0
            if ( rsp.flags & VM_EVENT_FLAG_SET_REGISTERS )
437
0
                vm_event_set_registers(v, &rsp);
438
0
439
0
            if ( rsp.flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
440
0
                vm_event_monitor_next_interrupt(v);
441
0
442
0
            if ( rsp.flags & VM_EVENT_FLAG_VCPU_PAUSED )
443
0
                vm_event_vcpu_unpause(v);
444
0
        }
445
0
    }
446
0
}
447
448
void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved)
449
0
{
450
0
    if( !vm_event_check_ring(ved) )
451
0
        return;
452
0
453
0
    vm_event_ring_lock(ved);
454
0
    vm_event_release_slot(d, ved);
455
0
    vm_event_ring_unlock(ved);
456
0
}
457
458
static int vm_event_grab_slot(struct vm_event_domain *ved, int foreign)
459
0
{
460
0
    unsigned int avail_req;
461
0
462
0
    if ( !ved->ring_page )
463
0
        return -ENOSYS;
464
0
465
0
    vm_event_ring_lock(ved);
466
0
467
0
    avail_req = vm_event_ring_available(ved);
468
0
    if ( avail_req == 0 )
469
0
    {
470
0
        vm_event_ring_unlock(ved);
471
0
        return -EBUSY;
472
0
    }
473
0
474
0
    if ( !foreign )
475
0
        ved->target_producers++;
476
0
    else
477
0
        ved->foreign_producers++;
478
0
479
0
    vm_event_ring_unlock(ved);
480
0
481
0
    return 0;
482
0
}
483
484
/* Simple try_grab wrapper for use in the wait_event() macro. */
485
static int vm_event_wait_try_grab(struct vm_event_domain *ved, int *rc)
486
0
{
487
0
    *rc = vm_event_grab_slot(ved, 0);
488
0
    return *rc;
489
0
}
490
491
/* Call vm_event_grab_slot() until the ring doesn't exist, or is available. */
492
static int vm_event_wait_slot(struct vm_event_domain *ved)
493
0
{
494
0
    int rc = -EBUSY;
495
0
    wait_event(ved->wq, vm_event_wait_try_grab(ved, &rc) != -EBUSY);
496
0
    return rc;
497
0
}
498
499
bool_t vm_event_check_ring(struct vm_event_domain *ved)
500
0
{
501
0
    return (ved && ved->ring_page);
502
0
}
503
504
/*
505
 * Determines whether or not the current vCPU belongs to the target domain,
506
 * and calls the appropriate wait function.  If it is a guest vCPU, then we
507
 * use vm_event_wait_slot() to reserve a slot.  As long as there is a ring,
508
 * this function will always return 0 for a guest.  For a non-guest, we check
509
 * for space and return -EBUSY if the ring is not available.
510
 *
511
 * Return codes: -ENOSYS: the ring is not yet configured
512
 *               -EBUSY: the ring is busy
513
 *               0: a spot has been reserved
514
 *
515
 */
516
int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
517
                          bool_t allow_sleep)
518
0
{
519
0
    if ( !vm_event_check_ring(ved) )
520
0
        return -EOPNOTSUPP;
521
0
522
0
    if ( (current->domain == d) && allow_sleep )
523
0
        return vm_event_wait_slot(ved);
524
0
    else
525
0
        return vm_event_grab_slot(ved, (current->domain != d));
526
0
}
527
528
#ifdef CONFIG_HAS_MEM_PAGING
529
/* Registered with Xen-bound event channel for incoming notifications. */
530
static void mem_paging_notification(struct vcpu *v, unsigned int port)
531
0
{
532
0
    struct domain *domain = v->domain;
533
0
534
0
    if ( likely(vm_event_check_ring(domain->vm_event_paging)) )
535
0
        vm_event_resume(domain, domain->vm_event_paging);
536
0
}
537
#endif
538
539
/* Registered with Xen-bound event channel for incoming notifications. */
540
static void monitor_notification(struct vcpu *v, unsigned int port)
541
0
{
542
0
    struct domain *domain = v->domain;
543
0
544
0
    if ( likely(vm_event_check_ring(domain->vm_event_monitor)) )
545
0
        vm_event_resume(domain, domain->vm_event_monitor);
546
0
}
547
548
#ifdef CONFIG_HAS_MEM_SHARING
549
/* Registered with Xen-bound event channel for incoming notifications. */
550
static void mem_sharing_notification(struct vcpu *v, unsigned int port)
551
0
{
552
0
    struct domain *domain = v->domain;
553
0
554
0
    if ( likely(vm_event_check_ring(domain->vm_event_share)) )
555
0
        vm_event_resume(domain, domain->vm_event_share);
556
0
}
557
#endif
558
559
/* Clean up on domain destruction */
560
void vm_event_cleanup(struct domain *d)
561
0
{
562
0
#ifdef CONFIG_HAS_MEM_PAGING
563
0
    if ( vm_event_check_ring(d->vm_event_paging) )
564
0
    {
565
0
        /* Destroying the wait queue head means waking up all
566
0
         * queued vcpus. This will drain the list, allowing
567
0
         * the disable routine to complete. It will also drop
568
0
         * all domain refs the wait-queued vcpus are holding.
569
0
         * Finally, because this code path involves previously
570
0
         * pausing the domain (domain_kill), unpausing the
571
0
         * vcpus causes no harm. */
572
0
        destroy_waitqueue_head(&d->vm_event_paging->wq);
573
0
        (void)vm_event_disable(d, &d->vm_event_paging);
574
0
    }
575
0
#endif
576
0
    if ( vm_event_check_ring(d->vm_event_monitor) )
577
0
    {
578
0
        destroy_waitqueue_head(&d->vm_event_monitor->wq);
579
0
        (void)vm_event_disable(d, &d->vm_event_monitor);
580
0
    }
581
0
#ifdef CONFIG_HAS_MEM_SHARING
582
0
    if ( vm_event_check_ring(d->vm_event_share) )
583
0
    {
584
0
        destroy_waitqueue_head(&d->vm_event_share->wq);
585
0
        (void)vm_event_disable(d, &d->vm_event_share);
586
0
    }
587
0
#endif
588
0
}
589
590
int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
591
                    XEN_GUEST_HANDLE_PARAM(void) u_domctl)
592
0
{
593
0
    int rc;
594
0
595
0
    rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op);
596
0
    if ( rc )
597
0
        return rc;
598
0
599
0
    if ( unlikely(d == current->domain) ) /* no domain_pause() */
600
0
    {
601
0
        gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n");
602
0
        return -EINVAL;
603
0
    }
604
0
605
0
    if ( unlikely(d->is_dying) )
606
0
    {
607
0
        gdprintk(XENLOG_INFO, "Ignoring memory event op on dying domain %u\n",
608
0
                 d->domain_id);
609
0
        return 0;
610
0
    }
611
0
612
0
    if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
613
0
    {
614
0
        gdprintk(XENLOG_INFO,
615
0
                 "Memory event op on a domain (%u) with no vcpus\n",
616
0
                 d->domain_id);
617
0
        return -EINVAL;
618
0
    }
619
0
620
0
    rc = -ENOSYS;
621
0
622
0
    switch ( vec->mode )
623
0
    {
624
0
#ifdef CONFIG_HAS_MEM_PAGING
625
0
    case XEN_DOMCTL_VM_EVENT_OP_PAGING:
626
0
    {
627
0
        rc = -EINVAL;
628
0
629
0
        switch( vec->op )
630
0
        {
631
0
        case XEN_VM_EVENT_ENABLE:
632
0
        {
633
0
            struct p2m_domain *p2m = p2m_get_hostp2m(d);
634
0
635
0
            rc = -EOPNOTSUPP;
636
0
            /* hvm fixme: p2m_is_foreign types need addressing */
637
0
            if ( is_hvm_domain(hardware_domain) )
638
0
                break;
639
0
640
0
            rc = -ENODEV;
641
0
            /* Only HAP is supported */
642
0
            if ( !hap_enabled(d) )
643
0
                break;
644
0
645
0
            /* No paging if iommu is used */
646
0
            rc = -EMLINK;
647
0
            if ( unlikely(need_iommu(d)) )
648
0
                break;
649
0
650
0
            rc = -EXDEV;
651
0
            /* Disallow paging in a PoD guest */
652
0
            if ( p2m->pod.entry_count )
653
0
                break;
654
0
655
0
            /* domain_pause() not required here, see XSA-99 */
656
0
            rc = vm_event_enable(d, vec, &d->vm_event_paging, _VPF_mem_paging,
657
0
                                 HVM_PARAM_PAGING_RING_PFN,
658
0
                                 mem_paging_notification);
659
0
        }
660
0
        break;
661
0
662
0
        case XEN_VM_EVENT_DISABLE:
663
0
            if ( vm_event_check_ring(d->vm_event_paging) )
664
0
            {
665
0
                domain_pause(d);
666
0
                rc = vm_event_disable(d, &d->vm_event_paging);
667
0
                domain_unpause(d);
668
0
            }
669
0
            break;
670
0
671
0
        case XEN_VM_EVENT_RESUME:
672
0
            if ( vm_event_check_ring(d->vm_event_paging) )
673
0
                vm_event_resume(d, d->vm_event_paging);
674
0
            else
675
0
                rc = -ENODEV;
676
0
            break;
677
0
678
0
        default:
679
0
            rc = -ENOSYS;
680
0
            break;
681
0
        }
682
0
    }
683
0
    break;
684
0
#endif
685
0
686
0
    case XEN_DOMCTL_VM_EVENT_OP_MONITOR:
687
0
    {
688
0
        rc = -EINVAL;
689
0
690
0
        switch( vec->op )
691
0
        {
692
0
        case XEN_VM_EVENT_ENABLE:
693
0
            /* domain_pause() not required here, see XSA-99 */
694
0
            rc = arch_monitor_init_domain(d);
695
0
            if ( rc )
696
0
                break;
697
0
            rc = vm_event_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
698
0
                                 HVM_PARAM_MONITOR_RING_PFN,
699
0
                                 monitor_notification);
700
0
            break;
701
0
702
0
        case XEN_VM_EVENT_DISABLE:
703
0
            if ( vm_event_check_ring(d->vm_event_monitor) )
704
0
            {
705
0
                domain_pause(d);
706
0
                rc = vm_event_disable(d, &d->vm_event_monitor);
707
0
                arch_monitor_cleanup_domain(d);
708
0
                domain_unpause(d);
709
0
            }
710
0
            break;
711
0
712
0
        case XEN_VM_EVENT_RESUME:
713
0
            if ( vm_event_check_ring(d->vm_event_monitor) )
714
0
                vm_event_resume(d, d->vm_event_monitor);
715
0
            else
716
0
                rc = -ENODEV;
717
0
            break;
718
0
719
0
        default:
720
0
            rc = -ENOSYS;
721
0
            break;
722
0
        }
723
0
    }
724
0
    break;
725
0
726
0
#ifdef CONFIG_HAS_MEM_SHARING
727
0
    case XEN_DOMCTL_VM_EVENT_OP_SHARING:
728
0
    {
729
0
        rc = -EINVAL;
730
0
731
0
        switch( vec->op )
732
0
        {
733
0
        case XEN_VM_EVENT_ENABLE:
734
0
            rc = -EOPNOTSUPP;
735
0
            /* hvm fixme: p2m_is_foreign types need addressing */
736
0
            if ( is_hvm_domain(hardware_domain) )
737
0
                break;
738
0
739
0
            rc = -ENODEV;
740
0
            /* Only HAP is supported */
741
0
            if ( !hap_enabled(d) )
742
0
                break;
743
0
744
0
            /* domain_pause() not required here, see XSA-99 */
745
0
            rc = vm_event_enable(d, vec, &d->vm_event_share, _VPF_mem_sharing,
746
0
                                 HVM_PARAM_SHARING_RING_PFN,
747
0
                                 mem_sharing_notification);
748
0
            break;
749
0
750
0
        case XEN_VM_EVENT_DISABLE:
751
0
            if ( vm_event_check_ring(d->vm_event_share) )
752
0
            {
753
0
                domain_pause(d);
754
0
                rc = vm_event_disable(d, &d->vm_event_share);
755
0
                domain_unpause(d);
756
0
            }
757
0
            break;
758
0
759
0
        case XEN_VM_EVENT_RESUME:
760
0
            if ( vm_event_check_ring(d->vm_event_share) )
761
0
                vm_event_resume(d, d->vm_event_share);
762
0
            else
763
0
                rc = -ENODEV;
764
0
            break;
765
0
766
0
        default:
767
0
            rc = -ENOSYS;
768
0
            break;
769
0
        }
770
0
    }
771
0
    break;
772
0
#endif
773
0
774
0
    default:
775
0
        rc = -ENOSYS;
776
0
    }
777
0
778
0
    return rc;
779
0
}
780
781
void vm_event_vcpu_pause(struct vcpu *v)
782
0
{
783
0
    ASSERT(v == current);
784
0
785
0
    atomic_inc(&v->vm_event_pause_count);
786
0
    vcpu_pause_nosync(v);
787
0
}
788
789
void vm_event_vcpu_unpause(struct vcpu *v)
790
0
{
791
0
    int old, new, prev = v->vm_event_pause_count.counter;
792
0
793
0
    /*
794
0
     * All unpause requests as a result of toolstack responses.
795
0
     * Prevent underflow of the vcpu pause count.
796
0
     */
797
0
    do
798
0
    {
799
0
        old = prev;
800
0
        new = old - 1;
801
0
802
0
        if ( new < 0 )
803
0
        {
804
0
            printk(XENLOG_G_WARNING
805
0
                   "%pv vm_event: Too many unpause attempts\n", v);
806
0
            return;
807
0
        }
808
0
809
0
        prev = cmpxchg(&v->vm_event_pause_count.counter, old, new);
810
0
    } while ( prev != old );
811
0
812
0
    vcpu_unpause(v);
813
0
}
814
815
/*
816
 * Local variables:
817
 * mode: C
818
 * c-file-style: "BSD"
819
 * c-basic-offset: 4
820
 * indent-tabs-mode: nil
821
 * End:
822
 */