hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2011 Wind River Systems,
 *   written by Ralf Baechle <ralf@linux-mips.org>
 */
#include <linux/compiler.h>
#include <linux/elf-randomize.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/export.h>
#include <linux/personality.h>
#include <linux/random.h>
#include <linux/sched/signal.h>
#include <linux/sched/mm.h>
 
unsigned long shm_align_mask = PAGE_SIZE - 1;    /* Sane caches */
EXPORT_SYMBOL(shm_align_mask);
 
#define COLOUR_ALIGN(addr, pgoff)                \
   ((((addr) + shm_align_mask) & ~shm_align_mask) +    \
    (((pgoff) << PAGE_SHIFT) & shm_align_mask))
 
enum mmap_allocation_direction {UP, DOWN};
 
static unsigned long arch_get_unmapped_area_common(struct file *filp,
   unsigned long addr0, unsigned long len, unsigned long pgoff,
   unsigned long flags, enum mmap_allocation_direction dir)
{
   struct mm_struct *mm = current->mm;
   struct vm_area_struct *vma;
   unsigned long addr = addr0;
   int do_color_align;
   struct vm_unmapped_area_info info;
 
   if (unlikely(len > TASK_SIZE))
       return -ENOMEM;
 
   if (flags & MAP_FIXED) {
       /* Even MAP_FIXED mappings must reside within TASK_SIZE */
       if (TASK_SIZE - len < addr)
           return -EINVAL;
 
       /*
        * We do not accept a shared mapping if it would violate
        * cache aliasing constraints.
        */
       if ((flags & MAP_SHARED) &&
           ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
           return -EINVAL;
       return addr;
   }
 
   do_color_align = 0;
   if (filp || (flags & MAP_SHARED))
       do_color_align = 1;
 
   /* requesting a specific address */
   if (addr) {
       if (do_color_align)
           addr = COLOUR_ALIGN(addr, pgoff);
       else
           addr = PAGE_ALIGN(addr);
 
       vma = find_vma(mm, addr);
       if (TASK_SIZE - len >= addr &&
           (!vma || addr + len <= vm_start_gap(vma)))
           return addr;
   }
 
   info.length = len;
   info.align_mask = do_color_align ? (PAGE_MASK & shm_align_mask) : 0;
   info.align_offset = pgoff << PAGE_SHIFT;
 
   if (dir == DOWN) {
       info.flags = VM_UNMAPPED_AREA_TOPDOWN;
       info.low_limit = PAGE_SIZE;
       info.high_limit = mm->mmap_base;
       addr = vm_unmapped_area(&info);
 
       if (!(addr & ~PAGE_MASK))
           return addr;
 
       /*
        * A failed mmap() very likely causes application failure,
        * so fall back to the bottom-up function here. This scenario
        * can happen with large stack limits and large mmap()
        * allocations.
        */
   }
 
   info.flags = 0;
   info.low_limit = mm->mmap_base;
   info.high_limit = TASK_SIZE;
   return vm_unmapped_area(&info);
}
 
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0,
   unsigned long len, unsigned long pgoff, unsigned long flags)
{
   return arch_get_unmapped_area_common(filp,
           addr0, len, pgoff, flags, UP);
}
 
/*
 * There is no need to export this but sched.h declares the function as
 * extern so making it static here results in an error.
 */
unsigned long arch_get_unmapped_area_topdown(struct file *filp,
   unsigned long addr0, unsigned long len, unsigned long pgoff,
   unsigned long flags)
{
   return arch_get_unmapped_area_common(filp,
           addr0, len, pgoff, flags, DOWN);
}
 
bool __virt_addr_valid(const volatile void *kaddr)
{
   unsigned long vaddr = (unsigned long)kaddr;
 
   if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE))
       return false;
 
   return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
}
EXPORT_SYMBOL_GPL(__virt_addr_valid);