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
|
/* $Id: r2300_misc.S,v 1.4 1999/08/09 19:43:14 harald Exp $
* 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)
*
* Further modifications to make this work:
* Copyright (c) 1998 Harald Koerfgen
* Copyright (c) 1998 Gleb Raiko & Vladimir Roganov
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/current.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/segment.h>
#include <asm/stackframe.h>
.text
.set mips1
.set noreorder
#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.
*/
#define LOAD_PTE(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
_GET_CURRENT(ptr); \
srl pte, pte, 22; \
lw ptr, THREAD_PGDIR(ptr); \
sll pte, pte, 2; \
addu ptr, pte, ptr; \
mfc0 pte, CP0_CONTEXT; \
lw ptr, (ptr); \
andi pte, pte, 0xffc; \
addu ptr, ptr, pte; \
lw pte, (ptr); \
nop;
/* 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) \
lw ptr, (ptr) ; \
nop ; \
mtc0 ptr, CP0_ENTRYLO0; \
nop;
#define DO_FAULT(write) \
.set noat; \
.set macro; \
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; \
.set nomacro;
/* 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; \
.set push; \
.set reorder; \
lw pte, (ptr); \
.set pop;
/* 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; \
.set push; \
.set reorder; \
lw pte, (ptr); \
.set pop;
/* 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
.align 5
NESTED(handle_tlbl, PT_SIZE, sp)
.set noat
#ifndef NOTLB_OPTIMIZE
/* Test present bit in entry. */
LOAD_PTE(k0, k1)
tlbp
nop
PTE_PRESENT(k0, k1, nopage_tlbl)
PTE_MAKEVALID(k0, k1)
PTE_RELOAD(k1)
tlbwi
nop
mfc0 k0, CP0_EPC
nop
jr k0
rfe
nopage_tlbl:
#endif
DO_FAULT(0)
END(handle_tlbl)
NESTED(handle_tlbs, PT_SIZE, sp)
.set noat
#ifndef NOTLB_OPTIMIZE
LOAD_PTE(k0, k1)
tlbp # find faulting entry
nop
PTE_WRITABLE(k0, k1, nopage_tlbs)
PTE_MAKEWRITE(k0, k1)
PTE_RELOAD(k1)
tlbwi
nop
mfc0 k0, CP0_EPC
nop
jr k0
rfe
nopage_tlbs:
#endif
DO_FAULT(1)
END(handle_tlbs)
.align 5
NESTED(handle_mod, PT_SIZE, sp)
.set noat
#ifndef NOTLB_OPTIMIZE
LOAD_PTE(k0, k1)
tlbp # find faulting entry
andi k0, k0, _PAGE_WRITE
beqz k0, nowrite_mod
.set push
.set reorder
lw k0, (k1)
.set pop
/* Present and writable bits set, set accessed and dirty bits. */
PTE_MAKEWRITE(k0, k1)
/* Now reload the entry into the tlb. */
PTE_RELOAD(k1)
nop
tlbwi
nop
mfc0 k0, CP0_EPC
nop
jr k0
rfe
#endif
nowrite_mod:
DO_FAULT(1)
END(handle_mod)
|