| 9811 | #endif /* INVARIANTS */ |
| 9812 | |
| 9813 | int |
| 9814 | pmap_emulate_accessed_dirty(pmap_t pmap, vm_offset_t va, int ftype) |
| 9815 | { |
| 9816 | int rv; |
| 9817 | struct rwlock *lock; |
| 9818 | #if VM_NRESERVLEVEL > 0 |
| 9819 | vm_page_t m, mpte; |
| 9820 | #endif |
| 9821 | pd_entry_t *pde; |
| 9822 | pt_entry_t *pte, PG_A, PG_M, PG_RW, PG_V; |
| 9823 | |
| 9824 | KASSERT(ftype == VM_PROT_READ || ftype == VM_PROT_WRITE, |
| 9825 | ("pmap_emulate_accessed_dirty: invalid fault type %d", ftype)); |
| 9826 | |
| 9827 | if (!pmap_emulate_ad_bits(pmap)) |
| 9828 | return (-1); |
| 9829 | |
| 9830 | PG_A = pmap_accessed_bit(pmap); |
| 9831 | PG_M = pmap_modified_bit(pmap); |
| 9832 | PG_V = pmap_valid_bit(pmap); |
| 9833 | PG_RW = pmap_rw_bit(pmap); |
| 9834 | |
| 9835 | rv = -1; |
| 9836 | lock = NULL; |
| 9837 | PMAP_LOCK(pmap); |
| 9838 | |
| 9839 | pde = pmap_pde(pmap, va); |
| 9840 | if (pde == NULL || (*pde & PG_V) == 0) |
| 9841 | goto done; |
| 9842 | |
| 9843 | if ((*pde & PG_PS) != 0) { |
| 9844 | if (ftype == VM_PROT_READ) { |
| 9845 | #ifdef INVARIANTS |
| 9846 | atomic_add_long(&num_superpage_accessed_emulations, 1); |
| 9847 | #endif |
| 9848 | *pde |= PG_A; |
| 9849 | rv = 0; |
| 9850 | } |
| 9851 | goto done; |
| 9852 | } |
| 9853 | |
| 9854 | pte = pmap_pde_to_pte(pde, va); |
| 9855 | if ((*pte & PG_V) == 0) |
| 9856 | goto done; |
| 9857 | |
| 9858 | if (ftype == VM_PROT_WRITE) { |
| 9859 | if ((*pte & PG_RW) == 0) |
| 9860 | goto done; |
| 9861 | /* |
| 9862 | * Set the modified and accessed bits simultaneously. |
| 9863 | * |
| 9864 | * Intel EPT PTEs that do software emulation of A/D bits map |
| 9865 | * PG_A and PG_M to EPT_PG_READ and EPT_PG_WRITE respectively. |
| 9866 | * An EPT misconfiguration is triggered if the PTE is writable |
| 9867 | * but not readable (WR=10). This is avoided by setting PG_A |
| 9868 | * and PG_M simultaneously. |
| 9869 | */ |
| 9870 | *pte |= PG_M | PG_A; |
no test coverage detected