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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
|
/* $Id: r2300_misc.S,v 1.2 1996/06/29 12:41:08 dm Exp $
* r2300_misc.S: Misc. exception handling code for R3000/R2000.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
*
* Multi-cpu abstraction reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.set mips1
.set noreorder
.align 5
NESTED(r2300_handle_tlbl, PT_SIZE, sp)
.set noat
/* Check whether this is a refill or an invalid exception */
mfc0 k0,CP0_BADVADDR
mfc0 k1,CP0_ENTRYHI
ori k0,0xfff # clear ASID...
xori k0,0xfff # in BadVAddr
andi k1,0xfc0 # get current ASID
or k0,k1 # make new entryhi
mfc0 k1,CP0_ENTRYHI
mtc0 k0,CP0_ENTRYHI
nop # for pipeline
nop
nop
tlbp
nop # for pipeline
nop
mfc0 k0,CP0_INDEX
bgez k0,invalid_tlbl # bad addr in c0_badvaddr
mtc0 k1,CP0_ENTRYHI
/* Damn... The next nop is required on the R4400PC V5.0, but
* I don't know why - at least there is no documented
* reason as for the others :-(
* And I haven't tested it as being necessary on R3000 - PMA.
* (The R3000 pipeline has only 5 stages, so it's probably not
* required -- Ralf)
*/
nop
#ifdef CONF_DEBUG_TLB
/* OK, this is a double fault. Let's see whether this is
* due to an invalid entry in the page_table.
*/
/* used to be dmfc0 */
mfc0 k0,CP0_BADVADDR
/* FIXME: This srl/sll sequence is as it is for the R4xx0,
* and I suspect that it should be different for
* the R[23]000. PMA
* (No, it's the assembler way to do
* k0 = k0 / PAGE_SIZE;
* k0 = k0 * sizeof(pte_t)
* Acutally the R4xx0 code will have to change when
* switching to 64 bit ... -- Ralf)
*/
srl k0,12 # get PFN?
sll k0,2
lui k1,%HI(TLBMAP)
addu k0,k1
lw k1,(k0)
andi k1,(_PAGE_PRESENT|_PAGE_ACCESSED)
bnez k1,reload_pgd_entries
nop
.set noat
SAVE_ALL
.set at
PRINT("Double fault caused by invalid entries in pgd:\n")
mfc0 a1,CP0_BADVADDR
PRINT("Double fault address : %08lx\n")
mfc0 a1,CP0_EPC
PRINT("c0_epc : %08lx\n")
jal show_regs
move a0,sp
jal dump_tlb_nonwired
nop
mfc0 a0,CP0_BADVADDR
jal dump_list_current
nop
.set noat
STI
.set at
PANIC("Corrupted pagedir")
.set noat
reload_pgd_entries:
#endif /* CONF_DEBUG_TLB */
/* Load missing pair of entries from the pgd and return. */
mfc0 k1,CP0_CONTEXT
lw k0,(k1) # Never causes nested exception
mfc0 k1,CP0_EPC # get the return PC
srl k0,12 # Convert to EntryLo format
mtc0 k0,CP0_ENTRYLO0
nop # for pipeline
tlbwr
nop # for pipeline
nop
nop
/* We don't know whether the original access was read or
* write, so return and see what happens...
*/
jr k1
rfe
/* Handle invalid exception
*
* There are two possible causes for an invalid (tlbl)
* exception:
* 1) pages with present bit set but the valid bit clear
* 2) nonexistant pages
* Case one needs fast handling, therefore don't save
* registers yet.
*
* k0 contains c0_index.
*/
invalid_tlbl:
#ifdef CONFIG_TLB_SHUTDOWN
/* Remove entry so we don't need to care later
* For sake of the pipeline the tlbwi insn has been moved down.
* Moving it around is juggling with explosives...
*/
/* FIXME: Why is Ralf setting bit 3 of k1? This may need to
* be changed for R[236]000! PMA
* (The new ENTRYHI value will then point represent a
* inique virtual address outside the 32 bit address
* limit. This is just paranoia to avoid a tlb
* shutdown. This whole part of the routine is probably
* no longer required and can be removed -- Ralf)
*/
lui k1,0x0008
or k0,k1
sll k0,12 # make it EntryHi format
mtc0 k0,CP0_ENTRYHI
mtc0 zero,CP0_ENTRYLO0
#endif
/* Test present bit in entry */
mfc0 k0,CP0_BADVADDR
/* FIXME: This srl/sll sequence is as it is for the R4xx0,
* and I suspect that it should be different for
* the R[23]000. PMA
* (No, it's the assembler way to do
* k0 = k0 / PAGE_SIZE;
* k0 = k0 * sizeof(pte_t)
* Acutally the R4xx0 code will have to change when
* switching to 64 bit ... -- Ralf)
*/
srl k0,12
sll k0,2
#ifdef CONFIG_TLB_SHUTDOWN
tlbwi # do not move!
#endif
lui k1,%HI(TLBMAP)
addu k0,k1
lw k1,(k0)
andi k1,(_PAGE_PRESENT|_PAGE_READ)
xori k1,(_PAGE_PRESENT|_PAGE_READ)
bnez k1,nopage_tlbl
lw k1,(k0)
/* Present and read bits are set -> set valid and accessed bits */
ori k1,(_PAGE_VALID|_PAGE_ACCESSED)
sw k1,(k0)
mfc0 k1,CP0_EPC
nop
jr k1
rfe
/* Page doesn't exist. Lots of work which is less important
* for speed needs to be done, so hand it all over to the
* kernel memory management routines.
*/
nopage_tlbl:
SAVE_ALL
mfc0 a2,CP0_BADVADDR
STI
.set at
/* a0 (struct pt_regs *) regs
* a1 (unsigned long) 0 for read access
* a2 (unsigned long) faulting virtual address
*/
move a0,sp
jal do_page_fault
li a1,0
j ret_from_sys_call
nop
END(r2300_handle_tlbl)
.text
.align 5
NESTED(r2300_handle_tlbs, PT_SIZE, sp)
.set noat
/* It is impossible that is a nested reload exception.
* Therefore this must be a invalid exception.
* Two possible cases:
* 1) Page exists but not dirty.
* 2) Page doesn't exist yet. Hand over to the kernel.
*
* Test whether present bit in entry is set
*/
/* used to be dmfc0 */
mfc0 k0,CP0_BADVADDR
/* FIXME: This srl/sll sequence is as it is for the R4xx0,
* and I suspect that it should be different for
* the R[23]000. PMA
*/
srl k0,12
sll k0,2
lui k1,%HI(TLBMAP)
addu k0,k1
lw k1,(k0)
tlbp # find faulting entry
andi k1,(_PAGE_PRESENT|_PAGE_WRITE)
xori k1,(_PAGE_PRESENT|_PAGE_WRITE)
bnez k1,nopage_tlbs
lw k1,(k0)
/* Present and writable bits set: set accessed and dirty bits. */
ori k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \
_PAGE_VALID|_PAGE_DIRTY)
sw k1,(k0)
/* Now reload the entry into the TLB */
/* FIXME: Why has Ralf set bit 2? Should it be different for
* R[23]000? PMA
* (The ori/xori combination actually _clears_ bit 2.
* This is required for the R4xx0 these CPUs always
* map page pairs; a page pair of 4k pages therfore
* has always an address with bit 2 set to zero. -- Ralf)
*/
ori k0,0x0004
xori k0,0x0004
lw k0,(k0)
srl k0,12
mtc0 k0,CP0_ENTRYLO0
mfc0 k1,CP0_EPC
nop # for pipeline
tlbwi
nop # for pipeline
nop
nop
jr k1
rfe
/* Page doesn't exist. Lots of work which is less important
* for speed needs to be done, so hand it all over to the
* kernel memory management routines.
*/
nopage_tlbs:
nowrite_mod:
#ifdef CONFIG_TLB_SHUTDOWN
/* Remove entry so we don't need to care later */
mfc0 k0,CP0_INDEX
#ifdef CONF_DEBUG_TLB
bgez k0,2f
nop
/* We got a tlbs exception but found no matching entry in
* the tlb. This should never happen. Paranoia makes us
* check it, though.
*/
SAVE_ALL
jal show_regs
move a0,sp
.set at
mfc0 a1,CP0_BADVADDR
PRINT("c0_badvaddr == %08lx\n")
mfc0 a1,CP0_INDEX
PRINT("c0_index == %08x\n")
mfc0 a1,CP0_ENTRYHI
PRINT("c0_entryhi == %08x\n")
.set noat
STI
.set at
PANIC("Tlbs or tlbm exception with no matching entry in tlb")
1:
j 1b
nop
2:
#endif /* CONF_DEBUG_TLB */
/* FIXME: Why is Ralf setting bit 3 of k1? This may need to
* be changed for R[236]000! PMA
* (The new ENTRYHI value will then point represent a
* inique virtual address outside the 32 bit address
* limit. This is just paranoia to avoid a tlb
* shutdown. This whole part of the routine is probably
* no longer required and can be removed -- Ralf)
*/
lui k1,0x0008
or k0,k1
sll k0,12
mtc0 k0,CP0_ENTRYHI
mtc0 zero,CP0_ENTRYLO0
nop # for pipeline
nop # R4000 V2.2 requires 4 NOPs
nop
nop
tlbwi
#endif /* CONFIG_TLB_SHUTDOWN */
.set noat
SAVE_ALL
mfc0 a2,CP0_BADVADDR
STI
.set at
/* a0 (struct pt_regs *) regs
* a1 (unsigned long) 1 for write access
* a2 (unsigned long) faulting virtual address
*/
move a0,sp
jal do_page_fault
li a1,1
j ret_from_sys_call
nop
END(r2300_handle_tlbs)
.align 5
NESTED(r2300_handle_mod, PT_SIZE, sp)
.set noat
/* Two possible cases:
* 1) Page is writable but not dirty -> set dirty and return
* 2) Page is not writable -> call C handler
*/
/* used to be dmfc0 */
mfc0 k0,CP0_BADVADDR
/* FIXME: This srl/sll sequence is as it is for the R4xx0,
* and I suspect that it should be different for
* the R[23]000. PMA
*/
srl k0,12
sll k0,2
lui k1,%HI(TLBMAP)
addu k0,k1
lw k1,(k0)
tlbp # find faulting entry
andi k1,_PAGE_WRITE
beqz k1,nowrite_mod
lw k1,(k0)
/* Present and writable bits set: set accessed and dirty bits. */
ori k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
sw k1,(k0)
/* Now reload the entry into the tlb */
/* FIXME: Why has Ralf set bit 2? Should it be different for
* R[23]000? PMA
* (The ori/xori combination actually _clears_ bit 2.
* This is required for the R4xx0 these CPUs always
* map page pairs; a page pair of 4k pages therfore
* has always an address with bit 2 set to zero. -- Ralf)
*/
ori k0,0x0004
xori k0,0x0004
lw k0,(k0)
srl k0,12
mtc0 k0,CP0_ENTRYLO0
mfc0 k1,CP0_EPC
nop # for pipeline
nop
nop
tlbwi
nop # for pipeline
nop
nop
jr k1
rfe
END(r2300_handle_mod)
.set at
|