Move user process stack initialization into a helper function

This commit is contained in:
Themis Demetriades
2024-11-08 16:46:18 +00:00
parent b866fa88cd
commit a19f02fad7

View File

@@ -68,6 +68,9 @@ push_to_stack (void **esp, void *data, size_t data_size)
return *esp; return *esp;
} }
static void process_init_stack (void *file_name_, char *saveptr, void **esp,
char *file_name);
/* A thread function that loads a user process and starts it /* A thread function that loads a user process and starts it
running. */ running. */
static void static void
@@ -76,13 +79,12 @@ start_process (void *file_name_)
struct intr_frame if_; struct intr_frame if_;
bool success; bool success;
/* Retrieve first argument of command, which is the file name /* Retrieve first argument of command, which is the file name
of the process. */ of the process. */
char *saveptr; char *saveptr;
char *arg = strtok_r (file_name_, " ", &saveptr); char *file_name = strtok_r (file_name_, " ", &saveptr);
if (strlen (file_name) > FNAME_MAX_LEN)
char file_name[FNAME_MAX_LEN + 1]; file_name[FNAME_MAX_LEN + 1] = '\n';
strlcpy (file_name, arg, FNAME_MAX_LEN + 1);
/* TODO: Move naming of thread to process_execute, so start /* TODO: Move naming of thread to process_execute, so start
tokenizing there. */ tokenizing there. */
@@ -95,90 +97,15 @@ start_process (void *file_name_)
if_.eflags = FLAG_IF | FLAG_MBS; if_.eflags = FLAG_IF | FLAG_MBS;
success = load (file_name, &if_.eip, &if_.esp); success = load (file_name, &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);
int arg_count = 0;
while (arg != NULL)
{
push_to_stack (&if_.esp, arg, (strlen (arg) + 1) * sizeof (char));
struct arg_elem *arg_elem = malloc (sizeof (struct arg_elem));
if (arg_elem == NULL)
{
printf("ERROR: Couldn't allocate argument pointer memory for %s!\n",
file_name);
palloc_free_page (file_name_);
if (success) process_exit ();
thread_exit ();
}
arg_elem->arg = if_.esp;
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) * sizeof (uint8_t);
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. */
}
/* Align stack pointer to word size before pushing argv elements for
performance. */
if_.esp -= align_size;
/* Push a null pointer sentinel inside argv. */
if_.esp -= sizeof (char *);
*(char *) if_.esp = 0;
/* Push pointer to the process file name to the stack. */
char **argv;
/* 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)
{
struct arg_elem *arg_elem = list_entry (e, struct arg_elem, elem);
argv = push_to_stack (&if_.esp, &arg_elem->arg, sizeof (arg_elem->arg));
e = list_next (e);
free (arg_elem);
}
/* Push pointer to the start of argv array. */
push_to_stack (&if_.esp, &argv, sizeof(argv));
/* Push the number of arguments to the stack. */
push_to_stack (&if_.esp, &arg_count, sizeof (arg_count));
/* Push fake return address (null pointer). */
if_.esp -= sizeof (char *);
*(char *) if_.esp = 0;
/* If load failed, quit. */ /* If load failed, quit. */
palloc_free_page (file_name_);
if (!success) if (!success)
thread_exit (); {
palloc_free_page (file_name_);
thread_exit ();
}
process_init_stack (file_name_, saveptr, &if_.esp, file_name);
palloc_free_page (file_name_);
/* Start the user process by simulating a return from an /* Start the user process by simulating a return from an
interrupt, implemented by intr_exit (in interrupt, implemented by intr_exit (in
@@ -190,6 +117,94 @@ start_process (void *file_name_)
NOT_REACHED (); NOT_REACHED ();
} }
/* Helper function that initializes the stack of a newly created
user process. */
static void
process_init_stack (void *file_name_, char *saveptr, void **esp,
char *file_name)
{
/* 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);
char *arg = file_name;
int arg_count = 0;
while (arg != NULL)
{
push_to_stack (esp, arg, (strlen (arg) + 1) * sizeof (char));
struct arg_elem *arg_elem = malloc (sizeof (struct arg_elem));
if (arg_elem == NULL)
{
printf("ERROR: Couldn't allocate argument pointer memory for %s!\n",
thread_current ()->name);
palloc_free_page (file_name_);
process_exit ();
thread_exit ();
}
arg_elem->arg = *esp;
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) *esp % 4) * sizeof (uint8_t);
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 - *esp + remaining_size > PGSIZE)
{
/* TODO: Allocate an extra page for the rest of the process stack. */
}
/* Align stack pointer to word size before pushing argv elements for
performance. */
*esp -= align_size;
/* Push a null pointer sentinel inside argv. */
*esp -= sizeof (char *);
*(char *) *esp = 0;
/* Push pointer to the process file name to the stack. */
char **argv;
/* 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)
{
struct arg_elem *arg_elem = list_entry (e, struct arg_elem, elem);
argv = push_to_stack (esp, &arg_elem->arg, sizeof (arg_elem->arg));
e = list_next (e);
free (arg_elem);
}
/* Push pointer to the start of argv array. */
push_to_stack (esp, &argv, sizeof(argv));
/* Push the number of arguments to the stack. */
push_to_stack (esp, &arg_count, sizeof (arg_count));
/* Push fake return address (null pointer). */
*esp -= sizeof (char *);
*(char *) *esp = 0;
}
/* Waits for thread TID to die and returns its exit status. /* Waits for thread TID to die and returns its exit status.
* If it was terminated by the kernel (i.e. killed due to an exception), * If it was terminated by the kernel (i.e. killed due to an exception),
* returns -1. * returns -1.