Refactor stack growth to be helper functions in exception for easier merging
This commit is contained in:
@@ -2,9 +2,15 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "userprog/gdt.h"
|
||||
#include "userprog/pagedir.h"
|
||||
#include "userprog/process.h"
|
||||
#include "threads/interrupt.h"
|
||||
#include "threads/palloc.h"
|
||||
#include "threads/thread.h"
|
||||
#include "vm/stackgrowth.h"
|
||||
#include "threads/vaddr.h"
|
||||
|
||||
#define MAX_STACK_SIZE (8 * 1024 * 1024) // 8MB
|
||||
#define MAX_STACK_OFFSET 32 // 32 bytes offset below stack pointer (ESP)
|
||||
|
||||
/* Number of page faults processed. */
|
||||
static long long page_fault_cnt;
|
||||
@@ -12,6 +18,9 @@ static long long page_fault_cnt;
|
||||
static void kill (struct intr_frame *);
|
||||
static void page_fault (struct intr_frame *);
|
||||
|
||||
static bool is_valid_stack_access (const void *fault_addr, const void *esp);
|
||||
static bool grow_stack (void *upage);
|
||||
|
||||
/* Registers handlers for interrupts that can be caused by user
|
||||
programs.
|
||||
|
||||
@@ -146,19 +155,26 @@ page_fault (struct intr_frame *f)
|
||||
write = (f->error_code & PF_W) != 0;
|
||||
user = (f->error_code & PF_U) != 0;
|
||||
|
||||
if (user && not_present)
|
||||
if (!user || !not_present)
|
||||
{
|
||||
f->eip = (void *)f->eax;
|
||||
f->eax = 0xffffffff;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the fault address is in a user page that is not present, then it might
|
||||
be just that the stack needs to grow. So we attempt to grow the stack. */
|
||||
void *upage = pg_round_down (fault_addr);
|
||||
if (not_present && is_user_vaddr (upage) && upage != NULL)
|
||||
{
|
||||
if (try_alloc_new_page (fault_addr, f->esp))
|
||||
return;
|
||||
if (is_valid_stack_access (fault_addr, f->esp))
|
||||
{
|
||||
if (grow_stack (upage))
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Check SPT for the page. */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (try_alloc_new_page (fault_addr, thread_current ()->curr_esp))
|
||||
return;
|
||||
f->eip = (void *)f->eax;
|
||||
f->eax = 0xffffffff;
|
||||
return;
|
||||
}
|
||||
|
||||
/* To implement virtual memory, delete the rest of the function
|
||||
body, and replace it with code that brings in the page to
|
||||
@@ -171,3 +187,50 @@ page_fault (struct intr_frame *f)
|
||||
kill (f);
|
||||
}
|
||||
|
||||
/* Validates whether the fault address is a valid stack access. Access is a
|
||||
valid stack access under the following two conditions:
|
||||
1. The fault address must be within MAX_STACK_OFFSET (32) bytes below
|
||||
the current stack pointer. (Accounts for both PUSH and PUSHA instructions)
|
||||
2. Growing this stack to this address does not cause it to exceed the
|
||||
MAX_STACK_SIZE (8MB) limit.
|
||||
|
||||
Returns true if both conditions are met, false otherwise.
|
||||
|
||||
Pre: fault_addr is a valid user virtual address (so also not NULL). */
|
||||
static bool
|
||||
is_valid_stack_access (const void *fault_addr, const void *esp)
|
||||
{
|
||||
uint32_t new_stack_size = PHYS_BASE - pg_round_down (fault_addr);
|
||||
|
||||
uint32_t *lowest_valid_push_addr = (uint32_t *)esp - MAX_STACK_OFFSET;
|
||||
bool is_within_push_range = (uint32_t *)fault_addr >= lowest_valid_push_addr;
|
||||
|
||||
return is_within_push_range && new_stack_size <= MAX_STACK_SIZE;
|
||||
}
|
||||
|
||||
/* Attempts to grow the stack by allocating and mapping a new page.
|
||||
This involves:
|
||||
1. Allocating a zeroed page from the user pool
|
||||
2. Installing it into the page table with write permissions
|
||||
|
||||
Returns true if the stack was successfully grown, false if either
|
||||
allocation or installation fails.
|
||||
|
||||
Pre: upage is a valid page-aligned address (so also not NULL). */
|
||||
static bool
|
||||
grow_stack (void *upage)
|
||||
{
|
||||
/* Allocate new page for stack */
|
||||
void *kpage = palloc_get_page (PAL_USER | PAL_ZERO);
|
||||
if (kpage == NULL)
|
||||
return false;
|
||||
|
||||
/* Install the page into user page table */
|
||||
if (!install_page (upage, kpage, true))
|
||||
{
|
||||
palloc_free_page (kpage);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user