* pmap_emulate_modified : do dirty bit emulation * * On SMP, update just the local TLB, other CPUs will update their * TLBs from PTE lazily, if they get the exception. * Returns 0 in case of sucess, 1 if the page is read only and we * need to fault. */
| 3496 | * need to fault. |
| 3497 | */ |
| 3498 | int |
| 3499 | pmap_emulate_modified(pmap_t pmap, vm_offset_t va) |
| 3500 | { |
| 3501 | pt_entry_t *pte; |
| 3502 | |
| 3503 | PMAP_LOCK(pmap); |
| 3504 | pte = pmap_pte(pmap, va); |
| 3505 | |
| 3506 | /* |
| 3507 | * It is possible that some other CPU or thread changed the pmap while |
| 3508 | * we weren't looking; in the SMP case, this is readily apparent, but |
| 3509 | * it can even happen in the UP case, because we may have been blocked |
| 3510 | * on PMAP_LOCK(pmap) above while someone changed this out from |
| 3511 | * underneath us. |
| 3512 | */ |
| 3513 | |
| 3514 | if (pte == NULL) { |
| 3515 | /* |
| 3516 | * This PTE's PTP (or one of its ancestors) has been reclaimed; |
| 3517 | * trigger a full fault to reconstruct it via pmap_enter. |
| 3518 | */ |
| 3519 | PMAP_UNLOCK(pmap); |
| 3520 | return (1); |
| 3521 | } |
| 3522 | |
| 3523 | if (!pte_test(pte, PTE_V)) { |
| 3524 | /* |
| 3525 | * This PTE is no longer valid; the other thread or other |
| 3526 | * processor must have arranged for our TLB to no longer |
| 3527 | * have this entry, possibly by IPI, so no tlb_update is |
| 3528 | * required. Fall out of the fast path and go take a |
| 3529 | * general fault before retrying the instruction (or taking |
| 3530 | * a signal). |
| 3531 | */ |
| 3532 | PMAP_UNLOCK(pmap); |
| 3533 | return (1); |
| 3534 | } |
| 3535 | |
| 3536 | if (pte_test(pte, PTE_D)) { |
| 3537 | /* |
| 3538 | * This PTE is valid and has the PTE_D bit asserted; since |
| 3539 | * this is an increase in permission, we may have been expected |
| 3540 | * to update the TLB lazily. Do so here and return, on the |
| 3541 | * fast path, to retry the instruction. |
| 3542 | */ |
| 3543 | tlb_update(pmap, va, *pte); |
| 3544 | PMAP_UNLOCK(pmap); |
| 3545 | return (0); |
| 3546 | } |
| 3547 | |
| 3548 | if (pte_test(pte, PTE_RO)) { |
| 3549 | /* |
| 3550 | * This PTE is valid, not dirty, and read-only. Go take a |
| 3551 | * full fault (most likely to upgrade this part of the address |
| 3552 | * space to writeable). |
| 3553 | */ |
| 3554 | PMAP_UNLOCK(pmap); |
| 3555 | return (1); |
no test coverage detected