Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/arm26/mm/proc-arm2,3.S | |
3 | * | |
4 | * Copyright (C) 1997-1999 Russell King | |
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 | * MMU functions for ARM2,3 | |
11 | * | |
12 | * These are the low level assembler for performing cache | |
13 | * and memory functions on ARM2, ARM250 and ARM3 processors. | |
14 | */ | |
15 | #include <linux/linkage.h> | |
16 | #include <asm/assembler.h> | |
47003497 | 17 | #include <asm/asm-offsets.h> |
1da177e4 LT |
18 | #include <asm/procinfo.h> |
19 | #include <asm/ptrace.h> | |
20 | ||
21 | /* | |
22 | * MEMC workhorse code. It's both a horse which things it's a pig. | |
23 | */ | |
24 | /* | |
25 | * Function: cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long addr) | |
26 | * Params : pgd Page tables/MEMC mapping | |
27 | * : phys_pte physical address, or PTE | |
28 | * : addr virtual address | |
29 | */ | |
30 | ENTRY(cpu_memc_update_entry) | |
31 | tst r1, #PAGE_PRESENT @ is the page present | |
32 | orreq r1, r1, #PAGE_OLD | PAGE_CLEAN | |
33 | moveq r2, #0x01f00000 | |
34 | mov r3, r1, lsr #13 @ convert to physical page nr | |
35 | and r3, r3, #0x3fc | |
36 | adr ip, memc_phys_table_32 | |
37 | ldr r3, [ip, r3] | |
38 | tst r1, #PAGE_OLD | PAGE_NOT_USER | |
39 | biceq r3, r3, #0x200 | |
40 | tsteq r1, #PAGE_READONLY | PAGE_CLEAN | |
41 | biceq r3, r3, #0x300 | |
42 | mov r2, r2, lsr #15 @ virtual -> nr | |
43 | orr r3, r3, r2, lsl #15 | |
44 | and r2, r2, #0x300 | |
45 | orr r3, r3, r2, lsl #2 | |
46 | and r2, r3, #255 | |
47 | sub r0, r0, #256 * 4 | |
48 | str r3, [r0, r2, lsl #2] | |
49 | strb r3, [r3] | |
50 | movs pc, lr | |
51 | /* | |
52 | * Params : r0 = preserved | |
53 | * : r1 = memc table base (preserved) | |
54 | * : r2 = page table entry | |
55 | * : r3 = preserved | |
56 | * : r4 = unused | |
57 | * : r5 = memc physical address translation table | |
58 | * : ip = virtual address (preserved) | |
59 | */ | |
60 | update_pte: | |
61 | mov r4, r2, lsr #13 | |
62 | and r4, r4, #0x3fc | |
63 | ldr r4, [r5, r4] @ covert to MEMC page | |
64 | ||
65 | tst r2, #PAGE_OLD | PAGE_NOT_USER @ check for MEMC read | |
66 | biceq r4, r4, #0x200 | |
67 | tsteq r2, #PAGE_READONLY | PAGE_CLEAN @ check for MEMC write | |
68 | biceq r4, r4, #0x300 | |
69 | ||
70 | orr r4, r4, ip | |
71 | and r2, ip, #0x01800000 | |
72 | orr r4, r4, r2, lsr #13 | |
73 | ||
74 | and r2, r4, #255 | |
75 | str r4, [r1, r2, lsl #2] | |
76 | movs pc, lr | |
77 | ||
78 | /* | |
79 | * Params : r0 = preserved | |
80 | * : r1 = memc table base (preserved) | |
81 | * : r2 = page table base | |
82 | * : r3 = preserved | |
83 | * : r4 = unused | |
84 | * : r5 = memc physical address translation table | |
85 | * : ip = virtual address (updated) | |
86 | */ | |
87 | update_pte_table: | |
88 | stmfd sp!, {r0, lr} | |
89 | bic r0, r2, #3 | |
90 | 1: ldr r2, [r0], #4 @ get entry | |
91 | tst r2, #PAGE_PRESENT @ page present | |
92 | blne update_pte @ process pte | |
93 | add ip, ip, #32768 @ increment virt addr | |
94 | ldr r2, [r0], #4 @ get entry | |
95 | tst r2, #PAGE_PRESENT @ page present | |
96 | blne update_pte @ process pte | |
97 | add ip, ip, #32768 @ increment virt addr | |
98 | ldr r2, [r0], #4 @ get entry | |
99 | tst r2, #PAGE_PRESENT @ page present | |
100 | blne update_pte @ process pte | |
101 | add ip, ip, #32768 @ increment virt addr | |
102 | ldr r2, [r0], #4 @ get entry | |
103 | tst r2, #PAGE_PRESENT @ page present | |
104 | blne update_pte @ process pte | |
105 | add ip, ip, #32768 @ increment virt addr | |
106 | tst ip, #32768 * 31 @ finished? | |
107 | bne 1b | |
108 | ldmfd sp!, {r0, pc}^ | |
109 | ||
110 | /* | |
111 | * Function: cpu_memc_update_all(pgd_t *pgd) | |
112 | * Params : pgd Page tables/MEMC mapping | |
113 | * Notes : this is optimised for 32k pages | |
114 | */ | |
115 | ENTRY(cpu_memc_update_all) | |
116 | stmfd sp!, {r4, r5, lr} | |
117 | bl clear_tables | |
118 | sub r1, r0, #256 * 4 @ start of MEMC tables | |
119 | adr r5, memc_phys_table_32 @ Convert to logical page number | |
120 | mov ip, #0 @ virtual address | |
121 | 1: ldmia r0!, {r2, r3} @ load two pgd entries | |
122 | tst r2, #PAGE_PRESENT @ is pgd entry present? | |
123 | addeq ip, ip, #1048576 @FIXME - PAGE_PRESENT is for PTEs technically... | |
124 | blne update_pte_table | |
125 | mov r2, r3 | |
126 | tst r2, #PAGE_PRESENT @ is pgd entry present? | |
127 | addeq ip, ip, #1048576 | |
128 | blne update_pte_table | |
129 | teq ip, #32 * 1048576 | |
130 | bne 1b | |
131 | ldmfd sp!, {r4, r5, pc}^ | |
132 | ||
133 | /* | |
134 | * Build the table to map from physical page number to memc page number | |
135 | */ | |
136 | .type memc_phys_table_32, #object | |
137 | memc_phys_table_32: | |
138 | .irp b7, 0x00, 0x80 | |
139 | .irp b6, 0x00, 0x02 | |
140 | .irp b5, 0x00, 0x04 | |
141 | .irp b4, 0x00, 0x01 | |
142 | ||
143 | .irp b3, 0x00, 0x40 | |
144 | .irp b2, 0x00, 0x20 | |
145 | .irp b1, 0x00, 0x10 | |
146 | .irp b0, 0x00, 0x08 | |
147 | .long 0x03800300 + \b7 + \b6 + \b5 + \b4 + \b3 + \b2 + \b1 + \b0 | |
148 | .endr | |
149 | .endr | |
150 | .endr | |
151 | .endr | |
152 | ||
153 | .endr | |
154 | .endr | |
155 | .endr | |
156 | .endr | |
157 | .size memc_phys_table_32, . - memc_phys_table_32 | |
158 | ||
159 | /* | |
160 | * helper for cpu_memc_update_all, this clears out all | |
161 | * mappings, setting them close to the top of memory, | |
162 | * and inaccessible (0x01f00000). | |
163 | * Params : r0 = page table pointer | |
164 | */ | |
165 | clear_tables: ldr r1, _arm3_set_pgd - 4 | |
166 | ldr r2, [r1] | |
167 | sub r1, r0, #256 * 4 @ start of MEMC tables | |
168 | add r2, r1, r2, lsl #2 @ end of tables | |
169 | mov r3, #0x03f00000 @ Default mapping (null mapping) | |
170 | orr r3, r3, #0x00000f00 | |
171 | orr r4, r3, #1 | |
172 | orr r5, r3, #2 | |
173 | orr ip, r3, #3 | |
174 | 1: stmia r1!, {r3, r4, r5, ip} | |
175 | add r3, r3, #4 | |
176 | add r4, r4, #4 | |
177 | add r5, r5, #4 | |
178 | add ip, ip, #4 | |
179 | stmia r1!, {r3, r4, r5, ip} | |
180 | add r3, r3, #4 | |
181 | add r4, r4, #4 | |
182 | add r5, r5, #4 | |
183 | add ip, ip, #4 | |
184 | teq r1, r2 | |
185 | bne 1b | |
186 | mov pc, lr | |
187 | ||
188 | /* | |
189 | * Function: *_set_pgd(pgd_t *pgd) | |
190 | * Params : pgd New page tables/MEMC mapping | |
191 | * Purpose : update MEMC hardware with new mapping | |
192 | */ | |
193 | .word page_nr @ extern - declared in mm-memc.c | |
194 | _arm3_set_pgd: mcr p15, 0, r1, c1, c0, 0 @ flush cache | |
195 | _arm2_set_pgd: stmfd sp!, {lr} | |
196 | ldr r1, _arm3_set_pgd - 4 | |
197 | ldr r2, [r1] | |
198 | sub r0, r0, #256 * 4 @ start of MEMC tables | |
199 | add r1, r0, r2, lsl #2 @ end of tables | |
200 | 1: ldmia r0!, {r2, r3, ip, lr} | |
201 | strb r2, [r2] | |
202 | strb r3, [r3] | |
203 | strb ip, [ip] | |
204 | strb lr, [lr] | |
205 | ldmia r0!, {r2, r3, ip, lr} | |
206 | strb r2, [r2] | |
207 | strb r3, [r3] | |
208 | strb ip, [ip] | |
209 | strb lr, [lr] | |
210 | teq r0, r1 | |
211 | bne 1b | |
212 | ldmfd sp!, {pc}^ | |
213 | ||
214 | /* | |
215 | * Function: *_proc_init (void) | |
216 | * Purpose : Initialise the cache control registers | |
217 | */ | |
218 | _arm3_proc_init: | |
219 | mov r0, #0x001f0000 | |
220 | orr r0, r0, #0x0000ff00 | |
221 | orr r0, r0, #0x000000ff | |
222 | mcr p15, 0, r0, c3, c0 @ ARM3 Cacheable | |
223 | mcr p15, 0, r0, c4, c0 @ ARM3 Updateable | |
224 | mov r0, #0 | |
225 | mcr p15, 0, r0, c5, c0 @ ARM3 Disruptive | |
226 | mcr p15, 0, r0, c1, c0 @ ARM3 Flush | |
227 | mov r0, #3 | |
228 | mcr p15, 0, r0, c2, c0 @ ARM3 Control | |
229 | _arm2_proc_init: | |
230 | movs pc, lr | |
231 | ||
232 | /* | |
233 | * Function: *_proc_fin (void) | |
234 | * Purpose : Finalise processor (disable caches) | |
235 | */ | |
236 | _arm3_proc_fin: mov r0, #2 | |
237 | mcr p15, 0, r0, c2, c0 | |
238 | _arm2_proc_fin: orrs pc, lr, #PSR_I_BIT|PSR_F_BIT | |
239 | ||
240 | /* | |
241 | * Function: *_xchg_1 (int new, volatile void *ptr) | |
242 | * Params : new New value to store at... | |
243 | * : ptr pointer to byte-wide location | |
244 | * Purpose : Performs an exchange operation | |
245 | * Returns : Original byte data at 'ptr' | |
246 | */ | |
247 | _arm2_xchg_1: mov r2, pc | |
248 | orr r2, r2, #PSR_I_BIT | |
249 | teqp r2, #0 | |
250 | ldrb r2, [r1] | |
251 | strb r0, [r1] | |
252 | mov r0, r2 | |
253 | movs pc, lr | |
254 | ||
255 | _arm3_xchg_1: swpb r0, r0, [r1] | |
256 | movs pc, lr | |
257 | ||
258 | /* | |
259 | * Function: *_xchg_4 (int new, volatile void *ptr) | |
260 | * Params : new New value to store at... | |
261 | * : ptr pointer to word-wide location | |
262 | * Purpose : Performs an exchange operation | |
263 | * Returns : Original word data at 'ptr' | |
264 | */ | |
265 | _arm2_xchg_4: mov r2, pc | |
266 | orr r2, r2, #PSR_I_BIT | |
267 | teqp r2, #0 | |
268 | ldr r2, [r1] | |
269 | str r0, [r1] | |
270 | mov r0, r2 | |
271 | movs pc, lr | |
272 | ||
273 | _arm3_xchg_4: swp r0, r0, [r1] | |
274 | movs pc, lr | |
275 | ||
276 | _arm2_3_check_bugs: | |
277 | bics pc, lr, #PSR_F_BIT @ Clear FIQ disable bit | |
278 | ||
279 | armvlsi_name: .asciz "ARM/VLSI" | |
280 | _arm2_name: .asciz "ARM 2" | |
281 | _arm250_name: .asciz "ARM 250" | |
282 | _arm3_name: .asciz "ARM 3" | |
283 | ||
284 | .section ".init.text", #alloc, #execinstr | |
285 | /* | |
286 | * Purpose : Function pointers used to access above functions - all calls | |
287 | * come through these | |
288 | */ | |
289 | .globl arm2_processor_functions | |
290 | arm2_processor_functions: | |
291 | .word _arm2_3_check_bugs | |
292 | .word _arm2_proc_init | |
293 | .word _arm2_proc_fin | |
294 | .word _arm2_set_pgd | |
295 | .word _arm2_xchg_1 | |
296 | .word _arm2_xchg_4 | |
297 | ||
298 | cpu_arm2_info: | |
299 | .long armvlsi_name | |
300 | .long _arm2_name | |
301 | ||
302 | .globl arm250_processor_functions | |
303 | arm250_processor_functions: | |
304 | .word _arm2_3_check_bugs | |
305 | .word _arm2_proc_init | |
306 | .word _arm2_proc_fin | |
307 | .word _arm2_set_pgd | |
308 | .word _arm3_xchg_1 | |
309 | .word _arm3_xchg_4 | |
310 | ||
311 | cpu_arm250_info: | |
312 | .long armvlsi_name | |
313 | .long _arm250_name | |
314 | ||
315 | .globl arm3_processor_functions | |
316 | arm3_processor_functions: | |
317 | .word _arm2_3_check_bugs | |
318 | .word _arm3_proc_init | |
319 | .word _arm3_proc_fin | |
320 | .word _arm3_set_pgd | |
321 | .word _arm3_xchg_1 | |
322 | .word _arm3_xchg_4 | |
323 | ||
324 | cpu_arm3_info: | |
325 | .long armvlsi_name | |
326 | .long _arm3_name | |
327 | ||
328 | arm2_arch_name: .asciz "armv1" | |
329 | arm3_arch_name: .asciz "armv2" | |
330 | arm2_elf_name: .asciz "v1" | |
331 | arm3_elf_name: .asciz "v2" | |
332 | .align | |
333 | ||
334 | .section ".proc.info", #alloc, #execinstr | |
335 | ||
336 | .long 0x41560200 | |
337 | .long 0xfffffff0 | |
338 | .long arm2_arch_name | |
339 | .long arm2_elf_name | |
340 | .long 0 | |
341 | .long cpu_arm2_info | |
342 | .long arm2_processor_functions | |
343 | ||
344 | .long 0x41560250 | |
345 | .long 0xfffffff0 | |
346 | .long arm3_arch_name | |
347 | .long arm3_elf_name | |
348 | .long 0 | |
349 | .long cpu_arm250_info | |
350 | .long arm250_processor_functions | |
351 | ||
352 | .long 0x41560300 | |
353 | .long 0xfffffff0 | |
354 | .long arm3_arch_name | |
355 | .long arm3_elf_name | |
356 | .long 0 | |
357 | .long cpu_arm3_info | |
358 | .long arm3_processor_functions | |
359 |