* Tries to create the specified 2MB page mapping. Returns KERN_SUCCESS if * the mapping was created, and either KERN_FAILURE or KERN_RESOURCE_SHORTAGE * otherwise. Returns KERN_FAILURE if PMAP_ENTER_NOREPLACE was specified and * a mapping already exists at the specified virtual address. Returns * KERN_RESOURCE_SHORTAGE if PMAP_ENTER_NOSLEEP was specified and a page table * page allocation
| 7056 | * The parameter "m" is only used when creating a managed, writeable mapping. |
| 7057 | */ |
| 7058 | static int |
| 7059 | pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags, |
| 7060 | vm_page_t m, struct rwlock **lockp) |
| 7061 | { |
| 7062 | struct spglist free; |
| 7063 | pd_entry_t oldpde, *pde; |
| 7064 | pt_entry_t PG_G, PG_RW, PG_V; |
| 7065 | vm_page_t mt, pdpg; |
| 7066 | |
| 7067 | KASSERT(pmap == kernel_pmap || (newpde & PG_W) == 0, |
| 7068 | ("pmap_enter_pde: cannot create wired user mapping")); |
| 7069 | PG_G = pmap_global_bit(pmap); |
| 7070 | PG_RW = pmap_rw_bit(pmap); |
| 7071 | KASSERT((newpde & (pmap_modified_bit(pmap) | PG_RW)) != PG_RW, |
| 7072 | ("pmap_enter_pde: newpde is missing PG_M")); |
| 7073 | PG_V = pmap_valid_bit(pmap); |
| 7074 | PMAP_LOCK_ASSERT(pmap, MA_OWNED); |
| 7075 | |
| 7076 | if (!pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap, |
| 7077 | newpde))) { |
| 7078 | CTR2(KTR_PMAP, "pmap_enter_pde: 2m x blocked for va %#lx" |
| 7079 | " in pmap %p", va, pmap); |
| 7080 | return (KERN_FAILURE); |
| 7081 | } |
| 7082 | if ((pde = pmap_alloc_pde(pmap, va, &pdpg, (flags & |
| 7083 | PMAP_ENTER_NOSLEEP) != 0 ? NULL : lockp)) == NULL) { |
| 7084 | CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx" |
| 7085 | " in pmap %p", va, pmap); |
| 7086 | return (KERN_RESOURCE_SHORTAGE); |
| 7087 | } |
| 7088 | |
| 7089 | /* |
| 7090 | * If pkru is not same for the whole pde range, return failure |
| 7091 | * and let vm_fault() cope. Check after pde allocation, since |
| 7092 | * it could sleep. |
| 7093 | */ |
| 7094 | if (!pmap_pkru_same(pmap, va, va + NBPDR)) { |
| 7095 | pmap_abort_ptp(pmap, va, pdpg); |
| 7096 | return (KERN_FAILURE); |
| 7097 | } |
| 7098 | if (va < VM_MAXUSER_ADDRESS && pmap->pm_type == PT_X86) { |
| 7099 | newpde &= ~X86_PG_PKU_MASK; |
| 7100 | newpde |= pmap_pkru_get(pmap, va); |
| 7101 | } |
| 7102 | |
| 7103 | /* |
| 7104 | * If there are existing mappings, either abort or remove them. |
| 7105 | */ |
| 7106 | oldpde = *pde; |
| 7107 | if ((oldpde & PG_V) != 0) { |
| 7108 | KASSERT(pdpg == NULL || pdpg->ref_count > 1, |
| 7109 | ("pmap_enter_pde: pdpg's reference count is too low")); |
| 7110 | if ((flags & PMAP_ENTER_NOREPLACE) != 0 && (va < |
| 7111 | VM_MAXUSER_ADDRESS || (oldpde & PG_PS) != 0 || |
| 7112 | !pmap_every_pte_zero(oldpde & PG_FRAME))) { |
| 7113 | if (pdpg != NULL) |
| 7114 | pdpg->ref_count--; |
| 7115 | CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx" |
no test coverage detected