Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/arm/mm/copypage-v6.c | |
3 | * | |
4 | * Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
10 | #include <linux/init.h> | |
11 | #include <linux/spinlock.h> | |
12 | #include <linux/mm.h> | |
13 | ||
14 | #include <asm/page.h> | |
15 | #include <asm/pgtable.h> | |
16 | #include <asm/shmparam.h> | |
17 | #include <asm/tlbflush.h> | |
18 | #include <asm/cacheflush.h> | |
19 | ||
1b2e2b73 RK |
20 | #include "mm.h" |
21 | ||
1da177e4 LT |
22 | #if SHMLBA > 16384 |
23 | #error FIX ME | |
24 | #endif | |
25 | ||
26 | #define from_address (0xffff8000) | |
1da177e4 | 27 | #define to_address (0xffffc000) |
1da177e4 | 28 | |
1da177e4 LT |
29 | static DEFINE_SPINLOCK(v6_lock); |
30 | ||
1da177e4 LT |
31 | /* |
32 | * Copy the user page. No aliasing to deal with so we can just | |
33 | * attack the kernel's existing mapping of these pages. | |
34 | */ | |
b4c2803c | 35 | static void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr) |
1da177e4 LT |
36 | { |
37 | copy_page(kto, kfrom); | |
38 | } | |
39 | ||
40 | /* | |
41 | * Clear the user page. No aliasing to deal with so we can just | |
42 | * attack the kernel's existing mapping of this page. | |
43 | */ | |
b4c2803c | 44 | static void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr) |
1da177e4 LT |
45 | { |
46 | clear_page(kaddr); | |
47 | } | |
48 | ||
49 | /* | |
50 | * Copy the page, taking account of the cache colour. | |
51 | */ | |
b4c2803c | 52 | static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr) |
1da177e4 | 53 | { |
b8a9b66f | 54 | unsigned int offset = CACHE_COLOUR(vaddr); |
1da177e4 LT |
55 | unsigned long from, to; |
56 | ||
57 | /* | |
58 | * Discard data in the kernel mapping for the new page. | |
59 | * FIXME: needs this MCRR to be supported. | |
60 | */ | |
61 | __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" | |
62 | : | |
63 | : "r" (kto), | |
64 | "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES) | |
65 | : "cc"); | |
66 | ||
67 | /* | |
68 | * Now copy the page using the same cache colour as the | |
69 | * pages ultimate destination. | |
70 | */ | |
71 | spin_lock(&v6_lock); | |
72 | ||
ad1ae2fe RK |
73 | set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL), 0); |
74 | set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL), 0); | |
1da177e4 LT |
75 | |
76 | from = from_address + (offset << PAGE_SHIFT); | |
77 | to = to_address + (offset << PAGE_SHIFT); | |
78 | ||
79 | flush_tlb_kernel_page(from); | |
80 | flush_tlb_kernel_page(to); | |
81 | ||
82 | copy_page((void *)to, (void *)from); | |
83 | ||
84 | spin_unlock(&v6_lock); | |
85 | } | |
86 | ||
87 | /* | |
88 | * Clear the user page. We need to deal with the aliasing issues, | |
89 | * so remap the kernel page into the same cache colour as the user | |
90 | * page. | |
91 | */ | |
b4c2803c | 92 | static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) |
1da177e4 | 93 | { |
b8a9b66f | 94 | unsigned int offset = CACHE_COLOUR(vaddr); |
1da177e4 LT |
95 | unsigned long to = to_address + (offset << PAGE_SHIFT); |
96 | ||
97 | /* | |
98 | * Discard data in the kernel mapping for the new page | |
99 | * FIXME: needs this MCRR to be supported. | |
100 | */ | |
101 | __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" | |
102 | : | |
103 | : "r" (kaddr), | |
104 | "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES) | |
105 | : "cc"); | |
106 | ||
107 | /* | |
108 | * Now clear the page using the same cache colour as | |
109 | * the pages ultimate destination. | |
110 | */ | |
111 | spin_lock(&v6_lock); | |
112 | ||
ad1ae2fe | 113 | set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL), 0); |
1da177e4 LT |
114 | flush_tlb_kernel_page(to); |
115 | clear_page((void *)to); | |
116 | ||
117 | spin_unlock(&v6_lock); | |
118 | } | |
119 | ||
120 | struct cpu_user_fns v6_user_fns __initdata = { | |
121 | .cpu_clear_user_page = v6_clear_user_page_nonaliasing, | |
122 | .cpu_copy_user_page = v6_copy_user_page_nonaliasing, | |
123 | }; | |
124 | ||
125 | static int __init v6_userpage_init(void) | |
126 | { | |
127 | if (cache_is_vipt_aliasing()) { | |
1da177e4 LT |
128 | cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; |
129 | cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; | |
130 | } | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
08ee4e4c | 135 | core_initcall(v6_userpage_init); |