debuggers.hg

view xen/drivers/passthrough/vtd/dmar.c @ 20970:8616a82df1c0

VT-d: ensure zapping ACPI DMAR signature in acpi_parse_dmar

VT-d is owned by Xen hypervisor. Xen zaps ACPI DMAR signature to
prevent dom0 to use VT-d. This patch changes the direct return when
DMAR width is zero, instead zaps ACPI DMAR signature before return.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 11 19:48:58 2010 +0000 (2010-02-11)
parents 9ec971345d9f
children f5da4b37f9ca
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/errno.h>
25 #include <xen/kernel.h>
26 #include <xen/acpi.h>
27 #include <xen/mm.h>
28 #include <xen/xmalloc.h>
29 #include <xen/pci.h>
30 #include <xen/pci_regs.h>
31 #include <asm/string.h>
32 #include "dmar.h"
33 #include "iommu.h"
34 #include "extern.h"
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_rhsa_units);
48 u8 dmar_host_address_width;
50 void dmar_scope_add_buses(struct dmar_scope *scope, u16 sec_bus, u16 sub_bus)
51 {
52 sub_bus &= 0xff;
53 if (sec_bus > sub_bus)
54 return;
56 while ( sec_bus <= sub_bus )
57 set_bit(sec_bus++, scope->buses);
58 }
60 void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec_bus, u16 sub_bus)
61 {
62 sub_bus &= 0xff;
63 if (sec_bus > sub_bus)
64 return;
66 while ( sec_bus <= sub_bus )
67 clear_bit(sec_bus++, scope->buses);
68 }
70 static int __init acpi_register_drhd_unit(struct acpi_drhd_unit *drhd)
71 {
72 /*
73 * add INCLUDE_ALL at the tail, so scan the list will find it at
74 * the very end.
75 */
76 if ( drhd->include_all )
77 list_add_tail(&drhd->list, &acpi_drhd_units);
78 else
79 list_add(&drhd->list, &acpi_drhd_units);
80 return 0;
81 }
83 static int __init acpi_register_rmrr_unit(struct acpi_rmrr_unit *rmrr)
84 {
85 list_add(&rmrr->list, &acpi_rmrr_units);
86 return 0;
87 }
89 static void __init disable_all_dmar_units(void)
90 {
91 struct acpi_drhd_unit *drhd, *_drhd;
92 struct acpi_rmrr_unit *rmrr, *_rmrr;
93 struct acpi_atsr_unit *atsr, *_atsr;
95 list_for_each_entry_safe ( drhd, _drhd, &acpi_drhd_units, list )
96 {
97 list_del(&drhd->list);
98 xfree(drhd);
99 }
100 list_for_each_entry_safe ( rmrr, _rmrr, &acpi_rmrr_units, list )
101 {
102 list_del(&rmrr->list);
103 xfree(rmrr);
104 }
105 list_for_each_entry_safe ( atsr, _atsr, &acpi_atsr_units, list )
106 {
107 list_del(&atsr->list);
108 xfree(atsr);
109 }
110 }
112 static int acpi_ioapic_device_match(
113 struct list_head *ioapic_list, unsigned int apic_id)
114 {
115 struct acpi_ioapic_unit *ioapic;
116 list_for_each_entry( ioapic, ioapic_list, list ) {
117 if (ioapic->apic_id == apic_id)
118 return 1;
119 }
120 return 0;
121 }
123 struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id)
124 {
125 struct acpi_drhd_unit *drhd;
126 list_for_each_entry( drhd, &acpi_drhd_units, list )
127 if ( acpi_ioapic_device_match(&drhd->ioapic_list, apic_id) )
128 return drhd;
129 return NULL;
130 }
132 struct acpi_drhd_unit * iommu_to_drhd(struct iommu *iommu)
133 {
134 struct acpi_drhd_unit *drhd;
136 if ( iommu == NULL )
137 return NULL;
139 list_for_each_entry( drhd, &acpi_drhd_units, list )
140 if ( drhd->iommu == iommu )
141 return drhd;
143 return NULL;
144 }
146 struct iommu * ioapic_to_iommu(unsigned int apic_id)
147 {
148 struct acpi_drhd_unit *drhd;
150 list_for_each_entry( drhd, &acpi_drhd_units, list )
151 if ( acpi_ioapic_device_match(&drhd->ioapic_list, apic_id) )
152 return drhd->iommu;
153 return NULL;
154 }
156 static int __init acpi_register_atsr_unit(struct acpi_atsr_unit *atsr)
157 {
158 /*
159 * add ALL_PORTS at the tail, so scan the list will find it at
160 * the very end.
161 */
162 if ( atsr->all_ports )
163 list_add_tail(&atsr->list, &acpi_atsr_units);
164 else
165 list_add(&atsr->list, &acpi_atsr_units);
166 return 0;
167 }
169 struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *pdev)
170 {
171 u8 bus, devfn;
172 struct acpi_drhd_unit *drhd;
173 struct acpi_drhd_unit *include_all = NULL;
174 int i;
176 if ( pdev == NULL )
177 return NULL;
179 if (pdev->info.is_extfn) {
180 bus = pdev->bus;
181 devfn = 0;
182 } else if (pdev->info.is_virtfn) {
183 bus = pdev->info.physfn.bus;
184 devfn = PCI_SLOT(pdev->info.physfn.devfn) ? 0 : pdev->info.physfn.devfn;
185 } else {
186 bus = pdev->bus;
187 devfn = pdev->devfn;
188 }
190 list_for_each_entry ( drhd, &acpi_drhd_units, list )
191 {
192 for (i = 0; i < drhd->scope.devices_cnt; i++)
193 if ( drhd->scope.devices[i] == PCI_BDF2(bus, devfn) )
194 return drhd;
196 if ( test_bit(bus, drhd->scope.buses) )
197 return drhd;
199 if ( drhd->include_all )
200 include_all = drhd;
201 }
202 return include_all;
203 }
205 struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u8 bus, u8 devfn)
206 {
207 struct acpi_atsr_unit *atsr;
208 struct acpi_atsr_unit *all_ports = NULL;
210 list_for_each_entry ( atsr, &acpi_atsr_units, list )
211 {
212 if ( test_bit(bus, atsr->scope.buses) )
213 return atsr;
215 if ( atsr->all_ports )
216 all_ports = atsr;
217 }
218 return all_ports;
219 }
221 struct acpi_rhsa_unit * drhd_to_rhsa(struct acpi_drhd_unit *drhd)
222 {
223 struct acpi_rhsa_unit *rhsa;
225 if ( drhd == NULL )
226 return NULL;
228 list_for_each_entry ( rhsa, &acpi_rhsa_units, list )
229 {
230 if ( rhsa->address == drhd->address )
231 return rhsa;
232 }
233 return NULL;
234 }
236 /*
237 * Count number of devices in device scope. Do not include PCI sub
238 * hierarchies.
239 */
240 static int scope_device_count(void *start, void *end)
241 {
242 struct acpi_dev_scope *scope;
243 int count = 0;
245 while ( start < end )
246 {
247 scope = start;
248 if ( (scope->length < MIN_SCOPE_LEN) ||
249 (scope->dev_type >= ACPI_DEV_ENTRY_COUNT) )
250 {
251 dprintk(XENLOG_WARNING VTDPREFIX, "Invalid device scope.\n");
252 return -EINVAL;
253 }
255 if ( scope->dev_type == ACPI_DEV_P2PBRIDGE ||
256 scope->dev_type == ACPI_DEV_ENDPOINT ||
257 scope->dev_type == ACPI_DEV_IOAPIC ||
258 scope->dev_type == ACPI_DEV_MSI_HPET )
259 count++;
261 start += scope->length;
262 }
264 return count;
265 }
268 static int __init acpi_parse_dev_scope(void *start, void *end,
269 void *acpi_entry, int type)
270 {
271 struct dmar_scope *scope = acpi_entry;
272 struct acpi_ioapic_unit *acpi_ioapic_unit;
273 struct acpi_dev_scope *acpi_scope;
274 u16 bus, sub_bus, sec_bus;
275 struct acpi_pci_path *path;
276 int depth, cnt, didx = 0;
278 if ( (cnt = scope_device_count(start, end)) < 0 )
279 return cnt;
281 scope->devices_cnt = cnt;
282 if ( cnt > 0 )
283 {
284 scope->devices = xmalloc_array(u16, cnt);
285 if ( !scope->devices )
286 return -ENOMEM;
287 memset(scope->devices, 0, sizeof(u16) * cnt);
288 }
290 while ( start < end )
291 {
292 acpi_scope = start;
293 path = (struct acpi_pci_path *)(acpi_scope + 1);
294 depth = (acpi_scope->length - sizeof(struct acpi_dev_scope))
295 / sizeof(struct acpi_pci_path);
296 bus = acpi_scope->start_bus;
298 while ( --depth > 0 )
299 {
300 bus = pci_conf_read8(bus, path->dev, path->fn, PCI_SECONDARY_BUS);
301 path++;
302 }
304 switch ( acpi_scope->dev_type )
305 {
306 case ACPI_DEV_P2PBRIDGE:
307 sec_bus = pci_conf_read8(
308 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
309 sub_bus = pci_conf_read8(
310 bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
311 dprintk(XENLOG_INFO VTDPREFIX,
312 " bridge: %x:%x.%x start = %x sec = %x sub = %x\n",
313 bus, path->dev, path->fn,
314 acpi_scope->start_bus, sec_bus, sub_bus);
316 dmar_scope_add_buses(scope, sec_bus, sub_bus);
317 break;
319 case ACPI_DEV_MSI_HPET:
320 dprintk(XENLOG_INFO VTDPREFIX, " MSI HPET: %x:%x.%x\n",
321 bus, path->dev, path->fn);
322 break;
324 case ACPI_DEV_ENDPOINT:
325 dprintk(XENLOG_INFO VTDPREFIX, " endpoint: %x:%x.%x\n",
326 bus, path->dev, path->fn);
327 break;
329 case ACPI_DEV_IOAPIC:
330 dprintk(XENLOG_INFO VTDPREFIX, " IOAPIC: %x:%x.%x\n",
331 bus, path->dev, path->fn);
333 if ( type == DMAR_TYPE )
334 {
335 struct acpi_drhd_unit *drhd = acpi_entry;
336 acpi_ioapic_unit = xmalloc(struct acpi_ioapic_unit);
337 if ( !acpi_ioapic_unit )
338 return -ENOMEM;
339 acpi_ioapic_unit->apic_id = acpi_scope->enum_id;
340 acpi_ioapic_unit->ioapic.bdf.bus = bus;
341 acpi_ioapic_unit->ioapic.bdf.dev = path->dev;
342 acpi_ioapic_unit->ioapic.bdf.func = path->fn;
343 list_add(&acpi_ioapic_unit->list, &drhd->ioapic_list);
344 }
346 break;
347 }
348 scope->devices[didx++] = PCI_BDF(bus, path->dev, path->fn);
349 start += acpi_scope->length;
350 }
352 return 0;
353 }
355 static int __init
356 acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
357 {
358 struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
359 void *dev_scope_start, *dev_scope_end;
360 struct acpi_drhd_unit *dmaru;
361 void *addr;
362 int ret = 0;
363 static int include_all = 0;
365 dmaru = xmalloc(struct acpi_drhd_unit);
366 if ( !dmaru )
367 return -ENOMEM;
368 memset(dmaru, 0, sizeof(struct acpi_drhd_unit));
370 dmaru->address = drhd->address;
371 dmaru->include_all = drhd->flags & 1; /* BIT0: INCLUDE_ALL */
372 INIT_LIST_HEAD(&dmaru->ioapic_list);
373 dprintk(XENLOG_INFO VTDPREFIX, " dmaru->address = %"PRIx64"\n",
374 dmaru->address);
376 addr = map_to_nocache_virt(0, drhd->address);
377 dmaru->ecap = dmar_readq(addr, DMAR_ECAP_REG);
379 dev_scope_start = (void *)(drhd + 1);
380 dev_scope_end = ((void *)drhd) + header->length;
381 ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
382 dmaru, DMAR_TYPE);
384 if ( dmaru->include_all )
385 {
386 dprintk(XENLOG_INFO VTDPREFIX, " flags: INCLUDE_ALL\n");
387 /* Only allow one INCLUDE_ALL */
388 if ( include_all )
389 {
390 dprintk(XENLOG_WARNING VTDPREFIX,
391 "Only one INCLUDE_ALL device scope is allowed\n");
392 ret = -EINVAL;
393 }
394 include_all = 1;
395 }
397 if ( ret )
398 xfree(dmaru);
399 else if ( force_iommu || dmaru->include_all )
400 acpi_register_drhd_unit(dmaru);
401 else
402 {
403 u8 b, d, f;
404 int i, invalid_cnt = 0;
406 for ( i = 0; i < dmaru->scope.devices_cnt; i++ )
407 {
408 b = PCI_BUS(dmaru->scope.devices[i]);
409 d = PCI_SLOT(dmaru->scope.devices[i]);
410 f = PCI_FUNC(dmaru->scope.devices[i]);
412 if ( pci_device_detect(b, d, f) == 0 )
413 {
414 dprintk(XENLOG_WARNING VTDPREFIX,
415 " Non-existent device (%x:%x.%x) is reported "
416 "in this DRHD's scope!\n", b, d, f);
417 invalid_cnt++;
418 }
419 }
421 if ( invalid_cnt )
422 {
423 xfree(dmaru);
425 if ( iommu_workaround_bios_bug &&
426 invalid_cnt == dmaru->scope.devices_cnt )
427 {
428 dprintk(XENLOG_WARNING VTDPREFIX,
429 " Workaround BIOS bug: ignore the DRHD due to all "
430 "devices under its scope are not PCI discoverable!\n");
431 }
432 else
433 {
434 dprintk(XENLOG_WARNING VTDPREFIX,
435 " The DRHD is invalid due to there are devices under "
436 "its scope are not PCI discoverable! Pls try option "
437 "iommu=force or iommu=workaround_bios_bug if you "
438 "really want VT-d\n");
439 ret = -EINVAL;
440 }
441 }
442 else
443 acpi_register_drhd_unit(dmaru);
444 }
446 return ret;
447 }
449 static int __init
450 acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
451 {
452 struct acpi_table_rmrr *rmrr = (struct acpi_table_rmrr *)header;
453 struct acpi_rmrr_unit *rmrru;
454 void *dev_scope_start, *dev_scope_end;
455 u64 base_addr = rmrr->base_address, end_addr = rmrr->end_address;
456 int ret = 0;
458 #ifdef CONFIG_X86
459 /* This check is here simply to detect when RMRR values are
460 * not properly represented in the system memory map and
461 * inform the user
462 */
463 if ( (!page_is_ram_type(paddr_to_pfn(base_addr), RAM_TYPE_RESERVED)) ||
464 (!page_is_ram_type(paddr_to_pfn(end_addr) - 1, RAM_TYPE_RESERVED)) )
465 {
466 dprintk(XENLOG_WARNING VTDPREFIX,
467 " RMRR address range not in reserved memory "
468 "base = %"PRIx64" end = %"PRIx64"; "
469 "iommu_inclusive_mapping=1 parameter may be needed.\n",
470 base_addr, end_addr);
471 }
472 #endif
474 rmrru = xmalloc(struct acpi_rmrr_unit);
475 if ( !rmrru )
476 return -ENOMEM;
477 memset(rmrru, 0, sizeof(struct acpi_rmrr_unit));
479 rmrru->base_address = base_addr;
480 rmrru->end_address = end_addr;
482 dev_scope_start = (void *)(rmrr + 1);
483 dev_scope_end = ((void *)rmrr) + header->length;
484 ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
485 rmrru, RMRR_TYPE);
487 if ( ret || (rmrru->scope.devices_cnt == 0) )
488 xfree(rmrru);
489 else
490 {
491 u8 b, d, f;
492 int i, ignore = 0;
494 for ( i = 0; i < rmrru->scope.devices_cnt; i++ )
495 {
496 b = PCI_BUS(rmrru->scope.devices[i]);
497 d = PCI_SLOT(rmrru->scope.devices[i]);
498 f = PCI_FUNC(rmrru->scope.devices[i]);
500 if ( pci_device_detect(b, d, f) == 0 )
501 {
502 dprintk(XENLOG_WARNING VTDPREFIX,
503 " Non-existent device (%x:%x.%x) is reported "
504 "in RMRR (%"PRIx64", %"PRIx64")'s scope!\n",
505 b, d, f, rmrru->base_address, rmrru->end_address);
506 ignore = 1;
507 }
508 else
509 {
510 ignore = 0;
511 break;
512 }
513 }
515 if ( ignore )
516 {
517 dprintk(XENLOG_WARNING VTDPREFIX,
518 " Ignore the RMRR (%"PRIx64", %"PRIx64") due to "
519 "devices under its scope are not PCI discoverable!\n",
520 rmrru->base_address, rmrru->end_address);
521 xfree(rmrru);
522 }
523 else if ( base_addr > end_addr )
524 {
525 dprintk(XENLOG_WARNING VTDPREFIX,
526 " The RMRR (%"PRIx64", %"PRIx64") is incorrect!\n",
527 rmrru->base_address, rmrru->end_address);
528 xfree(rmrru);
529 ret = -EFAULT;
530 }
531 else
532 {
533 dprintk(XENLOG_INFO VTDPREFIX,
534 " RMRR region: base_addr %"PRIx64" end_address %"PRIx64"\n",
535 rmrru->base_address, rmrru->end_address);
536 acpi_register_rmrr_unit(rmrru);
537 }
538 }
540 return ret;
541 }
543 static int __init
544 acpi_parse_one_atsr(struct acpi_dmar_entry_header *header)
545 {
546 struct acpi_table_atsr *atsr = (struct acpi_table_atsr *)header;
547 struct acpi_atsr_unit *atsru;
548 int ret = 0;
549 static int all_ports;
550 void *dev_scope_start, *dev_scope_end;
552 atsru = xmalloc(struct acpi_atsr_unit);
553 if ( !atsru )
554 return -ENOMEM;
555 memset(atsru, 0, sizeof(struct acpi_atsr_unit));
557 atsru->all_ports = atsr->flags & 1; /* BIT0: ALL_PORTS */
558 dprintk(XENLOG_INFO VTDPREFIX,
559 " atsru->all_ports: %x\n", atsru->all_ports);
560 if ( !atsru->all_ports )
561 {
562 dev_scope_start = (void *)(atsr + 1);
563 dev_scope_end = ((void *)atsr) + header->length;
564 ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
565 atsru, ATSR_TYPE);
566 }
567 else
568 {
569 dprintk(XENLOG_INFO VTDPREFIX, " flags: ALL_PORTS\n");
570 /* Only allow one ALL_PORTS */
571 if ( all_ports )
572 {
573 dprintk(XENLOG_WARNING VTDPREFIX,
574 "Only one ALL_PORTS device scope is allowed\n");
575 ret = -EINVAL;
576 }
577 all_ports = 1;
578 }
580 if ( ret )
581 xfree(atsr);
582 else
583 acpi_register_atsr_unit(atsru);
584 return ret;
585 }
587 static int __init
588 acpi_parse_one_rhsa(struct acpi_dmar_entry_header *header)
589 {
590 struct acpi_table_rhsa *rhsa = (struct acpi_table_rhsa *)header;
591 struct acpi_rhsa_unit *rhsau;
592 int ret = 0;
594 rhsau = xmalloc(struct acpi_rhsa_unit);
595 if ( !rhsau )
596 return -ENOMEM;
597 memset(rhsau, 0, sizeof(struct acpi_rhsa_unit));
599 rhsau->address = rhsa->address;
600 rhsau->proximity_domain = rhsa->proximity_domain;
601 list_add_tail(&rhsau->list, &acpi_rhsa_units);
602 dprintk(XENLOG_INFO VTDPREFIX,
603 " rhsau->address: %"PRIx64" rhsau->proximity_domain: %"PRIx32"\n",
604 rhsau->address, rhsau->proximity_domain);
606 return ret;
607 }
609 static int __init acpi_parse_dmar(struct acpi_table_header *table)
610 {
611 struct acpi_table_dmar *dmar;
612 struct acpi_dmar_entry_header *entry_header;
613 int ret = 0;
615 dmar = (struct acpi_table_dmar *)table;
617 if ( !iommu_enabled )
618 {
619 ret = -EINVAL;
620 goto out;
621 }
623 if ( !dmar->width )
624 {
625 dprintk(XENLOG_WARNING VTDPREFIX, "Zero: Invalid DMAR width\n");
626 ret = -EINVAL;
627 goto out;
628 }
630 dmar_host_address_width = dmar->width + 1;
631 dprintk(XENLOG_INFO VTDPREFIX, "Host address width %d\n",
632 dmar_host_address_width);
634 entry_header = (struct acpi_dmar_entry_header *)(dmar + 1);
635 while ( ((unsigned long)entry_header) <
636 (((unsigned long)dmar) + table->length) )
637 {
638 switch ( entry_header->type )
639 {
640 case ACPI_DMAR_DRHD:
641 dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_DRHD:\n");
642 ret = acpi_parse_one_drhd(entry_header);
643 break;
644 case ACPI_DMAR_RMRR:
645 dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_RMRR:\n");
646 ret = acpi_parse_one_rmrr(entry_header);
647 break;
648 case ACPI_DMAR_ATSR:
649 dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_ATSR:\n");
650 ret = acpi_parse_one_atsr(entry_header);
651 break;
652 case ACPI_DMAR_RHSA:
653 dprintk(XENLOG_INFO VTDPREFIX, "found ACPI_DMAR_RHSA:\n");
654 ret = acpi_parse_one_rhsa(entry_header);
655 break;
656 default:
657 dprintk(XENLOG_WARNING VTDPREFIX, "Unknown DMAR structure type\n");
658 ret = -EINVAL;
659 break;
660 }
661 if ( ret )
662 break;
664 entry_header = ((void *)entry_header + entry_header->length);
665 }
667 if ( ret )
668 {
669 printk(XENLOG_WARNING
670 "Failed to parse ACPI DMAR. Disabling VT-d.\n");
671 disable_all_dmar_units();
672 }
674 out:
675 /* Zap ACPI DMAR signature to prevent dom0 using vt-d HW. */
676 dmar->header.signature[0] = '\0';
677 return ret;
678 }
680 #ifdef CONFIG_X86
681 #include <asm/tboot.h>
682 /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
683 /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
684 #define parse_dmar_table(h) tboot_parse_dmar_table(h)
685 #else
686 #define parse_dmar_table(h) acpi_table_parse(ACPI_SIG_DMAR, h)
687 #endif
689 int __init acpi_dmar_init(void)
690 {
691 return parse_dmar_table(acpi_parse_dmar);
692 }