Merge remote-tracking branch 'origin/user-programs-stdout' into system-calls
This commit is contained in:
@@ -16,10 +16,20 @@
|
||||
#include "threads/interrupt.h"
|
||||
#include "threads/synch.h"
|
||||
#include "threads/palloc.h"
|
||||
#include "threads/malloc.h"
|
||||
#include "threads/thread.h"
|
||||
#include "threads/vaddr.h"
|
||||
#include "threads/synch.h"
|
||||
#include "devices/timer.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 bool load (const char *cmdline, void (**eip) (void), void **esp);
|
||||
|
||||
@@ -38,6 +48,9 @@ process_execute (const char *file_name)
|
||||
fn_copy = palloc_get_page (0);
|
||||
if (fn_copy == NULL)
|
||||
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);
|
||||
|
||||
/* Create a new thread to execute FILE_NAME. */
|
||||
@@ -47,15 +60,34 @@ process_execute (const char *file_name)
|
||||
return tid;
|
||||
}
|
||||
|
||||
static void *
|
||||
push_to_stack (void **esp, void *data, size_t data_size)
|
||||
{
|
||||
*esp -= data_size;
|
||||
memcpy (*esp, data, data_size);
|
||||
return *esp;
|
||||
}
|
||||
|
||||
/* A thread function that loads a user process and starts it
|
||||
running. */
|
||||
static void
|
||||
start_process (void *file_name_)
|
||||
{
|
||||
char *file_name = file_name_;
|
||||
struct intr_frame if_;
|
||||
bool success;
|
||||
|
||||
/* Retrieve first argument of command, which is the file name
|
||||
of the process. */
|
||||
char *saveptr;
|
||||
char *arg = strtok_r (file_name_, " ", &saveptr);
|
||||
|
||||
char file_name[15];
|
||||
strlcpy (file_name, arg, 15);
|
||||
|
||||
/* TODO: Move naming of thread to process_execute, so start
|
||||
tokenizing there. */
|
||||
strlcpy (thread_current ()->name, file_name, 15);
|
||||
|
||||
/* Initialize interrupt frame and load executable. */
|
||||
memset (&if_, 0, sizeof if_);
|
||||
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
|
||||
@@ -63,8 +95,88 @@ start_process (void *file_name_)
|
||||
if_.eflags = FLAG_IF | FLAG_MBS;
|
||||
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 = NULL;
|
||||
|
||||
/* 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 = NULL;
|
||||
|
||||
/* If load failed, quit. */
|
||||
palloc_free_page (file_name);
|
||||
palloc_free_page (file_name_);
|
||||
if (!success)
|
||||
thread_exit ();
|
||||
|
||||
@@ -458,7 +570,7 @@ setup_stack (void **esp)
|
||||
{
|
||||
success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
|
||||
if (success)
|
||||
*esp = PHYS_BASE - 12;
|
||||
*esp = PHYS_BASE;
|
||||
else
|
||||
palloc_free_page (kpage);
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ syscall_exit (int status)
|
||||
{
|
||||
/* Sets exit_status of the thread to status. thread_exit () will call
|
||||
process_exit () if user programs are allowed. */
|
||||
printf ("%s: exit(%d)\n", thread_current()->name, status);
|
||||
thread_current ()->exit_status = status;
|
||||
thread_exit ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user