Coverage Report

Created: 2017-10-25 09:10

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