Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/drivers/passthrough/vtd/utils.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2006, Intel Corporation.
3
 *
4
 * This program is free software; you can redistribute it and/or modify it
5
 * under the terms and conditions of the GNU General Public License,
6
 * version 2, as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11
 * more details.
12
 *
13
 * You should have received a copy of the GNU General Public License along with
14
 * this program; If not, see <http://www.gnu.org/licenses/>.
15
 *
16
 * Copyright (C) Allen Kay <allen.m.kay@intel.com>
17
 */
18
19
#include <xen/sched.h>
20
#include <xen/delay.h>
21
#include <xen/iommu.h>
22
#include <xen/time.h>
23
#include <xen/pci.h>
24
#include <xen/pci_regs.h>
25
#include "iommu.h"
26
#include "dmar.h"
27
#include "vtd.h"
28
#include "extern.h"
29
#include <asm/io_apic.h>
30
31
/* Disable vt-d protected memory registers. */
32
void disable_pmr(struct iommu *iommu)
33
1
{
34
1
    u32 val;
35
1
    unsigned long flags;
36
1
37
1
    val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
38
1
    if ( !(val & DMA_PMEN_PRS) )
39
1
        return;
40
1
41
0
    spin_lock_irqsave(&iommu->register_lock, flags);
42
0
    dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);
43
0
44
0
    IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG, dmar_readl,
45
0
                  !(val & DMA_PMEN_PRS), val);
46
0
    spin_unlock_irqrestore(&iommu->register_lock, flags);
47
0
48
0
    dprintk(XENLOG_INFO VTDPREFIX,
49
0
            "Disabled protected memory registers\n");
50
0
}
51
52
void print_iommu_regs(struct acpi_drhd_unit *drhd)
53
0
{
54
0
    struct iommu *iommu = drhd->iommu;
55
0
    u64 cap;
56
0
57
0
    printk("---- print_iommu_regs ----\n");
58
0
    printk(" drhd->address = %"PRIx64"\n", drhd->address);
59
0
    printk(" VER = %x\n", dmar_readl(iommu->reg, DMAR_VER_REG));
60
0
    printk(" CAP = %"PRIx64"\n", cap = dmar_readq(iommu->reg, DMAR_CAP_REG));
61
0
    printk(" n_fault_reg = %"PRIx64"\n", cap_num_fault_regs(cap));
62
0
    printk(" fault_recording_offset = %"PRIx64"\n", cap_fault_reg_offset(cap));
63
0
    if ( cap_fault_reg_offset(cap) < PAGE_SIZE )
64
0
    {
65
0
        printk(" fault_recording_reg_l = %"PRIx64"\n",
66
0
               dmar_readq(iommu->reg, cap_fault_reg_offset(cap)));
67
0
        printk(" fault_recording_reg_h = %"PRIx64"\n",
68
0
               dmar_readq(iommu->reg, cap_fault_reg_offset(cap) + 8));
69
0
    }
70
0
    printk(" ECAP = %"PRIx64"\n", dmar_readq(iommu->reg, DMAR_ECAP_REG));
71
0
    printk(" GCMD = %x\n", dmar_readl(iommu->reg, DMAR_GCMD_REG));
72
0
    printk(" GSTS = %x\n", dmar_readl(iommu->reg, DMAR_GSTS_REG));
73
0
    printk(" RTADDR = %"PRIx64"\n", dmar_readq(iommu->reg,DMAR_RTADDR_REG));
74
0
    printk(" CCMD = %"PRIx64"\n", dmar_readq(iommu->reg, DMAR_CCMD_REG));
75
0
    printk(" FSTS = %x\n", dmar_readl(iommu->reg, DMAR_FSTS_REG));
76
0
    printk(" FECTL = %x\n", dmar_readl(iommu->reg, DMAR_FECTL_REG));
77
0
    printk(" FEDATA = %x\n", dmar_readl(iommu->reg, DMAR_FEDATA_REG));
78
0
    printk(" FEADDR = %x\n", dmar_readl(iommu->reg, DMAR_FEADDR_REG));
79
0
    printk(" FEUADDR = %x\n", dmar_readl(iommu->reg, DMAR_FEUADDR_REG));
80
0
}
81
82
static u32 get_level_index(unsigned long gmfn, int level)
83
0
{
84
0
    while ( --level )
85
0
        gmfn = gmfn >> LEVEL_STRIDE;
86
0
87
0
    return gmfn & LEVEL_MASK;
88
0
}
89
90
void print_vtd_entries(struct iommu *iommu, int bus, int devfn, u64 gmfn)
91
0
{
92
0
    struct context_entry *ctxt_entry;
93
0
    struct root_entry *root_entry;
94
0
    struct dma_pte pte;
95
0
    u64 *l, val;
96
0
    u32 l_index, level;
97
0
98
0
    printk("print_vtd_entries: iommu #%u dev %04x:%02x:%02x.%u gmfn %"PRI_gfn"\n",
99
0
           iommu->index, iommu->intel->drhd->segment, bus,
100
0
           PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);
101
0
102
0
    if ( iommu->root_maddr == 0 )
103
0
    {
104
0
        printk("    iommu->root_maddr = 0\n");
105
0
        return;
106
0
    }
107
0
108
0
    root_entry = (struct root_entry *)map_vtd_domain_page(iommu->root_maddr);
109
0
    if ( root_entry == NULL )
110
0
    {
111
0
        printk("    root_entry == NULL\n");
112
0
        return;
113
0
    }
114
0
115
0
    printk("    root_entry[%02x] = %"PRIx64"\n", bus, root_entry[bus].val);
116
0
    if ( !root_present(root_entry[bus]) )
117
0
    {
118
0
        unmap_vtd_domain_page(root_entry);
119
0
        printk("    root_entry[%02x] not present\n", bus);
120
0
        return;
121
0
    }
122
0
123
0
    val = root_entry[bus].val;
124
0
    unmap_vtd_domain_page(root_entry);
125
0
    ctxt_entry = map_vtd_domain_page(val);
126
0
    if ( ctxt_entry == NULL )
127
0
    {
128
0
        printk("    ctxt_entry == NULL\n");
129
0
        return;
130
0
    }
131
0
132
0
    val = ctxt_entry[devfn].lo;
133
0
    printk("    context[%02x] = %"PRIx64"_%"PRIx64"\n",
134
0
           devfn, ctxt_entry[devfn].hi, val);
135
0
    if ( !context_present(ctxt_entry[devfn]) )
136
0
    {
137
0
        unmap_vtd_domain_page(ctxt_entry);
138
0
        printk("    ctxt_entry[%02x] not present\n", devfn);
139
0
        return;
140
0
    }
141
0
142
0
    level = agaw_to_level(context_address_width(ctxt_entry[devfn]));
143
0
    unmap_vtd_domain_page(ctxt_entry);
144
0
    if ( level != VTD_PAGE_TABLE_LEVEL_3 &&
145
0
         level != VTD_PAGE_TABLE_LEVEL_4)
146
0
    {
147
0
        printk("Unsupported VTD page table level (%d)!\n", level);
148
0
        return;
149
0
    }
150
0
151
0
    do
152
0
    {
153
0
        l = map_vtd_domain_page(val);
154
0
        if ( l == NULL )
155
0
        {
156
0
            printk("    l%u == NULL\n", level);
157
0
            break;
158
0
        }
159
0
        l_index = get_level_index(gmfn, level);
160
0
        pte.val = l[l_index];
161
0
        unmap_vtd_domain_page(l);
162
0
        printk("    l%u[%03x] = %"PRIx64"\n", level, l_index, pte.val);
163
0
164
0
        if ( !dma_pte_present(pte) )
165
0
        {
166
0
            printk("    l%u[%03x] not present\n", level, l_index);
167
0
            break;
168
0
        }
169
0
        if ( dma_pte_superpage(pte) )
170
0
            break;
171
0
        val = dma_pte_addr(pte);
172
0
    } while ( --level );
173
0
}
174
175
void vtd_dump_iommu_info(unsigned char key)
176
0
{
177
0
    struct acpi_drhd_unit *drhd;
178
0
    struct iommu *iommu;
179
0
    int i;
180
0
181
0
    for_each_drhd_unit ( drhd )
182
0
    {
183
0
        u32 status = 0;
184
0
185
0
        iommu = drhd->iommu;
186
0
        printk("\niommu %x: nr_pt_levels = %x.\n", iommu->index,
187
0
            iommu->nr_pt_levels);
188
0
189
0
        if ( ecap_queued_inval(iommu->ecap) ||  ecap_intr_remap(iommu->ecap) )
190
0
            status = dmar_readl(iommu->reg, DMAR_GSTS_REG);
191
0
192
0
        printk("  Queued Invalidation: %ssupported%s.\n",
193
0
            ecap_queued_inval(iommu->ecap) ? "" : "not ",
194
0
           (status & DMA_GSTS_QIES) ? " and enabled" : "" );
195
0
196
0
197
0
        printk("  Interrupt Remapping: %ssupported%s.\n",
198
0
            ecap_intr_remap(iommu->ecap) ? "" : "not ",
199
0
            (status & DMA_GSTS_IRES) ? " and enabled" : "" );
200
0
201
0
        printk("  Interrupt Posting: %ssupported.\n",
202
0
               cap_intr_post(iommu->cap) ? "" : "not ");
203
0
204
0
        if ( status & DMA_GSTS_IRES )
205
0
        {
206
0
            /* Dump interrupt remapping table. */
207
0
            u64 iremap_maddr = dmar_readq(iommu->reg, DMAR_IRTA_REG);
208
0
            int nr_entry = 1 << ((iremap_maddr & 0xF) + 1);
209
0
            struct iremap_entry *iremap_entries = NULL;
210
0
            int print_cnt = 0;
211
0
212
0
            printk("  Interrupt remapping table (nr_entry=%#x. "
213
0
                "Only dump P=1 entries here):\n", nr_entry);
214
0
            printk("R means remapped format, P means posted format.\n");
215
0
            printk("R:       SVT  SQ   SID  V  AVL FPD      DST DLM TM RH DM P\n");
216
0
            printk("P:       SVT  SQ   SID  V  AVL FPD              PDA  URG P\n");
217
0
            for ( i = 0; i < nr_entry; i++ )
218
0
            {
219
0
                struct iremap_entry *p;
220
0
                if ( i % (1 << IREMAP_ENTRY_ORDER) == 0 )
221
0
                {
222
0
                    /* This entry across page boundry */
223
0
                    if ( iremap_entries )
224
0
                        unmap_vtd_domain_page(iremap_entries);
225
0
226
0
                    GET_IREMAP_ENTRY(iremap_maddr, i,
227
0
                                     iremap_entries, p);
228
0
                }
229
0
                else
230
0
                    p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)];
231
0
232
0
                if ( !p->remap.p )
233
0
                    continue;
234
0
                if ( !p->remap.im )
235
0
                    printk("R:  %04x:  %x   %x  %04x %02x    %x   %x %08x   %x  %x  %x  %x %x\n",
236
0
                           i,
237
0
                           p->remap.svt, p->remap.sq, p->remap.sid,
238
0
                           p->remap.vector, p->remap.avail, p->remap.fpd,
239
0
                           p->remap.dst, p->remap.dlm, p->remap.tm, p->remap.rh,
240
0
                           p->remap.dm, p->remap.p);
241
0
                else
242
0
                    printk("P:  %04x:  %x   %x  %04x %02x    %x   %x %16lx    %x %x\n",
243
0
                           i,
244
0
                           p->post.svt, p->post.sq, p->post.sid, p->post.vector,
245
0
                           p->post.avail, p->post.fpd,
246
0
                           ((u64)p->post.pda_h << 32) | (p->post.pda_l << 6),
247
0
                           p->post.urg, p->post.p);
248
0
249
0
                print_cnt++;
250
0
            }
251
0
            if ( iremap_entries )
252
0
                unmap_vtd_domain_page(iremap_entries);
253
0
            if ( iommu_ir_ctrl(iommu)->iremap_num != print_cnt )
254
0
                printk("Warning: Print %d IRTE (actually have %d)!\n",
255
0
                        print_cnt, iommu_ir_ctrl(iommu)->iremap_num);
256
0
257
0
        }
258
0
    }
259
0
260
0
    /* Dump the I/O xAPIC redirection table(s). */
261
0
    if ( iommu_enabled )
262
0
    {
263
0
        int apic;
264
0
        union IO_APIC_reg_01 reg_01;
265
0
        struct IO_APIC_route_remap_entry *remap;
266
0
        struct ir_ctrl *ir_ctrl;
267
0
268
0
        for ( apic = 0; apic < nr_ioapics; apic++ )
269
0
        {
270
0
            iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
271
0
            ir_ctrl = iommu_ir_ctrl(iommu);
272
0
            if ( !ir_ctrl || !ir_ctrl->iremap_maddr || !ir_ctrl->iremap_num )
273
0
                continue;
274
0
275
0
            printk( "\nRedirection table of IOAPIC %x:\n", apic);
276
0
277
0
            /* IO xAPIC Version Register. */
278
0
            reg_01.raw = __io_apic_read(apic, 1);
279
0
280
0
            printk("  #entry IDX FMT MASK TRIG IRR POL STAT DELI  VECTOR\n");
281
0
            for ( i = 0; i <= reg_01.bits.entries; i++ )
282
0
            {
283
0
                struct IO_APIC_route_entry rte =
284
0
                    __ioapic_read_entry(apic, i, TRUE);
285
0
286
0
                remap = (struct IO_APIC_route_remap_entry *) &rte;
287
0
                if ( !remap->format )
288
0
                    continue;
289
0
290
0
                printk("   %02x:  %04x   %x    %x   %x   %x   %x    %x"
291
0
                    "    %x     %02x\n", i,
292
0
                    remap->index_0_14 | (remap->index_15 << 15),
293
0
                    remap->format, remap->mask, remap->trigger, remap->irr,
294
0
                    remap->polarity, remap->delivery_status, remap->delivery_mode,
295
0
                    remap->vector);
296
0
            }
297
0
        }
298
0
    }
299
0
}
300
301
/*
302
 * Local variables:
303
 * mode: C
304
 * c-file-style: "BSD"
305
 * c-basic-offset: 4
306
 * indent-tabs-mode: nil
307
 * End:
308
 */