* 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
| 4266 | * The parameter "m" is only used when creating a managed, writeable mapping. |
| 4267 | */ |
| 4268 | static int |
| 4269 | pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, |
| 4270 | vm_page_t m, struct rwlock **lockp) |
| 4271 | { |
| 4272 | struct spglist free; |
| 4273 | pd_entry_t *l2, old_l2; |
| 4274 | vm_page_t l2pg, mt; |
| 4275 | |
| 4276 | PMAP_LOCK_ASSERT(pmap, MA_OWNED); |
| 4277 | |
| 4278 | if ((l2 = pmap_alloc_l2(pmap, va, &l2pg, (flags & |
| 4279 | PMAP_ENTER_NOSLEEP) != 0 ? NULL : lockp)) == NULL) { |
| 4280 | CTR2(KTR_PMAP, "pmap_enter_l2: failure for va %#lx in pmap %p", |
| 4281 | va, pmap); |
| 4282 | return (KERN_RESOURCE_SHORTAGE); |
| 4283 | } |
| 4284 | |
| 4285 | /* |
| 4286 | * If there are existing mappings, either abort or remove them. |
| 4287 | */ |
| 4288 | if ((old_l2 = pmap_load(l2)) != 0) { |
| 4289 | KASSERT(l2pg == NULL || l2pg->ref_count > 1, |
| 4290 | ("pmap_enter_l2: l2pg's ref count is too low")); |
| 4291 | if ((flags & PMAP_ENTER_NOREPLACE) != 0 && (va < |
| 4292 | VM_MAXUSER_ADDRESS || (old_l2 & ATTR_DESCR_MASK) == |
| 4293 | L2_BLOCK || !pmap_every_pte_zero(old_l2 & ~ATTR_MASK))) { |
| 4294 | if (l2pg != NULL) |
| 4295 | l2pg->ref_count--; |
| 4296 | CTR2(KTR_PMAP, "pmap_enter_l2: failure for va %#lx" |
| 4297 | " in pmap %p", va, pmap); |
| 4298 | return (KERN_FAILURE); |
| 4299 | } |
| 4300 | SLIST_INIT(&free); |
| 4301 | if ((old_l2 & ATTR_DESCR_MASK) == L2_BLOCK) |
| 4302 | (void)pmap_remove_l2(pmap, l2, va, |
| 4303 | pmap_load(pmap_l1(pmap, va)), &free, lockp); |
| 4304 | else |
| 4305 | pmap_remove_l3_range(pmap, old_l2, va, va + L2_SIZE, |
| 4306 | &free, lockp); |
| 4307 | if (va < VM_MAXUSER_ADDRESS) { |
| 4308 | vm_page_free_pages_toq(&free, true); |
| 4309 | KASSERT(pmap_load(l2) == 0, |
| 4310 | ("pmap_enter_l2: non-zero L2 entry %p", l2)); |
| 4311 | } else { |
| 4312 | KASSERT(SLIST_EMPTY(&free), |
| 4313 | ("pmap_enter_l2: freed kernel page table page")); |
| 4314 | |
| 4315 | /* |
| 4316 | * Both pmap_remove_l2() and pmap_remove_l3_range() |
| 4317 | * will leave the kernel page table page zero filled. |
| 4318 | * Nonetheless, the TLB could have an intermediate |
| 4319 | * entry for the kernel page table page. |
| 4320 | */ |
| 4321 | mt = PHYS_TO_VM_PAGE(pmap_load(l2) & ~ATTR_MASK); |
| 4322 | if (pmap_insert_pt_page(pmap, mt, false)) |
| 4323 | panic("pmap_enter_l2: trie insert failed"); |
| 4324 | pmap_clear(l2); |
| 4325 | pmap_invalidate_page(pmap, va); |
no test coverage detected