From 346cfa75b7d837937960a5bf4af3f00d6af58128 Mon Sep 17 00:00:00 2001 From: lament Date: Mon, 3 Apr 2017 20:14:28 +0900 Subject: [PATCH] [#4] Implement argument passing 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. --- src/userprog/process.c | 135 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 13 deletions(-) diff --git a/src/userprog/process.c b/src/userprog/process.c index ce55d5c..42e1bca 100644 --- a/src/userprog/process.c +++ b/src/userprog/process.c @@ -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) @@ -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. @@ -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 @@ -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; @@ -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; @@ -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); } @@ -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; +}