Commit | Line | Data |
---|---|---|
013de2d6 GR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | |
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/random.h> | |
10 | #include <linux/io.h> | |
11 | ||
12 | unsigned long shm_align_mask = (0x4000 >> 1) - 1; /* Sane caches */ | |
13 | ||
14 | #define COLOUR_ALIGN(addr, pgoff) \ | |
15 | ((((addr) + shm_align_mask) & ~shm_align_mask) + \ | |
16 | (((pgoff) << PAGE_SHIFT) & shm_align_mask)) | |
17 | ||
18 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | |
19 | unsigned long len, unsigned long pgoff, unsigned long flags) | |
20 | { | |
21 | struct vm_area_struct *vmm; | |
22 | int do_color_align; | |
23 | ||
24 | if (flags & MAP_FIXED) { | |
25 | /* | |
26 | * We do not accept a shared mapping if it would violate | |
27 | * cache aliasing constraints. | |
28 | */ | |
29 | if ((flags & MAP_SHARED) && | |
30 | ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) | |
31 | return -EINVAL; | |
32 | return addr; | |
33 | } | |
34 | ||
35 | if (len > TASK_SIZE) | |
36 | return -ENOMEM; | |
37 | do_color_align = 0; | |
38 | if (filp || (flags & MAP_SHARED)) | |
39 | do_color_align = 1; | |
40 | if (addr) { | |
41 | if (do_color_align) | |
42 | addr = COLOUR_ALIGN(addr, pgoff); | |
43 | else | |
44 | addr = PAGE_ALIGN(addr); | |
45 | vmm = find_vma(current->mm, addr); | |
46 | if (TASK_SIZE - len >= addr && | |
47 | (!vmm || addr + len <= vmm->vm_start)) | |
48 | return addr; | |
49 | } | |
50 | addr = TASK_UNMAPPED_BASE; | |
51 | if (do_color_align) | |
52 | addr = COLOUR_ALIGN(addr, pgoff); | |
53 | else | |
54 | addr = PAGE_ALIGN(addr); | |
55 | ||
56 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { | |
57 | /* At this point: (!vmm || addr < vmm->vm_end). */ | |
58 | if (TASK_SIZE - len < addr) | |
59 | return -ENOMEM; | |
60 | if (!vmm || addr + len <= vmm->vm_start) | |
61 | return addr; | |
62 | addr = vmm->vm_end; | |
63 | if (do_color_align) | |
64 | addr = COLOUR_ALIGN(addr, pgoff); | |
65 | } | |
66 | } |