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