debuggers.hg

view xen/arch/x86/hvm/vmx/vtd/utils.c @ 16736:f983aa8e4b26

vt-d: Fix print_vtd_entries walk VTd mapping table.

DMA request to above guest physical memory will cause VTd fault, in
which print_vtd_entries() tries to walk VTd mapping table. However,
during walking, current Xen code didn't check if the PTE is valid and
may access to invalid memory address.

Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jan 09 10:35:52 2008 +0000 (2008-01-09)
parents 8ae3f083490a
children 2633dc4f55d4
line source
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, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Copyright (C) Allen Kay <allen.m.kay@intel.com>
18 */
20 #include <xen/init.h>
21 #include <xen/bitmap.h>
22 #include <xen/irq.h>
23 #include <xen/spinlock.h>
24 #include <xen/sched.h>
25 #include <asm/delay.h>
26 #include <asm/iommu.h>
27 #include <asm/hvm/vmx/intel-iommu.h>
28 #include "dmar.h"
29 #include "pci-direct.h"
30 #include "pci_regs.h"
31 #include "msi.h"
33 #include <xen/mm.h>
34 #include <xen/xmalloc.h>
35 #include <xen/inttypes.h>
37 #define INTEL 0x8086
38 #define SEABURG 0x4000
39 #define C_STEP 2
41 int vtd_hw_check(void)
42 {
43 u16 vendor, device;
44 u8 revision, stepping;
46 vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);
47 device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
48 revision = read_pci_config_byte(0, 0, 0, PCI_REVISION_ID);
49 stepping = revision & 0xf;
51 if ( (vendor == INTEL) && (device == SEABURG) )
52 {
53 if ( stepping < C_STEP )
54 {
55 dprintk(XENLOG_WARNING VTDPREFIX,
56 "*** VT-d disabled - pre C0-step Seaburg found\n");
57 dprintk(XENLOG_WARNING VTDPREFIX,
58 "*** vendor = %x device = %x revision = %x\n",
59 vendor, device, revision);
60 vtd_enabled = 0;
61 return -ENODEV;
62 }
63 }
64 return 0;
65 }
67 /* Disable vt-d protected memory registers. */
68 void disable_pmr(struct iommu *iommu)
69 {
70 unsigned long start_time;
71 unsigned int val;
73 val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
74 if ( !(val & DMA_PMEN_PRS) )
75 return;
77 dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);
78 start_time = jiffies;
80 for ( ; ; )
81 {
82 val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
83 if ( (val & DMA_PMEN_PRS) == 0 )
84 break;
86 if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )
87 panic("Disable PMRs timeout\n");
89 cpu_relax();
90 }
92 dprintk(XENLOG_INFO VTDPREFIX,
93 "Disabled protected memory registers\n");
94 }
97 void print_iommu_regs(struct acpi_drhd_unit *drhd)
98 {
99 struct iommu *iommu = drhd->iommu;
101 printk("---- print_iommu_regs ----\n");
102 printk("print_iommu_regs: drhd->address = %lx\n", drhd->address);
103 printk("print_iommu_regs: DMAR_VER_REG = %x\n",
104 dmar_readl(iommu->reg,DMAR_VER_REG));
105 printk("print_iommu_regs: DMAR_CAP_REG = %"PRIx64"\n",
106 dmar_readq(iommu->reg,DMAR_CAP_REG));
107 printk("print_iommu_regs: n_fault_reg = %"PRIx64"\n",
108 cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
109 printk("print_iommu_regs: fault_recording_offset_l = %"PRIx64"\n",
110 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
111 printk("print_iommu_regs: fault_recording_offset_h = %"PRIx64"\n",
112 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
113 printk("print_iommu_regs: fault_recording_reg_l = %"PRIx64"\n",
114 dmar_readq(iommu->reg,
115 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
116 printk("print_iommu_regs: fault_recording_reg_h = %"PRIx64"\n",
117 dmar_readq(iommu->reg,
118 cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));
119 printk("print_iommu_regs: DMAR_ECAP_REG = %"PRIx64"\n",
120 dmar_readq(iommu->reg,DMAR_ECAP_REG));
121 printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",
122 dmar_readl(iommu->reg,DMAR_GCMD_REG));
123 printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",
124 dmar_readl(iommu->reg,DMAR_GSTS_REG));
125 printk("print_iommu_regs: DMAR_RTADDR_REG = %"PRIx64"\n",
126 dmar_readq(iommu->reg,DMAR_RTADDR_REG));
127 printk("print_iommu_regs: DMAR_CCMD_REG = %"PRIx64"\n",
128 dmar_readq(iommu->reg,DMAR_CCMD_REG));
129 printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",
130 dmar_readl(iommu->reg,DMAR_FSTS_REG));
131 printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",
132 dmar_readl(iommu->reg,DMAR_FECTL_REG));
133 printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",
134 dmar_readl(iommu->reg,DMAR_FEDATA_REG));
135 printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",
136 dmar_readl(iommu->reg,DMAR_FEADDR_REG));
137 printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",
138 dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
139 }
141 u32 get_level_index(unsigned long gmfn, int level)
142 {
143 while ( --level )
144 gmfn = gmfn >> LEVEL_STRIDE;
146 return gmfn & LEVEL_MASK;
147 }
149 void print_vtd_entries(struct domain *d, int bus, int devfn,
150 unsigned long gmfn)
151 {
152 struct hvm_iommu *hd = domain_hvm_iommu(d);
153 struct acpi_drhd_unit *drhd;
154 struct iommu *iommu;
155 struct context_entry *ctxt_entry;
156 struct root_entry *root_entry;
157 struct dma_pte pte;
158 u64 *l;
159 u32 l_index;
160 u32 i = 0;
161 int level = agaw_to_level(hd->agaw);
163 printk("print_vtd_entries: domain_id = %x bdf = %x:%x:%x gmfn = %lx\n",
164 d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);
166 if ( hd->pgd == NULL )
167 {
168 printk(" hg->pgd == NULL\n");
169 return;
170 }
171 printk(" d->pgd = %p virt_to_maddr(hd->pgd) = %lx\n",
172 hd->pgd, virt_to_maddr(hd->pgd));
174 for_each_drhd_unit ( drhd )
175 {
176 printk("---- print_vtd_entries %d ----\n", i++);
178 iommu = drhd->iommu;
179 root_entry = iommu->root_entry;
180 if ( root_entry == NULL )
181 {
182 printk(" root_entry == NULL\n");
183 continue;
184 }
186 printk(" root_entry = %p\n", root_entry);
187 printk(" root_entry[%x] = %"PRIx64"\n", bus, root_entry[bus].val);
188 if ( !root_present(root_entry[bus]) )
189 {
190 printk(" root_entry[%x] not present\n", bus);
191 continue;
192 }
194 ctxt_entry =
195 maddr_to_virt((root_entry[bus].val >> PAGE_SHIFT) << PAGE_SHIFT);
196 if ( ctxt_entry == NULL )
197 {
198 printk(" ctxt_entry == NULL\n");
199 continue;
200 }
202 printk(" context = %p\n", ctxt_entry);
203 printk(" context[%x] = %"PRIx64" %"PRIx64"\n",
204 devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);
205 if ( !context_present(ctxt_entry[devfn]) )
206 {
207 printk(" ctxt_entry[%x] not present\n", devfn);
208 continue;
209 }
211 if ( level != VTD_PAGE_TABLE_LEVEL_3 &&
212 level != VTD_PAGE_TABLE_LEVEL_4)
213 {
214 printk("Unsupported VTD page table level (%d)!\n", level);
215 continue;
216 }
218 l = maddr_to_virt(ctxt_entry[devfn].lo);
219 do
220 {
221 l = (u64*)(((unsigned long)l >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
222 printk(" l%d = %p\n", level, l);
223 if ( l == NULL )
224 {
225 printk(" l%d == NULL\n", level);
226 break;
227 }
228 l_index = get_level_index(gmfn, level);
229 printk(" l%d_index = %x\n", level, l_index);
230 printk(" l%d[%x] = %"PRIx64"\n", level, l_index, l[l_index]);
232 pte.val = l[l_index];
233 if ( !dma_pte_present(pte) )
234 {
235 printk(" l%d[%x] not present\n", level, l_index);
236 break;
237 }
239 l = maddr_to_virt(l[l_index]);
240 } while ( --level );
241 }
242 }