From 57f2b5a0137be29081ab719ae33ebabddc95b78b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 5 Aug 2008 17:19:46 +0000 Subject: [PATCH] * Changed the meaning of the {KERNEL,USER}_STACK_SIZE macros to not include the guard pages. Adjusted the kernel and boot loader code accordingly -- the guard pages size is added/not removed respectively. The stack size passed to _kern_spawn_thread() is now the actually usable size, and it is no longer possible to specify a size smaller than or equal to the guard pages size. * vm_create_anonymous_area(): Precommit two pages maximum -- a stack with only one page usable size obviously doesn't need two pages. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26819 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/kernel.h | 9 +++--- headers/private/system/thread_defs.h | 13 +++++---- src/system/boot/platform/atari_m68k/mmu.cpp | 28 ++++++++++--------- src/system/boot/platform/bios_ia32/mmu.cpp | 7 +++-- src/system/boot/platform/bios_ia32/smp.cpp | 16 +++++++---- .../platform/openfirmware/arch/ppc/cpu.cpp | 12 ++++---- src/system/kernel/arch/m68k/arch_debug.cpp | 2 +- src/system/kernel/arch/m68k/arch_thread.c | 8 +++--- src/system/kernel/arch/ppc/arch_debug.cpp | 2 +- src/system/kernel/arch/ppc/arch_thread.c | 12 ++++---- src/system/kernel/arch/x86/arch_thread.cpp | 4 +-- src/system/kernel/team.cpp | 6 ++-- src/system/kernel/thread.cpp | 7 +++-- src/system/kernel/vm/vm.cpp | 9 +++--- 14 files changed, 78 insertions(+), 57 deletions(-) diff --git a/headers/private/kernel/kernel.h b/headers/private/kernel/kernel.h index 31cff76c9e..5dee855b8a 100644 --- a/headers/private/kernel/kernel.h +++ b/headers/private/kernel/kernel.h @@ -27,12 +27,13 @@ // At least, you then know that the stack overflows in this case :) /** Size of the kernel stack */ -#ifndef DEBUG_KERNEL_STACKS -# define KERNEL_STACK_SIZE (B_PAGE_SIZE * 3) // 12 kB +#define KERNEL_STACK_SIZE (B_PAGE_SIZE * 3) // 12 kB + +#ifdef DEBUG_KERNEL_STACKS +# define KERNEL_STACK_GUARD_PAGES 1 #else -# define KERNEL_STACK_SIZE (B_PAGE_SIZE * 4) // 12 kB + one guard page +# define KERNEL_STACK_GUARD_PAGES 0 #endif -#define KERNEL_STACK_GUARD_PAGES 1 /** Size of the environmental variables space for a process */ #define ENV_SIZE (B_PAGE_SIZE * 8) diff --git a/headers/private/system/thread_defs.h b/headers/private/system/thread_defs.h index 15a0e36d05..2d67e5183a 100644 --- a/headers/private/system/thread_defs.h +++ b/headers/private/system/thread_defs.h @@ -14,11 +14,14 @@ #define THREAD_CONTINUED 0x4 /** Size of the stack given to teams in user space */ -#define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024) // 16 MB -#define USER_STACK_SIZE (256 * 1024) // 256 kB -#define MIN_USER_STACK_SIZE (4 * 1024) // 4 KB -#define MAX_USER_STACK_SIZE (16 * 1024 * 1024) // 16 MB -#define USER_STACK_GUARD_PAGES 4 // 16 kB +#define USER_STACK_GUARD_PAGES 4 // 16 kB +#define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024 \ + - USER_STACK_GUARD_PAGES * B_PAGE_SIZE) // 16 MB +#define USER_STACK_SIZE (256 * 1024 \ + - USER_STACK_GUARD_PAGES * B_PAGE_SIZE) // 256 kB +#define MIN_USER_STACK_SIZE (4 * 1024) // 4 KB +#define MAX_USER_STACK_SIZE (16 * 1024 * 1024 \ + - USER_STACK_GUARD_PAGES * B_PAGE_SIZE) // 16 MB struct thread_creation_attributes { diff --git a/src/system/boot/platform/atari_m68k/mmu.cpp b/src/system/boot/platform/atari_m68k/mmu.cpp index 6ed808259c..e3dfbd872a 100644 --- a/src/system/boot/platform/atari_m68k/mmu.cpp +++ b/src/system/boot/platform/atari_m68k/mmu.cpp @@ -57,12 +57,12 @@ * 0xdNNNNN video buffer usually there, as per v_bas_ad * (=Logbase() but Physbase() is better) * - * The first 32 MB (2) are identity mapped (0x0 - 0x1000000); paging - * is turned on. The kernel is mapped at 0x80000000, all other stuff - * mapped by the loader (kernel args, modules, driver settings, ...) - * comes after 0x81000000 which means that there is currently only + * The first 32 MB (2) are identity mapped (0x0 - 0x1000000); paging + * is turned on. The kernel is mapped at 0x80000000, all other stuff + * mapped by the loader (kernel args, modules, driver settings, ...) + * comes after 0x81000000 which means that there is currently only * 1 MB reserved for the kernel itself (see kMaxKernelSize). - * + * * (1) no need for user stack, we are already in supervisor mode in the * loader. * (2) maps the whole regular ST space; transparent translation registers @@ -143,9 +143,9 @@ extern "C" addr_t mmu_get_next_page_tables() { #if 0 - TRACE(("mmu_get_next_page_tables, sNextPageTableAddress %p, kPageTableRegionEnd %p\n", + TRACE(("mmu_get_next_page_tables, sNextPageTableAddress %p, kPageTableRegionEnd %p\n", sNextPageTableAddress, kPageTableRegionEnd)); - + addr_t address = sNextPageTableAddress; if (address >= kPageTableRegionEnd) return (uint32 *)get_next_physical_page(); @@ -492,7 +492,7 @@ mmu_init_for_kernel(void) // seg 0x10 - kernel 4GB data set_segment_descriptor(&virtualGDT[2], 0, 0xffffffff, DT_DATA_WRITEABLE, DPL_KERNEL); - + // seg 0x1b - ring 3 user 4GB code set_segment_descriptor(&virtualGDT[3], 0, 0xffffffff, DT_CODE_READABLE, DPL_USER); @@ -613,10 +613,12 @@ mmu_init(void) // set virtual addr for interrupt vector table gKernelArgs.arch_args.vir_vbr = gKernelArgs.arch_args.vir_pgroot + VBR_PAGE_OFFSET; - + // map in a kernel stack - gKernelArgs.cpu_kstack[0].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE); - gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE; + gKernelArgs.cpu_kstack[0].start = (addr_t)mmu_allocate(NULL, + KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; TRACE(("kernel stack at 0x%lx to 0x%lx\n", gKernelArgs.cpu_kstack[0].start, gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size)); @@ -633,9 +635,9 @@ mmu_init(void) gKernelArgs.physical_memory_range[1].size = fastram_top - ATARI_FASTRAM_BASE; gKernelArgs.num_physical_memory_ranges++; - + } - + // mark the video area allocated addr_t video_base = *TOSVAR_memtop; video_base &= ~(B_PAGE_SIZE-1); diff --git a/src/system/boot/platform/bios_ia32/mmu.cpp b/src/system/boot/platform/bios_ia32/mmu.cpp index 0e870fba15..b3b9fd9207 100644 --- a/src/system/boot/platform/bios_ia32/mmu.cpp +++ b/src/system/boot/platform/bios_ia32/mmu.cpp @@ -302,7 +302,7 @@ get_memory_map(extended_memory **_extendedMemory) dprintf("extended memory info (from 0xe820):\n"); for (uint32 i = 0; i < count; i++) { dprintf(" base 0x%08Lx, len 0x%08Lx, type %lu (%s)\n", - block[i].base_addr, block[i].length, + block[i].base_addr, block[i].length, block[i].type, e820_memory_type(block[i].type)); } #endif @@ -606,8 +606,9 @@ mmu_init(void) // map in a kernel stack gKernelArgs.cpu_kstack[0].start = (addr_t)mmu_allocate(NULL, - KERNEL_STACK_SIZE); - gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE; + KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; TRACE(("kernel stack at 0x%lx to 0x%lx\n", gKernelArgs.cpu_kstack[0].start, gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size)); diff --git a/src/system/boot/platform/bios_ia32/smp.cpp b/src/system/boot/platform/bios_ia32/smp.cpp index be7799d717..650925691a 100644 --- a/src/system/boot/platform/bios_ia32/smp.cpp +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -396,8 +396,10 @@ smp_init_other_cpus(void) for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) { // create a final stack the trampoline code will put the ap processor on - gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE); - gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE; + gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL, + KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; } } @@ -438,14 +440,18 @@ smp_boot_other_cpus(void) // set this stack up finalStack = (uint32 *)gKernelArgs.cpu_kstack[i].start; - memset(finalStack, 0, KERNEL_STACK_SIZE); - tempStack = (finalStack + KERNEL_STACK_SIZE / sizeof(uint32)) - 1; + memset((uint8*)finalStack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0, + KERNEL_STACK_SIZE); + tempStack = (finalStack + + (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE) + / sizeof(uint32)) - 1; *tempStack = (uint32)&smp_cpu_ready; // set the trampoline stack up tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4); // final location of the stack - *tempStack = ((uint32)finalStack) + KERNEL_STACK_SIZE - sizeof(uint32); + *tempStack = ((uint32)finalStack) + KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE - sizeof(uint32); tempStack--; // page dir *tempStack = gKernelArgs.arch_args.phys_pgdir; diff --git a/src/system/boot/platform/openfirmware/arch/ppc/cpu.cpp b/src/system/boot/platform/openfirmware/arch/ppc/cpu.cpp index 800de3f153..d3baad3daa 100644 --- a/src/system/boot/platform/openfirmware/arch/ppc/cpu.cpp +++ b/src/system/boot/platform/openfirmware/arch/ppc/cpu.cpp @@ -76,7 +76,7 @@ boot_arch_cpu_init(void) gKernelArgs.arch_args.cpu_frequency = clockFrequency; gKernelArgs.arch_args.bus_frequency = busFrequency; gKernelArgs.arch_args.time_base_frequency = timeBaseFrequency; - + TRACE((" CPU clock frequency: %ld\n", clockFrequency)); TRACE((" bus clock frequency: %ld\n", busFrequency)); TRACE((" time base frequency: %ld\n", timeBaseFrequency)); @@ -84,7 +84,7 @@ boot_arch_cpu_init(void) cpuCount++; } - + if (cpuCount == 0) { printf("boot_arch_cpu_init(): Found no CPUs!\n"); return B_ERROR; @@ -95,7 +95,8 @@ boot_arch_cpu_init(void) // allocate the kernel stacks (the memory stuff is already initialized // at this point) addr_t stack = (addr_t)arch_mmu_allocate((void*)0x80000000, - cpuCount * KERNEL_STACK_SIZE, B_READ_AREA | B_WRITE_AREA, false); + cpuCount * (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), + B_READ_AREA | B_WRITE_AREA, false); if (!stack) { printf("boot_arch_cpu_init(): Failed to allocate kernel stack(s)!\n"); return B_NO_MEMORY; @@ -103,8 +104,9 @@ boot_arch_cpu_init(void) for (int i = 0; i < cpuCount; i++) { gKernelArgs.cpu_kstack[i].start = stack; - gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE; - stack += KERNEL_STACK_SIZE; + gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; + stack += KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; } return B_OK; diff --git a/src/system/kernel/arch/m68k/arch_debug.cpp b/src/system/kernel/arch/m68k/arch_debug.cpp index f710ef0b03..25f88a4db5 100644 --- a/src/system/kernel/arch/m68k/arch_debug.cpp +++ b/src/system/kernel/arch/m68k/arch_debug.cpp @@ -180,7 +180,7 @@ return 0; kprintf(" kernel stack: %p to %p\n", (void *)thread->kernel_stack_base, - (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); + (void *)(thread->kernel_stack_top)); if (thread->user_stack_base != 0) { kprintf(" user stack: %p to %p\n", (void *)thread->user_stack_base, diff --git a/src/system/kernel/arch/m68k/arch_thread.c b/src/system/kernel/arch/m68k/arch_thread.c index 07fe40cd97..8dbb2d0006 100644 --- a/src/system/kernel/arch/m68k/arch_thread.c +++ b/src/system/kernel/arch/m68k/arch_thread.c @@ -110,7 +110,7 @@ m68k_next_page_directory(struct thread *from, struct thread *to) // the one we're switching to is kernel space return m68k_translation_map_get_pgdir(&vm_kernel_address_space()->translation_map); } - + return m68k_translation_map_get_pgdir(&to->team->address_space->translation_map); } @@ -150,15 +150,15 @@ arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) { addr_t *kstack = (addr_t *)t->kernel_stack_base; - addr_t *kstackTop = kstack + KERNEL_STACK_SIZE / sizeof(addr_t); + addr_t *kstackTop = (addr_t *)t->kernel_stack_base; // clear the kernel stack #ifdef DEBUG_KERNEL_STACKS # ifdef STACK_GROWS_DOWNWARDS memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0, - KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + KERNEL_STACK_SIZE); # else - memset(kstack, 0, KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + memset(kstack, 0, KERNEL_STACK_SIZE); # endif #else memset(kstack, 0, KERNEL_STACK_SIZE); diff --git a/src/system/kernel/arch/ppc/arch_debug.cpp b/src/system/kernel/arch/ppc/arch_debug.cpp index de9139985a..94581ac3d1 100644 --- a/src/system/kernel/arch/ppc/arch_debug.cpp +++ b/src/system/kernel/arch/ppc/arch_debug.cpp @@ -179,7 +179,7 @@ return 0; kprintf(" kernel stack: %p to %p\n", (void *)thread->kernel_stack_base, - (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); + (void *)(thread->kernel_stack_top)); if (thread->user_stack_base != 0) { kprintf(" user stack: %p to %p\n", (void *)thread->user_stack_base, diff --git a/src/system/kernel/arch/ppc/arch_thread.c b/src/system/kernel/arch/ppc/arch_thread.c index 6b3163d807..3e63ecbc87 100644 --- a/src/system/kernel/arch/ppc/arch_thread.c +++ b/src/system/kernel/arch/ppc/arch_thread.c @@ -122,15 +122,15 @@ arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) { addr_t *kstack = (addr_t *)t->kernel_stack_base; - addr_t *kstackTop = kstack + KERNEL_STACK_SIZE / sizeof(addr_t); + addr_t *kstackTop = (addr_t *)t->kernel_stack_top; // clear the kernel stack #ifdef DEBUG_KERNEL_STACKS # ifdef STACK_GROWS_DOWNWARDS memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0, - KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + KERNEL_STACK_SIZE); # else - memset(kstack, 0, KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + memset(kstack, 0, KERNEL_STACK_SIZE); # endif #else memset(kstack, 0, KERNEL_STACK_SIZE); @@ -180,9 +180,9 @@ void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) { // set the new kernel stack in the EAR register. - // this is used in the exception handler code to decide what kernel stack to - // switch to if the exception had happened when the processor was in user mode - asm("mtear %0" :: "g"(t_to->kernel_stack_base + KERNEL_STACK_SIZE - 8)); + // this is used in the exception handler code to decide what kernel stack to + // switch to if the exception had happened when the processor was in user mode + asm("mtear %0" :: "g"(t_to->kernel_stack_top - 8)); // switch the asids if we need to if (t_to->team->address_space != NULL) { diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index 37addd3c67..62952e0e9b 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -261,9 +261,9 @@ arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), #ifdef DEBUG_KERNEL_STACKS # ifdef STACK_GROWS_DOWNWARDS memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0, - KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + KERNEL_STACK_SIZE); # else - memset(kstack, 0, KERNEL_STACK_SIZE - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE); + memset(kstack, 0, KERNEL_STACK_SIZE); # endif #else memset(kstack, 0, KERNEL_STACK_SIZE); diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 5a52383e7f..5558b63ec8 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -985,10 +985,12 @@ team_create_thread_start(void *args) // ToDo: ENV_SIZE is a) limited, and b) not used after libroot copied it to the heap // ToDo: we could reserve the whole USER_STACK_REGION upfront... - sizeLeft = PAGE_ALIGN(USER_MAIN_THREAD_STACK_SIZE + TLS_SIZE + sizeLeft = PAGE_ALIGN(USER_MAIN_THREAD_STACK_SIZE + + USER_STACK_GUARD_PAGES * B_PAGE_SIZE + TLS_SIZE + sizeof(struct user_space_program_args) + teamArgs->flat_args_size); t->user_stack_base = USER_STACK_REGION + USER_STACK_REGION_SIZE - sizeLeft; - t->user_stack_size = USER_MAIN_THREAD_STACK_SIZE; + t->user_stack_size = USER_MAIN_THREAD_STACK_SIZE + + USER_STACK_GUARD_PAGES * B_PAGE_SIZE; // the exact location at the end of the user stack area sprintf(ustack_name, "%s_main_stack", team->name); diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index b5c1cc1938..b2e88121a7 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -391,7 +391,8 @@ create_thread(thread_creation_attributes& attributes, bool kernel) thread->id); thread->kernel_stack_area = create_area(stack_name, (void **)&thread->kernel_stack_base, B_ANY_KERNEL_ADDRESS, - KERNEL_STACK_SIZE, B_FULL_LOCK, + KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, + B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_KERNEL_STACK_AREA); if (thread->kernel_stack_area < 0) { @@ -405,7 +406,8 @@ create_thread(thread_creation_attributes& attributes, bool kernel) return status; } - thread->kernel_stack_top = thread->kernel_stack_base + KERNEL_STACK_SIZE; + thread->kernel_stack_top = thread->kernel_stack_base + KERNEL_STACK_SIZE + + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; state = disable_interrupts(); GRAB_THREAD_LOCK(); @@ -499,6 +501,7 @@ create_thread(thread_creation_attributes& attributes, bool kernel) thread->user_stack_size = USER_STACK_SIZE; else thread->user_stack_size = PAGE_ALIGN(attributes.stack_size); + thread->user_stack_size += USER_STACK_GUARD_PAGES * B_PAGE_SIZE; snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%ld_stack", attributes.name, thread->id); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 87f6a061fb..d71fdf8fd8 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1576,6 +1576,7 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, vm_cache *cache; vm_page *page = NULL; bool isStack = (protection & B_STACK_AREA) != 0; + page_num_t guardPages; bool canOvercommit = false; addr_t physicalBase = 0; @@ -1693,10 +1694,10 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, // create an anonymous cache // if it's a stack, make sure that two pages are available at least - status = VMCacheFactory::CreateAnonymousCache(cache, - canOvercommit, isStack ? 2 : 0, - isStack ? ((protection & B_USER_PROTECTION) != 0 ? - USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0, + guardPages = isStack ? ((protection & B_USER_PROTECTION) != 0 + ? USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0; + status = VMCacheFactory::CreateAnonymousCache(cache, canOvercommit, + isStack ? (min_c(2, size / B_PAGE_SIZE - guardPages)) : 0, guardPages, wiring == B_NO_LOCK); if (status != B_OK) goto err1;