Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/drivers/passthrough/iommu.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This program is free software; you can redistribute it and/or modify it
3
 * under the terms and conditions of the GNU General Public License,
4
 * version 2, as published by the Free Software Foundation.
5
 *
6
 * This program is distributed in the hope it will be useful, but WITHOUT
7
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
9
 * more details.
10
 *
11
 * You should have received a copy of the GNU General Public License along with
12
 * this program; If not, see <http://www.gnu.org/licenses/>.
13
 */
14
15
#include <xen/sched.h>
16
#include <xen/iommu.h>
17
#include <xen/paging.h>
18
#include <xen/guest_access.h>
19
#include <xen/event.h>
20
#include <xen/softirq.h>
21
#include <xen/keyhandler.h>
22
#include <xsm/xsm.h>
23
24
static int parse_iommu_param(const char *s);
25
static void iommu_dump_p2m_table(unsigned char key);
26
27
unsigned int __read_mostly iommu_dev_iotlb_timeout = 1000;
28
integer_param("iommu_dev_iotlb_timeout", iommu_dev_iotlb_timeout);
29
30
/*
31
 * The 'iommu' parameter enables the IOMMU.  Optional comma separated
32
 * value may contain:
33
 *
34
 *   off|no|false|disable       Disable IOMMU (default)
35
 *   force|required             Don't boot unless IOMMU is enabled
36
 *   no-intremap                Disable interrupt remapping
37
 *   intpost                    Enable VT-d Interrupt posting
38
 *   verbose                    Be more verbose
39
 *   debug                      Enable debugging messages and checks
40
 *   workaround_bios_bug        Workaround some bios issue to still enable
41
 *                              VT-d, don't guarantee security
42
 *   dom0-passthrough           No DMA translation at all for Dom0
43
 *   dom0-strict                No 1:1 memory mapping for Dom0
44
 *   no-sharept                 Don't share VT-d and EPT page tables
45
 *   no-snoop                   Disable VT-d Snoop Control
46
 *   no-qinval                  Disable VT-d Queued Invalidation
47
 *   no-igfx                    Disable VT-d for IGD devices (insecure)
48
 *   no-amd-iommu-perdev-intremap Don't use per-device interrupt remapping
49
 *                              tables (insecure)
50
 */
51
custom_param("iommu", parse_iommu_param);
52
bool_t __initdata iommu_enable = 1;
53
bool_t __read_mostly iommu_enabled;
54
bool_t __read_mostly force_iommu;
55
bool_t __hwdom_initdata iommu_dom0_strict;
56
bool_t __read_mostly iommu_verbose;
57
bool_t __read_mostly iommu_workaround_bios_bug;
58
bool_t __read_mostly iommu_igfx = 1;
59
bool_t __read_mostly iommu_passthrough;
60
bool_t __read_mostly iommu_snoop = 1;
61
bool_t __read_mostly iommu_qinval = 1;
62
bool_t __read_mostly iommu_intremap = 1;
63
64
/*
65
 * In the current implementation of VT-d posted interrupts, in some extreme
66
 * cases, the per cpu list which saves the blocked vCPU will be very long,
67
 * and this will affect the interrupt latency, so let this feature off by
68
 * default until we find a good solution to resolve it.
69
 */
70
bool_t __read_mostly iommu_intpost;
71
bool_t __read_mostly iommu_hap_pt_share = 1;
72
bool_t __read_mostly iommu_debug;
73
bool_t __read_mostly amd_iommu_perdev_intremap = 1;
74
75
DEFINE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
76
77
DEFINE_SPINLOCK(iommu_pt_cleanup_lock);
78
PAGE_LIST_HEAD(iommu_pt_cleanup_list);
79
static struct tasklet iommu_pt_cleanup_tasklet;
80
81
static int __init parse_iommu_param(const char *s)
82
1
{
83
1
    const char *ss;
84
1
    int val, b, rc = 0;
85
1
86
3
    do {
87
3
        val = !!strncmp(s, "no-", 3);
88
3
        if ( !val )
89
1
            s += 3;
90
3
91
3
        ss = strchr(s, ',');
92
3
        if ( !ss )
93
1
            ss = strchr(s, '\0');
94
3
95
3
        b = parse_bool(s, ss);
96
3
        if ( b >= 0 )
97
0
            iommu_enable = b;
98
3
        else if ( !strncmp(s, "force", ss - s) ||
99
3
                  !strncmp(s, "required", ss - s) )
100
0
            force_iommu = val;
101
3
        else if ( !strncmp(s, "workaround_bios_bug", ss - s) )
102
0
            iommu_workaround_bios_bug = val;
103
3
        else if ( !strncmp(s, "igfx", ss - s) )
104
0
            iommu_igfx = val;
105
3
        else if ( !strncmp(s, "verbose", ss - s) )
106
1
            iommu_verbose = val;
107
2
        else if ( !strncmp(s, "snoop", ss - s) )
108
0
            iommu_snoop = val;
109
2
        else if ( !strncmp(s, "qinval", ss - s) )
110
0
            iommu_qinval = val;
111
2
        else if ( !strncmp(s, "intremap", ss - s) )
112
0
            iommu_intremap = val;
113
2
        else if ( !strncmp(s, "intpost", ss - s) )
114
0
            iommu_intpost = val;
115
2
        else if ( !strncmp(s, "debug", ss - s) )
116
1
        {
117
1
            iommu_debug = val;
118
1
            if ( val )
119
1
                iommu_verbose = 1;
120
1
        }
121
1
        else if ( !strncmp(s, "amd-iommu-perdev-intremap", ss - s) )
122
0
            amd_iommu_perdev_intremap = val;
123
1
        else if ( !strncmp(s, "dom0-passthrough", ss - s) )
124
0
            iommu_passthrough = val;
125
1
        else if ( !strncmp(s, "dom0-strict", ss - s) )
126
0
            iommu_dom0_strict = val;
127
1
        else if ( !strncmp(s, "sharept", ss - s) )
128
1
            iommu_hap_pt_share = val;
129
1
        else
130
0
            rc = -EINVAL;
131
3
132
3
        s = ss + 1;
133
3
    } while ( *ss );
134
1
135
1
    return rc;
136
1
}
137
138
int iommu_domain_init(struct domain *d)
139
1
{
140
1
    struct domain_iommu *hd = dom_iommu(d);
141
1
    int ret = 0;
142
1
143
1
    ret = arch_iommu_domain_init(d);
144
1
    if ( ret )
145
0
        return ret;
146
1
147
1
    if ( !iommu_enabled )
148
0
        return 0;
149
1
150
1
    hd->platform_ops = iommu_get_ops();
151
1
    return hd->platform_ops->init(d);
152
1
}
153
154
static void __hwdom_init check_hwdom_reqs(struct domain *d)
155
1
{
156
1
    if ( !paging_mode_translate(d) )
157
0
        return;
158
1
159
1
    arch_iommu_check_autotranslated_hwdom(d);
160
1
161
1
    if ( iommu_passthrough )
162
0
        panic("Dom0 uses paging translated mode, dom0-passthrough must not be "
163
0
              "enabled\n");
164
1
165
1
    iommu_dom0_strict = 1;
166
1
}
167
168
void __hwdom_init iommu_hwdom_init(struct domain *d)
169
1
{
170
1
    const struct domain_iommu *hd = dom_iommu(d);
171
1
172
1
    check_hwdom_reqs(d);
173
1
174
1
    if ( !iommu_enabled )
175
0
        return;
176
1
177
1
    register_keyhandler('o', &iommu_dump_p2m_table, "dump iommu p2m table", 0);
178
1
    d->need_iommu = !!iommu_dom0_strict;
179
1
    if ( need_iommu(d) && !iommu_use_hap_pt(d) )
180
1
    {
181
1
        struct page_info *page;
182
1
        unsigned int i = 0;
183
1
        int rc = 0;
184
1
185
1
        page_list_for_each ( page, &d->page_list )
186
0
        {
187
0
            unsigned long mfn = page_to_mfn(page);
188
0
            unsigned long gfn = mfn_to_gmfn(d, mfn);
189
0
            unsigned int mapping = IOMMUF_readable;
190
0
            int ret;
191
0
192
0
            if ( ((page->u.inuse.type_info & PGT_count_mask) == 0) ||
193
0
                 ((page->u.inuse.type_info & PGT_type_mask)
194
0
                  == PGT_writable_page) )
195
0
                mapping |= IOMMUF_writable;
196
0
197
0
            ret = hd->platform_ops->map_page(d, gfn, mfn, mapping);
198
0
            if ( !rc )
199
0
                rc = ret;
200
0
201
0
            if ( !(i++ & 0xfffff) )
202
0
                process_pending_softirqs();
203
0
        }
204
1
205
1
        if ( rc )
206
0
            printk(XENLOG_WARNING "d%d: IOMMU mapping failed: %d\n",
207
0
                   d->domain_id, rc);
208
1
    }
209
1
210
1
    return hd->platform_ops->hwdom_init(d);
211
1
}
212
213
void iommu_teardown(struct domain *d)
214
0
{
215
0
    const struct domain_iommu *hd = dom_iommu(d);
216
0
217
0
    d->need_iommu = 0;
218
0
    hd->platform_ops->teardown(d);
219
0
    tasklet_schedule(&iommu_pt_cleanup_tasklet);
220
0
}
221
222
int iommu_construct(struct domain *d)
223
0
{
224
0
    if ( need_iommu(d) > 0 )
225
0
        return 0;
226
0
227
0
    if ( !iommu_use_hap_pt(d) )
228
0
    {
229
0
        int rc;
230
0
231
0
        rc = arch_iommu_populate_page_table(d);
232
0
        if ( rc )
233
0
            return rc;
234
0
    }
235
0
236
0
    d->need_iommu = 1;
237
0
    /*
238
0
     * There may be dirty cache lines when a device is assigned
239
0
     * and before need_iommu(d) becoming true, this will cause
240
0
     * memory_type_changed lose effect if memory type changes.
241
0
     * Call memory_type_changed here to amend this.
242
0
     */
243
0
    memory_type_changed(d);
244
0
245
0
    return 0;
246
0
}
247
248
void iommu_domain_destroy(struct domain *d)
249
0
{
250
0
    if ( !iommu_enabled || !dom_iommu(d)->platform_ops )
251
0
        return;
252
0
253
0
    iommu_teardown(d);
254
0
255
0
    arch_iommu_domain_destroy(d);
256
0
}
257
258
int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
259
                   unsigned int flags)
260
4.34M
{
261
4.34M
    const struct domain_iommu *hd = dom_iommu(d);
262
4.34M
    int rc;
263
4.34M
264
4.34M
    if ( !iommu_enabled || !hd->platform_ops )
265
0
        return 0;
266
4.34M
267
4.34M
    rc = hd->platform_ops->map_page(d, gfn, mfn, flags);
268
4.34M
    if ( unlikely(rc) )
269
0
    {
270
0
        if ( !d->is_shutting_down && printk_ratelimit() )
271
0
            printk(XENLOG_ERR
272
0
                   "d%d: IOMMU mapping gfn %#lx to mfn %#lx failed: %d\n",
273
0
                   d->domain_id, gfn, mfn, rc);
274
0
275
0
        if ( !is_hardware_domain(d) )
276
0
            domain_crash(d);
277
0
    }
278
4.34M
279
4.34M
    return rc;
280
4.34M
}
281
282
int iommu_unmap_page(struct domain *d, unsigned long gfn)
283
218k
{
284
218k
    const struct domain_iommu *hd = dom_iommu(d);
285
218k
    int rc;
286
218k
287
218k
    if ( !iommu_enabled || !hd->platform_ops )
288
0
        return 0;
289
218k
290
218k
    rc = hd->platform_ops->unmap_page(d, gfn);
291
218k
    if ( unlikely(rc) )
292
0
    {
293
0
        if ( !d->is_shutting_down && printk_ratelimit() )
294
0
            printk(XENLOG_ERR
295
0
                   "d%d: IOMMU unmapping gfn %#lx failed: %d\n",
296
0
                   d->domain_id, gfn, rc);
297
0
298
0
        if ( !is_hardware_domain(d) )
299
0
            domain_crash(d);
300
0
    }
301
218k
302
218k
    return rc;
303
218k
}
304
305
static void iommu_free_pagetables(unsigned long unused)
306
0
{
307
0
    do {
308
0
        struct page_info *pg;
309
0
310
0
        spin_lock(&iommu_pt_cleanup_lock);
311
0
        pg = page_list_remove_head(&iommu_pt_cleanup_list);
312
0
        spin_unlock(&iommu_pt_cleanup_lock);
313
0
        if ( !pg )
314
0
            return;
315
0
        iommu_get_ops()->free_page_table(pg);
316
0
    } while ( !softirq_pending(smp_processor_id()) );
317
0
318
0
    tasklet_schedule_on_cpu(&iommu_pt_cleanup_tasklet,
319
0
                            cpumask_cycle(smp_processor_id(), &cpu_online_map));
320
0
}
321
322
int iommu_iotlb_flush(struct domain *d, unsigned long gfn,
323
                      unsigned int page_count)
324
0
{
325
0
    const struct domain_iommu *hd = dom_iommu(d);
326
0
    int rc;
327
0
328
0
    if ( !iommu_enabled || !hd->platform_ops || !hd->platform_ops->iotlb_flush )
329
0
        return 0;
330
0
331
0
    rc = hd->platform_ops->iotlb_flush(d, gfn, page_count);
332
0
    if ( unlikely(rc) )
333
0
    {
334
0
        if ( !d->is_shutting_down && printk_ratelimit() )
335
0
            printk(XENLOG_ERR
336
0
                   "d%d: IOMMU IOTLB flush failed: %d, gfn %#lx, page count %u\n",
337
0
                   d->domain_id, rc, gfn, page_count);
338
0
339
0
        if ( !is_hardware_domain(d) )
340
0
            domain_crash(d);
341
0
    }
342
0
343
0
    return rc;
344
0
}
345
346
int iommu_iotlb_flush_all(struct domain *d)
347
0
{
348
0
    const struct domain_iommu *hd = dom_iommu(d);
349
0
    int rc;
350
0
351
0
    if ( !iommu_enabled || !hd->platform_ops || !hd->platform_ops->iotlb_flush_all )
352
0
        return 0;
353
0
354
0
    rc = hd->platform_ops->iotlb_flush_all(d);
355
0
    if ( unlikely(rc) )
356
0
    {
357
0
        if ( !d->is_shutting_down && printk_ratelimit() )
358
0
            printk(XENLOG_ERR
359
0
                   "d%d: IOMMU IOTLB flush all failed: %d\n",
360
0
                   d->domain_id, rc);
361
0
362
0
        if ( !is_hardware_domain(d) )
363
0
            domain_crash(d);
364
0
    }
365
0
366
0
    return rc;
367
0
}
368
369
int __init iommu_setup(void)
370
1
{
371
1
    int rc = -ENODEV;
372
1
    bool_t force_intremap = force_iommu && iommu_intremap;
373
1
374
1
    if ( iommu_dom0_strict )
375
0
        iommu_passthrough = 0;
376
1
377
1
    if ( iommu_enable )
378
1
    {
379
1
        rc = iommu_hardware_setup();
380
1
        iommu_enabled = (rc == 0);
381
1
    }
382
1
    if ( !iommu_enabled )
383
0
        iommu_intremap = 0;
384
1
385
1
    if ( (force_iommu && !iommu_enabled) ||
386
1
         (force_intremap && !iommu_intremap) )
387
0
        panic("Couldn't enable %s and iommu=required/force",
388
0
              !iommu_enabled ? "IOMMU" : "Interrupt Remapping");
389
1
390
1
    if ( !iommu_intremap )
391
0
        iommu_intpost = 0;
392
1
393
1
    if ( !iommu_enabled )
394
0
    {
395
0
        iommu_snoop = 0;
396
0
        iommu_passthrough = 0;
397
0
        iommu_dom0_strict = 0;
398
0
    }
399
1
    printk("I/O virtualisation %sabled\n", iommu_enabled ? "en" : "dis");
400
1
    if ( iommu_enabled )
401
1
    {
402
1
        printk(" - Dom0 mode: %s\n",
403
0
               iommu_passthrough ? "Passthrough" :
404
1
               iommu_dom0_strict ? "Strict" : "Relaxed");
405
1
        printk("Interrupt remapping %sabled\n", iommu_intremap ? "en" : "dis");
406
1
        tasklet_init(&iommu_pt_cleanup_tasklet, iommu_free_pagetables, 0);
407
1
    }
408
1
409
1
    return rc;
410
1
}
411
412
int iommu_suspend()
413
0
{
414
0
    if ( iommu_enabled )
415
0
        return iommu_get_ops()->suspend();
416
0
417
0
    return 0;
418
0
}
419
420
void iommu_resume()
421
0
{
422
0
    if ( iommu_enabled )
423
0
        iommu_get_ops()->resume();
424
0
}
425
426
int iommu_do_domctl(
427
    struct xen_domctl *domctl, struct domain *d,
428
    XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
429
0
{
430
0
    int ret = -ENODEV;
431
0
432
0
    if ( !iommu_enabled )
433
0
        return -ENOSYS;
434
0
435
0
#ifdef CONFIG_HAS_PCI
436
0
    ret = iommu_do_pci_domctl(domctl, d, u_domctl);
437
0
#endif
438
0
439
0
#ifdef CONFIG_HAS_DEVICE_TREE
440
    if ( ret == -ENODEV )
441
        ret = iommu_do_dt_domctl(domctl, d, u_domctl);
442
#endif
443
0
444
0
    return ret;
445
0
}
446
447
void iommu_share_p2m_table(struct domain* d)
448
11
{
449
11
    if ( iommu_enabled && iommu_use_hap_pt(d) )
450
0
        iommu_get_ops()->share_p2m(d);
451
11
}
452
453
void iommu_crash_shutdown(void)
454
0
{
455
0
    if ( iommu_enabled )
456
0
        iommu_get_ops()->crash_shutdown();
457
0
    iommu_enabled = iommu_intremap = iommu_intpost = 0;
458
0
}
459
460
int iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt)
461
0
{
462
0
    const struct iommu_ops *ops;
463
0
464
0
    if ( !iommu_enabled )
465
0
        return 0;
466
0
467
0
    ops = iommu_get_ops();
468
0
    if ( !ops->get_reserved_device_memory )
469
0
        return 0;
470
0
471
0
    return ops->get_reserved_device_memory(func, ctxt);
472
0
}
473
474
bool_t iommu_has_feature(struct domain *d, enum iommu_feature feature)
475
0
{
476
0
    if ( !iommu_enabled )
477
0
        return 0;
478
0
479
0
    return test_bit(feature, dom_iommu(d)->features);
480
0
}
481
482
static void iommu_dump_p2m_table(unsigned char key)
483
0
{
484
0
    struct domain *d;
485
0
    const struct iommu_ops *ops;
486
0
487
0
    if ( !iommu_enabled )
488
0
    {
489
0
        printk("IOMMU not enabled!\n");
490
0
        return;
491
0
    }
492
0
493
0
    ops = iommu_get_ops();
494
0
    for_each_domain(d)
495
0
    {
496
0
        if ( is_hardware_domain(d) || need_iommu(d) <= 0 )
497
0
            continue;
498
0
499
0
        if ( iommu_use_hap_pt(d) )
500
0
        {
501
0
            printk("\ndomain%d IOMMU p2m table shared with MMU: \n", d->domain_id);
502
0
            continue;
503
0
        }
504
0
505
0
        printk("\ndomain%d IOMMU p2m table: \n", d->domain_id);
506
0
        ops->dump_p2m_table(d);
507
0
    }
508
0
}
509
510
/*
511
 * Local variables:
512
 * mode: C
513
 * c-file-style: "BSD"
514
 * c-basic-offset: 4
515
 * indent-tabs-mode: nil
516
 * End:
517
 */