aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2007-03-30 12:35:43 -0400
committerTony Luck <tony.luck@intel.com>2007-03-30 12:38:25 -0400
commit6d40fc514c9ea886dc18ddd20043a411816b63d1 (patch)
tree023271ce661d3b19bbaece0e84b04f855b9d11b3
parent2cb22e23a5fcbcac2de49493aa57c7694028a06a (diff)
[IA64] fail mmaps that span areas with incompatible attributes
Example memory map (from HP sx1000 with VGA enabled): 0x00000 - 0x9FFFF supports only WB (cacheable) access 0xA0000 - 0xBFFFF supports only UC (uncacheable) access 0xC0000 - 0xFFFFF supports only WB (cacheable) access Some versions of X map the entire 0x00000-0xFFFFF area at once. With the example above, this mmap must fail because there's no memory attribute that's safe for the entire area. Prior to this patch, we performed the mmap with a UC mapping. When X accessed the WB memory at 0xC0000, it caused an MCA. The crash can happen when mapping 0xC0000 from either /dev/mem or a /sys/.../legacy_mem file. Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r--arch/ia64/kernel/efi.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index f45f91d38cab..78d29b79947d 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -660,6 +660,29 @@ efi_memory_descriptor (unsigned long phys_addr)
660 return NULL; 660 return NULL;
661} 661}
662 662
663static int
664efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
665{
666 void *efi_map_start, *efi_map_end, *p;
667 efi_memory_desc_t *md;
668 u64 efi_desc_size;
669 unsigned long end;
670
671 efi_map_start = __va(ia64_boot_param->efi_memmap);
672 efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
673 efi_desc_size = ia64_boot_param->efi_memdesc_size;
674
675 end = phys_addr + size;
676
677 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
678 md = p;
679
680 if (md->phys_addr < end && efi_md_end(md) > phys_addr)
681 return 1;
682 }
683 return 0;
684}
685
663u32 686u32
664efi_mem_type (unsigned long phys_addr) 687efi_mem_type (unsigned long phys_addr)
665{ 688{
@@ -766,11 +789,28 @@ valid_phys_addr_range (unsigned long phys_addr, unsigned long size)
766int 789int
767valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size) 790valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
768{ 791{
792 unsigned long phys_addr = pfn << PAGE_SHIFT;
793 u64 attr;
794
795 attr = efi_mem_attribute(phys_addr, size);
796
769 /* 797 /*
770 * MMIO regions are often missing from the EFI memory map. 798 * /dev/mem mmap uses normal user pages, so we don't need the entire
771 * We must allow mmap of them for programs like X, so we 799 * granule, but the entire region we're mapping must support the same
772 * currently can't do any useful validation. 800 * attribute.
773 */ 801 */
802 if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
803 return 1;
804
805 /*
806 * Intel firmware doesn't tell us about all the MMIO regions, so
807 * in general we have to allow mmap requests. But if EFI *does*
808 * tell us about anything inside this region, we should deny it.
809 * The user can always map a smaller region to avoid the overlap.
810 */
811 if (efi_memmap_intersects(phys_addr, size))
812 return 0;
813
774 return 1; 814 return 1;
775} 815}
776 816