blob: 743687a303909a377a250059fc8ce5e1e164f9e7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
* platform_hypercall.c
*
* Hardware platform operations. Intended for use by domain-0 kernel.
*
* Copyright (c) 2015, Citrix
*/
#include <xen/types.h>
#include <xen/sched.h>
#include <xen/guest_access.h>
#include <xen/hypercall.h>
#include <xen/spinlock.h>
#include <public/platform.h>
#include <xsm/xsm.h>
#include <asm/current.h>
#include <asm/event.h>
DEFINE_SPINLOCK(xenpf_lock);
long do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
{
long ret;
struct xen_platform_op curop, *op = &curop;
struct domain *d;
if ( copy_from_guest(op, u_xenpf_op, 1) )
return -EFAULT;
if ( op->interface_version != XENPF_INTERFACE_VERSION )
return -EACCES;
d = rcu_lock_current_domain();
if ( d == NULL )
return -ESRCH;
ret = xsm_platform_op(XSM_PRIV, op->cmd);
if ( ret )
return ret;
/*
* Trylock here avoids deadlock with an existing platform critical section
* which might (for some current or future reason) want to synchronise
* with this vcpu.
*/
while ( !spin_trylock(&xenpf_lock) )
if ( hypercall_preempt_check() )
return hypercall_create_continuation(
__HYPERVISOR_platform_op, "h", u_xenpf_op);
switch ( op->cmd )
{
case XENPF_settime64:
if ( likely(!op->u.settime64.mbz) )
do_settime(op->u.settime64.secs,
op->u.settime64.nsecs,
op->u.settime64.system_time + SECONDS(d->time_offset.seconds));
else
ret = -EINVAL;
break;
default:
ret = -ENOSYS;
break;
}
spin_unlock(&xenpf_lock);
rcu_unlock_domain(d);
return ret;
}
|