/root/src/xen/xen/common/monitor.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
31 | | int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop) |
32 | 0 | { |
33 | 0 | int rc; |
34 | 0 | bool requested_status = false; |
35 | 0 |
|
36 | 0 | if ( unlikely(current->domain == d) ) /* no domain_pause() */ |
37 | 0 | return -EPERM; |
38 | 0 |
|
39 | 0 | rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event); |
40 | 0 | if ( unlikely(rc) ) |
41 | 0 | return rc; |
42 | 0 |
|
43 | 0 | switch ( mop->op ) |
44 | 0 | { |
45 | 0 | case XEN_DOMCTL_MONITOR_OP_ENABLE: |
46 | 0 | requested_status = true; |
47 | 0 | /* fallthrough */ |
48 | 0 | case XEN_DOMCTL_MONITOR_OP_DISABLE: |
49 | 0 | /* sanity check: avoid left-shift undefined behavior */ |
50 | 0 | if ( unlikely(mop->event > 31) ) |
51 | 0 | return -EINVAL; |
52 | 0 | /* Check if event type is available. */ |
53 | 0 | if ( unlikely(!(arch_monitor_get_capabilities(d) & (1U << mop->event))) ) |
54 | 0 | return -EOPNOTSUPP; |
55 | 0 | break; |
56 | 0 |
|
57 | 0 | case XEN_DOMCTL_MONITOR_OP_GET_CAPABILITIES: |
58 | 0 | mop->event = arch_monitor_get_capabilities(d); |
59 | 0 | return 0; |
60 | 0 |
|
61 | 0 | default: |
62 | 0 | /* The monitor op is probably handled on the arch-side. */ |
63 | 0 | return arch_monitor_domctl_op(d, mop); |
64 | 0 | } |
65 | 0 |
|
66 | 0 | switch ( mop->event ) |
67 | 0 | { |
68 | 0 | case XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST: |
69 | 0 | { |
70 | 0 | bool old_status = d->monitor.guest_request_enabled; |
71 | 0 |
|
72 | 0 | if ( unlikely(old_status == requested_status) ) |
73 | 0 | return -EEXIST; |
74 | 0 |
|
75 | 0 | domain_pause(d); |
76 | 0 | d->monitor.guest_request_sync = mop->u.guest_request.sync; |
77 | 0 | d->monitor.guest_request_enabled = requested_status; |
78 | 0 | arch_monitor_allow_userspace(d, mop->u.guest_request.allow_userspace); |
79 | 0 | domain_unpause(d); |
80 | 0 | break; |
81 | 0 | } |
82 | 0 |
|
83 | 0 | default: |
84 | 0 | /* Give arch-side the chance to handle this event */ |
85 | 0 | return arch_monitor_domctl_event(d, mop); |
86 | 0 | } |
87 | 0 |
|
88 | 0 | return 0; |
89 | 0 | } |
90 | | |
91 | | int monitor_traps(struct vcpu *v, bool sync, vm_event_request_t *req) |
92 | 0 | { |
93 | 0 | int rc; |
94 | 0 | struct domain *d = v->domain; |
95 | 0 |
|
96 | 0 | rc = vm_event_claim_slot(d, d->vm_event_monitor); |
97 | 0 | switch ( rc ) |
98 | 0 | { |
99 | 0 | case 0: |
100 | 0 | break; |
101 | 0 | case -ENOSYS: |
102 | 0 | /* |
103 | 0 | * If there was no ring to handle the event, then |
104 | 0 | * simply continue executing normally. |
105 | 0 | */ |
106 | 0 | return 0; |
107 | 0 | default: |
108 | 0 | return rc; |
109 | 0 | }; |
110 | 0 |
|
111 | 0 | req->vcpu_id = v->vcpu_id; |
112 | 0 |
|
113 | 0 | if ( sync ) |
114 | 0 | { |
115 | 0 | req->flags |= VM_EVENT_FLAG_VCPU_PAUSED; |
116 | 0 | vm_event_vcpu_pause(v); |
117 | 0 | rc = 1; |
118 | 0 | } |
119 | 0 |
|
120 | 0 | if ( altp2m_active(d) ) |
121 | 0 | { |
122 | 0 | req->flags |= VM_EVENT_FLAG_ALTERNATE_P2M; |
123 | 0 | req->altp2m_idx = altp2m_vcpu_idx(v); |
124 | 0 | } |
125 | 0 |
|
126 | 0 | vm_event_fill_regs(req); |
127 | 0 | vm_event_put_request(d, d->vm_event_monitor, req); |
128 | 0 |
|
129 | 0 | return rc; |
130 | 0 | } |
131 | | |
132 | | void monitor_guest_request(void) |
133 | 0 | { |
134 | 0 | struct vcpu *curr = current; |
135 | 0 | struct domain *d = curr->domain; |
136 | 0 |
|
137 | 0 | if ( d->monitor.guest_request_enabled ) |
138 | 0 | { |
139 | 0 | vm_event_request_t req = { |
140 | 0 | .reason = VM_EVENT_REASON_GUEST_REQUEST, |
141 | 0 | .vcpu_id = curr->vcpu_id, |
142 | 0 | }; |
143 | 0 |
|
144 | 0 | monitor_traps(curr, d->monitor.guest_request_sync, &req); |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | /* |
149 | | * Local variables: |
150 | | * mode: C |
151 | | * c-file-style: "BSD" |
152 | | * c-basic-offset: 4 |
153 | | * indent-tabs-mode: nil |
154 | | * End: |
155 | | */ |