diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 2ff9f5b1f65..14446e304e4 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -101,6 +101,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef DDB #ifndef KDB @@ -1227,6 +1228,12 @@ getmemsize(caddr_t kmdp, u_int64_t first) quad_t dcons_addr, dcons_size; int page_counter; + /* + * Tell the physical memory allocator about pages used to store + * the kernel and preloaded data. See kmem_bootstrap_free(). + */ + vm_phys_add_seg((vm_paddr_t)kernphys, trunc_page(first)); + bzero(physmap, sizeof(physmap)); physmap_idx = 0; diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 2766414b46c..171a8afd54b 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -101,6 +101,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef DDB #ifndef KDB @@ -1833,6 +1834,12 @@ getmemsize(int first) bzero(physmap, sizeof(physmap)); basemem = 0; + /* + * Tell the physical memory allocator about pages used to store + * the kernel and preloaded data. See kmem_bootstrap_free(). + */ + vm_phys_add_seg((vm_paddr_t)KERNLOAD, trunc_page(first)); + /* * Check if the loader supplied an SMAP memory map. If so, * use that and do not make any VM86 calls. diff --git a/sys/kern/subr_module.c b/sys/kern/subr_module.c index 7a05f5f2d63..883ba0a1948 100644 --- a/sys/kern/subr_module.c +++ b/sys/kern/subr_module.c @@ -33,6 +33,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include + /* * Preloaded module support */ @@ -204,29 +207,42 @@ preload_search_info(caddr_t mod, int inf) void preload_delete_name(const char *name) { - caddr_t curp; - uint32_t *hdr; + caddr_t addr, curp; + uint32_t *hdr, sz; int next; int clearing; + + addr = 0; + sz = 0; if (preload_metadata != NULL) { - + clearing = 0; curp = preload_metadata; for (;;) { hdr = (uint32_t *)curp; - if (hdr[0] == 0 && hdr[1] == 0) - break; + if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { + /* Free memory used to store the file. */ + if (addr != 0 && sz != 0) + kmem_bootstrap_free((vm_offset_t)addr, sz); + addr = 0; + sz = 0; - /* Search for a MODINFO_NAME field */ - if (hdr[0] == MODINFO_NAME) { + if (hdr[0] == 0) + break; if (!strcmp(name, curp + sizeof(uint32_t) * 2)) clearing = 1; /* got it, start clearing */ - else if (clearing) + else if (clearing) { clearing = 0; /* at next one now.. better stop */ + } } - if (clearing) + if (clearing) { + if (hdr[0] == MODINFO_ADDR) + addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); + else if (hdr[0] == MODINFO_SIZE) + sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); hdr[0] = MODINFO_EMPTY; + } /* skip to next field */ next = sizeof(uint32_t) * 2 + hdr[1]; diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h index 22f945b197d..5754ea269f5 100644 --- a/sys/vm/vm_extern.h +++ b/sys/vm/vm_extern.h @@ -75,6 +75,7 @@ int kmem_back_domain(int, vm_object_t, vm_offset_t, vm_size_t, int); void kmem_unback(vm_object_t, vm_offset_t, vm_size_t); /* Bootstrapping. */ +void kmem_bootstrap_free(vm_offset_t, vm_size_t); vm_map_t kmem_suballoc(vm_map_t, vm_offset_t *, vm_offset_t *, vm_size_t, boolean_t); void kmem_init(vm_offset_t, vm_offset_t); diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index 037db572339..724205c9530 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -688,6 +688,38 @@ kmem_init(vm_offset_t start, vm_offset_t end) vm_map_unlock(m); } +/* + * kmem_bootstrap_free: + * + * Free pages backing preloaded data (e.g., kernel modules) to the + * system. Currently only supported on platforms that create a + * vm_phys segment for preloaded data. + */ +void +kmem_bootstrap_free(vm_offset_t start, vm_size_t size) +{ +#if defined(__i386__) || defined(__amd64__) + struct vm_domain *vmd; + vm_offset_t end; + vm_paddr_t pa; + vm_page_t m; + + end = trunc_page(start + size); + start = round_page(start); + + (void)vm_map_remove(kernel_map, start, end); + for (; start < end; start += PAGE_SIZE) { + pa = pmap_kextract(start); + m = PHYS_TO_VM_PAGE(pa); + + vmd = vm_pagequeue_domain(m); + vm_domain_free_lock(vmd); + vm_phys_free_pages(m, 0); + vm_domain_free_unlock(vmd); + } +#endif +} + #ifdef DIAGNOSTIC /* * Allow userspace to directly trigger the VM drain routine for testing