#include #include "stackgrowth.h" #include "frame.h" #include "threads/palloc.h" #include "threads/thread.h" #include "threads/vaddr.h" #include "userprog/pagedir.h" #define MAX_STACK_ACCESS_DIST 32 static bool is_stack_fault (const void *addr, const void *esp); static bool grow_stack (const void *addr); /* Determine whether a particular page fault occured due to a stack access below the stack pointer that should induce stack growth, and if so grow the stack by a single page (capped at MAX_STACK_SIZE). */ bool handle_stack_fault (const void *ptr, const void *esp) { return is_stack_fault (ptr, esp) && grow_stack (ptr); } /* Determines whether a particular page fault appears to be caused by a stack access that should induce dynamic stack growth. Stack size is capped at MAX_STACK_SIZE. */ static bool is_stack_fault (const void *addr, const void *esp) { return ((uint32_t*)addr >= ((uint32_t*)esp - MAX_STACK_ACCESS_DIST) && ((PHYS_BASE - pg_round_down (addr)) <= MAX_STACK_SIZE)); } /* Grows the stack of the process running inside the current thread by a single page given a user virtual address inside of the page wherein the new section of the stack should be allocated. */ static bool grow_stack (const void *addr) { struct thread *t = thread_current (); void *last_page = pg_round_down (addr); /* This function should only be called when dealing with a faulting stack access that induces stack growth, so the provided address shouldn't be present in a page within the current thread's page directory. */ ASSERT (pagedir_get_page (t->pagedir, last_page) == NULL); uint8_t *new_page = frame_alloc (PAL_ZERO, last_page, t); if (new_page == NULL) return false; if (!pagedir_set_page (t->pagedir, last_page, new_page, true)) { frame_free (new_page); return false; } return true; }