Implement dynamic stack growth #54

Merged
td1223 merged 14 commits from ethan-stack-growth into virtual-memory 2024-11-30 23:21:34 +00:00
28 changed files with 314 additions and 863 deletions
Showing only changes of commit cf4bf90cbb - Show all commits

View File

@@ -14,6 +14,8 @@
#include <stdbool.h>
#include <syscall-nr.h>
#define MAX_SYSCALL_ARGS 3
static struct lock filesys_lock;
static unsigned fd_counter = MIN_USER_FD;
@@ -47,8 +49,9 @@ static unsigned syscall_tell (int fd);
static void syscall_close (int fd);
static struct open_file *fd_get_file (int fd);
static void *validate_user_pointer (const void *ptr, size_t size,
bool check_write);
static void validate_user_pointer (const void *ptr, size_t size,
bool check_write);
static void validate_user_string (const char *str, bool check_write);
static int get_user (const uint8_t *);
static bool put_user (uint8_t *, uint8_t);
@@ -100,8 +103,8 @@ static void
syscall_handler (struct intr_frame *f)
{
/* First, read the system call number from the stack. */
validate_user_pointer (f->esp, 1, false);
unsigned syscall_number = *(int *)f->esp;
validate_user_pointer (f->esp, sizeof (uintptr_t), false);
uintptr_t syscall_number = *(int *)f->esp;
/* Ensures the number corresponds to a system call that can be handled. */
if (syscall_number >= LOOKUP_SIZE)
@@ -112,8 +115,8 @@ syscall_handler (struct intr_frame *f)
/* Next, read and copy the arguments from the stack pointer. */
validate_user_pointer (f->esp + sizeof (uintptr_t),
syscall.arity * sizeof (uintptr_t), false);
uintptr_t args[3] = { 0 };
for (int i = 0; i < syscall.arity; i++)
uintptr_t args[MAX_SYSCALL_ARGS] = { 0 };
for (int i = 0; i < syscall.arity && i < MAX_SYSCALL_ARGS; i++)
args[i] = *(uintptr_t *)(f->esp + sizeof (uintptr_t) * (i + 1));
/* Call the function that handles this system call with the arguments. When
@@ -145,7 +148,7 @@ syscall_exit (int status)
static pid_t
syscall_exec (const char *cmd_line)
{
validate_user_pointer (cmd_line, 1, false);
validate_user_string (cmd_line, false);
lock_acquire (&filesys_lock);
pid_t pid = process_execute(cmd_line);
@@ -168,7 +171,7 @@ syscall_wait (pid_t pid)
static bool
syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
{
validate_user_pointer (file, 1, false);
validate_user_string (file, false);
lock_acquire (&filesys_lock);
bool status = filesys_create (file, initial_size);
@@ -183,7 +186,7 @@ syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
static bool
syscall_remove (const char *file)
{
validate_user_pointer (file, 1, false);
validate_user_string (file, false);
lock_acquire (&filesys_lock);
bool status = filesys_remove (file);
@@ -199,7 +202,7 @@ syscall_remove (const char *file)
static int
syscall_open (const char *file)
{
validate_user_pointer (file, 1, false);
validate_user_string (file, false);
lock_acquire (&filesys_lock);
struct file *ptr = filesys_open (file);
@@ -405,26 +408,49 @@ fd_get_file (int fd)
}
/* Validates if a block of memory starting at PTR and of size SIZE bytes is
fully contained within user virtual memory. Returns NULL if the memory
is invalid. Otherwise, returns the PTR given.
If the size is 0, the function does no checks and returns PTR.*/
static void *
fully contained within valid user virtual memory. thread_exit () if the
memory is invalid.
If the size is 0, the function does no checks and returns PTR. */
static void
validate_user_pointer (const void *ptr, size_t size, bool check_write)
{
if (size == 0)
return ptr;
return;
/* ptr < ptr + size - 1, so sufficient to check that (ptr + size -1) is a
valid user virtual memory address. */
if (!is_user_vaddr (ptr + size - 1))
void *last = ptr + size - 1;
if (!is_user_vaddr (last))
thread_exit ();
/* Check read access to pointer. */
int result;
if ((result = get_user (ptr)) == -1)
thread_exit ();
/* Check write access to pointer (if required). */
if (check_write && !put_user (ptr, result))
thread_exit ();
return ptr;
for (; ptr <= last; ptr++)
{
int result;
/* Check read access to pointer. */
if ((result = get_user (ptr)) == -1)
thread_exit ();
/* Check write access to pointer (if required). */
if (check_write && !put_user (ptr, result))
thread_exit ();
}
}
/* Validates of a C-string starting at ptr is fully contained within valid
user virtual memory. thread_exit () if the memory is invalid. */
static void
validate_user_string (const char *ptr, bool check_write)
{
while (true)
{
if (!is_user_vaddr (ptr))
thread_exit ();
int result;
if ((result = get_user ((const uint8_t *)ptr)) == -1)
thread_exit ();
if (check_write && !put_user ((uint8_t *)ptr, result))
thread_exit ();
if (*ptr == '\0')
return;
ptr++;
}
}
/* PROVIDED BY SPEC.