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