Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/cris/arch-v32/mm/mmu.S
15125 views
1
; WARNING : The refill handler has been modified, see below !!!
2
3
/*
4
* Copyright (C) 2003 Axis Communications AB
5
*
6
* Authors: Mikael Starvik ([email protected])
7
*
8
* Code for the fault low-level handling routines.
9
*
10
*/
11
12
#include <asm/page.h>
13
#include <asm/pgtable.h>
14
15
; Save all register. Must save in same order as struct pt_regs.
16
.macro SAVE_ALL
17
subq 12, $sp
18
move $erp, [$sp]
19
subq 4, $sp
20
move $srp, [$sp]
21
subq 4, $sp
22
move $ccs, [$sp]
23
subq 4, $sp
24
move $spc, [$sp]
25
subq 4, $sp
26
move $mof, [$sp]
27
subq 4, $sp
28
move $srs, [$sp]
29
subq 4, $sp
30
move.d $acr, [$sp]
31
subq 14*4, $sp
32
movem $r13, [$sp]
33
subq 4, $sp
34
move.d $r10, [$sp]
35
.endm
36
37
; Bus fault handler. Extracts relevant information and calls mm subsystem
38
; to handle the fault.
39
.macro MMU_BUS_FAULT_HANDLER handler, mmu, we, ex
40
.globl \handler
41
.type \handler,"function"
42
\handler:
43
SAVE_ALL
44
move \mmu, $srs ; Select MMU support register bank
45
move.d $sp, $r11 ; regs
46
moveq 1, $r12 ; protection fault
47
moveq \we, $r13 ; write exception?
48
orq \ex << 1, $r13 ; execute?
49
move $s3, $r10 ; rw_mm_cause
50
and.d ~8191, $r10 ; Get faulting page start address
51
52
jsr do_page_fault
53
nop
54
ba ret_from_intr
55
nop
56
.size \handler, . - \handler
57
.endm
58
59
; Refill handler. Three cases may occur:
60
; 1. PMD and PTE exists in mm subsystem but not in TLB
61
; 2. PMD exists but not PTE
62
; 3. PMD doesn't exist
63
; The code below handles case 1 and calls the mm subsystem for case 2 and 3.
64
; Do not touch this code without very good reasons and extensive testing.
65
; Note that the code is optimized to minimize stalls (makes the code harder
66
; to read).
67
;
68
; WARNING !!!
69
; Modified by Mikael Asker 060725: added a workaround for strange TLB
70
; behavior. If the same PTE is present in more than one set, the TLB
71
; doesn't recognize it and we get stuck in a loop of refill exceptions.
72
; The workaround detects such loops and exits them by flushing
73
; the TLB contents. The problem and workaround were verified
74
; in VCS by Mikael Starvik.
75
;
76
; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each
77
; PMD holds 16 MB of virtual memory.
78
; Bits 0-12 : Offset within a page
79
; Bits 13-23 : PTE offset within a PMD
80
; Bits 24-31 : PMD offset within the PGD
81
82
.macro MMU_REFILL_HANDLER handler, mmu
83
.data
84
1: .dword 0 ; refill_count
85
; == 0 <=> last_refill_cause is invalid
86
2: .dword 0 ; last_refill_cause
87
.text
88
.globl \handler
89
.type \handler, "function"
90
\handler:
91
subq 4, $sp
92
; (The pipeline stalls for one cycle; $sp used as address in the next cycle.)
93
move $srs, [$sp]
94
subq 4, $sp
95
move \mmu, $srs ; Select MMU support register bank
96
move.d $acr, [$sp]
97
subq 12, $sp
98
move.d 1b, $acr ; Point to refill_count
99
movem $r2, [$sp]
100
101
test.d [$acr] ; refill_count == 0 ?
102
beq 5f ; yes, last_refill_cause is invalid
103
move.d $acr, $r1
104
105
; last_refill_cause is valid, investigate cause
106
addq 4, $r1 ; Point to last_refill_cause
107
move $s3, $r0 ; Get rw_mm_cause
108
move.d [$r1], $r2 ; Get last_refill_cause
109
cmp.d $r0, $r2 ; rw_mm_cause == last_refill_cause ?
110
beq 6f ; yes, increment count
111
moveq 1, $r2
112
113
; rw_mm_cause != last_refill_cause
114
move.d $r2, [$acr] ; refill_count = 1
115
move.d $r0, [$r1] ; last_refill_cause = rw_mm_cause
116
117
3: ; Probably not in a loop, continue normal processing
118
#ifdef CONFIG_SMP
119
move $s7, $acr ; PGD
120
#else
121
move.d current_pgd, $acr ; PGD
122
#endif
123
; Look up PMD in PGD
124
lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31)
125
move.d [$acr], $acr ; PGD for the current process
126
addi $r0.d, $acr, $acr
127
move $s3, $r0 ; rw_mm_cause
128
move.d [$acr], $acr ; Get PMD
129
beq 8f
130
; Look up PTE in PMD
131
lsrq PAGE_SHIFT, $r0
132
and.w PAGE_MASK, $acr ; Remove PMD flags
133
and.d 0x7ff, $r0 ; Get PTE index into PMD (bit 13-23)
134
addi $r0.d, $acr, $acr
135
move.d [$acr], $acr ; Get PTE
136
beq 9f
137
movem [$sp], $r2 ; Restore r0-r2 in delay slot
138
addq 12, $sp
139
; Store in TLB
140
move $acr, $s5
141
4: ; Return
142
move.d [$sp+], $acr
143
move [$sp], $srs
144
addq 4, $sp
145
rete
146
rfe
147
148
5: ; last_refill_cause is invalid
149
moveq 1, $r2
150
addq 4, $r1 ; Point to last_refill_cause
151
move.d $r2, [$acr] ; refill_count = 1
152
move $s3, $r0 ; Get rw_mm_cause
153
ba 3b ; Continue normal processing
154
move.d $r0,[$r1] ; last_refill_cause = rw_mm_cause
155
156
6: ; rw_mm_cause == last_refill_cause
157
move.d [$acr], $r2 ; Get refill_count
158
cmpq 4, $r2 ; refill_count > 4 ?
159
bhi 7f ; yes
160
addq 1, $r2 ; refill_count++
161
ba 3b ; Continue normal processing
162
move.d $r2, [$acr]
163
164
7: ; refill_count > 4, error
165
move.d $acr, $r0 ; Save pointer to refill_count
166
clear.d [$r0] ; refill_count = 0
167
168
;; rewind the short stack
169
movem [$sp], $r2 ; Restore r0-r2
170
addq 12, $sp
171
move.d [$sp+], $acr
172
move [$sp], $srs
173
addq 4, $sp
174
;; Keep it simple (slow), save all the regs.
175
SAVE_ALL
176
jsr __flush_tlb_all
177
nop
178
ba ret_from_intr ; Return
179
nop
180
181
8: ; PMD missing, let the mm subsystem fix it up.
182
movem [$sp], $r2 ; Restore r0-r2
183
9: ; PTE missing, let the mm subsystem fix it up.
184
addq 12, $sp
185
move.d [$sp+], $acr
186
move [$sp], $srs
187
addq 4, $sp
188
SAVE_ALL
189
move \mmu, $srs
190
move.d $sp, $r11 ; regs
191
clear.d $r12 ; Not a protection fault
192
move.w PAGE_MASK, $acr
193
move $s3, $r10 ; rw_mm_cause
194
btstq 9, $r10 ; Check if write access
195
smi $r13
196
and.w PAGE_MASK, $r10 ; Get VPN (virtual address)
197
jsr do_page_fault
198
and.w $acr, $r10
199
; Return
200
ba ret_from_intr
201
nop
202
.size \handler, . - \handler
203
.endm
204
205
; This is the MMU bus fault handlers.
206
207
MMU_REFILL_HANDLER i_mmu_refill, 1
208
MMU_BUS_FAULT_HANDLER i_mmu_invalid, 1, 0, 0
209
MMU_BUS_FAULT_HANDLER i_mmu_access, 1, 0, 0
210
MMU_BUS_FAULT_HANDLER i_mmu_execute, 1, 0, 1
211
MMU_REFILL_HANDLER d_mmu_refill, 2
212
MMU_BUS_FAULT_HANDLER d_mmu_invalid, 2, 0, 0
213
MMU_BUS_FAULT_HANDLER d_mmu_access, 2, 0, 0
214
MMU_BUS_FAULT_HANDLER d_mmu_write, 2, 1, 0
215
216