]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/cpufunc_asm_armv5_ec.S
MFH
[FreeBSD/FreeBSD.git] / sys / arm / arm / cpufunc_asm_armv5_ec.S
1 /*      $NetBSD: cpufunc_asm_armv5_ec.S,v 1.1 2007/01/06 00:50:54 christos Exp $        */
2
3 /*
4  * Copyright (c) 2002, 2005 ARM Limited
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the company may not be used to endorse or promote
16  *    products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * ARMv5 assembly functions for manipulating caches.
32  * These routines can be used by any core that supports both the set/index
33  * operations and the test and clean operations for efficiently cleaning the
34  * entire DCache.  If a core does not have the test and clean operations, but
35  * does have the set/index operations, use the routines in cpufunc_asm_armv5.S.
36  * This source was derived from that file.
37  */
38
39 #include <machine/asm.h>
40 __FBSDID("$FreeBSD$");
41
42 #ifndef ELF_TRAMPOLINE
43 /*
44  * Functions to set the MMU Translation Table Base register
45  *
46  * We need to clean and flush the cache as it uses virtual
47  * addresses that are about to change.
48  */
49 ENTRY(armv5_ec_setttb)
50         /*
51          * Some other ARM ports save registers on the stack, call the
52          * idcache_wbinv_all function and then restore the registers from the
53          * stack before setting the TTB.  I observed that this caused a
54          * problem when the old and new translation table entries' buffering
55          * bits were different.  If I saved the registers in other registers
56          * or invalidated the caches when I returned from idcache_wbinv_all,
57          * it worked fine.  If not, I ended up executing at an invalid PC.
58          * For armv5_ec_settb, the idcache_wbinv_all is simple enough, I just
59          * do it directly and entirely avoid the problem.
60          */
61         mcr     p15, 0, r0, c7, c5, 0   /* Invalidate ICache */
62 1:      mrc     p15, 0, APSR_nzcv, c7, c14, 3   /* Test, clean and invalidate DCache */
63         bne     1b                      /* More to do? */
64         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
65
66         mcr     p15, 0, r0, c2, c0, 0   /* load new TTB */
67
68         mcr     p15, 0, r0, c8, c7, 0   /* invalidate I+D TLBs */
69         RET
70 END(armv5_ec_setttb)
71
72 /*
73  * Cache operations.  For the entire cache we use the enhanced cache
74  * operations.
75  */
76
77 ENTRY_NP(armv5_ec_icache_sync_range)
78         ldr     ip, .Larmv5_ec_line_size
79         cmp     r1, #0x4000
80         bcs     .Larmv5_ec_icache_sync_all
81         ldr     ip, [ip]
82         sub     r1, r1, #1              /* Don't overrun */
83         sub     r3, ip, #1
84         and     r2, r0, r3
85         add     r1, r1, r2
86         bic     r0, r0, r3
87 1:
88         mcr     p15, 0, r0, c7, c5, 1   /* Invalidate I cache SE with VA */
89         mcr     p15, 0, r0, c7, c10, 1  /* Clean D cache SE with VA */
90         add     r0, r0, ip
91         subs    r1, r1, ip
92         bpl     1b
93         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
94         RET
95
96 .Larmv5_ec_icache_sync_all:
97         /*
98          * We assume that the code here can never be out of sync with the
99          * dcache, so that we can safely flush the Icache and fall through
100          * into the Dcache cleaning code.
101          */
102         mcr     p15, 0, r0, c7, c5, 0   /* Flush I cache */
103         /* Fall through to clean Dcache. */
104
105 .Larmv5_ec_dcache_wb:
106 1:
107         mrc     p15, 0, APSR_nzcv, c7, c10, 3   /* Test and clean (don't invalidate) */
108         bne     1b                      /* More to do? */
109         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
110         RET
111 END(armv5_ec_icache_sync_range)
112
113 .Larmv5_ec_line_size:
114         .word   _C_LABEL(arm_pdcache_line_size)
115
116 ENTRY(armv5_ec_dcache_wb_range)
117         ldr     ip, .Larmv5_ec_line_size
118         cmp     r1, #0x4000
119         bcs     .Larmv5_ec_dcache_wb
120         ldr     ip, [ip]
121         sub     r1, r1, #1              /* Don't overrun */
122         sub     r3, ip, #1
123         and     r2, r0, r3
124         add     r1, r1, r2
125         bic     r0, r0, r3
126 1:
127         mcr     p15, 0, r0, c7, c10, 1  /* Clean D cache SE with VA */
128         add     r0, r0, ip
129         subs    r1, r1, ip
130         bpl     1b
131         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
132         RET
133 END(armv5_ec_dcache_wb_range)
134
135 ENTRY(armv5_ec_dcache_wbinv_range)
136         ldr     ip, .Larmv5_ec_line_size
137         cmp     r1, #0x4000
138         bcs     .Larmv5_ec_dcache_wbinv_all
139         ldr     ip, [ip]
140         sub     r1, r1, #1              /* Don't overrun */
141         sub     r3, ip, #1
142         and     r2, r0, r3
143         add     r1, r1, r2
144         bic     r0, r0, r3
145 1:
146         mcr     p15, 0, r0, c7, c14, 1  /* Purge D cache SE with VA */
147         add     r0, r0, ip
148         subs    r1, r1, ip
149         bpl     1b
150         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
151         RET
152 END(armv5_ec_dcache_wbinv_range)
153
154 /*
155  * Note, we must not invalidate everything.  If the range is too big we
156  * must use wb-inv of the entire cache.
157  */
158 ENTRY(armv5_ec_dcache_inv_range)
159         ldr     ip, .Larmv5_ec_line_size
160         cmp     r1, #0x4000
161         bcs     .Larmv5_ec_dcache_wbinv_all
162         ldr     ip, [ip]
163         sub     r1, r1, #1              /* Don't overrun */
164         sub     r3, ip, #1
165         and     r2, r0, r3
166         add     r1, r1, r2
167         bic     r0, r0, r3
168 1:
169         mcr     p15, 0, r0, c7, c6, 1   /* Invalidate D cache SE with VA */
170         add     r0, r0, ip
171         subs    r1, r1, ip
172         bpl     1b
173         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
174         RET
175 END(armv5_ec_dcache_inv_range)
176
177 ENTRY(armv5_ec_idcache_wbinv_range)
178         ldr     ip, .Larmv5_ec_line_size
179         cmp     r1, #0x4000
180         bcs     .Larmv5_ec_idcache_wbinv_all
181         ldr     ip, [ip]
182         sub     r1, r1, #1              /* Don't overrun */
183         sub     r3, ip, #1
184         and     r2, r0, r3
185         add     r1, r1, r2
186         bic     r0, r0, r3
187 1:
188         mcr     p15, 0, r0, c7, c5, 1   /* Invalidate I cache SE with VA */
189         mcr     p15, 0, r0, c7, c14, 1  /* Purge D cache SE with VA */
190         add     r0, r0, ip
191         subs    r1, r1, ip
192         bpl     1b
193         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
194         RET
195 END(armv5_ec_idcache_wbinv_range)
196 #endif /* !ELF_TRAMPOLINE */
197
198 ENTRY_NP(armv5_ec_idcache_wbinv_all)
199 .Larmv5_ec_idcache_wbinv_all:
200         /*
201          * We assume that the code here can never be out of sync with the
202          * dcache, so that we can safely flush the Icache and fall through
203          * into the Dcache purging code.
204          */
205         mcr     p15, 0, r0, c7, c5, 0   /* Invalidate ICache */
206         /* Fall through to purge Dcache. */
207 END(armv5_ec_idcache_wbinv_all)
208
209 #ifndef ELF_TRAMPOLINE
210 ENTRY(armv5_ec_dcache_wbinv_all)
211 .Larmv5_ec_dcache_wbinv_all:
212 1:      mrc     p15, 0, APSR_nzcv, c7, c14, 3   /* Test, clean and invalidate DCache */
213         bne     1b                      /* More to do? */
214         mcr     p15, 0, r0, c7, c10, 4  /* drain the write buffer */
215         RET
216 END(armv5_ec_dcache_wbinv_all)
217 #endif