return NULL;
 }
 
+static int
+efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
+{
+       void *efi_map_start, *efi_map_end, *p;
+       efi_memory_desc_t *md;
+       u64 efi_desc_size;
+       unsigned long end;
+
+       efi_map_start = __va(ia64_boot_param->efi_memmap);
+       efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+       efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+       end = phys_addr + size;
+
+       for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+               md = p;
+
+               if (md->phys_addr < end && efi_md_end(md) > phys_addr)
+                       return 1;
+       }
+       return 0;
+}
+
 u32
 efi_mem_type (unsigned long phys_addr)
 {
 int
 valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
 {
+       unsigned long phys_addr = pfn << PAGE_SHIFT;
+       u64 attr;
+
+       attr = efi_mem_attribute(phys_addr, size);
+
        /*
-        * MMIO regions are often missing from the EFI memory map.
-        * We must allow mmap of them for programs like X, so we
-        * currently can't do any useful validation.
+        * /dev/mem mmap uses normal user pages, so we don't need the entire
+        * granule, but the entire region we're mapping must support the same
+        * attribute.
         */
+       if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
+               return 1;
+
+       /*
+        * Intel firmware doesn't tell us about all the MMIO regions, so
+        * in general we have to allow mmap requests.  But if EFI *does*
+        * tell us about anything inside this region, we should deny it.
+        * The user can always map a smaller region to avoid the overlap.
+        */
+       if (efi_memmap_intersects(phys_addr, size))
+               return 0;
+
        return 1;
 }