LCOV - code coverage report
Current view: top level - arch/arm/mm - mmap.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 18 44 40.9 %
Date: 2020-09-30 20:25:40 Functions: 1 4 25.0 %
Branches: 11 30 36.7 %

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

Generated by: LCOV version 1.14