debuggers.hg

view xen/arch/x86/hvm/vmx/vtd/dmar.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) Ashok Raj <ashok.raj@intel.com>
18 * Copyright (C) Shaohua Li <shaohua.li@intel.com>
19 * Copyright (C) Allen Kay <allen.m.kay@intel.com> - adapted to xen
20 */
22 #include <xen/init.h>
23 #include <xen/bitmap.h>
24 #include <xen/kernel.h>
25 #include <xen/acpi.h>
26 #include <xen/mm.h>
27 #include <xen/xmalloc.h>
28 #include <asm/string.h>
29 #include "dmar.h"
30 #include "pci-direct.h"
31 #include "pci_regs.h"
33 int vtd_enabled;
34 boolean_param("vtd", vtd_enabled);
36 #undef PREFIX
37 #define PREFIX VTDPREFIX "ACPI DMAR:"
38 #define DEBUG
40 #define MIN_SCOPE_LEN (sizeof(struct acpi_pci_path) + \
41 sizeof(struct acpi_dev_scope))
43 LIST_HEAD(acpi_drhd_units);
44 LIST_HEAD(acpi_rmrr_units);
45 LIST_HEAD(acpi_atsr_units);
46 LIST_HEAD(acpi_ioapic_units);
48 u8 dmar_host_address_width;
50 static int __init acpi_register_drhd_unit(struct acpi_drhd_unit *drhd)
51 {
52 /*
53 * add INCLUDE_ALL at the tail, so scan the list will find it at
54 * the very end.
55 */
56 if ( drhd->include_all )
57 list_add_tail(&drhd->list, &acpi_drhd_units);
58 else
59 list_add(&drhd->list, &acpi_drhd_units);
60 return 0;
61 }
63 static int __init acpi_register_rmrr_unit(struct acpi_rmrr_unit *rmrr)
64 {
65 list_add(&rmrr->list, &acpi_rmrr_units);
66 return 0;
67 }
69 static int acpi_pci_device_match(struct pci_dev *devices, int cnt,
70 struct pci_dev *dev)
71 {
72 int i;
74 for ( i = 0; i < cnt; i++ )
75 {
76 if ( (dev->bus == devices->bus) &&
77 (dev->devfn == devices->devfn) )
78 return 1;
79 devices++;
80 }
81 return 0;
82 }
84 static int __init acpi_register_atsr_unit(struct acpi_atsr_unit *atsr)
85 {
86 /*
87 * add ALL_PORTS at the tail, so scan the list will find it at
88 * the very end.
89 */
90 if ( atsr->all_ports )
91 list_add_tail(&atsr->list, &acpi_atsr_units);
92 else
93 list_add(&atsr->list, &acpi_atsr_units);
94 return 0;
95 }
97 struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *dev)
98 {
99 struct acpi_drhd_unit *drhd;
100 struct acpi_drhd_unit *include_all_drhd;
102 include_all_drhd = NULL;
103 list_for_each_entry ( drhd, &acpi_drhd_units, list )
104 {
105 if ( drhd->include_all )
106 {
107 include_all_drhd = drhd;
108 continue;
109 }
111 if ( acpi_pci_device_match(drhd->devices,
112 drhd->devices_cnt, dev) )
113 {
114 gdprintk(XENLOG_INFO VTDPREFIX,
115 "acpi_find_matched_drhd_unit: drhd->address = %lx\n",
116 drhd->address);
117 return drhd;
118 }
119 }
121 if ( include_all_drhd )
122 {
123 gdprintk(XENLOG_INFO VTDPREFIX,
124 "acpi_find_matched_drhd_unit:include_all_drhd->addr = %lx\n",
125 include_all_drhd->address);
126 return include_all_drhd;
127 }
129 return NULL;
130 }
132 struct acpi_rmrr_unit * acpi_find_matched_rmrr_unit(struct pci_dev *dev)
133 {
134 struct acpi_rmrr_unit *rmrr;
136 list_for_each_entry ( rmrr, &acpi_rmrr_units, list )
137 {
138 if ( acpi_pci_device_match(rmrr->devices,
139 rmrr->devices_cnt, dev) )
140 return rmrr;
141 }
143 return NULL;
144 }
146 struct acpi_atsr_unit * acpi_find_matched_atsr_unit(struct pci_dev *dev)
147 {
148 struct acpi_atsr_unit *atsru;
149 struct acpi_atsr_unit *all_ports_atsru;
151 all_ports_atsru = NULL;
152 list_for_each_entry ( atsru, &acpi_atsr_units, list )
153 {
154 if ( atsru->all_ports )
155 all_ports_atsru = atsru;
156 if ( acpi_pci_device_match(atsru->devices,
157 atsru->devices_cnt, dev) )
158 return atsru;
159 }
161 if ( all_ports_atsru )
162 {
163 gdprintk(XENLOG_INFO VTDPREFIX,
164 "acpi_find_matched_atsr_unit: all_ports_atsru\n");
165 return all_ports_atsru;;
166 }
168 return NULL;
169 }
171 static int scope_device_count(void *start, void *end)
172 {
173 struct acpi_dev_scope *scope;
174 u8 bus, sub_bus, sec_bus;
175 struct acpi_pci_path *path;
176 int depth, count = 0;
177 u8 dev, func;
178 u32 l;
180 while ( start < end )
181 {
182 scope = start;
183 if ( scope->length < MIN_SCOPE_LEN )
184 {
185 printk(KERN_WARNING PREFIX "Invalid device scope\n");
186 return -EINVAL;
187 }
189 path = (struct acpi_pci_path *)(scope + 1);
190 bus = scope->start_bus;
191 depth = (scope->length - sizeof(struct acpi_dev_scope))
192 / sizeof(struct acpi_pci_path);
193 while ( --depth )
194 {
195 bus = read_pci_config_byte(
196 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
197 path++;
198 }
200 if ( scope->dev_type == ACPI_DEV_ENDPOINT )
201 {
202 printk(KERN_INFO PREFIX
203 "found endpoint: bdf = %x:%x:%x\n",
204 bus, path->dev, path->fn);
205 count++;
206 }
207 else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
208 {
209 printk(KERN_INFO PREFIX
210 "found bridge: bdf = %x:%x:%x\n",
211 bus, path->dev, path->fn);
212 sec_bus = read_pci_config_byte(
213 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
214 sub_bus = read_pci_config_byte(
215 bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
217 while ( sec_bus <= sub_bus )
218 {
219 for ( dev = 0; dev < 32; dev++ )
220 {
221 for ( func = 0; func < 8; func++ )
222 {
223 l = read_pci_config(
224 sec_bus, dev, func, PCI_VENDOR_ID);
226 /* some broken boards return 0 or
227 * ~0 if a slot is empty
228 */
229 if ( l == 0xffffffff || l == 0x00000000 ||
230 l == 0x0000ffff || l == 0xffff0000 )
231 break;
232 count++;
233 }
234 }
235 sec_bus++;
236 }
237 }
238 else if ( scope->dev_type == ACPI_DEV_IOAPIC )
239 {
240 printk(KERN_INFO PREFIX
241 "found IOAPIC: bdf = %x:%x:%x\n",
242 bus, path->dev, path->fn);
243 count++;
244 }
245 else
246 {
247 printk(KERN_INFO PREFIX
248 "found MSI HPET: bdf = %x:%x:%x\n",
249 bus, path->dev, path->fn);
250 count++;
251 }
253 start += scope->length;
254 }
256 return count;
257 }
259 static int __init acpi_parse_dev_scope(void *start, void *end, int *cnt,
260 struct pci_dev **devices)
261 {
262 struct acpi_dev_scope *scope;
263 u8 bus, sub_bus, sec_bus;
264 struct acpi_pci_path *path;
265 struct acpi_ioapic_unit *acpi_ioapic_unit = NULL;
266 int depth;
267 struct pci_dev *pdev;
268 u8 dev, func;
269 u32 l;
271 *cnt = scope_device_count(start, end);
272 if ( *cnt == 0 )
273 {
274 printk(KERN_INFO PREFIX "acpi_parse_dev_scope: no device\n");
275 return 0;
276 }
278 *devices = xmalloc_array(struct pci_dev, *cnt);
279 if ( !*devices )
280 return -ENOMEM;
281 memset(*devices, 0, sizeof(struct pci_dev) * (*cnt));
283 pdev = *devices;
284 while ( start < end )
285 {
286 scope = start;
287 path = (struct acpi_pci_path *)(scope + 1);
288 depth = (scope->length - sizeof(struct acpi_dev_scope))
289 / sizeof(struct acpi_pci_path);
290 bus = scope->start_bus;
292 while ( --depth )
293 {
294 bus = read_pci_config_byte(
295 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
296 path++;
297 }
299 if ( scope->dev_type == ACPI_DEV_ENDPOINT )
300 {
301 printk(KERN_INFO PREFIX
302 "found endpoint: bdf = %x:%x:%x\n",
303 bus, path->dev, path->fn);
304 pdev->bus = bus;
305 pdev->devfn = PCI_DEVFN(path->dev, path->fn);
306 pdev++;
307 }
308 else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
309 {
310 printk(KERN_INFO PREFIX
311 "found bridge: bus = %x dev = %x func = %x\n",
312 bus, path->dev, path->fn);
313 sec_bus = read_pci_config_byte(
314 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
315 sub_bus = read_pci_config_byte(
316 bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
318 while ( sec_bus <= sub_bus )
319 {
320 for ( dev = 0; dev < 32; dev++ )
321 {
322 for ( func = 0; func < 8; func++ )
323 {
324 l = read_pci_config(
325 sec_bus, dev, func, PCI_VENDOR_ID);
327 /* some broken boards return 0 or
328 * ~0 if a slot is empty
329 */
330 if ( l == 0xffffffff || l == 0x00000000 ||
331 l == 0x0000ffff || l == 0xffff0000 )
332 break;
334 pdev->bus = sec_bus;
335 pdev->devfn = PCI_DEVFN(dev, func);
336 pdev++;
337 }
338 }
339 sec_bus++;
340 }
341 }
342 else if ( scope->dev_type == ACPI_DEV_IOAPIC )
343 {
344 acpi_ioapic_unit = xmalloc(struct acpi_ioapic_unit);
345 if ( !acpi_ioapic_unit )
346 return -ENOMEM;
347 acpi_ioapic_unit->apic_id = scope->enum_id;
348 acpi_ioapic_unit->ioapic.bdf.bus = bus;
349 acpi_ioapic_unit->ioapic.bdf.dev = path->dev;
350 acpi_ioapic_unit->ioapic.bdf.func = path->fn;
351 list_add(&acpi_ioapic_unit->list, &acpi_ioapic_units);
352 printk(KERN_INFO PREFIX
353 "found IOAPIC: bus = %x dev = %x func = %x\n",
354 bus, path->dev, path->fn);
355 }
356 else
357 printk(KERN_INFO PREFIX
358 "found MSI HPET: bus = %x dev = %x func = %x\n",
359 bus, path->dev, path->fn);
361 start += scope->length;
362 }
364 return 0;
365 }
367 static int __init
368 acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
369 {
370 struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
371 struct acpi_drhd_unit *dmaru;
372 int ret = 0;
373 static int include_all;
375 dmaru = xmalloc(struct acpi_drhd_unit);
376 if ( !dmaru )
377 return -ENOMEM;
378 memset(dmaru, 0, sizeof(struct acpi_drhd_unit));
380 dmaru->address = drhd->address;
381 dmaru->include_all = drhd->flags & 1; /* BIT0: INCLUDE_ALL */
382 printk(KERN_INFO PREFIX "dmaru->address = %lx\n", dmaru->address);
384 if ( !dmaru->include_all )
385 ret = acpi_parse_dev_scope(
386 (void *)(drhd + 1),
387 ((void *)drhd) + header->length,
388 &dmaru->devices_cnt, &dmaru->devices);
389 else
390 {
391 printk(KERN_INFO PREFIX "found INCLUDE_ALL\n");
392 /* Only allow one INCLUDE_ALL */
393 if ( include_all )
394 {
395 printk(KERN_WARNING PREFIX "Only one INCLUDE_ALL "
396 "device scope is allowed\n");
397 ret = -EINVAL;
398 }
399 include_all = 1;
400 }
402 if ( ret )
403 xfree(dmaru);
404 else
405 acpi_register_drhd_unit(dmaru);
406 return ret;
407 }
409 static int __init
410 acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
411 {
412 struct acpi_table_rmrr *rmrr = (struct acpi_table_rmrr *)header;
413 struct acpi_rmrr_unit *rmrru;
414 int ret = 0;
416 rmrru = xmalloc(struct acpi_rmrr_unit);
417 if ( !rmrru )
418 return -ENOMEM;
419 memset(rmrru, 0, sizeof(struct acpi_rmrr_unit));
421 rmrru->base_address = rmrr->base_address;
422 rmrru->end_address = rmrr->end_address;
423 printk(KERN_INFO PREFIX
424 "acpi_parse_one_rmrr: base=%"PRIx64" end=%"PRIx64"\n",
425 rmrr->base_address, rmrr->end_address);
427 ret = acpi_parse_dev_scope(
428 (void *)(rmrr + 1),
429 ((void*)rmrr) + header->length,
430 &rmrru->devices_cnt, &rmrru->devices);
432 if ( ret || (rmrru->devices_cnt == 0) )
433 xfree(rmrru);
434 else
435 acpi_register_rmrr_unit(rmrru);
436 return ret;
437 }
439 static int __init
440 acpi_parse_one_atsr(struct acpi_dmar_entry_header *header)
441 {
442 struct acpi_table_atsr *atsr = (struct acpi_table_atsr *)header;
443 struct acpi_atsr_unit *atsru;
444 int ret = 0;
445 static int all_ports;
447 atsru = xmalloc(struct acpi_atsr_unit);
448 if ( !atsru )
449 return -ENOMEM;
450 memset(atsru, 0, sizeof(struct acpi_atsr_unit));
452 atsru->all_ports = atsr->flags & 1; /* BIT0: ALL_PORTS */
453 if ( !atsru->all_ports )
454 ret = acpi_parse_dev_scope(
455 (void *)(atsr + 1),
456 ((void *)atsr) + header->length,
457 &atsru->devices_cnt, &atsru->devices);
458 else
459 {
460 printk(KERN_INFO PREFIX "found ALL_PORTS\n");
461 /* Only allow one ALL_PORTS */
462 if ( all_ports )
463 {
464 printk(KERN_WARNING PREFIX "Only one ALL_PORTS "
465 "device scope is allowed\n");
466 ret = -EINVAL;
467 }
468 all_ports = 1;
469 }
471 if ( ret )
472 xfree(atsr);
473 else
474 acpi_register_atsr_unit(atsru);
475 return ret;
476 }
478 static int __init acpi_parse_dmar(unsigned long phys_addr,
479 unsigned long size)
480 {
481 struct acpi_table_dmar *dmar = NULL;
482 struct acpi_dmar_entry_header *entry_header;
483 int ret = 0;
485 if ( !phys_addr || !size )
486 return -EINVAL;
488 dmar = (struct acpi_table_dmar *)__acpi_map_table(phys_addr, size);
489 if ( !dmar )
490 {
491 printk(KERN_WARNING PREFIX "Unable to map DMAR\n");
492 return -ENODEV;
493 }
495 if ( !dmar->haw )
496 {
497 printk(KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
498 return -EINVAL;
499 }
501 dmar_host_address_width = dmar->haw;
502 printk(KERN_INFO PREFIX "Host address width %d\n",
503 dmar_host_address_width);
505 entry_header = (struct acpi_dmar_entry_header *)(dmar + 1);
506 while ( ((unsigned long)entry_header) <
507 (((unsigned long)dmar) + size) )
508 {
509 switch ( entry_header->type )
510 {
511 case ACPI_DMAR_DRHD:
512 printk(KERN_INFO PREFIX "found ACPI_DMAR_DRHD\n");
513 ret = acpi_parse_one_drhd(entry_header);
514 break;
515 case ACPI_DMAR_RMRR:
516 printk(KERN_INFO PREFIX "found ACPI_DMAR_RMRR\n");
517 ret = acpi_parse_one_rmrr(entry_header);
518 break;
519 case ACPI_DMAR_ATSR:
520 printk(KERN_INFO PREFIX "found ACPI_DMAR_ATSR\n");
521 ret = acpi_parse_one_atsr(entry_header);
522 break;
523 default:
524 printk(KERN_WARNING PREFIX "Unknown DMAR structure type\n");
525 ret = -EINVAL;
526 break;
527 }
528 if ( ret )
529 break;
531 entry_header = ((void *)entry_header + entry_header->length);
532 }
534 /* Zap APCI DMAR signature to prevent dom0 using vt-d HW. */
535 dmar->header.signature[0] = '\0';
537 return ret;
538 }
540 int acpi_dmar_init(void)
541 {
542 int rc;
544 if ( !vtd_enabled )
545 return -ENODEV;
547 if ( (rc = vtd_hw_check()) != 0 )
548 return rc;
550 acpi_table_parse(ACPI_DMAR, acpi_parse_dmar);
552 if ( list_empty(&acpi_drhd_units) )
553 {
554 printk(KERN_ERR PREFIX "No DMAR devices found\n");
555 vtd_enabled = 0;
556 return -ENODEV;
557 }
559 printk("Intel VT-d has been enabled\n");
561 return 0;
562 }