aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/intr_remapping.c
diff options
context:
space:
mode:
authorWeidong Han <weidong.han@intel.com>2009-05-22 12:41:15 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-06-23 17:09:17 -0400
commitf007e99c8e2e322b8331aba72414715119a2920d (patch)
tree616bfcdda74341dc8b5d9ea1013bb7506407a961 /drivers/pci/intr_remapping.c
parentc4658b4e777bebf69884f4884a9bfb2f84dd71d9 (diff)
Intel-IOMMU, intr-remap: source-id checking
To support domain-isolation usages, the platform hardware must be capable of uniquely identifying the requestor (source-id) for each interrupt message. Without source-id checking for interrupt remapping , a rouge guest/VM with assigned devices can launch interrupt attacks to bring down anothe guest/VM or the VMM itself. This patch adds source-id checking for interrupt remapping, and then really isolates interrupts for guests/VMs with assigned devices. Because PCI subsystem is not initialized yet when set up IOAPIC entries, use read_pci_config_byte to access PCI config space directly. Signed-off-by: Weidong Han <weidong.han@intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/pci/intr_remapping.c')
-rw-r--r--drivers/pci/intr_remapping.c120
1 files changed, 117 insertions, 3 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 44025a0c2bb..4f5b8712931 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -10,6 +10,8 @@
10#include <linux/intel-iommu.h> 10#include <linux/intel-iommu.h>
11#include "intr_remapping.h" 11#include "intr_remapping.h"
12#include <acpi/acpi.h> 12#include <acpi/acpi.h>
13#include <asm/pci-direct.h>
14#include "pci.h"
13 15
14static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; 16static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
15static int ir_ioapic_num; 17static int ir_ioapic_num;
@@ -418,6 +420,91 @@ int free_irte(int irq)
418 return rc; 420 return rc;
419} 421}
420 422
423/*
424 * source validation type
425 */
426#define SVT_NO_VERIFY 0x0 /* no verification is required */
427#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fiels */
428#define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */
429
430/*
431 * source-id qualifier
432 */
433#define SQ_ALL_16 0x0 /* verify all 16 bits of request-id */
434#define SQ_13_IGNORE_1 0x1 /* verify most significant 13 bits, ignore
435 * the third least significant bit
436 */
437#define SQ_13_IGNORE_2 0x2 /* verify most significant 13 bits, ignore
438 * the second and third least significant bits
439 */
440#define SQ_13_IGNORE_3 0x3 /* verify most significant 13 bits, ignore
441 * the least three significant bits
442 */
443
444/*
445 * set SVT, SQ and SID fields of irte to verify
446 * source ids of interrupt requests
447 */
448static void set_irte_sid(struct irte *irte, unsigned int svt,
449 unsigned int sq, unsigned int sid)
450{
451 irte->svt = svt;
452 irte->sq = sq;
453 irte->sid = sid;
454}
455
456int set_ioapic_sid(struct irte *irte, int apic)
457{
458 int i;
459 u16 sid = 0;
460
461 if (!irte)
462 return -1;
463
464 for (i = 0; i < MAX_IO_APICS; i++) {
465 if (ir_ioapic[i].id == apic) {
466 sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn;
467 break;
468 }
469 }
470
471 if (sid == 0) {
472 pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic);
473 return -1;
474 }
475
476 set_irte_sid(irte, 1, 0, sid);
477
478 return 0;
479}
480
481int set_msi_sid(struct irte *irte, struct pci_dev *dev)
482{
483 struct pci_dev *bridge;
484
485 if (!irte || !dev)
486 return -1;
487
488 /* PCIe device or Root Complex integrated PCI device */
489 if (dev->is_pcie || !dev->bus->parent) {
490 set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
491 (dev->bus->number << 8) | dev->devfn);
492 return 0;
493 }
494
495 bridge = pci_find_upstream_pcie_bridge(dev);
496 if (bridge) {
497 if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */
498 set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16,
499 (bridge->bus->number << 8) | dev->bus->number);
500 else /* this is a legacy PCI bridge */
501 set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
502 (bridge->bus->number << 8) | bridge->devfn);
503 }
504
505 return 0;
506}
507
421static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) 508static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
422{ 509{
423 u64 addr; 510 u64 addr;
@@ -624,6 +711,35 @@ error:
624 return -1; 711 return -1;
625} 712}
626 713
714static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
715 struct intel_iommu *iommu)
716{
717 struct acpi_dmar_pci_path *path;
718 u8 bus;
719 int count;
720
721 bus = scope->bus;
722 path = (struct acpi_dmar_pci_path *)(scope + 1);
723 count = (scope->length - sizeof(struct acpi_dmar_device_scope))
724 / sizeof(struct acpi_dmar_pci_path);
725
726 while (--count > 0) {
727 /*
728 * Access PCI directly due to the PCI
729 * subsystem isn't initialized yet.
730 */
731 bus = read_pci_config_byte(bus, path->dev, path->fn,
732 PCI_SECONDARY_BUS);
733 path++;
734 }
735
736 ir_ioapic[ir_ioapic_num].bus = bus;
737 ir_ioapic[ir_ioapic_num].devfn = PCI_DEVFN(path->dev, path->fn);
738 ir_ioapic[ir_ioapic_num].iommu = iommu;
739 ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
740 ir_ioapic_num++;
741}
742
627static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, 743static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
628 struct intel_iommu *iommu) 744 struct intel_iommu *iommu)
629{ 745{
@@ -648,9 +764,7 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
648 " 0x%Lx\n", scope->enumeration_id, 764 " 0x%Lx\n", scope->enumeration_id,
649 drhd->address); 765 drhd->address);
650 766
651 ir_ioapic[ir_ioapic_num].iommu = iommu; 767 ir_parse_one_ioapic_scope(scope, iommu);
652 ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
653 ir_ioapic_num++;
654 } 768 }
655 start += scope->length; 769 start += scope->length;
656 } 770 }