diff options
| -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 |
