diff --git a/userprog/argument_parsing.h b/userprog/argument_parsing.h index 78f4e0eca38b95a4c16e3963d9944105bc1906ef..d5cef69f63d1e20c7ab9ee15d643ee9390064401 100644 --- a/userprog/argument_parsing.h +++ b/userprog/argument_parsing.h @@ -3,12 +3,11 @@ /* * Given a string containing the command invoking the program `command_line` - * and a pointer to an array of C strings (pointer to `char* argv[]`), parse - * `command_line` into individual arguments, populate `argv` with these and - * return the number of arguments that were parsed (this is the value that can - * be used for `argc`). + * and an array of C strings (pointer to `char* argv[]`), parse `command_line` + * into individual arguments, populate `argv` with these and return the number + * of arguments that were parsed (this is the value that can be used for `argc`). */ -int parse_arguments(const char* command_line, char***argv); +int parse_arguments(const char* command_line, char**argv); /* * Given stack pointer `esp`, argument count `argc` and arguments array `argv`, diff --git a/userprog/parse_arguments.c b/userprog/parse_arguments.c index aeaefd0778156808a54f8c2b1da7b1197886efbc..c86364fdd2408b978f019f9df3d7c09a48b0ec31 100644 --- a/userprog/parse_arguments.c +++ b/userprog/parse_arguments.c @@ -1,6 +1,11 @@ #include "userprog/argument_parsing.h" -int parse_arguments(const char* command_line, char***argv) { - #warning "Implement me" +int parse_arguments(const char* command_line, char**argv) { + /* + * XXX: Dummy implementation which sets argv[0] to "echo" so at least there's + * a filename to load. + */ + argv[0] = "echo"; + return 1; } diff --git a/userprog/process.c b/userprog/process.c index 7aa158189374917306d5021e01bc54caea8b38fe..87fd42a738663bdcfd7c5d2e1da8f92bc950bee4 100644 --- a/userprog/process.c +++ b/userprog/process.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "userprog/argument_parsing.h" #include "userprog/gdt.h" #include "userprog/pagedir.h" #include "userprog/tss.h" @@ -19,7 +20,7 @@ #include "threads/vaddr.h" static thread_func start_process NO_RETURN; -static bool load (const char *cmdline, void (**eip) (void), void **esp); +static bool load (const char *command, void (**eip) (void), void **esp); /* Starts a new thread running a user program loaded by parsing COMMAND. The new thread may be scheduled (and may even exit) @@ -29,24 +30,22 @@ tid_t process_execute (const char *command) { char *command_copy; - tid_t tid; - /* Make a copy of COMMAND. Otherwise there's a race between the caller and load(). */ command_copy = palloc_get_page (0); if (command_copy == NULL) return TID_ERROR; strlcpy (command_copy, command, PGSIZE); + // we need to extract out the filename from the command string + char* file_name; + char* save_ptr; // this is the save pointer expected by strtok_r() + // file name is the first part of the command-line (space-delimited) + file_name = strtok_r(command, " ", &save_ptr); + tid_t tid; + /* Create a new thread to execute COMMAND. */ - /* - * FIXME: right now, COMMAND is assumed to be just the filename on its own - * - * If this is not the case (if the user passed a program name with arguments), - * then loading will fail. - * NOTE: remove this comment block when argument parsing is implemented. - */ - tid = thread_create (command, PRI_DEFAULT, start_process, command_copy); + tid = thread_create (file_name, PRI_DEFAULT, start_process, command_copy); if (tid == TID_ERROR) palloc_free_page (command_copy); @@ -212,18 +211,18 @@ struct Elf32_Phdr #define PF_W 2 /* Writable. */ #define PF_R 4 /* Readable. */ -static bool setup_stack (void **esp); +static bool setup_stack (void **esp, char **argv, int argc); 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); -/* Loads an ELF executable from FILE_NAME into the current thread. +/* Loads an ELF executable from COMMAND 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 (const char *command, void (**eip) (void), void **esp) { struct thread *t = thread_current (); struct Elf32_Ehdr ehdr; @@ -232,6 +231,12 @@ load (const char *file_name, void (**eip) (void), void **esp) bool success = false; int i; + // extract arguments (including file name) + // NOTE: decide how many arguments we want --is 255 the standard number? + char* argv[255]; + int argc = parse_arguments(command, argv); + char* file_name = argv[0]; // file name is always argument 0 + /* Allocate and activate page directory. */ t->pagedir = pagedir_create (); if (t->pagedir == NULL) @@ -320,7 +325,7 @@ load (const char *file_name, void (**eip) (void), void **esp) } /* Set up stack. */ - if (!setup_stack (esp)) + if (!setup_stack (esp, argv, argc)) goto done; /* Start address. */ @@ -445,7 +450,7 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage, /* Create a minimal stack by mapping a zeroed page at the top of user virtual memory. */ static bool -setup_stack (void **esp) +setup_stack (void **esp, char **argv, int argc) { uint8_t *kpage; bool success = false; @@ -456,6 +461,7 @@ setup_stack (void **esp) success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true); if (success) { *esp = PHYS_BASE - 12; + populate_stack(esp, argc, argv); } else palloc_free_page (kpage); }