Move user process stack initialization into a helper function
This commit is contained in:
@@ -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
|
||||||
@@ -79,10 +82,9 @@ start_process (void *file_name_)
|
|||||||
/* 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,6 +97,32 @@ 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);
|
||||||
|
|
||||||
|
/* If load failed, quit. */
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
interrupt, implemented by intr_exit (in
|
||||||
|
threads/intr-stubs.S). Because intr_exit takes all of its
|
||||||
|
arguments on the stack in the form of a `struct intr_frame',
|
||||||
|
we just point the stack pointer (%esp) to our stack frame
|
||||||
|
and jump to it. */
|
||||||
|
asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory");
|
||||||
|
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.
|
/* Load command line argument *data* to user process stack.
|
||||||
This can't cause overflow due to enforcing that the size of
|
This can't cause overflow due to enforcing that the size of
|
||||||
command line input must fit in a page. Also keep track
|
command line input must fit in a page. Also keep track
|
||||||
@@ -102,22 +130,23 @@ start_process (void *file_name_)
|
|||||||
struct list arg_list;
|
struct list arg_list;
|
||||||
list_init (&arg_list);
|
list_init (&arg_list);
|
||||||
|
|
||||||
|
char *arg = file_name;
|
||||||
int arg_count = 0;
|
int arg_count = 0;
|
||||||
while (arg != NULL)
|
while (arg != NULL)
|
||||||
{
|
{
|
||||||
push_to_stack (&if_.esp, arg, (strlen (arg) + 1) * sizeof (char));
|
push_to_stack (esp, arg, (strlen (arg) + 1) * sizeof (char));
|
||||||
|
|
||||||
struct arg_elem *arg_elem = malloc (sizeof (struct arg_elem));
|
struct arg_elem *arg_elem = malloc (sizeof (struct arg_elem));
|
||||||
if (arg_elem == NULL)
|
if (arg_elem == NULL)
|
||||||
{
|
{
|
||||||
printf("ERROR: Couldn't allocate argument pointer memory for %s!\n",
|
printf("ERROR: Couldn't allocate argument pointer memory for %s!\n",
|
||||||
file_name);
|
thread_current ()->name);
|
||||||
palloc_free_page (file_name_);
|
palloc_free_page (file_name_);
|
||||||
if (success) process_exit ();
|
process_exit ();
|
||||||
thread_exit ();
|
thread_exit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_elem->arg = if_.esp;
|
arg_elem->arg = *esp;
|
||||||
list_push_front (&arg_list, &arg_elem->elem);
|
list_push_front (&arg_list, &arg_elem->elem);
|
||||||
|
|
||||||
arg_count++;
|
arg_count++;
|
||||||
@@ -126,7 +155,7 @@ start_process (void *file_name_)
|
|||||||
|
|
||||||
/* Calculate the remaining number of bytes that need to be written
|
/* Calculate the remaining number of bytes that need to be written
|
||||||
to the user process stack in order to check for possible overflow. */
|
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 align_size = ((unsigned int) *esp % 4) * sizeof (uint8_t);
|
||||||
size_t argv_data_size = (arg_count + 1) * sizeof (char *);
|
size_t argv_data_size = (arg_count + 1) * sizeof (char *);
|
||||||
size_t argv_size = sizeof (char **);
|
size_t argv_size = sizeof (char **);
|
||||||
size_t argc_size = sizeof (int);
|
size_t argc_size = sizeof (int);
|
||||||
@@ -136,18 +165,18 @@ start_process (void *file_name_)
|
|||||||
|
|
||||||
/* If pushing the rest of the data required for the stack would cause
|
/* If pushing the rest of the data required for the stack would cause
|
||||||
overflow, allocate an extra page. */
|
overflow, allocate an extra page. */
|
||||||
if (PHYS_BASE - if_.esp + remaining_size > PGSIZE)
|
if (PHYS_BASE - *esp + remaining_size > PGSIZE)
|
||||||
{
|
{
|
||||||
/* TODO: Allocate an extra page for the rest of the process stack. */
|
/* TODO: Allocate an extra page for the rest of the process stack. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Align stack pointer to word size before pushing argv elements for
|
/* Align stack pointer to word size before pushing argv elements for
|
||||||
performance. */
|
performance. */
|
||||||
if_.esp -= align_size;
|
*esp -= align_size;
|
||||||
|
|
||||||
/* Push a null pointer sentinel inside argv. */
|
/* Push a null pointer sentinel inside argv. */
|
||||||
if_.esp -= sizeof (char *);
|
*esp -= sizeof (char *);
|
||||||
*(char *) if_.esp = 0;
|
*(char *) *esp = 0;
|
||||||
|
|
||||||
/* Push pointer to the process file name to the stack. */
|
/* Push pointer to the process file name to the stack. */
|
||||||
char **argv;
|
char **argv;
|
||||||
@@ -159,35 +188,21 @@ start_process (void *file_name_)
|
|||||||
{
|
{
|
||||||
struct arg_elem *arg_elem = list_entry (e, struct arg_elem, elem);
|
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));
|
argv = push_to_stack (esp, &arg_elem->arg, sizeof (arg_elem->arg));
|
||||||
|
|
||||||
e = list_next (e);
|
e = list_next (e);
|
||||||
free (arg_elem);
|
free (arg_elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push pointer to the start of argv array. */
|
/* Push pointer to the start of argv array. */
|
||||||
push_to_stack (&if_.esp, &argv, sizeof(argv));
|
push_to_stack (esp, &argv, sizeof(argv));
|
||||||
|
|
||||||
/* Push the number of arguments to the stack. */
|
/* Push the number of arguments to the stack. */
|
||||||
push_to_stack (&if_.esp, &arg_count, sizeof (arg_count));
|
push_to_stack (esp, &arg_count, sizeof (arg_count));
|
||||||
|
|
||||||
/* Push fake return address (null pointer). */
|
/* Push fake return address (null pointer). */
|
||||||
if_.esp -= sizeof (char *);
|
*esp -= sizeof (char *);
|
||||||
*(char *) if_.esp = 0;
|
*(char *) *esp = 0;
|
||||||
|
|
||||||
/* If load failed, quit. */
|
|
||||||
palloc_free_page (file_name_);
|
|
||||||
if (!success)
|
|
||||||
thread_exit ();
|
|
||||||
|
|
||||||
/* Start the user process by simulating a return from an
|
|
||||||
interrupt, implemented by intr_exit (in
|
|
||||||
threads/intr-stubs.S). Because intr_exit takes all of its
|
|
||||||
arguments on the stack in the form of a `struct intr_frame',
|
|
||||||
we just point the stack pointer (%esp) to our stack frame
|
|
||||||
and jump to it. */
|
|
||||||
asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory");
|
|
||||||
NOT_REACHED ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Waits for thread TID to die and returns its exit status.
|
/* Waits for thread TID to die and returns its exit status.
|
||||||
|
|||||||
Reference in New Issue
Block a user