diff --git a/headers/private/kernel/vm.h b/headers/private/kernel/vm.h index 086dac4fec..a82d8e0e0d 100644 --- a/headers/private/kernel/vm.h +++ b/headers/private/kernel/vm.h @@ -32,7 +32,8 @@ addr_t vm_allocate_early(kernel_args *args, size_t virtualSize, size_t physicalSize, uint32 attributes); -void slab_init(addr_t initialBase, size_t initialSize); +void slab_init(struct kernel_args *args, addr_t initialBase, + size_t initialSize); void slab_init_post_sem(); // to protect code regions with interrupts turned on diff --git a/src/system/kernel/slab/Slab.cpp b/src/system/kernel/slab/Slab.cpp index 674a3eb77b..3e7f83976f 100644 --- a/src/system/kernel/slab/Slab.cpp +++ b/src/system/kernel/slab/Slab.cpp @@ -72,6 +72,10 @@ struct object_cache : DoublyLinkedListLinkImpl { object_cache_destructor destructor; object_cache_reclaimer reclaimer; + status_t (*allocate_pages)(object_cache *cache, void **pages, + uint32 flags); + void (*free_pages)(object_cache *cache, void *pages); + object_depot depot; virtual slab *CreateSlab(uint32 flags) = 0; @@ -156,6 +160,7 @@ static ObjectCacheList sObjectCaches; static benaphore sObjectCacheListLock; static uint8 *sInitialBegin, *sInitialLimit, *sInitialPointer; +static kernel_args *sKernelArgs; static status_t object_cache_reserve_internal(object_cache *cache, @@ -258,7 +263,7 @@ benaphore_boot_init(benaphore *lock, const char *name, uint32 flags) static status_t -allocate_pages(object_cache *cache, void **pages, uint32 flags) +area_allocate_pages(object_cache *cache, void **pages, uint32 flags) { TRACE_CACHE(cache, "allocate pages (%lu, 0x0%lx)", cache->slab_size, flags); @@ -283,7 +288,7 @@ allocate_pages(object_cache *cache, void **pages, uint32 flags) static void -free_pages(object_cache *cache, void *pages) +area_free_pages(object_cache *cache, void *pages) { area_id id = area_for(pages); @@ -298,6 +303,24 @@ free_pages(object_cache *cache, void *pages) } +static status_t +early_allocate_pages(object_cache *cache, void **pages, uint32 flags) +{ + addr_t base = vm_allocate_early(sKernelArgs, cache->slab_size, + cache->slab_size, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); + + *pages = (void *)base; + return B_OK; +} + + +static void +early_free_pages(object_cache *cache, void *pages) +{ + panic("memory pressure on bootup?"); +} + + static void object_cache_low_memory(void *_self, int32 level) { @@ -409,6 +432,14 @@ object_cache_init(object_cache *cache, const char *name, size_t objectSize, cache->destructor = destructor; cache->reclaimer = reclaimer; + if (cache->flags & CACHE_DURING_BOOT) { + cache->allocate_pages = early_allocate_pages; + cache->free_pages = early_free_pages; + } else { + cache->allocate_pages = area_allocate_pages; + cache->free_pages = area_free_pages; + } + register_low_memory_handler(object_cache_low_memory, cache, 0); BenaphoreLocker _(sObjectCacheListLock); @@ -432,6 +463,36 @@ object_cache_init_locks(object_cache *cache) } +static void +object_cache_commit_slab(object_cache *cache, slab *slab) +{ + void *pages = (void *)ROUNDOWN((addr_t)slab->pages, B_PAGE_SIZE); + if (create_area(cache->name, &pages, B_EXACT_ADDRESS, cache->slab_size, + B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < B_OK) + panic("failed to create_area()"); +} + + +static void +object_cache_commit_pre_pages(object_cache *cache) +{ + SlabList::Iterator it = cache->full.GetIterator(); + while (it.HasNext()) + object_cache_commit_slab(cache, it.Next()); + + it = cache->partial.GetIterator(); + while (it.HasNext()) + object_cache_commit_slab(cache, it.Next()); + + it = cache->empty.GetIterator(); + while (it.HasNext()) + object_cache_commit_slab(cache, it.Next()); + + cache->allocate_pages = area_allocate_pages; + cache->free_pages = area_free_pages; +} + + static void delete_cache(object_cache *cache) { @@ -1202,12 +1263,14 @@ dump_cache_info(int argc, char *argv[]) void -slab_init(addr_t initialBase, size_t initialSize) +slab_init(kernel_args *args, addr_t initialBase, size_t initialSize) { sInitialBegin = (uint8 *)initialBase; sInitialLimit = sInitialBegin + initialSize; sInitialPointer = sInitialBegin; + sKernelArgs = args; + new (&sObjectCaches) ObjectCacheList(); block_allocator_init_boot(); @@ -1228,8 +1291,11 @@ slab_init_post_sem() ObjectCacheList::Iterator it = sObjectCaches.GetIterator(); while (it.HasNext()) { - if (object_cache_init_locks(it.Next()) < B_OK) + object_cache *cache = it.Next(); + if (object_cache_init_locks(cache) < B_OK) panic("slab_init: failed to create sems"); + if (cache->allocate_pages == early_allocate_pages) + object_cache_commit_pre_pages(cache); } block_allocator_init_rest(); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index ff7118a892..d1cb2fb888 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -2894,7 +2894,7 @@ vm_init(kernel_args *args) size_t slabInitialSize = 2 * B_PAGE_SIZE; addr_t slabInitialBase = vm_allocate_early(args, slabInitialSize, slabInitialSize, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - slab_init(slabInitialBase, slabInitialSize); + slab_init(args, slabInitialBase, slabInitialSize); // initialize the free page list and physical page mapper vm_page_init(args);