diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -570,6 +570,11 @@ static vm_pindex_t pti_pg_idx; static bool pti_finalized; +static int __read_frequently pmap_growkernel_panic = 0; +SYSCTL_INT(_vm_pmap, OID_AUTO, growkernel_panic, CTLFLAG_RDTUN, + &pmap_growkernel_panic, 0, + "panic on failure to allocate kernel page table page"); + struct pmap_pkru_range { struct rs_el pkru_rs_el; u_int pkru_keyidx; @@ -5115,17 +5120,19 @@ /* * grow the number of kernel page table entries, if needed */ -void -pmap_growkernel(vm_offset_t addr) +static int +pmap_growkernel_nopanic(vm_offset_t addr) { vm_paddr_t paddr; vm_page_t nkpg; pd_entry_t *pde, newpdir; pdp_entry_t *pdpe; vm_offset_t end; + int rv; TSENTER(); mtx_assert(&kernel_map->system_mtx, MA_OWNED); + rv = KERN_SUCCESS; /* * The kernel map covers two distinct regions of KVA: that used @@ -5153,7 +5160,7 @@ end = KERNBASE + nkpt * NBPDR; if (end == 0) { TSEXIT(); - return; + return (rv); } } else { end = kernel_vm_end; @@ -5168,7 +5175,7 @@ * nothing to do. */ TSEXIT(); - return; + return (rv); } kasan_shadow_map(end, addr - end); @@ -5179,8 +5186,12 @@ nkpg = pmap_alloc_pt_page(kernel_pmap, pmap_pdpe_pindex(end), VM_ALLOC_INTERRUPT | VM_ALLOC_NOFREE | VM_ALLOC_WIRED | VM_ALLOC_ZERO); - if (nkpg == NULL) - panic("pmap_growkernel: no memory to grow kernel"); + if (nkpg == NULL) { + printf( + "pmap_growkernel: no memory to grow kernel"); + rv = KERN_RESOURCE_SHORTAGE; + break; + } paddr = VM_PAGE_TO_PHYS(nkpg); *pdpe = (pdp_entry_t)(paddr | X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M); @@ -5199,8 +5210,12 @@ nkpg = pmap_alloc_pt_page(kernel_pmap, pmap_pde_pindex(end), VM_ALLOC_INTERRUPT | VM_ALLOC_NOFREE | VM_ALLOC_WIRED | VM_ALLOC_ZERO); - if (nkpg == NULL) - panic("pmap_growkernel: no memory to grow kernel"); + if (nkpg == NULL) { + printf("pmap_growkernel: no memory to grow kernel"); + rv = KERN_RESOURCE_SHORTAGE; + break; + } + paddr = VM_PAGE_TO_PHYS(nkpg); newpdir = paddr | X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M; pde_store(pde, newpdir); @@ -5217,8 +5232,21 @@ else nkpt = howmany(end - KERNBASE, NBPDR); TSEXIT(); + return (rv); } +int +pmap_growkernel(vm_offset_t addr) +{ + int rv; + + rv = pmap_growkernel_nopanic(addr); + if (rv != KERN_SUCCESS && pmap_growkernel_panic) + panic("pmap_growkernel: no memory to grow kernel"); + return (rv); +} + + /*************************************************** * page management routines. ***************************************************/ diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h --- a/sys/vm/pmap.h +++ b/sys/vm/pmap.h @@ -136,7 +136,7 @@ vm_paddr_t pmap_extract(pmap_t pmap, vm_offset_t va); vm_page_t pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot); -void pmap_growkernel(vm_offset_t); +int pmap_growkernel(vm_offset_t); void pmap_init(void); bool pmap_is_modified(vm_page_t m); bool pmap_is_prefaultable(pmap_t pmap, vm_offset_t va); diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -1709,8 +1709,13 @@ charged: /* Expand the kernel pmap, if necessary. */ - if (map == kernel_map && end > kernel_vm_end) - pmap_growkernel(end); + if (map == kernel_map && end > kernel_vm_end) { + int rv; + + rv = pmap_growkernel(end); + if (rv != KERN_SUCCESS) + return (rv); + } if (object != NULL) { /* * OBJ_ONEMAPPING must be cleared unless this mapping