1/*
2 * TLB exception handling code for R2000/R3000.
3 *
4 * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
5 *
6 * Multi-CPU abstraction reworking:
7 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
8 *
9 * Further modifications to make this work:
10 * Copyright (c) 1998 Harald Koerfgen
11 * Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov
12 * Copyright (c) 2001 Ralf Baechle
13 * Copyright (c) 2001 MIPS Technologies, Inc.
14 */
15#include <linux/init.h>
16#include <asm/asm.h>
17#include <asm/current.h>
18#include <asm/cachectl.h>
19#include <asm/fpregdef.h>
20#include <asm/mipsregs.h>
21#include <asm/page.h>
22#include <asm/pgtable-bits.h>
23#include <asm/processor.h>
24#include <asm/regdef.h>
25#include <asm/stackframe.h>
26
27#define TLB_OPTIMIZE /* If you are paranoid, disable this. */
28
29	.text
30	.set	mips1
31	.set	noreorder
32
33	__INIT
34
35	/* TLB refill, R[23]00 version */
36	LEAF(except_vec0_r2300)
37	.set	noat
38	.set	mips1
39	mfc0	k0, CP0_BADVADDR
40	lw	k1, pgd_current			# get pgd pointer
41	srl	k0, k0, 22
42	sll	k0, k0, 2
43	addu	k1, k1, k0
44	mfc0	k0, CP0_CONTEXT
45	lw	k1, (k1)
46	and	k0, k0, 0xffc
47	addu	k1, k1, k0
48	lw	k0, (k1)
49	nop
50	mtc0	k0, CP0_ENTRYLO0
51	mfc0	k1, CP0_EPC
52	tlbwr
53	jr	k1
54	rfe
55	END(except_vec0_r2300)
56
57	__FINIT
58
59	/* ABUSE of CPP macros 101. */
60
61	/* After this macro runs, the pte faulted on is
62	 * in register PTE, a ptr into the table in which
63	 * the pte belongs is in PTR.
64	 */
65#define LOAD_PTE(pte, ptr) \
66	mfc0	pte, CP0_BADVADDR; \
67	lw	ptr, pgd_current; \
68	srl	pte, pte, 22; \
69	sll	pte, pte, 2; \
70	addu	ptr, ptr, pte; \
71	mfc0	pte, CP0_CONTEXT; \
72	lw	ptr, (ptr); \
73	andi	pte, pte, 0xffc; \
74	addu	ptr, ptr, pte; \
75	lw	pte, (ptr); \
76	nop;
77
78	/* This places the even/odd pte pair in the page
79	 * table at PTR into ENTRYLO0 and ENTRYLO1 using
80	 * TMP as a scratch register.
81	 */
82#define PTE_RELOAD(ptr) \
83	lw	ptr, (ptr)	; \
84	nop			; \
85	mtc0	ptr, CP0_ENTRYLO0; \
86	nop;
87
88#define DO_FAULT(write) \
89	.set	noat; \
90	.set	macro; \
91	SAVE_ALL; \
92	mfc0	a2, CP0_BADVADDR; \
93	KMODE; \
94	.set	at; \
95	move	a0, sp; \
96	jal	do_page_fault; \
97	 li	a1, write; \
98	j	ret_from_exception; \
99	 nop; \
100	.set	noat; \
101	.set	nomacro;
102
103	/* Check is PTE is present, if not then jump to LABEL.
104	 * PTR points to the page table where this PTE is located,
105	 * when the macro is done executing PTE will be restored
106	 * with it's original value.
107	 */
108#define PTE_PRESENT(pte, ptr, label) \
109	andi	pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
110	xori	pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
111	bnez	pte, label; \
112	.set	push;       \
113	.set	reorder;    \
114	 lw	pte, (ptr); \
115	.set	pop;
116
117	/* Make PTE valid, store result in PTR. */
118#define PTE_MAKEVALID(pte, ptr) \
119	ori	pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
120	sw	pte, (ptr);
121
122	/* Check if PTE can be written to, if not branch to LABEL.
123	 * Regardless restore PTE with value from PTR when done.
124	 */
125#define PTE_WRITABLE(pte, ptr, label) \
126	andi	pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
127	xori	pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
128	bnez	pte, label; \
129	.set    push;       \
130	.set    reorder;    \
131	lw      pte, (ptr); \
132	.set    pop;
133
134
135	/* Make PTE writable, update software status bits as well,
136	 * then store at PTR.
137	 */
138#define PTE_MAKEWRITE(pte, ptr) \
139	ori	pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
140			   _PAGE_VALID | _PAGE_DIRTY); \
141	sw	pte, (ptr);
142
143/*
144 * The index register may have the probe fail bit set,
145 * because we would trap on access kseg2, i.e. without refill.
146 */
147#define TLB_WRITE(reg) \
148	mfc0	reg, CP0_INDEX; \
149	nop; \
150	bltz    reg, 1f; \
151	 nop; \
152	tlbwi; \
153	j	2f; \
154	 nop; \
1551:	tlbwr; \
1562:
157
158#define RET(reg) \
159	mfc0	reg, CP0_EPC; \
160	nop; \
161	jr	reg; \
162	 rfe
163
164	.set	noreorder
165
166	.align	5
167NESTED(handle_tlbl, PT_SIZE, sp)
168	.set	noat
169
170#ifdef TLB_OPTIMIZE
171	/* Test present bit in entry. */
172	LOAD_PTE(k0, k1)
173        tlbp
174        PTE_PRESENT(k0, k1, nopage_tlbl)
175        PTE_MAKEVALID(k0, k1)
176        PTE_RELOAD(k1)
177	TLB_WRITE(k0)
178	RET(k0)
179nopage_tlbl:
180#endif
181
182	DO_FAULT(0)
183END(handle_tlbl)
184
185NESTED(handle_tlbs, PT_SIZE, sp)
186	.set	noat
187
188#ifdef TLB_OPTIMIZE
189	LOAD_PTE(k0, k1)
190	tlbp                            # find faulting entry
191	PTE_WRITABLE(k0, k1, nopage_tlbs)
192	PTE_MAKEWRITE(k0, k1)
193	PTE_RELOAD(k1)
194	TLB_WRITE(k0)
195	RET(k0)
196nopage_tlbs:
197#endif
198
199	DO_FAULT(1)
200END(handle_tlbs)
201
202	.align	5
203NESTED(handle_mod, PT_SIZE, sp)
204	.set	noat
205#ifdef TLB_OPTIMIZE
206	LOAD_PTE(k0, k1)
207	tlbp					# find faulting entry
208	andi	k0, k0, _PAGE_WRITE
209	beqz	k0, nowrite_mod
210	.set	push
211	.set    reorder
212	lw	k0, (k1)
213	.set    pop
214
215	/* Present and writable bits set, set accessed and dirty bits. */
216	PTE_MAKEWRITE(k0, k1)
217
218	/* Now reload the entry into the tlb. */
219	PTE_RELOAD(k1)
220	tlbwi
221	RET(k0)
222#endif
223
224nowrite_mod:
225	DO_FAULT(1)
226END(handle_mod)
227