Update start_process to push process argument values to its thread's stack
This commit is contained in:
@@ -15,10 +15,19 @@
|
|||||||
#include "threads/init.h"
|
#include "threads/init.h"
|
||||||
#include "threads/interrupt.h"
|
#include "threads/interrupt.h"
|
||||||
#include "threads/palloc.h"
|
#include "threads/palloc.h"
|
||||||
|
#include "threads/malloc.h"
|
||||||
#include "threads/thread.h"
|
#include "threads/thread.h"
|
||||||
#include "threads/vaddr.h"
|
#include "threads/vaddr.h"
|
||||||
#include "threads/synch.h"
|
#include "threads/synch.h"
|
||||||
|
|
||||||
|
/* Keeps track of the position of pointers to user program arguments
|
||||||
|
within a linked list. */
|
||||||
|
struct arg_elem
|
||||||
|
{
|
||||||
|
char* arg;
|
||||||
|
struct list_elem elem;
|
||||||
|
};
|
||||||
|
|
||||||
static thread_func start_process NO_RETURN;
|
static thread_func start_process NO_RETURN;
|
||||||
static bool load (const char *cmdline, void (**eip) (void), void **esp);
|
static bool load (const char *cmdline, void (**eip) (void), void **esp);
|
||||||
|
|
||||||
@@ -37,6 +46,9 @@ process_execute (const char *file_name)
|
|||||||
fn_copy = palloc_get_page (0);
|
fn_copy = palloc_get_page (0);
|
||||||
if (fn_copy == NULL)
|
if (fn_copy == NULL)
|
||||||
return TID_ERROR;
|
return TID_ERROR;
|
||||||
|
|
||||||
|
/* Imposing implicit limit that the command line arguments
|
||||||
|
including the user program name fit within a single page. */
|
||||||
strlcpy (fn_copy, file_name, PGSIZE);
|
strlcpy (fn_copy, file_name, PGSIZE);
|
||||||
|
|
||||||
/* Create a new thread to execute FILE_NAME. */
|
/* Create a new thread to execute FILE_NAME. */
|
||||||
@@ -51,19 +63,76 @@ process_execute (const char *file_name)
|
|||||||
static void
|
static void
|
||||||
start_process (void *file_name_)
|
start_process (void *file_name_)
|
||||||
{
|
{
|
||||||
char *file_name = file_name_;
|
|
||||||
struct intr_frame if_;
|
struct intr_frame if_;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
|
/* Retrieve first argument of command, which is the file name
|
||||||
|
of the process. */
|
||||||
|
char *saveptr;
|
||||||
|
char *arg = strtok_r (file_name_, " ", &saveptr);
|
||||||
|
|
||||||
/* Initialize interrupt frame and load executable. */
|
/* Initialize interrupt frame and load executable. */
|
||||||
memset (&if_, 0, sizeof if_);
|
memset (&if_, 0, sizeof if_);
|
||||||
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
|
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
|
||||||
if_.cs = SEL_UCSEG;
|
if_.cs = SEL_UCSEG;
|
||||||
if_.eflags = FLAG_IF | FLAG_MBS;
|
if_.eflags = FLAG_IF | FLAG_MBS;
|
||||||
success = load (file_name, &if_.eip, &if_.esp);
|
success = load (arg, &if_.eip, &if_.esp);
|
||||||
|
|
||||||
|
/* Load command line argument *data* to user process stack.
|
||||||
|
This can't cause overflow due to enforcing that the size of
|
||||||
|
command line input must fit in a page. Also keep track
|
||||||
|
of pointers to the argument data within a linked list. */
|
||||||
|
struct list arg_list;
|
||||||
|
list_init(&arg_list);
|
||||||
|
|
||||||
|
unsigned int arg_count = 1;
|
||||||
|
while (arg != NULL)
|
||||||
|
{
|
||||||
|
size_t arg_size = (strlen(arg) + 1) * sizeof (char);
|
||||||
|
if_.esp -= arg_size;
|
||||||
|
memcpy (if_.esp, arg, arg_size);
|
||||||
|
|
||||||
|
struct arg_elem *arg_elem = malloc(sizeof (struct arg_elem));
|
||||||
|
ASSERT (arg_elem != NULL);
|
||||||
|
arg_elem->arg = arg;
|
||||||
|
list_push_front (&arg_list, &arg_elem->elem);
|
||||||
|
|
||||||
|
arg_count++;
|
||||||
|
arg = strtok_r (NULL, " ", &saveptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the remaining number of bytes that need to be written
|
||||||
|
to the user process stack in order to check for possible overflow. */
|
||||||
|
size_t align_size = (unsigned int) if_.esp % 4;
|
||||||
|
size_t argv_data_size = (arg_count + 1) * sizeof (char *);
|
||||||
|
size_t argv_size = sizeof (char **);
|
||||||
|
size_t argc_size = sizeof (int);
|
||||||
|
size_t return_addr_size = sizeof (void *);
|
||||||
|
size_t remaining_size = align_size + argv_data_size + argv_size + argc_size
|
||||||
|
+ return_addr_size;
|
||||||
|
|
||||||
|
/* If pushing the rest of the data required for the stack would cause
|
||||||
|
overflow, allocate an extra page. */
|
||||||
|
if (PHYS_BASE - if_.esp + remaining_size > PGSIZE)
|
||||||
|
{
|
||||||
|
/* TODO: Allocate an extra page for the rest of the process stack. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push pointers to process arguments from argument linked list */
|
||||||
|
struct list_elem *e = list_begin (&arg_list);
|
||||||
|
struct list_elem *tail = list_tail (&arg_list);
|
||||||
|
while (e != tail)
|
||||||
|
{
|
||||||
|
/* TODO: Push argument pointers to process stack. */
|
||||||
|
|
||||||
|
struct list_elem *prev_e = e;
|
||||||
|
e = list_next (e);
|
||||||
|
|
||||||
|
free (list_entry (prev_e, struct arg_elem, elem));
|
||||||
|
}
|
||||||
|
|
||||||
/* If load failed, quit. */
|
/* If load failed, quit. */
|
||||||
palloc_free_page (file_name);
|
palloc_free_page (file_name_);
|
||||||
if (!success)
|
if (!success)
|
||||||
thread_exit ();
|
thread_exit ();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user