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
@@ -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,36 +188,22 @@ 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.
* 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),