1/* 2 * arch/sh/mm/mmap.c 3 * 4 * Copyright (C) 2008 - 2009 Paul Mundt 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 */ 10#include <linux/io.h> 11#include <linux/mm.h> 12#include <linux/mman.h> 13#include <linux/module.h> 14#include <asm/page.h> 15#include <asm/processor.h> 16 17unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ 18EXPORT_SYMBOL(shm_align_mask); 19 20#ifdef CONFIG_MMU 21/* 22 * To avoid cache aliases, we map the shared page with same color. 23 */ 24static inline unsigned long COLOUR_ALIGN(unsigned long addr, 25 unsigned long pgoff) 26{ 27 unsigned long base = (addr + shm_align_mask) & ~shm_align_mask; 28 unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask; 29 30 return base + off; 31} 32 33unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, 34 unsigned long len, unsigned long pgoff, unsigned long flags) 35{ 36 struct mm_struct *mm = current->mm; 37 struct vm_area_struct *vma; 38 int do_colour_align; 39 struct vm_unmapped_area_info info; 40 41 if (flags & MAP_FIXED) { 42 /* We do not accept a shared mapping if it would violate 43 * cache aliasing constraints. 44 */ 45 if ((flags & MAP_SHARED) && 46 ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) 47 return -EINVAL; 48 return addr; 49 } 50 51 if (unlikely(len > TASK_SIZE)) 52 return -ENOMEM; 53 54 do_colour_align = 0; 55 if (filp || (flags & MAP_SHARED)) 56 do_colour_align = 1; 57 58 if (addr) { 59 if (do_colour_align) 60 addr = COLOUR_ALIGN(addr, pgoff); 61 else 62 addr = PAGE_ALIGN(addr); 63 64 vma = find_vma(mm, addr); 65 if (TASK_SIZE - len >= addr && 66 (!vma || addr + len <= vma->vm_start)) 67 return addr; 68 } 69 70 info.flags = 0; 71 info.length = len; 72 info.low_limit = TASK_UNMAPPED_BASE; 73 info.high_limit = TASK_SIZE; 74 info.align_mask = do_colour_align ? (PAGE_MASK & shm_align_mask) : 0; 75 info.align_offset = pgoff << PAGE_SHIFT; 76 return vm_unmapped_area(&info); 77} 78 79unsigned long 80arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, 81 const unsigned long len, const unsigned long pgoff, 82 const unsigned long flags) 83{ 84 struct vm_area_struct *vma; 85 struct mm_struct *mm = current->mm; 86 unsigned long addr = addr0; 87 int do_colour_align; 88 struct vm_unmapped_area_info info; 89 90 if (flags & MAP_FIXED) { 91 /* We do not accept a shared mapping if it would violate 92 * cache aliasing constraints. 93 */ 94 if ((flags & MAP_SHARED) && 95 ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) 96 return -EINVAL; 97 return addr; 98 } 99 100 if (unlikely(len > TASK_SIZE)) 101 return -ENOMEM; 102 103 do_colour_align = 0; 104 if (filp || (flags & MAP_SHARED)) 105 do_colour_align = 1; 106 107 /* requesting a specific address */ 108 if (addr) { 109 if (do_colour_align) 110 addr = COLOUR_ALIGN(addr, pgoff); 111 else 112 addr = PAGE_ALIGN(addr); 113 114 vma = find_vma(mm, addr); 115 if (TASK_SIZE - len >= addr && 116 (!vma || addr + len <= vma->vm_start)) 117 return addr; 118 } 119 120 info.flags = VM_UNMAPPED_AREA_TOPDOWN; 121 info.length = len; 122 info.low_limit = PAGE_SIZE; 123 info.high_limit = mm->mmap_base; 124 info.align_mask = do_colour_align ? (PAGE_MASK & shm_align_mask) : 0; 125 info.align_offset = pgoff << PAGE_SHIFT; 126 addr = vm_unmapped_area(&info); 127 128 /* 129 * A failed mmap() very likely causes application failure, 130 * so fall back to the bottom-up function here. This scenario 131 * can happen with large stack limits and large mmap() 132 * allocations. 133 */ 134 if (addr & ~PAGE_MASK) { 135 VM_BUG_ON(addr != -ENOMEM); 136 info.flags = 0; 137 info.low_limit = TASK_UNMAPPED_BASE; 138 info.high_limit = TASK_SIZE; 139 addr = vm_unmapped_area(&info); 140 } 141 142 return addr; 143} 144#endif /* CONFIG_MMU */ 145 146/* 147 * You really shouldn't be using read() or write() on /dev/mem. This 148 * might go away in the future. 149 */ 150int valid_phys_addr_range(phys_addr_t addr, size_t count) 151{ 152 if (addr < __MEMORY_START) 153 return 0; 154 if (addr + count > __pa(high_memory)) 155 return 0; 156 157 return 1; 158} 159 160int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) 161{ 162 return 1; 163} 164