1 /*
2 * xen/common/monitor.c
3 *
4 * Common monitor_op domctl handler.
5 *
6 * Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
7 * Copyright (c) 2016, Bitdefender S.R.L.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License v2 as published by the Free Software Foundation.
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 GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <xen/event.h>
23 #include <xen/monitor.h>
24 #include <xen/sched.h>
25 #include <xen/vm_event.h>
26 #include <xsm/xsm.h>
27 #include <asm/altp2m.h>
28 #include <asm/monitor.h>
29 #include <asm/vm_event.h>
30
monitor_domctl(struct domain * d,struct xen_domctl_monitor_op * mop)31 int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
32 {
33 int rc;
34 bool requested_status = false;
35
36 if ( unlikely(current->domain == d) ) /* no domain_pause() */
37 return -EPERM;
38
39 rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event);
40 if ( unlikely(rc) )
41 return rc;
42
43 switch ( mop->op )
44 {
45 case XEN_DOMCTL_MONITOR_OP_ENABLE:
46 requested_status = true;
47 /* fallthrough */
48 case XEN_DOMCTL_MONITOR_OP_DISABLE:
49 /* sanity check: avoid left-shift undefined behavior */
50 if ( unlikely(mop->event > 31) )
51 return -EINVAL;
52 /* Check if event type is available. */
53 if ( unlikely(!(arch_monitor_get_capabilities(d) & (1U << mop->event))) )
54 return -EOPNOTSUPP;
55 break;
56
57 case XEN_DOMCTL_MONITOR_OP_GET_CAPABILITIES:
58 mop->event = arch_monitor_get_capabilities(d);
59 return 0;
60
61 default:
62 /* The monitor op is probably handled on the arch-side. */
63 return arch_monitor_domctl_op(d, mop);
64 }
65
66 switch ( mop->event )
67 {
68 case XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST:
69 {
70 bool old_status = d->monitor.guest_request_enabled;
71
72 if ( unlikely(old_status == requested_status) )
73 return -EEXIST;
74
75 domain_pause(d);
76 d->monitor.guest_request_sync = mop->u.guest_request.sync;
77 d->monitor.guest_request_enabled = requested_status;
78 arch_monitor_allow_userspace(d, mop->u.guest_request.allow_userspace);
79 domain_unpause(d);
80 break;
81 }
82
83 default:
84 /* Give arch-side the chance to handle this event */
85 return arch_monitor_domctl_event(d, mop);
86 }
87
88 return 0;
89 }
90
monitor_traps(struct vcpu * v,bool sync,vm_event_request_t * req)91 int monitor_traps(struct vcpu *v, bool sync, vm_event_request_t *req)
92 {
93 int rc;
94 struct domain *d = v->domain;
95
96 rc = vm_event_claim_slot(d, d->vm_event_monitor);
97 switch ( rc )
98 {
99 case 0:
100 break;
101 case -EOPNOTSUPP:
102 /*
103 * If there was no ring to handle the event, then
104 * simply continue executing normally.
105 */
106 return 0;
107 default:
108 return rc;
109 };
110
111 req->vcpu_id = v->vcpu_id;
112
113 if ( sync )
114 {
115 req->flags |= VM_EVENT_FLAG_VCPU_PAUSED;
116 vm_event_sync_event(v, true);
117 vm_event_vcpu_pause(v);
118 rc = 1;
119 }
120
121 if ( altp2m_active(d) )
122 {
123 req->flags |= VM_EVENT_FLAG_ALTERNATE_P2M;
124 req->altp2m_idx = altp2m_vcpu_idx(v);
125 }
126
127 vm_event_fill_regs(req);
128 vm_event_put_request(d, d->vm_event_monitor, req);
129
130 return rc;
131 }
132
monitor_guest_request(void)133 void monitor_guest_request(void)
134 {
135 struct vcpu *curr = current;
136 struct domain *d = curr->domain;
137
138 if ( d->monitor.guest_request_enabled )
139 {
140 vm_event_request_t req = {
141 .reason = VM_EVENT_REASON_GUEST_REQUEST,
142 .vcpu_id = curr->vcpu_id,
143 };
144
145 monitor_traps(curr, d->monitor.guest_request_sync, &req);
146 }
147 }
148
149 /*
150 * Local variables:
151 * mode: C
152 * c-file-style: "BSD"
153 * c-basic-offset: 4
154 * indent-tabs-mode: nil
155 * End:
156 */
157