LCOV - code coverage report
Current view: top level - arch/arm/mm - mmap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 44 62 71.0 %
Date: 2014-04-16 Functions: 3 6 50.0 %
Branches: 26 46 56.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  linux/arch/arm/mm/mmap.c
       3                 :            :  */
       4                 :            : #include <linux/fs.h>
       5                 :            : #include <linux/mm.h>
       6                 :            : #include <linux/mman.h>
       7                 :            : #include <linux/shm.h>
       8                 :            : #include <linux/sched.h>
       9                 :            : #include <linux/io.h>
      10                 :            : #include <linux/personality.h>
      11                 :            : #include <linux/random.h>
      12                 :            : #include <asm/cachetype.h>
      13                 :            : 
      14                 :            : #define COLOUR_ALIGN(addr,pgoff)                \
      15                 :            :         ((((addr)+SHMLBA-1)&~(SHMLBA-1)) +  \
      16                 :            :          (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
      17                 :            : 
      18                 :            : /* gap between mmap and stack */
      19                 :            : #define MIN_GAP (128*1024*1024UL)
      20                 :            : #define MAX_GAP ((TASK_SIZE)/6*5)
      21                 :            : 
      22                 :            : static int mmap_is_legacy(void)
      23                 :            : {
      24         [ +  + ]:      27240 :         if (current->personality & ADDR_COMPAT_LAYOUT)
      25                 :            :                 return 1;
      26                 :            : 
      27         [ +  + ]:      27234 :         if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
      28                 :            :                 return 1;
      29                 :            : 
      30                 :      26502 :         return sysctl_legacy_va_layout;
      31                 :            : }
      32                 :            : 
      33                 :            : static unsigned long mmap_base(unsigned long rnd)
      34                 :            : {
      35                 :            :         unsigned long gap = rlimit(RLIMIT_STACK);
      36                 :            : 
      37         [ -  + ]:      26509 :         if (gap < MIN_GAP)
      38                 :            :                 gap = MIN_GAP;
      39         [ #  # ]:          0 :         else if (gap > MAX_GAP)
      40                 :            :                 gap = MAX_GAP;
      41                 :            : 
      42                 :      26509 :         return PAGE_ALIGN(TASK_SIZE - gap - rnd);
      43                 :            : }
      44                 :            : 
      45                 :            : /*
      46                 :            :  * We need to ensure that shared mappings are correctly aligned to
      47                 :            :  * avoid aliasing issues with VIPT caches.  We need to ensure that
      48                 :            :  * a specific page of an object is always mapped at a multiple of
      49                 :            :  * SHMLBA bytes.
      50                 :            :  *
      51                 :            :  * We unconditionally provide this function for all cases, however
      52                 :            :  * in the VIVT case, we optimise out the alignment rules.
      53                 :            :  */
      54                 :            : unsigned long
      55                 :          0 : arch_get_unmapped_area(struct file *filp, unsigned long addr,
      56                 :            :                 unsigned long len, unsigned long pgoff, unsigned long flags)
      57                 :            : {
      58                 :      16980 :         struct mm_struct *mm = current->mm;
      59                 :            :         struct vm_area_struct *vma;
      60                 :            :         int do_align = 0;
      61                 :            :         int aliasing = cache_is_vipt_aliasing();
      62                 :            :         struct vm_unmapped_area_info info;
      63                 :            : 
      64                 :            :         /*
      65                 :            :          * We only need to do colour alignment if either the I or D
      66                 :            :          * caches alias.
      67                 :            :          */
      68                 :            :         if (aliasing)
      69                 :            :                 do_align = filp || (flags & MAP_SHARED);
      70                 :            : 
      71                 :            :         /*
      72                 :            :          * We enforce the MAP_FIXED case.
      73                 :            :          */
      74         [ +  + ]:      16980 :         if (flags & MAP_FIXED) {
      75                 :            :                 if (aliasing && flags & MAP_SHARED &&
      76                 :            :                     (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
      77                 :            :                         return -EINVAL;
      78                 :            :                 return addr;
      79                 :            :         }
      80                 :            : 
      81            [ + ]:      11266 :         if (len > TASK_SIZE)
      82                 :            :                 return -ENOMEM;
      83                 :            : 
      84         [ -  + ]:      11267 :         if (addr) {
      85                 :            :                 if (do_align)
      86                 :            :                         addr = COLOUR_ALIGN(addr, pgoff);
      87                 :            :                 else
      88                 :          0 :                         addr = PAGE_ALIGN(addr);
      89                 :            : 
      90                 :          0 :                 vma = find_vma(mm, addr);
      91 [ #  # ][ #  # ]:          0 :                 if (TASK_SIZE - len >= addr &&
      92         [ #  # ]:          0 :                     (!vma || addr + len <= vma->vm_start))
      93                 :            :                         return addr;
      94                 :            :         }
      95                 :            : 
      96                 :      11267 :         info.flags = 0;
      97                 :      11267 :         info.length = len;
      98                 :      11267 :         info.low_limit = mm->mmap_base;
      99                 :      11267 :         info.high_limit = TASK_SIZE;
     100                 :      11267 :         info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
     101                 :      11267 :         info.align_offset = pgoff << PAGE_SHIFT;
     102                 :      11267 :         return vm_unmapped_area(&info);
     103                 :            : }
     104                 :            : 
     105                 :            : unsigned long
     106                 :          0 : arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
     107                 :            :                         const unsigned long len, const unsigned long pgoff,
     108                 :            :                         const unsigned long flags)
     109                 :            : {
     110                 :            :         struct vm_area_struct *vma;
     111                 :    1856444 :         struct mm_struct *mm = current->mm;
     112                 :            :         unsigned long addr = addr0;
     113                 :            :         int do_align = 0;
     114                 :            :         int aliasing = cache_is_vipt_aliasing();
     115                 :            :         struct vm_unmapped_area_info info;
     116                 :            : 
     117                 :            :         /*
     118                 :            :          * We only need to do colour alignment if either the I or D
     119                 :            :          * caches alias.
     120                 :            :          */
     121                 :            :         if (aliasing)
     122                 :            :                 do_align = filp || (flags & MAP_SHARED);
     123                 :            : 
     124                 :            :         /* requested length too big for entire address space */
     125            [ + ]:    1856444 :         if (len > TASK_SIZE)
     126                 :            :                 return -ENOMEM;
     127                 :            : 
     128         [ +  + ]:    1856480 :         if (flags & MAP_FIXED) {
     129                 :            :                 if (aliasing && flags & MAP_SHARED &&
     130                 :            :                     (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
     131                 :            :                         return -EINVAL;
     132                 :            :                 return addr;
     133                 :            :         }
     134                 :            : 
     135                 :            :         /* requesting a specific address */
     136         [ +  + ]:    1608429 :         if (addr) {
     137                 :            :                 if (do_align)
     138                 :            :                         addr = COLOUR_ALIGN(addr, pgoff);
     139                 :            :                 else
     140                 :        134 :                         addr = PAGE_ALIGN(addr);
     141                 :        134 :                 vma = find_vma(mm, addr);
     142 [ +  - ][ +  - ]:        134 :                 if (TASK_SIZE - len >= addr &&
     143         [ +  + ]:        134 :                                 (!vma || addr + len <= vma->vm_start))
     144                 :            :                         return addr;
     145                 :            :         }
     146                 :            : 
     147                 :    1608338 :         info.flags = VM_UNMAPPED_AREA_TOPDOWN;
     148                 :    1608338 :         info.length = len;
     149                 :    1608338 :         info.low_limit = FIRST_USER_ADDRESS;
     150                 :    1608338 :         info.high_limit = mm->mmap_base;
     151                 :    1608338 :         info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
     152                 :    1608338 :         info.align_offset = pgoff << PAGE_SHIFT;
     153                 :            :         addr = vm_unmapped_area(&info);
     154                 :            : 
     155                 :            :         /*
     156                 :            :          * A failed mmap() very likely causes application failure,
     157                 :            :          * so fall back to the bottom-up function here. This scenario
     158                 :            :          * can happen with large stack limits and large mmap()
     159                 :            :          * allocations.
     160                 :            :          */
     161         [ +  + ]:    1608277 :         if (addr & ~PAGE_MASK) {
     162                 :            :                 VM_BUG_ON(addr != -ENOMEM);
     163                 :      23181 :                 info.flags = 0;
     164                 :      23181 :                 info.low_limit = mm->mmap_base;
     165                 :      23181 :                 info.high_limit = TASK_SIZE;
     166                 :            :                 addr = vm_unmapped_area(&info);
     167                 :            :         }
     168                 :            : 
     169                 :    1608286 :         return addr;
     170                 :            : }
     171                 :            : 
     172                 :          0 : void arch_pick_mmap_layout(struct mm_struct *mm)
     173                 :            : {
     174                 :            :         unsigned long random_factor = 0UL;
     175                 :            : 
     176                 :            :         /* 8 bits of randomness in 20 address space bits */
     177 [ +  + ][ +  + ]:      27250 :         if ((current->flags & PF_RANDOMIZE) &&
     178                 :      27244 :             !(current->personality & ADDR_NO_RANDOMIZE))
     179                 :      27243 :                 random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
     180                 :            : 
     181         [ +  + ]:      27240 :         if (mmap_is_legacy()) {
     182                 :        731 :                 mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
     183                 :        731 :                 mm->get_unmapped_area = arch_get_unmapped_area;
     184                 :            :         } else {
     185                 :      26509 :                 mm->mmap_base = mmap_base(random_factor);
     186                 :      26509 :                 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
     187                 :            :         }
     188                 :      27240 : }
     189                 :            : 
     190                 :            : /*
     191                 :            :  * You really shouldn't be using read() or write() on /dev/mem.  This
     192                 :            :  * might go away in the future.
     193                 :            :  */
     194                 :          0 : int valid_phys_addr_range(phys_addr_t addr, size_t size)
     195                 :            : {
     196         [ #  # ]:          0 :         if (addr < PHYS_OFFSET)
     197                 :            :                 return 0;
     198         [ #  # ]:          0 :         if (addr + size > __pa(high_memory - 1) + 1)
     199                 :            :                 return 0;
     200                 :            : 
     201                 :          0 :         return 1;
     202                 :            : }
     203                 :            : 
     204                 :            : /*
     205                 :            :  * Do not allow /dev/mem mappings beyond the supported physical range.
     206                 :            :  */
     207                 :          0 : int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
     208                 :            : {
     209                 :          0 :         return (pfn + (size >> PAGE_SHIFT)) <= (1 + (PHYS_MASK >> PAGE_SHIFT));
     210                 :            : }
     211                 :            : 
     212                 :            : #ifdef CONFIG_STRICT_DEVMEM
     213                 :            : 
     214                 :            : #include <linux/ioport.h>
     215                 :            : 
     216                 :            : /*
     217                 :            :  * devmem_is_allowed() checks to see if /dev/mem access to a certain
     218                 :            :  * address is valid. The argument is a physical page number.
     219                 :            :  * We mimic x86 here by disallowing access to system RAM as well as
     220                 :            :  * device-exclusive MMIO regions. This effectively disable read()/write()
     221                 :            :  * on /dev/mem.
     222                 :            :  */
     223                 :          0 : int devmem_is_allowed(unsigned long pfn)
     224                 :            : {
     225         [ #  # ]:          0 :         if (iomem_is_exclusive(pfn << PAGE_SHIFT))
     226                 :            :                 return 0;
     227         [ #  # ]:          0 :         if (!page_is_ram(pfn))
     228                 :            :                 return 1;
     229                 :          0 :         return 0;
     230                 :            : }
     231                 :            : 
     232                 :            : #endif

Generated by: LCOV version 1.9