]> xenbits.xensource.com Git - people/ssmith/netchannel2-pvops.git/commitdiff
xen/swiotlb: make sure dma address is really local before testing for swiotlb
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Tue, 15 Sep 2009 21:27:30 +0000 (14:27 -0700)
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Tue, 15 Sep 2009 21:27:30 +0000 (14:27 -0700)
When doing DMA on behalf of another domain, we operate on granted pages.
These pages are temporarily mapped into dom0, and don't have a proper
machine-to-phys mapping.  If we blindly perform a m2p mapping then
check the resulting address against the swiotlb range, we may end up
misidentifying the address as needing bouncing, which at best will result
in data corruption for the guest, and could end up corrupting dom0 memory.

To determine whether a page is local, we need to see if the mfn<->pfn
mappings work both ways.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
arch/x86/xen/pci-swiotlb.c

index 8aad35a7a5ba22e2d51f83d7689d45c8943d532f..017304cc6b24f80dbe89d394ea75ece65fb973cf 100644 (file)
@@ -344,8 +344,15 @@ static inline int range_needs_mapping(phys_addr_t paddr, size_t size)
        return swiotlb_force || xen_swiotlb_arch_range_needs_mapping(paddr, size);
 }
 
-static int is_xen_swiotlb_buffer(char *addr)
+static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
 {
+       unsigned long mfn = PFN_DOWN(dma_addr);
+       unsigned long pfn = mfn_to_local_pfn(mfn);
+       char *addr = NULL;
+
+       if (pfn_valid(pfn))
+               addr = __va(pfn << PAGE_SHIFT);
+
        return addr >= xen_io_tlb_start && addr < xen_io_tlb_end;
 }
 
@@ -702,7 +709,7 @@ static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
 
        BUG_ON(dir == DMA_NONE);
 
-       if (is_xen_swiotlb_buffer(dma_addr)) {
+       if (is_xen_swiotlb_buffer(dev_addr)) {
                do_unmap_single(hwdev, dma_addr, size, dir);
                return;
        }
@@ -738,7 +745,7 @@ xen_swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
 
        BUG_ON(dir == DMA_NONE);
 
-       if (is_xen_swiotlb_buffer(dma_addr)) {
+       if (is_xen_swiotlb_buffer(dev_addr)) {
                sync_single(hwdev, dma_addr, size, dir, target);
                return;
        }