diff options
author | Jan Beulich <jbeulich@suse.com> | 2012-06-22 13:43:00 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2012-06-22 13:43:00 +0200 |
commit | 56b3130c1a4ffc3c1a045559240261b892b9b880 (patch) | |
tree | cfa39d69fc251380e7358e1230c3a1c3c654cf0a /xen/arch/x86/traps.c | |
parent | 7f15d8540d2ea880170194700a8fb4600da8643b (diff) | |
download | xen-56b3130c1a4ffc3c1a045559240261b892b9b880.tar.gz xen-56b3130c1a4ffc3c1a045559240261b892b9b880.tar.bz2 xen-56b3130c1a4ffc3c1a045559240261b892b9b880.zip |
AMD IOMMU: add mechanism to protect their PCI devices' config spaces
Recent Dom0 kernels want to disable PCI MSI on all devices, yet doing
so on AMD IOMMUs (which get represented by a PCI device) disables part
of the functionality set up by the hypervisor.
Add a mechanism to mark certain PCI devices as having write protected
config spaces (both through port based [method 1] accesses and, for
x86-64, mmconfig), and use that for AMD's IOMMUs.
Note that due to ptwr_do_page_fault() being run first, there'll be a
MEM_LOG() issued for each such mmconfig based write attempt. If that's
undesirable, the order of the calls in fixup_page_fault() would need
to be swapped.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Wei Wang <wei.wang2@amd.com>
Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/traps.c')
-rw-r--r-- | xen/arch/x86/traps.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index dc80c6f506..f0ef7626f8 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1349,20 +1349,23 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs) return 0; } - if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && - guest_kernel_mode(v, regs) ) - { - unsigned int mbs = PFEC_write_access; - unsigned int mbz = PFEC_reserved_bit | PFEC_insn_fetch; - - /* Do not check if access-protection fault since the page may - legitimately be not present in shadow page tables */ - if ( !paging_mode_enabled(d) ) - mbs |= PFEC_page_present; - - if ( ((regs->error_code & (mbs | mbz)) == mbs) && + if ( guest_kernel_mode(v, regs) && + !(regs->error_code & (PFEC_reserved_bit | PFEC_insn_fetch)) && + (regs->error_code & PFEC_write_access) ) + { + if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && + /* Do not check if access-protection fault since the page may + legitimately be not present in shadow page tables */ + (paging_mode_enabled(d) || + (regs->error_code & PFEC_page_present)) && ptwr_do_page_fault(v, addr, regs) ) return EXCRET_fault_fixed; + +#ifdef __x86_64__ + if ( IS_PRIV(d) && (regs->error_code & PFEC_page_present) && + mmio_ro_do_page_fault(v, addr, regs) ) + return EXCRET_fault_fixed; +#endif } /* For non-external shadowed guests, we fix up both their own @@ -1690,6 +1693,13 @@ static int pci_cfg_ok(struct domain *d, int write, int size) return 0; machine_bdf = (d->arch.pci_cf8 >> 8) & 0xFFFF; + if ( write ) + { + const unsigned long *ro_map = pci_get_ro_map(0); + + if ( ro_map && test_bit(machine_bdf, ro_map) ) + return 0; + } start = d->arch.pci_cf8 & 0xFF; end = start + size - 1; if (xsm_pci_config_permission(d, machine_bdf, start, end, write)) |