~ubuntu-branches/ubuntu/trusty/xen/trusty

« back to all changes in this revision

Viewing changes to .pc/CVE-2013-0153-4/xen/drivers/passthrough/amd/pci_amd_iommu.c

  • Committer: Package Import Robot
  • Author(s): Stefan Bader
  • Date: 2013-06-14 10:01:32 UTC
  • mfrom: (40.1.2 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130614100132-ozzr5yioa5r1e797
Tags: 4.2.1-2ubuntu1
* Merge with Debian unstable. Dropping the following patches in favour
  of Debian ones:
  - xsa33-4.2-unstable.patch
  - xsa36-4.2.patch
  - xsa44-4.2.patch
  - xsa45-4.2-01-vcpu-destroy-pagetables-preemptible.patch
  - xsa45-4.2-02-new-guest-cr3-preemptible.patch
  - xsa45-4.2-03-new-user-base-preemptible.patch
  - xsa45-4.2-04-vcpu-reset-preemptible.patch
  - xsa45-4.2-05-set-info-guest-preemptible.patch
  - xsa45-4.2-06-unpin-preemptible.patch
  - xsa45-4.2-07-mm-error-paths-preemptible.patch
  - xsa46-4.2.patch
  - xsa47-4.2-unstable.patch
  - xsa49-4.2.patch
* Remaining changes:
  - debian/control: Depend on libssl-dev
  - Use dpkg-buildflags and strip the gcc prefix for getting LDFLAGS.
    This will again use the Ubuntu specific LDFLAGS (using some
    hardening options). Older releases would always pass those options
    in the environment but that changed.
  - Ressurrect qemu-dm for now (upstream qemu would not support
    migration, yet). Forward-port some patches from the old Debian
    package which still included qemu-dm:
    - qemu-prefix (modify LDFLAGS to point to lib dir for qemu-dm)
    - qemu-disable-blktap (this is not present in upstream)
    - ubuntu-qemu-disable-qemu-upstream (breaks build and also should
      be provided by qemu/kvm package)
* Remaining additional patches:
  - qemu-cve-2012-6075-1.patch / qemu-cve-2012-6075-2.patch
  - xsa34-4.2.patch
  - xsa35-4.2-with-xsa34.patch
  - xsa38.patch
  - xsa52-4.2-unstable.patch
  - xsa53-4.2.patch
  - xsa54.patch
  - xsa56.patch
  - qemu-fix-librt-test.patch
    Fix build regression caused by glibc not requiring to link against
    librt for the clock_gettime function. Patch picked from xen-devel
    mailing list.
  - tools-gdbsx-fix-build-failure-with-glibc-2.17.patch
    Add direct include to sys/types.h for xg_main.c which likely was
    indirectly done before. Needed to get ulong type definition.
  - tools-ocaml-fix-build: refresh and reenable (and fix the description
    of) this patch.  Without it the ocam native libraries (*.cmxa)
    build in /build local paths rather than appropriatly versioned
    library references.
  - APIC Register Virtualization (backported from Xen 4.3)
    - 0001-xen-enable-APIC-Register-Virtualization.patch
    - 0002-xen-enable-Virtual-interrupt-delivery.patch
    - 0003-xen-add-virtual-x2apic-support-for-apicv.patch
  - TSC Adjust Support (backported from Xen 4.3)
    - 0004-x86-Implement-TSC-adjust-feature-for-HVM-guest.patch
    - 0005-x86-Save-restore-TSC-adjust-during-HVM-guest-migrati.patch
    - 0006-x86-Expose-TSC-adjust-to-HVM-guest.patch
  - Fix FTBS on i386
    - 0007-x86-Fix-i386-virtual-apic.patch
  - Fix HVM regression when host supports SMEP
    - 0008-vmx-Simplify-cr0-update-handling-by-deferring-cr4-ch.patch
    - 0009-VMX-disable-SMEP-feature-when-guest-is-in-non-paging.patch
    - 0010-VMX-Always-disable-SMEP-when-guest-is-in-non-paging-.patch
  - silence-gcc-warnings.patch: Silence gcc warnings.
  - gcc48-ftbfs.patch
  - gcc48-ftbfs-2.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 Advanced Micro Devices, Inc.
 
3
 * Author: Leo Duran <leo.duran@amd.com>
 
4
 * Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
19
 */
 
20
 
 
21
#include <xen/sched.h>
 
22
#include <xen/pci.h>
 
23
#include <xen/pci_regs.h>
 
24
#include <xen/paging.h>
 
25
#include <xen/softirq.h>
 
26
#include <asm/hvm/iommu.h>
 
27
#include <asm/amd-iommu.h>
 
28
#include <asm/hvm/svm/amd-iommu-proto.h>
 
29
#include "../ats.h"
 
30
 
 
31
struct amd_iommu *find_iommu_for_device(int seg, int bdf)
 
32
{
 
33
    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
 
34
 
 
35
    BUG_ON ( bdf >= ivrs_bdf_entries );
 
36
    return ivrs_mappings ? ivrs_mappings[bdf].iommu : NULL;
 
37
}
 
38
 
 
39
/*
 
40
 * Some devices will use alias id and original device id to index interrupt
 
41
 * table and I/O page table respectively. Such devices will have
 
42
 * both alias entry and select entry in IVRS structure.
 
43
 *
 
44
 * Return original device id, if device has valid interrupt remapping
 
45
 * table setup for both select entry and alias entry.
 
46
 */
 
47
int get_dma_requestor_id(u16 seg, u16 bdf)
 
48
{
 
49
    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
 
50
    int req_id;
 
51
 
 
52
    BUG_ON ( bdf >= ivrs_bdf_entries );
 
53
    req_id = ivrs_mappings[bdf].dte_requestor_id;
 
54
    if ( (ivrs_mappings[bdf].intremap_table != NULL) &&
 
55
         (ivrs_mappings[req_id].intremap_table != NULL) )
 
56
        req_id = bdf;
 
57
 
 
58
    return req_id;
 
59
}
 
60
 
 
61
static int is_translation_valid(u32 *entry)
 
62
{
 
63
    return (get_field_from_reg_u32(entry[0],
 
64
                                   IOMMU_DEV_TABLE_VALID_MASK,
 
65
                                   IOMMU_DEV_TABLE_VALID_SHIFT) &&
 
66
            get_field_from_reg_u32(entry[0],
 
67
                                   IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
 
68
                                   IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT));
 
69
}
 
70
 
 
71
static void disable_translation(u32 *dte)
 
72
{
 
73
    u32 entry;
 
74
 
 
75
    entry = dte[0];
 
76
    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
 
77
                         IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
 
78
                         IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &entry);
 
79
    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
 
80
                         IOMMU_DEV_TABLE_VALID_MASK,
 
81
                         IOMMU_DEV_TABLE_VALID_SHIFT, &entry);
 
82
    dte[0] = entry;
 
83
}
 
84
 
 
85
static void amd_iommu_setup_domain_device(
 
86
    struct domain *domain, struct amd_iommu *iommu, int bdf)
 
87
{
 
88
    void *dte;
 
89
    unsigned long flags;
 
90
    int req_id, valid = 1;
 
91
    int dte_i = 0;
 
92
    u8 bus = PCI_BUS(bdf);
 
93
    u8 devfn = PCI_DEVFN2(bdf);
 
94
 
 
95
    struct hvm_iommu *hd = domain_hvm_iommu(domain);
 
96
 
 
97
    BUG_ON( !hd->root_table || !hd->paging_mode || !iommu->dev_table.buffer );
 
98
 
 
99
    if ( iommu_passthrough && (domain->domain_id == 0) )
 
100
        valid = 0;
 
101
 
 
102
    if ( ats_enabled )
 
103
        dte_i = 1;
 
104
 
 
105
    /* get device-table entry */
 
106
    req_id = get_dma_requestor_id(iommu->seg, bdf);
 
107
    dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
 
108
 
 
109
    spin_lock_irqsave(&iommu->lock, flags);
 
110
 
 
111
    if ( !is_translation_valid((u32 *)dte) )
 
112
    {
 
113
        /* bind DTE to domain page-tables */
 
114
        amd_iommu_set_root_page_table(
 
115
            (u32 *)dte, page_to_maddr(hd->root_table), hd->domain_id,
 
116
            hd->paging_mode, valid);
 
117
 
 
118
        if ( pci_ats_device(iommu->seg, bus, devfn) &&
 
119
             iommu_has_cap(iommu, PCI_CAP_IOTLB_SHIFT) )
 
120
            iommu_dte_set_iotlb((u32 *)dte, dte_i);
 
121
 
 
122
        amd_iommu_flush_device(iommu, req_id);
 
123
 
 
124
        AMD_IOMMU_DEBUG("Setup I/O page table: device id = 0x%04x, "
 
125
                        "root table = 0x%"PRIx64", "
 
126
                        "domain = %d, paging mode = %d\n", req_id,
 
127
                        page_to_maddr(hd->root_table),
 
128
                        hd->domain_id, hd->paging_mode);
 
129
    }
 
130
 
 
131
    spin_unlock_irqrestore(&iommu->lock, flags);
 
132
 
 
133
    ASSERT(spin_is_locked(&pcidevs_lock));
 
134
 
 
135
    if ( pci_ats_device(iommu->seg, bus, devfn) &&
 
136
         !pci_ats_enabled(iommu->seg, bus, devfn) )
 
137
    {
 
138
        struct pci_dev *pdev;
 
139
 
 
140
        enable_ats_device(iommu->seg, bus, devfn);
 
141
 
 
142
        ASSERT(spin_is_locked(&pcidevs_lock));
 
143
        pdev = pci_get_pdev(iommu->seg, bus, devfn);
 
144
 
 
145
        ASSERT( pdev != NULL );
 
146
        amd_iommu_flush_iotlb(pdev, INV_IOMMU_ALL_PAGES_ADDRESS, 0);
 
147
    }
 
148
}
 
149
 
 
150
static void __init amd_iommu_setup_dom0_device(struct pci_dev *pdev)
 
151
{
 
152
    int bdf = PCI_BDF2(pdev->bus, pdev->devfn);
 
153
    struct amd_iommu *iommu = find_iommu_for_device(pdev->seg, bdf);
 
154
 
 
155
    if ( likely(iommu != NULL) )
 
156
        amd_iommu_setup_domain_device(pdev->domain, iommu, bdf);
 
157
    else
 
158
        AMD_IOMMU_DEBUG("No iommu for device %04x:%02x:%02x.%u\n",
 
159
                        pdev->seg, pdev->bus,
 
160
                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
161
}
 
162
 
 
163
int __init amd_iov_detect(void)
 
164
{
 
165
    INIT_LIST_HEAD(&amd_iommu_head);
 
166
 
 
167
    if ( (amd_iommu_detect_acpi() !=0) || (iommu_found() == 0) )
 
168
    {
 
169
        printk("AMD-Vi: IOMMU not found!\n");
 
170
        return -ENODEV;
 
171
    }
 
172
 
 
173
    if ( amd_iommu_init() != 0 )
 
174
    {
 
175
        printk("AMD-Vi: Error initialization\n");
 
176
        return -ENODEV;
 
177
    }
 
178
 
 
179
    /*
 
180
     * AMD IOMMUs don't distinguish between vectors destined for
 
181
     * different cpus when doing interrupt remapping.  This means
 
182
     * that interrupts going through the same intremap table
 
183
     * can't share the same vector.
 
184
     *
 
185
     * If irq_vector_map isn't specified, choose a sensible default:
 
186
     * - If we're using per-device interemap tables, per-device
 
187
     *   vector non-sharing maps
 
188
     * - If we're using a global interemap table, global vector
 
189
     *   non-sharing map
 
190
     */
 
191
    if ( opt_irq_vector_map == OPT_IRQ_VECTOR_MAP_DEFAULT )
 
192
    {
 
193
        if ( amd_iommu_perdev_intremap )
 
194
        {
 
195
            printk("AMD-Vi: Enabling per-device vector maps\n");
 
196
            opt_irq_vector_map = OPT_IRQ_VECTOR_MAP_PERDEV;
 
197
        }
 
198
        else
 
199
        {
 
200
            printk("AMD-Vi: Enabling global vector map\n");
 
201
            opt_irq_vector_map = OPT_IRQ_VECTOR_MAP_GLOBAL;
 
202
        }
 
203
    }
 
204
    else
 
205
    {
 
206
        printk("AMD-Vi: Not overriding irq_vector_map setting\n");
 
207
    }
 
208
    return scan_pci_devices();
 
209
}
 
210
 
 
211
static int allocate_domain_resources(struct hvm_iommu *hd)
 
212
{
 
213
    /* allocate root table */
 
214
    spin_lock(&hd->mapping_lock);
 
215
    if ( !hd->root_table )
 
216
    {
 
217
        hd->root_table = alloc_amd_iommu_pgtable();
 
218
        if ( !hd->root_table )
 
219
        {
 
220
            spin_unlock(&hd->mapping_lock);
 
221
            return -ENOMEM;
 
222
        }
 
223
    }
 
224
    spin_unlock(&hd->mapping_lock);
 
225
    return 0;
 
226
}
 
227
 
 
228
static int get_paging_mode(unsigned long entries)
 
229
{
 
230
    int level = 1;
 
231
 
 
232
    BUG_ON( !entries );
 
233
 
 
234
    while ( entries > PTE_PER_TABLE_SIZE )
 
235
    {
 
236
        entries = PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT;
 
237
        if ( ++level > 6 )
 
238
            return -ENOMEM;
 
239
    }
 
240
 
 
241
    return level;
 
242
}
 
243
 
 
244
static int amd_iommu_domain_init(struct domain *d)
 
245
{
 
246
    struct hvm_iommu *hd = domain_hvm_iommu(d);
 
247
 
 
248
    /* allocate page directroy */
 
249
    if ( allocate_domain_resources(hd) != 0 )
 
250
    {
 
251
        if ( hd->root_table )
 
252
            free_domheap_page(hd->root_table);
 
253
        return -ENOMEM;
 
254
    }
 
255
 
 
256
    /* For pv and dom0, stick with get_paging_mode(max_page)
 
257
     * For HVM dom0, use 2 level page table at first */
 
258
    hd->paging_mode = is_hvm_domain(d) ?
 
259
                      IOMMU_PAGING_MODE_LEVEL_2 :
 
260
                      get_paging_mode(max_page);
 
261
 
 
262
    hd->domain_id = d->domain_id;
 
263
 
 
264
    guest_iommu_init(d);
 
265
 
 
266
    return 0;
 
267
}
 
268
 
 
269
static void __init amd_iommu_dom0_init(struct domain *d)
 
270
{
 
271
    unsigned long i; 
 
272
 
 
273
    if ( !iommu_passthrough && !need_iommu(d) )
 
274
    {
 
275
        /* Set up 1:1 page table for dom0 */
 
276
        for ( i = 0; i < max_pdx; i++ )
 
277
        {
 
278
            unsigned long pfn = pdx_to_pfn(i);
 
279
 
 
280
            /*
 
281
             * XXX Should we really map all non-RAM (above 4G)? Minimally
 
282
             * a pfn_valid() check would seem desirable here.
 
283
             */
 
284
            if ( mfn_valid(pfn) )
 
285
                amd_iommu_map_page(d, pfn, pfn, 
 
286
                                   IOMMUF_readable|IOMMUF_writable);
 
287
        }
 
288
    }
 
289
 
 
290
    setup_dom0_pci_devices(d, amd_iommu_setup_dom0_device);
 
291
}
 
292
 
 
293
void amd_iommu_disable_domain_device(struct domain *domain,
 
294
                                     struct amd_iommu *iommu, int bdf)
 
295
{
 
296
    void *dte;
 
297
    unsigned long flags;
 
298
    int req_id;
 
299
    u8 bus = PCI_BUS(bdf);
 
300
    u8 devfn = PCI_DEVFN2(bdf);
 
301
 
 
302
    BUG_ON ( iommu->dev_table.buffer == NULL );
 
303
    req_id = get_dma_requestor_id(iommu->seg, bdf);
 
304
    dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
 
305
 
 
306
    spin_lock_irqsave(&iommu->lock, flags);
 
307
    if ( is_translation_valid((u32 *)dte) )
 
308
    {
 
309
        disable_translation((u32 *)dte);
 
310
 
 
311
        if ( pci_ats_device(iommu->seg, bus, devfn) &&
 
312
             iommu_has_cap(iommu, PCI_CAP_IOTLB_SHIFT) )
 
313
            iommu_dte_set_iotlb((u32 *)dte, 0);
 
314
 
 
315
        amd_iommu_flush_device(iommu, req_id);
 
316
 
 
317
        AMD_IOMMU_DEBUG("Disable: device id = 0x%04x, "
 
318
                        "domain = %d, paging mode = %d\n",
 
319
                        req_id,  domain_hvm_iommu(domain)->domain_id,
 
320
                        domain_hvm_iommu(domain)->paging_mode);
 
321
    }
 
322
    spin_unlock_irqrestore(&iommu->lock, flags);
 
323
 
 
324
    ASSERT(spin_is_locked(&pcidevs_lock));
 
325
 
 
326
    if ( pci_ats_device(iommu->seg, bus, devfn) &&
 
327
         pci_ats_enabled(iommu->seg, bus, devfn) )
 
328
        disable_ats_device(iommu->seg, bus, devfn);
 
329
}
 
330
 
 
331
static int reassign_device( struct domain *source, struct domain *target,
 
332
                            u16 seg, u8 bus, u8 devfn)
 
333
{
 
334
    struct pci_dev *pdev;
 
335
    struct amd_iommu *iommu;
 
336
    int bdf;
 
337
    struct hvm_iommu *t = domain_hvm_iommu(target);
 
338
 
 
339
    ASSERT(spin_is_locked(&pcidevs_lock));
 
340
    pdev = pci_get_pdev_by_domain(source, seg, bus, devfn);
 
341
    if ( !pdev )
 
342
        return -ENODEV;
 
343
 
 
344
    bdf = PCI_BDF2(bus, devfn);
 
345
    iommu = find_iommu_for_device(seg, bdf);
 
346
    if ( !iommu )
 
347
    {
 
348
        AMD_IOMMU_DEBUG("Fail to find iommu."
 
349
                        " %04x:%02x:%x02.%x cannot be assigned to dom%d\n",
 
350
                        seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
 
351
                        target->domain_id);
 
352
        return -ENODEV;
 
353
    }
 
354
 
 
355
    amd_iommu_disable_domain_device(source, iommu, bdf);
 
356
 
 
357
    list_move(&pdev->domain_list, &target->arch.pdev_list);
 
358
    pdev->domain = target;
 
359
 
 
360
    /* IO page tables might be destroyed after pci-detach the last device
 
361
     * In this case, we have to re-allocate root table for next pci-attach.*/
 
362
    if ( t->root_table == NULL )
 
363
        allocate_domain_resources(t);
 
364
 
 
365
    amd_iommu_setup_domain_device(target, iommu, bdf);
 
366
    AMD_IOMMU_DEBUG("Re-assign %04x:%02x:%02x.%u from dom%d to dom%d\n",
 
367
                    seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
 
368
                    source->domain_id, target->domain_id);
 
369
 
 
370
    return 0;
 
371
}
 
372
 
 
373
static int amd_iommu_assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
 
374
{
 
375
    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
 
376
    int bdf = (bus << 8) | devfn;
 
377
    int req_id = get_dma_requestor_id(seg, bdf);
 
378
 
 
379
    if ( ivrs_mappings[req_id].unity_map_enable )
 
380
    {
 
381
        amd_iommu_reserve_domain_unity_map(
 
382
            d,
 
383
            ivrs_mappings[req_id].addr_range_start,
 
384
            ivrs_mappings[req_id].addr_range_length,
 
385
            ivrs_mappings[req_id].write_permission,
 
386
            ivrs_mappings[req_id].read_permission);
 
387
    }
 
388
 
 
389
    return reassign_device(dom0, d, seg, bus, devfn);
 
390
}
 
391
 
 
392
static void deallocate_next_page_table(struct page_info* pg, int level)
 
393
{
 
394
    void *table_vaddr, *pde;
 
395
    u64 next_table_maddr;
 
396
    int index, next_level, present;
 
397
    u32 *entry;
 
398
 
 
399
    table_vaddr = __map_domain_page(pg);
 
400
 
 
401
    if ( level > 1 )
 
402
    {
 
403
        for ( index = 0; index < PTE_PER_TABLE_SIZE; index++ )
 
404
        {
 
405
            pde = table_vaddr + (index * IOMMU_PAGE_TABLE_ENTRY_SIZE);
 
406
            next_table_maddr = amd_iommu_get_next_table_from_pte(pde);
 
407
            entry = (u32*)pde;
 
408
 
 
409
            next_level = get_field_from_reg_u32(entry[0],
 
410
                                                IOMMU_PDE_NEXT_LEVEL_MASK,
 
411
                                                IOMMU_PDE_NEXT_LEVEL_SHIFT);
 
412
 
 
413
            present = get_field_from_reg_u32(entry[0],
 
414
                                             IOMMU_PDE_PRESENT_MASK,
 
415
                                             IOMMU_PDE_PRESENT_SHIFT);
 
416
 
 
417
            if ( (next_table_maddr != 0) && (next_level != 0)
 
418
                && present )
 
419
            {
 
420
                deallocate_next_page_table(
 
421
                    maddr_to_page(next_table_maddr), level - 1);
 
422
            }
 
423
        }
 
424
    }
 
425
 
 
426
    unmap_domain_page(table_vaddr);
 
427
    free_amd_iommu_pgtable(pg);
 
428
}
 
429
 
 
430
static void deallocate_iommu_page_tables(struct domain *d)
 
431
{
 
432
    struct hvm_iommu *hd  = domain_hvm_iommu(d);
 
433
 
 
434
    if ( iommu_use_hap_pt(d) )
 
435
        return;
 
436
 
 
437
    spin_lock(&hd->mapping_lock);
 
438
    if ( hd->root_table )
 
439
    {
 
440
        deallocate_next_page_table(hd->root_table, hd->paging_mode);
 
441
        hd->root_table = NULL;
 
442
    }
 
443
    spin_unlock(&hd->mapping_lock);
 
444
}
 
445
 
 
446
 
 
447
static void amd_iommu_domain_destroy(struct domain *d)
 
448
{
 
449
    guest_iommu_destroy(d);
 
450
    deallocate_iommu_page_tables(d);
 
451
    amd_iommu_flush_all_pages(d);
 
452
}
 
453
 
 
454
static int amd_iommu_return_device(
 
455
    struct domain *s, struct domain *t, u16 seg, u8 bus, u8 devfn)
 
456
{
 
457
    return reassign_device(s, t, seg, bus, devfn);
 
458
}
 
459
 
 
460
static int amd_iommu_add_device(struct pci_dev *pdev)
 
461
{
 
462
    struct amd_iommu *iommu;
 
463
    u16 bdf;
 
464
    if ( !pdev->domain )
 
465
        return -EINVAL;
 
466
 
 
467
    bdf = PCI_BDF2(pdev->bus, pdev->devfn);
 
468
    iommu = find_iommu_for_device(pdev->seg, bdf);
 
469
    if ( !iommu )
 
470
    {
 
471
        AMD_IOMMU_DEBUG("Fail to find iommu."
 
472
                        " %04x:%02x:%02x.%u cannot be assigned to dom%d\n",
 
473
                        pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
 
474
                        PCI_FUNC(pdev->devfn), pdev->domain->domain_id);
 
475
        return -ENODEV;
 
476
    }
 
477
 
 
478
    amd_iommu_setup_domain_device(pdev->domain, iommu, bdf);
 
479
    return 0;
 
480
}
 
481
 
 
482
static int amd_iommu_remove_device(struct pci_dev *pdev)
 
483
{
 
484
    struct amd_iommu *iommu;
 
485
    u16 bdf;
 
486
    if ( !pdev->domain )
 
487
        return -EINVAL;
 
488
 
 
489
    bdf = PCI_BDF2(pdev->bus, pdev->devfn);
 
490
    iommu = find_iommu_for_device(pdev->seg, bdf);
 
491
    if ( !iommu )
 
492
    {
 
493
        AMD_IOMMU_DEBUG("Fail to find iommu."
 
494
                        " %04x:%02x:%02x.%u cannot be removed from dom%d\n",
 
495
                        pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
 
496
                        PCI_FUNC(pdev->devfn), pdev->domain->domain_id);
 
497
        return -ENODEV;
 
498
    }
 
499
 
 
500
    amd_iommu_disable_domain_device(pdev->domain, iommu, bdf);
 
501
    return 0;
 
502
}
 
503
 
 
504
static int amd_iommu_group_id(u16 seg, u8 bus, u8 devfn)
 
505
{
 
506
    int rt;
 
507
    int bdf = (bus << 8) | devfn;
 
508
    rt = ( bdf < ivrs_bdf_entries ) ?
 
509
        get_dma_requestor_id(seg, bdf) :
 
510
        bdf;
 
511
    return rt;
 
512
}
 
513
 
 
514
#include <asm/io_apic.h>
 
515
 
 
516
static void amd_dump_p2m_table_level(struct page_info* pg, int level, 
 
517
                                     paddr_t gpa, int indent)
 
518
{
 
519
    paddr_t address;
 
520
    void *table_vaddr, *pde;
 
521
    paddr_t next_table_maddr;
 
522
    int index, next_level, present;
 
523
    u32 *entry;
 
524
 
 
525
    if ( level < 1 )
 
526
        return;
 
527
 
 
528
    table_vaddr = __map_domain_page(pg);
 
529
    if ( table_vaddr == NULL )
 
530
    {
 
531
        printk("Failed to map IOMMU domain page %"PRIpaddr"\n", 
 
532
                page_to_maddr(pg));
 
533
        return;
 
534
    }
 
535
 
 
536
    for ( index = 0; index < PTE_PER_TABLE_SIZE; index++ )
 
537
    {
 
538
        if ( !(index % 2) )
 
539
            process_pending_softirqs();
 
540
 
 
541
        pde = table_vaddr + (index * IOMMU_PAGE_TABLE_ENTRY_SIZE);
 
542
        next_table_maddr = amd_iommu_get_next_table_from_pte(pde);
 
543
        entry = (u32*)pde;
 
544
 
 
545
        present = get_field_from_reg_u32(entry[0],
 
546
                                         IOMMU_PDE_PRESENT_MASK,
 
547
                                         IOMMU_PDE_PRESENT_SHIFT);
 
548
 
 
549
        if ( !present )
 
550
            continue;
 
551
 
 
552
        next_level = get_field_from_reg_u32(entry[0],
 
553
                                            IOMMU_PDE_NEXT_LEVEL_MASK,
 
554
                                            IOMMU_PDE_NEXT_LEVEL_SHIFT);
 
555
 
 
556
        if ( next_level && (next_level != (level - 1)) )
 
557
        {
 
558
            printk("IOMMU p2m table error. next_level = %d, expected %d\n",
 
559
                   next_level, level - 1);
 
560
 
 
561
            continue;
 
562
        }
 
563
 
 
564
        address = gpa + amd_offset_level_address(index, level);
 
565
        if ( next_level >= 1 )
 
566
            amd_dump_p2m_table_level(
 
567
                maddr_to_page(next_table_maddr), next_level,
 
568
                address, indent + 1);
 
569
        else
 
570
            printk("%*sgfn: %08lx  mfn: %08lx\n",
 
571
                   indent, "",
 
572
                   (unsigned long)PFN_DOWN(address),
 
573
                   (unsigned long)PFN_DOWN(next_table_maddr));
 
574
    }
 
575
 
 
576
    unmap_domain_page(table_vaddr);
 
577
}
 
578
 
 
579
static void amd_dump_p2m_table(struct domain *d)
 
580
{
 
581
    struct hvm_iommu *hd  = domain_hvm_iommu(d);
 
582
 
 
583
    if ( !hd->root_table ) 
 
584
        return;
 
585
 
 
586
    printk("p2m table has %d levels\n", hd->paging_mode);
 
587
    amd_dump_p2m_table_level(hd->root_table, hd->paging_mode, 0, 0);
 
588
}
 
589
 
 
590
const struct iommu_ops amd_iommu_ops = {
 
591
    .init = amd_iommu_domain_init,
 
592
    .dom0_init = amd_iommu_dom0_init,
 
593
    .add_device = amd_iommu_add_device,
 
594
    .remove_device = amd_iommu_remove_device,
 
595
    .assign_device  = amd_iommu_assign_device,
 
596
    .teardown = amd_iommu_domain_destroy,
 
597
    .map_page = amd_iommu_map_page,
 
598
    .unmap_page = amd_iommu_unmap_page,
 
599
    .reassign_device = amd_iommu_return_device,
 
600
    .get_device_group_id = amd_iommu_group_id,
 
601
    .update_ire_from_apic = amd_iommu_ioapic_update_ire,
 
602
    .update_ire_from_msi = amd_iommu_msi_msg_update_ire,
 
603
    .read_apic_from_ire = __io_apic_read,
 
604
    .read_msi_from_ire = amd_iommu_read_msi_from_ire,
 
605
    .suspend = amd_iommu_suspend,
 
606
    .resume = amd_iommu_resume,
 
607
    .share_p2m = amd_iommu_share_p2m,
 
608
    .crash_shutdown = amd_iommu_suspend,
 
609
    .dump_p2m_table = amd_dump_p2m_table,
 
610
};