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
|
/* $Id: r4k_misc.S,v 1.8 1999/10/09 00:00:58 ralf Exp $
*
* r4k_misc.S: Misc. exception handling code for r4k.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
*
* Multi-cpu abstraction and reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
/**************************************************************************
* 14 Nov, 2000.
* Made support for MIPS32 CPUs.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*************************************************************************/
#include <asm/asm.h>
#include <asm/current.h>
#include <asm/offset.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
#include <asm/fpregdef.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>
#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */
/* ABUSE of CPP macros 101. */
/* After this macro runs, the pte faulted on is
* in register PTE, a ptr into the table in which
* the pte belongs is in PTR.
*/
#ifdef CONFIG_SMP
#define GET_PGD(scratch, ptr) \
mfc0 ptr, CP0_CONTEXT; \
la scratch, current_pgd;\
srl ptr, 23; \
sll ptr, 2; \
addu ptr, scratch, ptr; \
lw ptr, (ptr);
#else
#define GET_PGD(scratch, ptr) \
lw ptr, current_pgd;
#endif
#define LOAD_PTE(pte, ptr) \
GET_PGD(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
srl pte, pte, 22; \
sll pte, pte, 2; \
addu ptr, ptr, pte; \
mfc0 pte, CP0_BADVADDR; \
lw ptr, (ptr); \
srl pte, pte, 10; \
and pte, pte, 0xffc; \
addu ptr, ptr, pte; \
lw pte, (ptr);
/* This places the even/odd pte pair in the page
* table at PTR into ENTRYLO0 and ENTRYLO1 using
* TMP as a scratch register.
*/
#define PTE_RELOAD(ptr, tmp) \
ori ptr, ptr, 0x4; \
xori ptr, ptr, 0x4; \
lw tmp, 4(ptr); \
lw ptr, 0(ptr); \
srl tmp, tmp, 6; \
mtc0 tmp, CP0_ENTRYLO1; \
srl ptr, ptr, 6; \
mtc0 ptr, CP0_ENTRYLO0;
#define DO_FAULT(write) \
.set noat; \
SAVE_ALL; \
mfc0 a2, CP0_BADVADDR; \
STI; \
.set at; \
move a0, sp; \
jal do_page_fault; \
li a1, write; \
j ret_from_sys_call; \
nop; \
.set noat;
/* Check is PTE is present, if not then jump to LABEL.
* PTR points to the page table where this PTE is located,
* when the macro is done executing PTE will be restored
* with it's original value.
*/
#define PTE_PRESENT(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
bnez pte, label; \
lw pte, (ptr);
/* Make PTE valid, store result in PTR. */
#define PTE_MAKEVALID(pte, ptr) \
ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
sw pte, (ptr);
/* Check if PTE can be written to, if not branch to LABEL.
* Regardless restore PTE with value from PTR when done.
*/
#define PTE_WRITABLE(pte, ptr, label) \
andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
bnez pte, label; \
lw pte, (ptr);
/* Make PTE writable, update software status bits as well,
* then store at PTR.
*/
#define PTE_MAKEWRITE(pte, ptr) \
ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
_PAGE_VALID | _PAGE_DIRTY); \
sw pte, (ptr);
.set noreorder
/*
* From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
* 2. A timing hazard exists for the TLBP instruction.
*
* stalling_instruction
* TLBP
*
* The JTLB is being read for the TLBP throughout the stall generated by the
* previous instruction. This is not really correct as the stalling instruction
* can modify the address used to access the JTLB. The failure symptom is that
* the TLBP instruction will use an address created for the stalling instruction
* and not the address held in C0_ENHI and thus report the wrong results.
*
* The software work-around is to not allow the instruction preceding the TLBP
* to stall - make it an NOP or some other instruction guaranteed not to stall.
*
* Errata 2 will not be fixed. This errata is also on the R5000.
*
* As if we MIPS hackers wouldn't know how to nop pipelines happy ...
*/
#define R5K_HAZARD nop
/*
* Note for many R4k variants tlb probes cannot be executed out
* of the instruction cache else you get bogus results.
*/
.align 5
NESTED(handle_tlbl, PT_SIZE, sp)
.set noat
invalid_tlbl:
#ifndef NOTLB_OPTIMIZE
/* Test present bit in entry. */
LOAD_PTE(k0, k1)
R5K_HAZARD
tlbp
PTE_PRESENT(k0, k1, nopage_tlbl)
PTE_MAKEVALID(k0, k1)
PTE_RELOAD(k1, k0)
nop
b 1f
tlbwi
1:
nop
.set mips3
eret
.set mips0
#endif
nopage_tlbl:
DO_FAULT(0)
END(handle_tlbl)
.align 5
NESTED(handle_tlbs, PT_SIZE, sp)
.set noat
#ifndef NOTLB_OPTIMIZE
LOAD_PTE(k0, k1)
R5K_HAZARD
tlbp # find faulting entry
PTE_WRITABLE(k0, k1, nopage_tlbs)
PTE_MAKEWRITE(k0, k1)
PTE_RELOAD(k1, k0)
nop
b 1f
tlbwi
1:
nop
.set mips3
eret
.set mips0
#endif
nopage_tlbs:
DO_FAULT(1)
END(handle_tlbs)
.align 5
NESTED(handle_mod, PT_SIZE, sp)
.set noat
#ifndef NOTLB_OPTIMIZE
LOAD_PTE(k0, k1)
R5K_HAZARD
tlbp # find faulting entry
andi k0, k0, _PAGE_WRITE
beqz k0, nowrite_mod
lw k0, (k1)
/* Present and writable bits set, set accessed and dirty bits. */
PTE_MAKEWRITE(k0, k1)
#if 0
ori k0, k0, (_PAGE_ACCESSED | _PAGE_DIRTY)
sw k0, (k1)
#endif
/* Now reload the entry into the tlb. */
PTE_RELOAD(k1, k0)
nop
b 1f
tlbwi
1:
nop
.set mips3
eret
.set mips0
#endif
nowrite_mod:
DO_FAULT(1)
END(handle_mod)
|