]> git.corax.cc Git - corax/commitdiff
kernel: Grow the userspace stack if an application runs out of stack space userstack
authorMatthias Kruk <m@m10k.eu>
Wed, 29 Jul 2020 00:54:42 +0000 (09:54 +0900)
committerMatthias Kruk <m@m10k.eu>
Wed, 29 Jul 2020 00:54:42 +0000 (09:54 +0900)
config.h
kernel/arch/interrupt.c
kernel/arch/paging.c
kernel/include/arch.h

index 7cad81f2e50d5ebf36a99df22557fb130bb17114..eeef1b2fc744c572393e2725504d69f2e388212e 100644 (file)
--- 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
index 60e3399312cdad5d5faf502bf3f23182ac2c26db..fdd734662df6d121f53d92a690e9f5a09645fe7b 100644 (file)
@@ -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)
index e02b668638b56d735a72b8b9f88ba961fe27daae..0fec7d17f78199a89155d638b01e3e5f591db32f 100644 (file)
@@ -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)
 {
index 161fed50f0f053792c17659d8815be04f1a5770c..cfa3a20f60e1e0cdcf8cbb821db8d542faa96202 100644 (file)
@@ -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);