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