diff options
Diffstat (limited to 'arch/ia64')
-rw-r--r-- | arch/ia64/kernel/ivt.S | 133 |
1 files changed, 71 insertions, 62 deletions
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index c71c79262a48..301f2e9d262e 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S | |||
@@ -91,16 +91,17 @@ ENTRY(vhpt_miss) | |||
91 | * (the "original") TLB miss, which may either be caused by an instruction | 91 | * (the "original") TLB miss, which may either be caused by an instruction |
92 | * fetch or a data access (or non-access). | 92 | * fetch or a data access (or non-access). |
93 | * | 93 | * |
94 | * What we do here is normal TLB miss handing for the _original_ miss, followed | 94 | * What we do here is normal TLB miss handing for the _original_ miss, |
95 | * by inserting the TLB entry for the virtual page table page that the VHPT | 95 | * followed by inserting the TLB entry for the virtual page table page |
96 | * walker was attempting to access. The latter gets inserted as long | 96 | * that the VHPT walker was attempting to access. The latter gets |
97 | * as both L1 and L2 have valid mappings for the faulting address. | 97 | * inserted as long as page table entry above pte level have valid |
98 | * The TLB entry for the original miss gets inserted only if | 98 | * mappings for the faulting address. The TLB entry for the original |
99 | * the L3 entry indicates that the page is present. | 99 | * miss gets inserted only if the pte entry indicates that the page is |
100 | * present. | ||
100 | * | 101 | * |
101 | * do_page_fault gets invoked in the following cases: | 102 | * do_page_fault gets invoked in the following cases: |
102 | * - the faulting virtual address uses unimplemented address bits | 103 | * - the faulting virtual address uses unimplemented address bits |
103 | * - the faulting virtual address has no L1, L2, or L3 mapping | 104 | * - the faulting virtual address has no valid page table mapping |
104 | */ | 105 | */ |
105 | mov r16=cr.ifa // get address that caused the TLB miss | 106 | mov r16=cr.ifa // get address that caused the TLB miss |
106 | #ifdef CONFIG_HUGETLB_PAGE | 107 | #ifdef CONFIG_HUGETLB_PAGE |
@@ -126,7 +127,7 @@ ENTRY(vhpt_miss) | |||
126 | #endif | 127 | #endif |
127 | ;; | 128 | ;; |
128 | cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? | 129 | cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? |
129 | shr.u r18=r22,PGDIR_SHIFT // get bits 33-63 of the faulting address | 130 | shr.u r18=r22,PGDIR_SHIFT // get bottom portion of pgd index bit |
130 | ;; | 131 | ;; |
131 | (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place | 132 | (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place |
132 | 133 | ||
@@ -137,38 +138,38 @@ ENTRY(vhpt_miss) | |||
137 | (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT | 138 | (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT |
138 | (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 | 139 | (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 |
139 | ;; | 140 | ;; |
140 | (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 | 141 | (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=pgd_offset for region 5 |
141 | (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) | 142 | (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=pgd_offset for region[0-4] |
142 | cmp.eq p7,p6=0,r21 // unused address bits all zeroes? | 143 | cmp.eq p7,p6=0,r21 // unused address bits all zeroes? |
143 | #ifdef CONFIG_PGTABLE_4 | 144 | #ifdef CONFIG_PGTABLE_4 |
144 | shr.u r28=r22,PUD_SHIFT // shift L2 index into position | 145 | shr.u r28=r22,PUD_SHIFT // shift pud index into position |
145 | #else | 146 | #else |
146 | shr.u r18=r22,PMD_SHIFT // shift L3 index into position | 147 | shr.u r18=r22,PMD_SHIFT // shift pmd index into position |
147 | #endif | 148 | #endif |
148 | ;; | 149 | ;; |
149 | ld8 r17=[r17] // fetch the L1 entry (may be 0) | 150 | ld8 r17=[r17] // get *pgd (may be 0) |
150 | ;; | 151 | ;; |
151 | (p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? | 152 | (p7) cmp.eq p6,p7=r17,r0 // was pgd_present(*pgd) == NULL? |
152 | #ifdef CONFIG_PGTABLE_4 | 153 | #ifdef CONFIG_PGTABLE_4 |
153 | dep r28=r28,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry | 154 | dep r28=r28,r17,3,(PAGE_SHIFT-3) // r28=pud_offset(pgd,addr) |
154 | ;; | 155 | ;; |
155 | shr.u r18=r22,PMD_SHIFT // shift L3 index into position | 156 | shr.u r18=r22,PMD_SHIFT // shift pmd index into position |
156 | (p7) ld8 r29=[r28] // fetch the L2 entry (may be 0) | 157 | (p7) ld8 r29=[r28] // get *pud (may be 0) |
157 | ;; | 158 | ;; |
158 | (p7) cmp.eq.or.andcm p6,p7=r29,r0 // was L2 entry NULL? | 159 | (p7) cmp.eq.or.andcm p6,p7=r29,r0 // was pud_present(*pud) == NULL? |
159 | dep r17=r18,r29,3,(PAGE_SHIFT-3) // compute address of L3 page table entry | 160 | dep r17=r18,r29,3,(PAGE_SHIFT-3) // r17=pmd_offset(pud,addr) |
160 | #else | 161 | #else |
161 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry | 162 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=pmd_offset(pgd,addr) |
162 | #endif | 163 | #endif |
163 | ;; | 164 | ;; |
164 | (p7) ld8 r20=[r17] // fetch the L3 entry (may be 0) | 165 | (p7) ld8 r20=[r17] // get *pmd (may be 0) |
165 | shr.u r19=r22,PAGE_SHIFT // shift L4 index into position | 166 | shr.u r19=r22,PAGE_SHIFT // shift pte index into position |
166 | ;; | 167 | ;; |
167 | (p7) cmp.eq.or.andcm p6,p7=r20,r0 // was L3 entry NULL? | 168 | (p7) cmp.eq.or.andcm p6,p7=r20,r0 // was pmd_present(*pmd) == NULL? |
168 | dep r21=r19,r20,3,(PAGE_SHIFT-3) // compute address of L4 page table entry | 169 | dep r21=r19,r20,3,(PAGE_SHIFT-3) // r21=pte_offset(pmd,addr) |
169 | ;; | 170 | ;; |
170 | (p7) ld8 r18=[r21] // read the L4 PTE | 171 | (p7) ld8 r18=[r21] // read *pte |
171 | mov r19=cr.isr // cr.isr bit 0 tells us if this is an insn miss | 172 | mov r19=cr.isr // cr.isr bit 32 tells us if this is an insn miss |
172 | ;; | 173 | ;; |
173 | (p7) tbit.z p6,p7=r18,_PAGE_P_BIT // page present bit cleared? | 174 | (p7) tbit.z p6,p7=r18,_PAGE_P_BIT // page present bit cleared? |
174 | mov r22=cr.iha // get the VHPT address that caused the TLB miss | 175 | mov r22=cr.iha // get the VHPT address that caused the TLB miss |
@@ -202,25 +203,33 @@ ENTRY(vhpt_miss) | |||
202 | dv_serialize_data | 203 | dv_serialize_data |
203 | 204 | ||
204 | /* | 205 | /* |
205 | * Re-check L2 and L3 pagetable. If they changed, we may have received a ptc.g | 206 | * Re-check pagetable entry. If they changed, we may have received a ptc.g |
206 | * between reading the pagetable and the "itc". If so, flush the entry we | 207 | * between reading the pagetable and the "itc". If so, flush the entry we |
207 | * inserted and retry. | 208 | * inserted and retry. At this point, we have: |
209 | * | ||
210 | * r28 = equivalent of pud_offset(pgd, ifa) | ||
211 | * r17 = equivalent of pmd_offset(pud, ifa) | ||
212 | * r21 = equivalent of pte_offset(pmd, ifa) | ||
213 | * | ||
214 | * r29 = *pud | ||
215 | * r20 = *pmd | ||
216 | * r18 = *pte | ||
208 | */ | 217 | */ |
209 | ld8 r25=[r21] // read L4 entry again | 218 | ld8 r25=[r21] // read *pte again |
210 | ld8 r26=[r17] // read L3 PTE again | 219 | ld8 r26=[r17] // read *pmd again |
211 | #ifdef CONFIG_PGTABLE_4 | 220 | #ifdef CONFIG_PGTABLE_4 |
212 | ld8 r19=[r28] // read L2 entry again | 221 | ld8 r19=[r28] // read *pud again |
213 | #endif | 222 | #endif |
214 | cmp.ne p6,p7=r0,r0 | 223 | cmp.ne p6,p7=r0,r0 |
215 | ;; | 224 | ;; |
216 | cmp.ne.or.andcm p6,p7=r26,r20 // did L3 entry change | 225 | cmp.ne.or.andcm p6,p7=r26,r20 // did *pmd change |
217 | #ifdef CONFIG_PGTABLE_4 | 226 | #ifdef CONFIG_PGTABLE_4 |
218 | cmp.ne.or.andcm p6,p7=r19,r29 // did L4 PTE change | 227 | cmp.ne.or.andcm p6,p7=r19,r29 // did *pud change |
219 | #endif | 228 | #endif |
220 | mov r27=PAGE_SHIFT<<2 | 229 | mov r27=PAGE_SHIFT<<2 |
221 | ;; | 230 | ;; |
222 | (p6) ptc.l r22,r27 // purge PTE page translation | 231 | (p6) ptc.l r22,r27 // purge PTE page translation |
223 | (p7) cmp.ne.or.andcm p6,p7=r25,r18 // did L4 PTE change | 232 | (p7) cmp.ne.or.andcm p6,p7=r25,r18 // did *pte change |
224 | ;; | 233 | ;; |
225 | (p6) ptc.l r16,r27 // purge translation | 234 | (p6) ptc.l r16,r27 // purge translation |
226 | #endif | 235 | #endif |
@@ -235,19 +244,19 @@ END(vhpt_miss) | |||
235 | ENTRY(itlb_miss) | 244 | ENTRY(itlb_miss) |
236 | DBG_FAULT(1) | 245 | DBG_FAULT(1) |
237 | /* | 246 | /* |
238 | * The ITLB handler accesses the L3 PTE via the virtually mapped linear | 247 | * The ITLB handler accesses the PTE via the virtually mapped linear |
239 | * page table. If a nested TLB miss occurs, we switch into physical | 248 | * page table. If a nested TLB miss occurs, we switch into physical |
240 | * mode, walk the page table, and then re-execute the L3 PTE read | 249 | * mode, walk the page table, and then re-execute the PTE read and |
241 | * and go on normally after that. | 250 | * go on normally after that. |
242 | */ | 251 | */ |
243 | mov r16=cr.ifa // get virtual address | 252 | mov r16=cr.ifa // get virtual address |
244 | mov r29=b0 // save b0 | 253 | mov r29=b0 // save b0 |
245 | mov r31=pr // save predicates | 254 | mov r31=pr // save predicates |
246 | .itlb_fault: | 255 | .itlb_fault: |
247 | mov r17=cr.iha // get virtual address of L3 PTE | 256 | mov r17=cr.iha // get virtual address of PTE |
248 | movl r30=1f // load nested fault continuation point | 257 | movl r30=1f // load nested fault continuation point |
249 | ;; | 258 | ;; |
250 | 1: ld8 r18=[r17] // read L3 PTE | 259 | 1: ld8 r18=[r17] // read *pte |
251 | ;; | 260 | ;; |
252 | mov b0=r29 | 261 | mov b0=r29 |
253 | tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? | 262 | tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? |
@@ -262,7 +271,7 @@ ENTRY(itlb_miss) | |||
262 | */ | 271 | */ |
263 | dv_serialize_data | 272 | dv_serialize_data |
264 | 273 | ||
265 | ld8 r19=[r17] // read L3 PTE again and see if same | 274 | ld8 r19=[r17] // read *pte again and see if same |
266 | mov r20=PAGE_SHIFT<<2 // setup page size for purge | 275 | mov r20=PAGE_SHIFT<<2 // setup page size for purge |
267 | ;; | 276 | ;; |
268 | cmp.ne p7,p0=r18,r19 | 277 | cmp.ne p7,p0=r18,r19 |
@@ -279,19 +288,19 @@ END(itlb_miss) | |||
279 | ENTRY(dtlb_miss) | 288 | ENTRY(dtlb_miss) |
280 | DBG_FAULT(2) | 289 | DBG_FAULT(2) |
281 | /* | 290 | /* |
282 | * The DTLB handler accesses the L3 PTE via the virtually mapped linear | 291 | * The DTLB handler accesses the PTE via the virtually mapped linear |
283 | * page table. If a nested TLB miss occurs, we switch into physical | 292 | * page table. If a nested TLB miss occurs, we switch into physical |
284 | * mode, walk the page table, and then re-execute the L3 PTE read | 293 | * mode, walk the page table, and then re-execute the PTE read and |
285 | * and go on normally after that. | 294 | * go on normally after that. |
286 | */ | 295 | */ |
287 | mov r16=cr.ifa // get virtual address | 296 | mov r16=cr.ifa // get virtual address |
288 | mov r29=b0 // save b0 | 297 | mov r29=b0 // save b0 |
289 | mov r31=pr // save predicates | 298 | mov r31=pr // save predicates |
290 | dtlb_fault: | 299 | dtlb_fault: |
291 | mov r17=cr.iha // get virtual address of L3 PTE | 300 | mov r17=cr.iha // get virtual address of PTE |
292 | movl r30=1f // load nested fault continuation point | 301 | movl r30=1f // load nested fault continuation point |
293 | ;; | 302 | ;; |
294 | 1: ld8 r18=[r17] // read L3 PTE | 303 | 1: ld8 r18=[r17] // read *pte |
295 | ;; | 304 | ;; |
296 | mov b0=r29 | 305 | mov b0=r29 |
297 | tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? | 306 | tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? |
@@ -306,7 +315,7 @@ dtlb_fault: | |||
306 | */ | 315 | */ |
307 | dv_serialize_data | 316 | dv_serialize_data |
308 | 317 | ||
309 | ld8 r19=[r17] // read L3 PTE again and see if same | 318 | ld8 r19=[r17] // read *pte again and see if same |
310 | mov r20=PAGE_SHIFT<<2 // setup page size for purge | 319 | mov r20=PAGE_SHIFT<<2 // setup page size for purge |
311 | ;; | 320 | ;; |
312 | cmp.ne p7,p0=r18,r19 | 321 | cmp.ne p7,p0=r18,r19 |
@@ -420,7 +429,7 @@ ENTRY(nested_dtlb_miss) | |||
420 | * r30: continuation address | 429 | * r30: continuation address |
421 | * r31: saved pr | 430 | * r31: saved pr |
422 | * | 431 | * |
423 | * Output: r17: physical address of L3 PTE of faulting address | 432 | * Output: r17: physical address of PTE of faulting address |
424 | * r29: saved b0 | 433 | * r29: saved b0 |
425 | * r30: continuation address | 434 | * r30: continuation address |
426 | * r31: saved pr | 435 | * r31: saved pr |
@@ -450,33 +459,33 @@ ENTRY(nested_dtlb_miss) | |||
450 | (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT | 459 | (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT |
451 | (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 | 460 | (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 |
452 | ;; | 461 | ;; |
453 | (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 | 462 | (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=pgd_offset for region 5 |
454 | (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) | 463 | (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=pgd_offset for region[0-4] |
455 | cmp.eq p7,p6=0,r21 // unused address bits all zeroes? | 464 | cmp.eq p7,p6=0,r21 // unused address bits all zeroes? |
456 | #ifdef CONFIG_PGTABLE_4 | 465 | #ifdef CONFIG_PGTABLE_4 |
457 | shr.u r18=r22,PUD_SHIFT // shift L2 index into position | 466 | shr.u r18=r22,PUD_SHIFT // shift pud index into position |
458 | #else | 467 | #else |
459 | shr.u r18=r22,PMD_SHIFT // shift L3 index into position | 468 | shr.u r18=r22,PMD_SHIFT // shift pmd index into position |
460 | #endif | 469 | #endif |
461 | ;; | 470 | ;; |
462 | ld8 r17=[r17] // fetch the L1 entry (may be 0) | 471 | ld8 r17=[r17] // get *pgd (may be 0) |
463 | ;; | 472 | ;; |
464 | (p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? | 473 | (p7) cmp.eq p6,p7=r17,r0 // was pgd_present(*pgd) == NULL? |
465 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry | 474 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=p[u|m]d_offset(pgd,addr) |
466 | ;; | 475 | ;; |
467 | #ifdef CONFIG_PGTABLE_4 | 476 | #ifdef CONFIG_PGTABLE_4 |
468 | (p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) | 477 | (p7) ld8 r17=[r17] // get *pud (may be 0) |
469 | shr.u r18=r22,PMD_SHIFT // shift L3 index into position | 478 | shr.u r18=r22,PMD_SHIFT // shift pmd index into position |
470 | ;; | 479 | ;; |
471 | (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? | 480 | (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was pud_present(*pud) == NULL? |
472 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry | 481 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=pmd_offset(pud,addr) |
473 | ;; | 482 | ;; |
474 | #endif | 483 | #endif |
475 | (p7) ld8 r17=[r17] // fetch the L3 entry (may be 0) | 484 | (p7) ld8 r17=[r17] // get *pmd (may be 0) |
476 | shr.u r19=r22,PAGE_SHIFT // shift L4 index into position | 485 | shr.u r19=r22,PAGE_SHIFT // shift pte index into position |
477 | ;; | 486 | ;; |
478 | (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L3 entry NULL? | 487 | (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was pmd_present(*pmd) == NULL? |
479 | dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L4 page table entry | 488 | dep r17=r19,r17,3,(PAGE_SHIFT-3) // r17=pte_offset(pmd,addr); |
480 | (p6) br.cond.spnt page_fault | 489 | (p6) br.cond.spnt page_fault |
481 | mov b0=r30 | 490 | mov b0=r30 |
482 | br.sptk.many b0 // return to continuation point | 491 | br.sptk.many b0 // return to continuation point |