1 /*
2 * arch/x86/monitor.c
3 *
4 * Arch-specific 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 <asm/monitor.h>
23 #include <public/vm_event.h>
24
arch_monitor_init_domain(struct domain * d)25 int arch_monitor_init_domain(struct domain *d)
26 {
27 if ( !d->arch.monitor.msr_bitmap )
28 d->arch.monitor.msr_bitmap = xzalloc(struct monitor_msr_bitmap);
29
30 if ( !d->arch.monitor.msr_bitmap )
31 return -ENOMEM;
32
33 return 0;
34 }
35
arch_monitor_cleanup_domain(struct domain * d)36 void arch_monitor_cleanup_domain(struct domain *d)
37 {
38 xfree(d->arch.monitor.msr_bitmap);
39
40 memset(&d->arch.monitor, 0, sizeof(d->arch.monitor));
41 memset(&d->monitor, 0, sizeof(d->monitor));
42 }
43
monitor_bitmap_for_msr(const struct domain * d,u32 * msr)44 static unsigned long *monitor_bitmap_for_msr(const struct domain *d, u32 *msr)
45 {
46 ASSERT(d->arch.monitor.msr_bitmap && msr);
47
48 switch ( *msr )
49 {
50 case 0 ... 0x1fff:
51 BUILD_BUG_ON(sizeof(d->arch.monitor.msr_bitmap->low) * 8 <= 0x1fff);
52 return d->arch.monitor.msr_bitmap->low;
53
54 case 0x40000000 ... 0x40001fff:
55 BUILD_BUG_ON(
56 sizeof(d->arch.monitor.msr_bitmap->hypervisor) * 8 <= 0x1fff);
57 *msr &= 0x1fff;
58 return d->arch.monitor.msr_bitmap->hypervisor;
59
60 case 0xc0000000 ... 0xc0001fff:
61 BUILD_BUG_ON(sizeof(d->arch.monitor.msr_bitmap->high) * 8 <= 0x1fff);
62 *msr &= 0x1fff;
63 return d->arch.monitor.msr_bitmap->high;
64
65 default:
66 return NULL;
67 }
68 }
69
monitor_enable_msr(struct domain * d,u32 msr)70 static int monitor_enable_msr(struct domain *d, u32 msr)
71 {
72 unsigned long *bitmap;
73 u32 index = msr;
74
75 if ( !d->arch.monitor.msr_bitmap )
76 return -ENXIO;
77
78 bitmap = monitor_bitmap_for_msr(d, &index);
79
80 if ( !bitmap )
81 return -EINVAL;
82
83 __set_bit(index, bitmap);
84
85 hvm_enable_msr_interception(d, msr);
86
87 return 0;
88 }
89
monitor_disable_msr(struct domain * d,u32 msr)90 static int monitor_disable_msr(struct domain *d, u32 msr)
91 {
92 unsigned long *bitmap;
93
94 if ( !d->arch.monitor.msr_bitmap )
95 return -ENXIO;
96
97 bitmap = monitor_bitmap_for_msr(d, &msr);
98
99 if ( !bitmap )
100 return -EINVAL;
101
102 __clear_bit(msr, bitmap);
103
104 return 0;
105 }
106
monitored_msr(const struct domain * d,u32 msr)107 bool monitored_msr(const struct domain *d, u32 msr)
108 {
109 const unsigned long *bitmap;
110
111 if ( !d->arch.monitor.msr_bitmap )
112 return false;
113
114 bitmap = monitor_bitmap_for_msr(d, &msr);
115
116 if ( !bitmap )
117 return false;
118
119 return test_bit(msr, bitmap);
120 }
121
arch_monitor_domctl_event(struct domain * d,struct xen_domctl_monitor_op * mop)122 int arch_monitor_domctl_event(struct domain *d,
123 struct xen_domctl_monitor_op *mop)
124 {
125 struct arch_domain *ad = &d->arch;
126 bool requested_status = (XEN_DOMCTL_MONITOR_OP_ENABLE == mop->op);
127
128 switch ( mop->event )
129 {
130 case XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG:
131 {
132 unsigned int ctrlreg_bitmask;
133 bool old_status;
134
135 if ( unlikely(mop->u.mov_to_cr.index >=
136 ARRAY_SIZE(ad->monitor.write_ctrlreg_mask)) )
137 return -EINVAL;
138
139 if ( unlikely(mop->u.mov_to_cr.pad1 || mop->u.mov_to_cr.pad2) )
140 return -EINVAL;
141
142 ctrlreg_bitmask = monitor_ctrlreg_bitmask(mop->u.mov_to_cr.index);
143 old_status = !!(ad->monitor.write_ctrlreg_enabled & ctrlreg_bitmask);
144
145 if ( unlikely(old_status == requested_status) )
146 return -EEXIST;
147
148 domain_pause(d);
149
150 if ( mop->u.mov_to_cr.sync )
151 ad->monitor.write_ctrlreg_sync |= ctrlreg_bitmask;
152 else
153 ad->monitor.write_ctrlreg_sync &= ~ctrlreg_bitmask;
154
155 if ( mop->u.mov_to_cr.onchangeonly )
156 ad->monitor.write_ctrlreg_onchangeonly |= ctrlreg_bitmask;
157 else
158 ad->monitor.write_ctrlreg_onchangeonly &= ~ctrlreg_bitmask;
159
160 if ( requested_status )
161 {
162 ad->monitor.write_ctrlreg_mask[mop->u.mov_to_cr.index] = mop->u.mov_to_cr.bitmask;
163 ad->monitor.write_ctrlreg_enabled |= ctrlreg_bitmask;
164 }
165 else
166 {
167 ad->monitor.write_ctrlreg_mask[mop->u.mov_to_cr.index] = 0;
168 ad->monitor.write_ctrlreg_enabled &= ~ctrlreg_bitmask;
169 }
170
171 if ( VM_EVENT_X86_CR3 == mop->u.mov_to_cr.index )
172 {
173 struct vcpu *v;
174 /* Latches new CR3 mask through CR0 code. */
175 for_each_vcpu ( d, v )
176 hvm_update_guest_cr(v, 0);
177 }
178
179 domain_unpause(d);
180
181 break;
182 }
183
184 case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR:
185 {
186 bool old_status;
187 int rc;
188 u32 msr = mop->u.mov_to_msr.msr;
189
190 domain_pause(d);
191
192 old_status = monitored_msr(d, msr);
193
194 if ( unlikely(old_status == requested_status) )
195 {
196 domain_unpause(d);
197 return -EEXIST;
198 }
199
200 if ( requested_status )
201 rc = monitor_enable_msr(d, msr);
202 else
203 rc = monitor_disable_msr(d, msr);
204
205 domain_unpause(d);
206
207 return rc;
208 }
209
210 case XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP:
211 {
212 bool old_status = ad->monitor.singlestep_enabled;
213
214 if ( unlikely(old_status == requested_status) )
215 return -EEXIST;
216
217 domain_pause(d);
218 ad->monitor.singlestep_enabled = requested_status;
219 domain_unpause(d);
220 break;
221 }
222
223 case XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS:
224 {
225 bool old_status = ad->monitor.descriptor_access_enabled;
226 struct vcpu *v;
227
228 if ( unlikely(old_status == requested_status) )
229 return -EEXIST;
230
231 if ( !hvm_funcs.set_descriptor_access_exiting )
232 return -EOPNOTSUPP;
233
234 domain_pause(d);
235 ad->monitor.descriptor_access_enabled = requested_status;
236
237 for_each_vcpu ( d, v )
238 hvm_funcs.set_descriptor_access_exiting(v, requested_status);
239
240 domain_unpause(d);
241 break;
242 }
243
244 case XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT:
245 {
246 bool old_status = ad->monitor.software_breakpoint_enabled;
247
248 if ( unlikely(old_status == requested_status) )
249 return -EEXIST;
250
251 domain_pause(d);
252 ad->monitor.software_breakpoint_enabled = requested_status;
253 domain_unpause(d);
254 break;
255 }
256
257 case XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION:
258 {
259 bool old_status = ad->monitor.debug_exception_enabled;
260
261 if ( unlikely(old_status == requested_status) )
262 return -EEXIST;
263
264 domain_pause(d);
265 ad->monitor.debug_exception_enabled = requested_status;
266 ad->monitor.debug_exception_sync = requested_status ?
267 mop->u.debug_exception.sync :
268 0;
269 domain_unpause(d);
270 break;
271 }
272
273 case XEN_DOMCTL_MONITOR_EVENT_CPUID:
274 {
275 bool old_status = ad->monitor.cpuid_enabled;
276
277 if ( unlikely(old_status == requested_status) )
278 return -EEXIST;
279
280 domain_pause(d);
281 ad->monitor.cpuid_enabled = requested_status;
282 domain_unpause(d);
283 break;
284 }
285
286 case XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED:
287 {
288 bool old_status = ad->monitor.emul_unimplemented_enabled;
289
290 if ( unlikely(old_status == requested_status) )
291 return -EEXIST;
292
293 domain_pause(d);
294 ad->monitor.emul_unimplemented_enabled = requested_status;
295 domain_unpause(d);
296 break;
297 }
298
299 default:
300 /*
301 * Should not be reached unless arch_monitor_get_capabilities() is
302 * not properly implemented.
303 */
304 ASSERT_UNREACHABLE();
305 return -EOPNOTSUPP;
306 }
307
308 return 0;
309 }
310
311 /*
312 * Local variables:
313 * mode: C
314 * c-file-style: "BSD"
315 * c-basic-offset: 4
316 * indent-tabs-mode: nil
317 * End:
318 */
319