Skip to content

Commit

Permalink
[#4] Implement argument passing
Browse files Browse the repository at this point in the history
Now an execution of process supports multiple arguments,
by pushing arguments onto stack that has been previously allocated,
but not used. esp now points bottom of the stack frame, which is extended
from PHYS_BASE to accommodate arguments and pointers to that
arguments.

This implementation is now following calling convention, which
is defined in pintos manual.
  • Loading branch information
Lment committed Apr 7, 2017
1 parent 9cbfdfe commit 346cfa7
Showing 1 changed file with 122 additions and 13 deletions.
135 changes: 122 additions & 13 deletions src/userprog/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,23 @@
#include "threads/palloc.h"
#include "threads/thread.h"
#include "threads/vaddr.h"
#include "threads/malloc.h"

#define WORD_SIZE sizeof(uintptr_t)

/* Structure for argument, which saves arguments in argv,
and count the number of arguments. */
struct arguments
{
int argc;
char **argv;
};


static thread_func start_process NO_RETURN;
static bool load (const char *cmdline, void (**eip) (void), void **esp);
static bool load (struct arguments *args, void (**eip) (void), void **esp);

static void argument_parser(char *str, struct arguments *args);

/* Starts a new thread running a user program loaded from
FILENAME. The new thread may be scheduled (and may even exit)
Expand All @@ -29,6 +43,7 @@ tid_t
process_execute (const char *file_name)
{
char *fn_copy;
struct arguments *args = malloc (sizeof *args);
tid_t tid;

/* Make a copy of FILE_NAME.
Expand All @@ -38,34 +53,66 @@ process_execute (const char *file_name)
return TID_ERROR;
strlcpy (fn_copy, file_name, PGSIZE);

argument_parser (fn_copy, args);

/* Create a new thread to execute FILE_NAME. */
tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
tid = thread_create (args->argv[0], PRI_DEFAULT, start_process, args);
if (tid == TID_ERROR)
palloc_free_page (fn_copy);
{
palloc_free_page (fn_copy);
free(args->argv);
free(args);
}

return tid;
}

/* Starts string tokenizer, which cuts given input string into tokens
divided by delimeter, and stores it in given argument struct by pointer. */
static void
argument_parser (char *string_input, struct arguments *args)
{
char *leftover;
char *token;
char *curr;

args->argc = 0;
args->argv = (char **) calloc ((strlen (string_input) + 1), sizeof(char *));

token = " ";
curr = strtok_r (string_input, token, &leftover);

while(curr != NULL)
{
args->argv[args->argc] = curr;
args->argc ++;
curr = strtok_r (NULL, token, &leftover);
}
}

/* A thread function that loads a user process and makes it start
running. */
static void
start_process (void *f_name)
start_process (void *arg)
{
char *file_name = f_name;
struct argument *args = arg;
struct intr_frame if_;
bool success;


/* Initialize interrupt frame and load executable. */
memset (&if_, 0, sizeof if_);
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS;
success = load (file_name, &if_.eip, &if_.esp);

/* If load failed, quit. */
palloc_free_page (file_name);
if (!success)
thread_exit ();
success = load (args, &if_.eip, &if_.esp);

/* If load failed, quit. */
if (!success)
{
free(args);
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
Expand Down Expand Up @@ -201,17 +248,19 @@ static bool validate_segment (const struct Elf32_Phdr *, struct file *);
static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
uint32_t read_bytes, uint32_t zero_bytes,
bool writable);
static void push_args_on_stack(struct arguments *args, void **esp);

/* Loads an ELF executable from FILE_NAME into the current thread.
Stores the executable's entry point into *EIP
and its initial stack pointer into *ESP.
Returns true if successful, false otherwise. */
bool
load (const char *file_name, void (**eip) (void), void **esp)
load (struct arguments *args, void (**eip) (void), void **esp)
{
struct thread *t = thread_current ();
struct Elf32_Ehdr ehdr;
struct file *file = NULL;
char *file_name = args->argv[0];
off_t file_ofs;
bool success = false;
int i;
Expand Down Expand Up @@ -306,6 +355,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
if (!setup_stack (esp))
goto done;

push_args_on_stack (args, esp);
/* Start address. */
*eip = (void (*) (void)) ehdr.e_entry;

Expand Down Expand Up @@ -438,7 +488,7 @@ setup_stack (void **esp)
{
success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
if (success)
*esp = PHYS_BASE - 12; // Temporary measure
*esp = PHYS_BASE;
else
palloc_free_page (kpage);
}
Expand All @@ -464,3 +514,62 @@ install_page (void *upage, void *kpage, bool writable)
return (pagedir_get_page (t->pagedir, upage) == NULL
&& pagedir_set_page (t->pagedir, upage, kpage, writable));
}

/* Push arguments on newly initialized stack, following calling conventions.
This invention does not use esp dynamically, just making it point bottom of
stack frame after all push is done.*/

static void
push_args_on_stack(struct arguments *args, void **esp)
{
void **arg_ptrs = calloc (args->argc, sizeof(uintptr_t));
void *curr = (char *) PHYS_BASE;

int arg_len;
int alignment;
int zero = 0;
int i;
void *dest;

/* Pushing arguments on stack, saving their address in arg_ptrs. */
for(i = (args->argc - 1); i >= 0; i--)
{
arg_len = strlen (args->argv[i]) + 1;
dest = curr - arg_len;
memcpy (dest, (args->argv[i]), arg_len);
arg_ptrs[i] = dest;
curr = dest;
}

alignment = ((uint32_t) curr) % WORD_SIZE;

/* Aligning, and push bytes required for aligning. */
for(i = 0; i < alignment ; i++)
memcpy (--curr, &zero, 1);

curr -= WORD_SIZE;
memcpy (curr, &zero, WORD_SIZE);

for(i = (args->argc -1); i >= 0; i--)
{
curr -= WORD_SIZE;
memcpy (curr, &arg_ptrs[i], WORD_SIZE);
}

free (arg_ptrs);

/* Push address of argv on stack. */
curr -= WORD_SIZE;
memcpy (curr, &curr, WORD_SIZE);

/* Push argument count on stack. */
curr -= WORD_SIZE;
memcpy (curr, &(args->argc), WORD_SIZE);

/* Push return address as 0 values. */
curr -= WORD_SIZE;
memcpy (curr, &zero, WORD_SIZE);

/* esp pointing bottom of the stack */
*esp = (void *) curr;
}

0 comments on commit 346cfa7

Please sign in to comment.