From: Matthias Kruk Date: Wed, 29 Jul 2020 00:54:42 +0000 (+0900) Subject: kernel: Grow the userspace stack if an application runs out of stack space X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=refs%2Fheads%2Fuserstack;p=corax kernel: Grow the userspace stack if an application runs out of stack space --- diff --git a/config.h b/config.h index 7cad81f..eeef1b2 100644 --- a/config.h +++ b/config.h @@ -29,6 +29,7 @@ #define CONFIG_KERNEL_STACK_BASE ((void*)0xffffe000) #endif /* !__ASSEMBLY_SOURCE */ #define CONFIG_USER_STACK_SIZE 4096 +#define CONFIG_USER_STACK_LIMIT (16 * 1048576) #define CONFIG_PROC_MAXTASKS 8 #define CONFIG_MUTEX_WAITQLEN 8 #define CONFIG_SEM_WAITQLEN 8 diff --git a/kernel/arch/interrupt.c b/kernel/arch/interrupt.c index 60e3399..fdd7346 100644 --- a/kernel/arch/interrupt.c +++ b/kernel/arch/interrupt.c @@ -172,6 +172,24 @@ void _int_handle(stack_frame_t ctx) return; } +static int _handle_pagefault(process_t *proc, task_t *task, u32_t addr) +{ + pg_dir_t *pd; + int ret_val; + + ret_val = process_get_pagedir(proc, &pd); + + if(!ret_val) { + /* + * pg_dir_grow_ustack() checks the address and only grows the + * stack if would not exceed the statically defined limit. + */ + ret_val = pg_dir_grow_ustack(pd, (void*)addr); + } + + return(ret_val); +} + void _exc_handle(stack_frame_t ctx) { process_t *cproc; @@ -184,7 +202,7 @@ void _exc_handle(stack_frame_t ctx) /* kernel bug */ dbg_printf("Exception %u [%s] occurred. Error code 0x%08x.\n", - ctx.intn, ctx.intn < EXC_MAX ? _exc_name[ctx.intn] : 0, ctx.error); + ctx.intn, ctx.intn < EXC_MAX ? _exc_name[ctx.intn] : 0, ctx.error); dbg_printf("In context %p [pid %u]\n", cproc, process_get_id(cproc)); dbg_printf("Fault in 0x%02x:%08x; EFLAGS = 0x%08x\n", ctx.cs, ctx.eip, ctx.eflags); @@ -207,20 +225,22 @@ void _exc_handle(stack_frame_t ctx) int sig; - dbg_printf("User-mode exception %u at 0x%08x\n", ctx.intn, ctx.eip); + dbg_printf("User-mode exception %u in pid %u at 0x%08x\n", + ctx.intn, process_get_id(cproc), ctx.eip); if(ctx.intn == EXC_PAGEFAULT) { u32_t cr2; - pg_dir_t *pd; asm volatile("movl %%cr2, %%eax; movl %%eax, %0" : "=r"(cr2)); dbg_printf("CR2: 0x%08x\n", cr2); - if(process_get_pagedir(cproc, &pd) == 0) { - pg_fault_debug(pd, (void*)cr2); + if(_handle_pagefault(cproc, ctask, cr2) >= 0) { + goto skip_signal; } } + for(;;); + switch(ctx.intn) { default: case EXC_DEBUG: @@ -267,7 +287,8 @@ void _exc_handle(stack_frame_t ctx) task_signal_deliver(ctask, &ctx, sig, NULL); } - return; +skip_signal: + return; } void _sys_handle(stack_frame_t ctx) diff --git a/kernel/arch/paging.c b/kernel/arch/paging.c index e02b668..0fec7d1 100644 --- a/kernel/arch/paging.c +++ b/kernel/arch/paging.c @@ -469,6 +469,77 @@ void* pg_dir_get_ustack(struct pagedir *pgdir) return(ret_val); } +void* pg_dir_get_ustack_top(struct pagedir *pgdir) +{ + struct region *reg; + void *ret_val; + int i; + + for(ret_val = NULL, i = 0; i < CONFIG_PAGING_DIR_MAXREGIONS; i++) { + reg = pgdir->pd_regions[i]; + + if(reg->reg_type == REGION_STACK) { + ret_val = (char*)reg->reg_base + reg->reg_size; + break; + } + } + + return(ret_val); +} + +int pg_dir_grow_ustack(struct pagedir *pgdir, void *new_bottom) +{ + struct region *stack; + char *stack_max; + char *stack_min; + char *new_aligned; + int ret_val; + int i; + + for(stack = NULL, i = 0; i < CONFIG_PAGING_DIR_MAXREGIONS; i++) { + if(pgdir->pd_regions[i]->reg_type == REGION_STACK) { + stack = pgdir->pd_regions[i]; + break; + } + } + + if(!stack) { + ret_val = -EBADFD; + goto gtfo; + } + + stack_max = (char*)stack->reg_base + stack->reg_size; + stack_min = stack_max - CONFIG_USER_STACK_LIMIT; + new_aligned = (char*)((unsigned long)new_bottom & + ~(stack->reg_pgsize - 1)); + + if(stack_min < new_aligned && new_aligned < stack_max) { + unsigned long map_size; + + map_size = (unsigned long)stack->reg_base - + (unsigned long)new_aligned; + + ret_val = pg_dir_map(pgdir, 0, new_aligned, map_size, + stack->reg_attrs); + + if(!ret_val) { + stack->reg_base = new_aligned; + stack->reg_size = (unsigned long)stack_max - + (unsigned long)new_aligned; + + dbg_printf("%s: Mapped %u bytes at 0x%08x\n", __func__, + map_size, new_aligned); + dbg_printf("%s: Stack is now at 0x%08x+0x%08x\n", + __func__, stack->reg_base, stack->reg_size); + } + } else { + ret_val = -ENOMEM; + } + +gtfo: + return(ret_val); +} + int pg_dir_memcpy(struct pagedir *ddir, void *dvaddr, struct pagedir *sdir, void *svaddr, u32_t bytes) { diff --git a/kernel/include/arch.h b/kernel/include/arch.h index 161fed5..cfa3a20 100644 --- a/kernel/include/arch.h +++ b/kernel/include/arch.h @@ -234,6 +234,8 @@ void* pg_dir_get_pdbr(pg_dir_t*); int _pg_dir_vpxlate(pg_dir_t*, u32_t, u32_t*); void* pg_dir_get_kstack(pg_dir_t*); void* pg_dir_get_ustack(pg_dir_t*); +void* pg_dir_get_ustack_top(pg_dir_t*); +int pg_dir_grow_ustack(pg_dir_t*, void*); void* pg_dir_sbrk(pg_dir_t*, i32_t); int pg_dir_foreach_region(pg_dir_t*, int(*)(pg_dir_t*, struct region*, void*), void*); int pg_dir_memcpy(pg_dir_t*, void*, pg_dir_t*, void*, u32_t);