diff --git a/headers/private/kernel/memheap.h b/headers/private/kernel/memheap.h index f501250f1c..44d318e1ab 100644 --- a/headers/private/kernel/memheap.h +++ b/headers/private/kernel/memheap.h @@ -24,7 +24,7 @@ extern "C" { void *memalign(size_t alignment, size_t size); -status_t heap_init(addr_t heapBase); +status_t heap_init(addr_t heapBase, size_t heapSize); status_t heap_init_post_sem(struct kernel_args *args); status_t heap_init_post_thread(struct kernel_args *args); diff --git a/headers/private/kernel/vm_page.h b/headers/private/kernel/vm_page.h index 29eed78e48..d3cdf42e20 100644 --- a/headers/private/kernel/vm_page.h +++ b/headers/private/kernel/vm_page.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -19,6 +19,7 @@ struct kernel_args; extern "C" { #endif +void vm_page_init_num_pages(kernel_args *args); status_t vm_page_init(struct kernel_args *args); status_t vm_page_init_post_area(struct kernel_args *args); status_t vm_page_init_post_thread(struct kernel_args *args); diff --git a/src/system/kernel/heap.c b/src/system/kernel/heap.c index ba29cad883..2fd9ae9d7c 100644 --- a/src/system/kernel/heap.c +++ b/src/system/kernel/heap.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. @@ -315,12 +315,12 @@ dump_bin_list(int argc, char **argv) */ status_t -heap_init(addr_t heapBase) +heap_init(addr_t heapBase, size_t heapSize) { const unsigned int page_entries = B_PAGE_SIZE / sizeof(struct heap_page); // set some global pointers heap_alloc_table = (struct heap_page *)heapBase; - heap_size = ((uint64)HEAP_SIZE * page_entries / (page_entries + 1)) & ~(B_PAGE_SIZE-1); + heap_size = ((uint64)heapSize * page_entries / (page_entries + 1)) & ~(B_PAGE_SIZE-1); heap_base = (unsigned int)heap_alloc_table + PAGE_ALIGN(heap_size / page_entries); heap_base_ptr = heap_base; TRACE(("heap_alloc_table = %p, heap_base = 0x%lx, heap_size = 0x%lx\n", diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 38a21448de..8251271716 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -2228,7 +2228,6 @@ status_t vm_init(kernel_args *args) { struct preloaded_image *image; - addr_t heap_base; void *address; status_t err = 0; uint32 i; @@ -2242,14 +2241,24 @@ vm_init(kernel_args *args) sAreaHashLock = -1; sAvailableMemoryLock.sem = -1; + vm_page_init_num_pages(args); + sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE; + + // reduce the heap size if we have not so much RAM + size_t heapSize = HEAP_SIZE; + if (sAvailableMemory < 100 * 1024 * 1024) + heapSize /= 4; + else if (sAvailableMemory < 200 * 1024 * 1024) + heapSize /= 2; + // map in the new heap and initialize it - heap_base = vm_alloc_from_kernel_args(args, HEAP_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - TRACE(("heap at 0x%lx\n", heap_base)); - heap_init(heap_base); + addr_t heapBase = vm_alloc_from_kernel_args(args, heapSize, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); + TRACE(("heap at 0x%lx\n", heapBase)); + heap_init(heapBase, heapSize); // initialize the free page list and physical page mapper vm_page_init(args); - sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE; // initialize the hash table that stores the pages mapped to caches vm_cache_init(args); @@ -2272,8 +2281,8 @@ vm_init(kernel_args *args) // allocate areas to represent stuff that already exists - address = (void *)ROUNDOWN(heap_base, B_PAGE_SIZE); - create_area("kernel heap", &address, B_EXACT_ADDRESS, HEAP_SIZE, + address = (void *)ROUNDOWN(heapBase, B_PAGE_SIZE); + create_area("kernel heap", &address, B_EXACT_ADDRESS, heapSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); allocate_kernel_args(args); diff --git a/src/system/kernel/vm/vm_page.c b/src/system/kernel/vm/vm_page.c index df9b1a9f5d..d51f472fbc 100644 --- a/src/system/kernel/vm/vm_page.c +++ b/src/system/kernel/vm/vm_page.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -46,11 +46,11 @@ static page_queue page_clear_queue; static page_queue page_modified_queue; static page_queue page_active_queue; -static vm_page *all_pages; -static addr_t physical_page_offset; -static unsigned int num_pages; +static vm_page *sPages; +static addr_t sPhysicalPageOffset; +static size_t sNumPages; -static spinlock page_lock; +static spinlock sPageLock; static sem_id modified_pages_available; @@ -178,7 +178,7 @@ vm_page_write_modified(vm_cache *cache) vm_area *area; cpu_status state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); if (page->state == PAGE_STATE_MODIFIED) { remove_page_from_queue(&page_modified_queue, page); @@ -186,7 +186,7 @@ vm_page_write_modified(vm_cache *cache) gotPage = true; } - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); // We may have a modified page - however, while we're writing it back, the page @@ -238,7 +238,7 @@ vm_page_write_modified(vm_cache *cache) // put it into the active queue state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); if (page->ref_count > 0) page->state = PAGE_STATE_ACTIVE; @@ -247,7 +247,7 @@ vm_page_write_modified(vm_cache *cache) enqueue_page(&page_active_queue, page); - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); } } else { @@ -277,11 +277,11 @@ static int pageout_daemon() dprintf("here\n"); state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); page = dequeue_page(&page_modified_queue); page->state = PAGE_STATE_BUSY; vm_cache_acquire_ref(page->cache_ref, true); - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); dprintf("got page %p\n", page); @@ -290,10 +290,10 @@ static int pageout_daemon() // unless we're in the trimming cycle, dont write out pages // that back anonymous stores state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); enqueue_page(&page_modified_queue, page); page->state = PAGE_STATE_MODIFIED; - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); vm_cache_release_ref(page->cache_ref); continue; @@ -323,14 +323,14 @@ static int pageout_daemon() vm_put_physical_page((addr_t)vecs->vec[0].iov_base); state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); if(page->ref_count > 0) { page->state = PAGE_STATE_ACTIVE; } else { page->state = PAGE_STATE_INACTIVE; } enqueue_page(&page_active_queue, page); - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); vm_cache_release_ref(page->cache_ref); @@ -339,14 +339,35 @@ static int pageout_daemon() #endif -status_t -vm_page_init(kernel_args *ka) +void +vm_page_init_num_pages(kernel_args *args) { - unsigned int i; + uint32 i; + + // calculate the size of memory by looking at the physical_memory_range array + addr_t physicalPagesEnd = 0; + sPhysicalPageOffset = args->physical_memory_range[0].start / B_PAGE_SIZE; + + for (i = 0; i < args->num_physical_memory_ranges; i++) { + physicalPagesEnd = (args->physical_memory_range[i].start + + args->physical_memory_range[i].size) / B_PAGE_SIZE; + } + + TRACE(("first phys page = 0x%lx, end 0x%x\n", sPhysicalPageOffset, + physicalPagesEnd)); + + sNumPages = physicalPagesEnd - sPhysicalPageOffset; +} + + +status_t +vm_page_init(kernel_args *args) +{ + uint32 i; TRACE(("vm_page_init: entry\n")); - page_lock = 0; + sPageLock = 0; // initialize queues page_free_queue.head = NULL; @@ -362,42 +383,28 @@ vm_page_init(kernel_args *ka) page_active_queue.tail = NULL; page_active_queue.count = 0; - // calculate the size of memory by looking at the physical_memory_range array - { - unsigned int physicalPagesEnd = 0; - - physical_page_offset = ka->physical_memory_range[0].start / B_PAGE_SIZE; - for (i = 0; inum_physical_memory_ranges; i++) { - physicalPagesEnd = (ka->physical_memory_range[i].start - + ka->physical_memory_range[i].size) / B_PAGE_SIZE; - } - TRACE(("first phys page = 0x%lx, end 0x%x\n", physical_page_offset, - physicalPagesEnd)); - num_pages = physicalPagesEnd - physical_page_offset; - } - // map in the new free page table - all_pages = (vm_page *)vm_alloc_from_kernel_args(ka, num_pages * sizeof(vm_page), - B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); + sPages = (vm_page *)vm_alloc_from_kernel_args(args, sNumPages * sizeof(vm_page), + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); TRACE(("vm_init: putting free_page_table @ %p, # ents %d (size 0x%x)\n", - all_pages, num_pages, (unsigned int)(num_pages * sizeof(vm_page)))); + sPages, sNumPages, (unsigned int)(sNumPages * sizeof(vm_page)))); // initialize the free page table - for (i = 0; i < num_pages; i++) { - all_pages[i].physical_page_number = physical_page_offset + i; - all_pages[i].type = PAGE_TYPE_PHYSICAL; - all_pages[i].state = PAGE_STATE_FREE; - all_pages[i].ref_count = 0; - enqueue_page(&page_free_queue, &all_pages[i]); + for (i = 0; i < sNumPages; i++) { + sPages[i].physical_page_number = sPhysicalPageOffset + i; + sPages[i].type = PAGE_TYPE_PHYSICAL; + sPages[i].state = PAGE_STATE_FREE; + sPages[i].ref_count = 0; + enqueue_page(&page_free_queue, &sPages[i]); } TRACE(("initialized table\n")); // mark some of the page ranges inuse - for (i = 0; i < ka->num_physical_allocated_ranges; i++) { - vm_mark_page_range_inuse(ka->physical_allocated_range[i].start / B_PAGE_SIZE, - ka->physical_allocated_range[i].size / B_PAGE_SIZE); + for (i = 0; i < args->num_physical_allocated_ranges; i++) { + vm_mark_page_range_inuse(args->physical_allocated_range[i].start / B_PAGE_SIZE, + args->physical_allocated_range[i].size / B_PAGE_SIZE); } TRACE(("vm_page_init: exit\n")); @@ -411,9 +418,9 @@ vm_page_init_post_area(kernel_args *args) { void *dummy; - dummy = all_pages; + dummy = sPages; create_area("page structures", &dummy, B_EXACT_ADDRESS, - PAGE_ALIGN(num_pages * sizeof(vm_page)), B_ALREADY_WIRED, + PAGE_ALIGN(sNumPages * sizeof(vm_page)), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); add_debugger_command("page_stats", &dump_page_stats, "Dump statistics about page usage"); @@ -468,7 +475,7 @@ page_scrubber(void *unused) // get some pages from the free queue state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); for (i = 0; i < SCRUB_SIZE; i++) { page[i] = dequeue_page(&page_free_queue); @@ -476,7 +483,7 @@ page_scrubber(void *unused) break; } - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); // clear them @@ -488,7 +495,7 @@ page_scrubber(void *unused) } state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); // and put them into the clear queue @@ -497,7 +504,7 @@ page_scrubber(void *unused) enqueue_page(&page_clear_queue, page[i]); } - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); } } @@ -537,21 +544,21 @@ vm_mark_page_range_inuse(addr_t start_page, addr_t length) TRACE(("vm_mark_page_range_inuse: start 0x%lx, len 0x%lx\n", start_page, length)); - if (physical_page_offset > start_page) { + if (sPhysicalPageOffset > start_page) { dprintf("vm_mark_page_range_inuse: start page %ld is before free list\n", start_page); return B_BAD_VALUE; } - start_page -= physical_page_offset; - if (start_page + length > num_pages) { + start_page -= sPhysicalPageOffset; + if (start_page + length > sNumPages) { dprintf("vm_mark_page_range_inuse: range would extend past free list\n"); return B_BAD_VALUE; } state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); for (i = 0; i < length; i++) { - page = &all_pages[start_page + i]; + page = &sPages[start_page + i]; switch (page->state) { case PAGE_STATE_FREE: case PAGE_STATE_CLEAR: @@ -570,7 +577,7 @@ vm_mark_page_range_inuse(addr_t start_page, addr_t length) } } - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); return B_OK; @@ -585,7 +592,7 @@ vm_page_allocate_specific_page(addr_t page_num, int page_state) int state; state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); p = vm_lookup_page(page_num); if (p == NULL) @@ -614,7 +621,7 @@ vm_page_allocate_specific_page(addr_t page_num, int page_state) enqueue_page(&page_active_queue, p); out: - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); if (p != NULL && page_state == PAGE_STATE_CLEAR @@ -648,7 +655,7 @@ vm_page_allocate_page(int page_state) } state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); p = dequeue_page(q); if (p == NULL) { @@ -676,7 +683,7 @@ vm_page_allocate_page(int page_state) enqueue_page(&page_active_queue, p); - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); // if needed take the page from the free queue and zero it out @@ -724,16 +731,16 @@ vm_page_allocate_page_run(int page_state, addr_t len) start = 0; state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); for (;;) { bool foundit = true; - if (start + len > num_pages) + if (start + len > sNumPages) break; for (i = 0; i < len; i++) { - if (all_pages[start + i].state != PAGE_STATE_FREE - && all_pages[start + i].state != PAGE_STATE_CLEAR) { + if (sPages[start + i].state != PAGE_STATE_FREE + && sPages[start + i].state != PAGE_STATE_CLEAR) { foundit = false; i++; break; @@ -742,14 +749,14 @@ vm_page_allocate_page_run(int page_state, addr_t len) if (foundit) { // pull the pages out of the appropriate queues for (i = 0; i < len; i++) - vm_page_set_state_nolock(&all_pages[start + i], PAGE_STATE_BUSY); - first_page = &all_pages[start]; + vm_page_set_state_nolock(&sPages[start + i], PAGE_STATE_BUSY); + first_page = &sPages[start]; break; } else { start += i; } } - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); return first_page; @@ -759,14 +766,14 @@ vm_page_allocate_page_run(int page_state, addr_t len) vm_page * vm_lookup_page(addr_t page_num) { - if (page_num < physical_page_offset) + if (page_num < sPhysicalPageOffset) return NULL; - page_num -= physical_page_offset; - if (page_num >= num_pages) + page_num -= sPhysicalPageOffset; + if (page_num >= sNumPages) return NULL; - return &all_pages[page_num]; + return &sPages[page_num]; } @@ -830,11 +837,11 @@ vm_page_set_state(vm_page *page, int page_state) status_t status; cpu_status state = disable_interrupts(); - acquire_spinlock(&page_lock); + acquire_spinlock(&sPageLock); status = vm_page_set_state_nolock(page, page_state); - release_spinlock(&page_lock); + release_spinlock(&sPageLock); restore_interrupts(state); return status; @@ -844,7 +851,7 @@ vm_page_set_state(vm_page *page, int page_state) size_t vm_page_num_pages(void) { - return num_pages; + return sNumPages; } @@ -951,11 +958,11 @@ dump_page_stats(int argc, char **argv) memset(counter, 0, sizeof(counter)); - for (i = 0; i < num_pages; i++) { - if (all_pages[i].state > 7) - panic("page %i at %p has invalid state!\n", i, &all_pages[i]); + for (i = 0; i < sNumPages; i++) { + if (sPages[i].state > 7) + panic("page %i at %p has invalid state!\n", i, &sPages[i]); - counter[all_pages[i].state]++; + counter[sPages[i].state]++; } kprintf("page stats:\n");