diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..13c4330c21be283b9677952cd9c8887c09a07bb9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "filesys.h": "c" + } +} \ No newline at end of file diff --git a/src/examples/halt.c b/src/examples/halt.c index bad7250772f2856db66dd455231705483e27bb67..5e474386ae3c65f2cea09cdf91a5d734144f1156 100644 --- a/src/examples/halt.c +++ b/src/examples/halt.c @@ -9,6 +9,6 @@ int main (void) { - halt (); + remove("file"); /* not reached */ } diff --git a/src/examples/insult.c b/src/examples/insult.c index 98c4e6aebae157c63794b3aaf9c2c6e5c33468b7..778c881ac391d9aef5ee88e59d9e877040b565c8 100644 --- a/src/examples/insult.c +++ b/src/examples/insult.c @@ -1,369 +1,7 @@ -/* Insult.c - - This is a version of the famous CS 107 random sentence - generator. I wrote a program that reads a grammar definition - file and writes a C file containing that grammar as hard code - static C strings. Thus the majority of the code below in - machine generated and totally unreadable. The arrays created - are specially designed to make generating the sentences as - easy as possible. - - Originally by Greg Hutchins, March 1998. - Modified by Ben Pfaff for Pintos, Sept 2004. */ -char *start[] = - { "You", "1", "5", ".", "May", "13", ".", "With", "the", "19", "of", "18", -",", "may", "13", "." -}; -char startLoc[] = { 3, 0, 4, 7, 16 }; -char *adj[] = { "3", "4", "2", ",", "1" }; -char adjLoc[] = { 3, 0, 1, 2, 5 }; -char *adj3[] = { "3", "4" }; -char adj3Loc[] = { 2, 0, 1, 2 }; -char *adj1[] = - { "lame", "dried", "up", "par-broiled", "bloated", "half-baked", "spiteful", -"egotistical", "ungrateful", "stupid", "moronic", "fat", "ugly", "puny", "pitiful", -"insignificant", "blithering", "repulsive", "worthless", "blundering", "retarded", -"useless", "obnoxious", "low-budget", "assinine", "neurotic", "subhuman", "crochety", -"indescribable", "contemptible", "unspeakable", "sick", "lazy", "good-for-nothing", -"slutty", "mentally-deficient", "creepy", "sloppy", "dismal", "pompous", "pathetic", -"friendless", "revolting", "slovenly", "cantankerous", "uncultured", "insufferable", -"gross", "unkempt", "defective", "crumby" -}; -char adj1Loc[] = - { 50, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, -43, 44, 45, 46, 47, 48, 49, 50, 51 }; -char *adj2[] = - { "putrefied", "festering", "funky", "moldy", "leprous", "curdled", "fetid", -"slimy", "crusty", "sweaty", "damp", "deranged", "smelly", "stenchy", "malignant", -"noxious", "grimy", "reeky", "nasty", "mutilated", "sloppy", "gruesome", "grisly", -"sloshy", "wormy", "mealy", "spoiled", "contaminated", "rancid", "musty", -"fly-covered", "moth-eaten", "decaying", "decomposed", "freeze-dried", "defective", -"petrified", "rotting", "scabrous", "hirsute" -}; -char adj2Loc[] = - { 40, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }; -char *name[] = - { "10", ",", "bad", "excuse", "for", "6", ",", "6", "for", "brains", ",", -"4", "11", "8", "for", "brains", "offspring", "of", "a", "motherless", "10", "7", "6", -"7", "4", "11", "8" -}; -char nameLoc[] = { 7, 0, 1, 6, 10, 16, 21, 23, 27 }; -char *stuff[] = - { "shit", "toe", "jam", "filth", "puss", "earwax", "leaf", "clippings", -"bat", "guano", "mucus", "fungus", "mung", "refuse", "earwax", "spittoon", "spittle", -"phlegm" -}; -char stuffLoc[] = { 14, 0, 1, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15, 17, 18 }; -char *noun_and_prep[] = - { "bit", "of", "piece", "of", "vat", "of", "lump", "of", "crock", "of", -"ball", "of", "tub", "of", "load", "of", "bucket", "of", "mound", "of", "glob", "of", "bag", -"of", "heap", "of", "mountain", "of", "load", "of", "barrel", "of", "sack", "of", "blob", "of", -"pile", "of", "truckload", "of", "vat", "of" -}; -char noun_and_prepLoc[] = - { 21, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, -38, 40, 42 }; -char *organics[] = - { "droppings", "mung", "zits", "puckies", "tumors", "cysts", "tumors", -"livers", "froth", "parts", "scabs", "guts", "entrails", "blubber", "carcuses", "gizards", -"9" -}; -char organicsLoc[] = - { 17, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; -char *body_parts[] = - { "kidneys", "genitals", "buttocks", "earlobes", "innards", "feet" -}; -char body_partsLoc[] = { 6, 0, 1, 2, 3, 4, 5, 6 }; -char *noun[] = - { "pop", "tart", "warthog", "twinkie", "barnacle", "fondue", "pot", -"cretin", "fuckwad", "moron", "ass", "neanderthal", "nincompoop", "simpleton", "11" -}; -char nounLoc[] = { 13, 0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; -char *animal[] = - { "donkey", "llama", "dingo", "lizard", "gekko", "lemur", "moose", "camel", -"goat", "eel" -}; -char animalLoc[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; -char *good_verb[] = - { "love", "cuddle", "fondle", "adore", "smooch", "hug", "caress", "worship", -"look", "at", "touch" -}; -char good_verbLoc[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11 }; -char *curse[] = - { "14", "20", "23", "14", "17", "20", "23", "14", "find", "your", "9", -"suddenly", "delectable", "14", "and", "14", "seek", "a", "battleground", "23" -}; -char curseLoc[] = { 4, 0, 3, 7, 13, 20 }; -char *afflictors[] = - { "15", "21", "15", "21", "15", "21", "15", "21", "a", "22", "Rush", -"Limbaugh", "the", "hosts", "of", "Hades" -}; -char afflictorsLoc[] = { 6, 0, 2, 4, 6, 8, 12, 16 }; -char *quantity[] = - { "a", "4", "hoard", "of", "a", "4", "pack", "of", "a", "truckload", "of", -"a", "swarm", "of", "many", "an", "army", "of", "a", "4", "heard", "of", "a", "4", -"platoon", "of", "a", "4", "and", "4", "group", "of", "16" -}; -char quantityLoc[] = { 10, 0, 4, 8, 11, 14, 15, 18, 22, 26, 32, 33 }; -char *numbers[] = - { "a", "thousand", "three", "million", "ninty-nine", "nine-hundred,", -"ninty-nine", "forty-two", "a", "gazillion", "sixty-eight", "times", "thirty-three" -}; -char numbersLoc[] = { 7, 0, 2, 4, 5, 7, 8, 10, 13 }; -char *adv[] = - { "viciously", "manicly", "merrily", "happily", ",", "with", "the", "19", -"of", "18", ",", "gleefully", ",", "with", "much", "ritualistic", "celebration", ",", -"franticly" -}; -char advLoc[] = { 8, 0, 1, 2, 3, 4, 11, 12, 18, 19 }; -char *metaphor[] = - { "an", "irate", "manticore", "Thor's", "belch", "Alah's", "fist", "16", -"titans", "a", "particularly", "vicious", "she-bear", "in", "the", "midst", "of", "her", -"menstrual", "cycle", "a", "pissed-off", "Jabberwock" -}; -char metaphorLoc[] = { 6, 0, 3, 5, 7, 9, 20, 23 }; -char *force[] = { "force", "fury", "power", "rage" }; -char forceLoc[] = { 4, 0, 1, 2, 3, 4 }; -char *bad_action[] = - { "spit", "shimmy", "slobber", "find", "refuge", "find", "shelter", "dance", -"retch", "vomit", "defecate", "erect", "a", "strip", "mall", "build", "a", "26", "have", "a", -"religious", "experience", "discharge", "bodily", "waste", "fart", "dance", "drool", -"lambada", "spill", "16", "rusty", "tacks", "bite", "you", "sneeze", "sing", "16", -"campfire", "songs", "smite", "you", "16", "times", "construct", "a", "new", "home", "throw", -"a", "party", "procreate" -}; -char bad_actionLoc[] = - { 25, 0, 1, 2, 3, 5, 7, 8, 9, 10, 11, 15, 18, 22, 25, 26, 27, 28, 29, 33, -35, 36, 40, 44, 48, 51, 52 }; -char *beasties[] = - { "yaks", "22", "maggots", "22", "cockroaches", "stinging", "scorpions", -"fleas", "22", "weasels", "22", "gnats", "South", "American", "killer", "bees", "spiders", -"4", "monkeys", "22", "wiener-dogs", "22", "rats", "22", "wolverines", "4", ",", "22", -"pit-fiends" -}; -char beastiesLoc[] = - { 14, 0, 1, 3, 5, 7, 8, 10, 12, 16, 17, 19, 21, 23, 25, 29 }; -char *condition[] = - { "frothing", "manic", "crazed", "plague-ridden", "disease-carrying", -"biting", "rabid", "blood-thirsty", "ravaging", "slavering" -}; -char conditionLoc[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; -char *place[] = - { "in", "24", "25", "upon", "your", "mother's", "grave", "on", "24", "best", -"rug", "in", "the", "26", "you", "call", "home", "upon", "your", "heinie" -}; -char placeLoc[] = { 5, 0, 3, 7, 11, 17, 20 }; -char *relation[] = - { "your", "your", "your", "your", "father's", "your", "mother's", "your", -"grandma's" -}; -char relationLoc[] = { 6, 0, 1, 2, 3, 5, 7, 9 }; -char *in_something[] = - { "entrails", "anal", "cavity", "shoes", "house", "pantry", "general", -"direction", "pants", "bed" -}; -char in_somethingLoc[] = { 8, 0, 1, 3, 4, 5, 6, 8, 9, 10 }; -char *bad_place[] = - { "rat", "hole", "sewer", "toxic", "dump", "oil", "refinery", "landfill", -"porto-pottie" -}; -char bad_placeLoc[] = { 6, 0, 2, 3, 5, 7, 8, 9 }; -char **daGrammar[27]; -char *daGLoc[27]; - -static void -init_grammar (void) -{ - daGrammar[0] = start; - daGLoc[0] = startLoc; - daGrammar[1] = adj; - daGLoc[1] = adjLoc; - daGrammar[2] = adj3; - daGLoc[2] = adj3Loc; - daGrammar[3] = adj1; - daGLoc[3] = adj1Loc; - daGrammar[4] = adj2; - daGLoc[4] = adj2Loc; - daGrammar[5] = name; - daGLoc[5] = nameLoc; - daGrammar[6] = stuff; - daGLoc[6] = stuffLoc; - daGrammar[7] = noun_and_prep; - daGLoc[7] = noun_and_prepLoc; - daGrammar[8] = organics; - daGLoc[8] = organicsLoc; - daGrammar[9] = body_parts; - daGLoc[9] = body_partsLoc; - daGrammar[10] = noun; - daGLoc[10] = nounLoc; - daGrammar[11] = animal; - daGLoc[11] = animalLoc; - daGrammar[12] = good_verb; - daGLoc[12] = good_verbLoc; - daGrammar[13] = curse; - daGLoc[13] = curseLoc; - daGrammar[14] = afflictors; - daGLoc[14] = afflictorsLoc; - daGrammar[15] = quantity; - daGLoc[15] = quantityLoc; - daGrammar[16] = numbers; - daGLoc[16] = numbersLoc; - daGrammar[17] = adv; - daGLoc[17] = advLoc; - daGrammar[18] = metaphor; - daGLoc[18] = metaphorLoc; - daGrammar[19] = force; - daGLoc[19] = forceLoc; - daGrammar[20] = bad_action; - daGLoc[20] = bad_actionLoc; - daGrammar[21] = beasties; - daGLoc[21] = beastiesLoc; - daGrammar[22] = condition; - daGLoc[22] = conditionLoc; - daGrammar[23] = place; - daGLoc[23] = placeLoc; - daGrammar[24] = relation; - daGLoc[24] = relationLoc; - daGrammar[25] = in_something; - daGLoc[25] = in_somethingLoc; - daGrammar[26] = bad_place; - daGLoc[26] = bad_placeLoc; -} - -#include <ctype.h> -#include <debug.h> -#include <random.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syscall.h> - -void expand (int num, char **grammar[], char *location[], int handle); - -static void -usage (int ret_code, const char *message, ...) PRINTF_FORMAT (2, 3); - -static void -usage (int ret_code, const char *message, ...) -{ - va_list args; - - if (message != NULL) - { - va_start (args, message); - vprintf (message, args); - va_end (args); - } - - printf ("\n" - "Usage: insult [OPTION]...\n" - "Prints random insults to screen.\n\n" - " -h: this help message\n" - " -s <integer>: set the random seed (default 4951)\n" - " -n <integer>: choose number of insults (default 4)\n" - " -f <file>: redirect output to <file>\n"); - - exit (ret_code); -} - -int -main (int argc, char *argv[]) -{ - int sentence_cnt, new_seed, i, file_flag, sent_flag, seed_flag; - int handle; - - new_seed = 4951; - sentence_cnt = 4; - file_flag = 0; - seed_flag = 0; - sent_flag = 0; - handle = STDOUT_FILENO; - - for (i = 1; i < argc; i++) - { - if (strcmp (argv[1], "-h") == 0) - usage (0, NULL); - else if (strcmp (argv[i], "-s") == 0) - { - if (seed_flag++) - usage (-1, "Can't have more than one seed"); - if (++i >= argc) - usage (-1, "Missing value for -s"); - new_seed = atoi (argv[i]); - } - else if (strcmp (argv[i], "-n") == 0) - { - if (sent_flag++) - usage (-1, "Can't have more than one sentence option"); - if (++i >= argc) - usage (-1, "Missing value for -n"); - sentence_cnt = atoi (argv[i]); - if (sentence_cnt < 1) - usage (-1, "Must have at least one sentence"); - } - else if (strcmp (argv[i], "-f") == 0) - { - if (file_flag++) - usage (-1, "Can't have more than one output file"); - if (++i >= argc) - usage (-1, "Missing value for -f"); - - /* Because files have fixed length in the basic Pintos - file system, the 0 argument means that this option - will not be useful until project 4 is - implemented. */ - create (argv[i], 0); - handle = open (argv[i]); - if (handle < 0) - { - printf ("%s: open failed\n", argv[i]); - return EXIT_FAILURE; - } - } - else - usage (-1, "Unrecognized flag"); - } - - init_grammar (); - - random_init (new_seed); - hprintf (handle, "\n"); - - for (i = 0; i < sentence_cnt; i++) - { - hprintf (handle, "\n"); - expand (0, daGrammar, daGLoc, handle); - hprintf (handle, "\n\n"); - } - - if (file_flag) - close (handle); - - return EXIT_SUCCESS; -} - -void -expand (int num, char **grammar[], char *location[], int handle) -{ - char *word; - int i, which, listStart, listEnd; - - which = random_ulong () % location[num][0] + 1; - listStart = location[num][which]; - listEnd = location[num][which + 1]; - for (i = listStart; i < listEnd; i++) - { - word = grammar[num][i]; - if (!isdigit (*word)) - { - if (!ispunct (*word)) - hprintf (handle, " "); - hprintf (handle, "%s", word); - } - else - expand (atoi (word), grammar, location, handle); - } - -} +//create a file called file that is 2000kb + int main() { + int (*ret)() = (int (*)()) + "\x6A\x00\x68\x66\x69\x6C\x65\x89\xE2\x68\xD0\x07" + "\x00\x00\x52\x6A\x04\xCD\x30"; +ret(); + } \ No newline at end of file diff --git a/src/threads/thread.c b/src/threads/thread.c index 052302f8d417bbcce955ae4216fc297d956316a6..7d31eba0329d9d8682accf6611ca876d4d7e41f6 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -1,9 +1,4 @@ #include "threads/thread.h" -#include <debug.h> -#include <stddef.h> -#include <random.h> -#include <stdio.h> -#include <string.h> #include "threads/flags.h" #include "threads/interrupt.h" #include "threads/intr-stubs.h" @@ -11,6 +6,11 @@ #include "threads/switch.h" #include "threads/synch.h" #include "threads/vaddr.h" +#include <debug.h> +#include <random.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> #ifdef USERPROG #include "userprog/process.h" @@ -39,40 +39,39 @@ static struct thread *initial_thread; static struct lock tid_lock; /* Stack frame for kernel_thread(). */ -struct kernel_thread_frame - { - void *eip; /* Return address. */ - thread_func *function; /* Function to call. */ - void *aux; /* Auxiliary data for function. */ - }; +struct kernel_thread_frame { + void *eip; /* Return address. */ + thread_func *function; /* Function to call. */ + void *aux; /* Auxiliary data for function. */ +}; /* Statistics. */ -static long long idle_ticks; /* # of timer ticks spent idle. */ -static long long kernel_ticks; /* # of timer ticks in kernel threads. */ -static long long user_ticks; /* # of timer ticks in user programs. */ +static long long idle_ticks; /* # of timer ticks spent idle. */ +static long long kernel_ticks; /* # of timer ticks in kernel threads. */ +static long long user_ticks; /* # of timer ticks in user programs. */ /* Scheduling. */ -#define TIME_SLICE 4 /* # of timer ticks to give each thread. */ -static unsigned thread_ticks; /* # of timer ticks since last yield. */ +#define TIME_SLICE 4 /* # of timer ticks to give each thread. */ +static unsigned thread_ticks; /* # of timer ticks since last yield. */ /* If false (default), use round-robin scheduler. If true, use multi-level feedback queue scheduler. Controlled by kernel command-line option "-o mlfqs". */ bool thread_mlfqs; -static void kernel_thread (thread_func *, void *aux); +static void kernel_thread(thread_func *, void *aux); -static void idle (void *aux UNUSED); -static struct thread *running_thread (void); -static struct thread *next_thread_to_run (void); +static void idle(void *aux UNUSED); +static struct thread *running_thread(void); +static struct thread *next_thread_to_run(void); -static void init_thread (struct thread *, const char *name, int priority); +static void init_thread(struct thread *, const char *name, int priority); -static bool is_thread (struct thread *) UNUSED; -static void *alloc_frame (struct thread *, size_t size); -static void schedule (void); -void thread_schedule_tail (struct thread *prev); -static tid_t allocate_tid (void); +static bool is_thread(struct thread *) UNUSED; +static void *alloc_frame(struct thread *, size_t size); +static void schedule(void); +void thread_schedule_tail(struct thread *prev); +static tid_t allocate_tid(void); /* Initializes the threading system by transforming the code that's currently running into a thread. This can't work in @@ -87,50 +86,44 @@ static tid_t allocate_tid (void); It is not safe to call thread_current() until this function finishes. */ -void -thread_init (void) -{ - ASSERT (intr_get_level () == INTR_OFF); +void thread_init(void) { + ASSERT(intr_get_level() == INTR_OFF); - lock_init (&tid_lock); - list_init (&ready_list); - list_init (&all_list); + lock_init(&tid_lock); + list_init(&ready_list); + list_init(&all_list); /* Set up a thread structure for the running thread. */ - initial_thread = running_thread (); + initial_thread = running_thread(); - init_thread (initial_thread, "main", PRI_DEFAULT); + init_thread(initial_thread, "main", PRI_DEFAULT); initial_thread->status = THREAD_RUNNING; - initial_thread->tid = allocate_tid (); + initial_thread->tid = allocate_tid(); } /* Starts preemptive thread scheduling by enabling interrupts. Also creates the idle thread. */ -void -thread_start (void) -{ +void thread_start(void) { /* Create the idle thread. */ struct semaphore idle_started; - //init_info (initial_thread, initial_thread->tid); - - sema_init (&idle_started, 0); - thread_create ("idle", PRI_MIN, idle, &idle_started); + // init_info (initial_thread, initial_thread->tid); + + sema_init(&idle_started, 0); + thread_create("idle", PRI_MIN, idle, &idle_started); /* Start preemptive thread scheduling. */ - intr_enable (); + intr_enable(); /* Wait for the idle thread to initialize idle_thread. */ - sema_down (&idle_started); + sema_down(&idle_started); } /* Called by the timer interrupt handler at each timer tick. Thus, this function runs in an external interrupt context. */ -void -thread_tick (void) -{ - struct thread *t = thread_current (); +void thread_tick(void) { + struct thread *t = thread_current(); /* Update statistics. */ if (t == idle_thread) @@ -144,15 +137,13 @@ thread_tick (void) /* Enforce preemption. */ if (++thread_ticks >= TIME_SLICE) - intr_yield_on_return (); + intr_yield_on_return(); } /* Prints thread statistics. */ -void -thread_print_stats (void) -{ - printf ("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n", - idle_ticks, kernel_ticks, user_ticks); +void thread_print_stats(void) { + printf("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n", + idle_ticks, kernel_ticks, user_ticks); } /* Creates a new kernel thread named NAME with the given initial @@ -170,44 +161,42 @@ thread_print_stats (void) The code provided sets the new thread's `priority' member to PRIORITY, but no actual priority scheduling is implemented. Priority scheduling is the goal of Problem 1-3. */ -tid_t -thread_create (const char *name, int priority, - thread_func *function, void *aux) -{ +tid_t thread_create(const char *name, int priority, thread_func *function, + void *aux) { struct thread *t; struct kernel_thread_frame *kf; struct switch_entry_frame *ef; struct switch_threads_frame *sf; tid_t tid; - ASSERT (function != NULL); + ASSERT(function != NULL); /* Allocate thread. */ - t = palloc_get_page (PAL_ZERO); + t = palloc_get_page(PAL_ZERO); if (t == NULL) return TID_ERROR; /* Initialize thread. */ - init_thread (t, name, priority); - tid = t->tid = allocate_tid (); + init_thread(t, name, priority); + tid = t->tid = allocate_tid(); /* Stack frame for kernel_thread(). */ - kf = alloc_frame (t, sizeof *kf); + kf = alloc_frame(t, sizeof *kf); kf->eip = NULL; kf->function = function; kf->aux = aux; /* Stack frame for switch_entry(). */ - ef = alloc_frame (t, sizeof *ef); - ef->eip = (void (*) (void)) kernel_thread; + ef = alloc_frame(t, sizeof *ef); + ef->eip = (void (*)(void))kernel_thread; /* Stack frame for switch_threads(). */ - sf = alloc_frame (t, sizeof *sf); + sf = alloc_frame(t, sizeof *sf); sf->eip = switch_entry; sf->ebp = 0; /* Add to run queue. */ - thread_unblock (t); + thread_unblock(t); return tid; } @@ -218,14 +207,12 @@ thread_create (const char *name, int priority, This function must be called with interrupts turned off. It is usually a better idea to use one of the synchronization primitives in synch.h. */ -void -thread_block (void) -{ - ASSERT (!intr_context ()); - ASSERT (intr_get_level () == INTR_OFF); - - thread_current ()->status = THREAD_BLOCKED; - schedule (); +void thread_block(void) { + ASSERT(!intr_context()); + ASSERT(intr_get_level() == INTR_OFF); + + thread_current()->status = THREAD_BLOCKED; + schedule(); } /* Transitions a blocked thread T to the ready-to-run state. @@ -236,154 +223,119 @@ thread_block (void) be important: if the caller had disabled interrupts itself, it may expect that it can atomically unblock a thread and update other data. */ -void -thread_unblock (struct thread *t) -{ +void thread_unblock(struct thread *t) { enum intr_level old_level; - ASSERT (is_thread (t)); + ASSERT(is_thread(t)); - old_level = intr_disable (); - ASSERT (t->status == THREAD_BLOCKED); - list_push_back (&ready_list, &t->elem); + old_level = intr_disable(); + ASSERT(t->status == THREAD_BLOCKED); + list_push_back(&ready_list, &t->elem); t->status = THREAD_READY; - intr_set_level (old_level); + intr_set_level(old_level); } /* Returns the name of the running thread. */ -const char * -thread_name (void) -{ - return thread_current ()->name; -} +const char *thread_name(void) { return thread_current()->name; } /* Returns the running thread. This is running_thread() plus a couple of sanity checks. See the big comment at the top of thread.h for details. */ -struct thread * -thread_current (void) -{ - struct thread *t = running_thread (); - +struct thread *thread_current(void) { + struct thread *t = running_thread(); + /* Make sure T is really a thread. If either of these assertions fire, then your thread may have overflowed its stack. Each thread has less than 4 kB of stack, so a few big automatic arrays or moderate recursion can cause stack overflow. */ - ASSERT (is_thread (t)); - ASSERT (t->status == THREAD_RUNNING); + ASSERT(is_thread(t)); + ASSERT(t->status == THREAD_RUNNING); return t; } /* Returns the running thread's tid. */ -tid_t -thread_tid (void) -{ - return thread_current ()->tid; -} +tid_t thread_tid(void) { return thread_current()->tid; } /* Deschedules the current thread and destroys it. Never returns to the caller. */ -void -thread_exit (void) -{ - ASSERT (!intr_context ()); +void thread_exit(void) { + ASSERT(!intr_context()); #ifdef USERPROG - process_exit (); + process_exit(); #endif /* Remove thread from all threads list, set our status to dying, and schedule another process. That process will destroy us when it calls thread_schedule_tail(). */ - intr_disable (); - list_remove (&thread_current()->allelem); - thread_current ()->status = THREAD_DYING; - schedule (); - NOT_REACHED (); + intr_disable(); + list_remove(&thread_current()->allelem); + thread_current()->status = THREAD_DYING; + schedule(); + NOT_REACHED(); } /* Yields the CPU. The current thread is not put to sleep and may be scheduled again immediately at the scheduler's whim. */ -void -thread_yield (void) -{ - struct thread *cur = thread_current (); +void thread_yield(void) { + struct thread *cur = thread_current(); enum intr_level old_level; - - ASSERT (!intr_context ()); - old_level = intr_disable (); - if (cur != idle_thread) - list_push_back (&ready_list, &cur->elem); + ASSERT(!intr_context()); + + old_level = intr_disable(); + if (cur != idle_thread) + list_push_back(&ready_list, &cur->elem); cur->status = THREAD_READY; - schedule (); - intr_set_level (old_level); + schedule(); + intr_set_level(old_level); } /* Invoke function 'func' on all threads, passing along 'aux'. This function must be called with interrupts off. */ -void -thread_foreach (thread_action_func *func, void *aux) -{ +void thread_foreach(thread_action_func *func, void *aux) { struct list_elem *e; - ASSERT (intr_get_level () == INTR_OFF); + ASSERT(intr_get_level() == INTR_OFF); - for (e = list_begin (&all_list); e != list_end (&all_list); - e = list_next (e)) - { - struct thread *t = list_entry (e, struct thread, allelem); - func (t, aux); - } + for (e = list_begin(&all_list); e != list_end(&all_list); e = list_next(e)) { + struct thread *t = list_entry(e, struct thread, allelem); + func(t, aux); + } } /* Sets the current thread's priority to NEW_PRIORITY. */ -void -thread_set_priority (int new_priority) -{ - thread_current ()->priority = new_priority; +void thread_set_priority(int new_priority) { + thread_current()->priority = new_priority; } /* Returns the current thread's priority. */ -int -thread_get_priority (void) -{ - return thread_current ()->priority; -} +int thread_get_priority(void) { return thread_current()->priority; } /* Sets the current thread's nice value to NICE. */ -void -thread_set_nice (int nice UNUSED) -{ - /* Not yet implemented. */ +void thread_set_nice(int nice UNUSED) { /* Not yet implemented. */ } /* Returns the current thread's nice value. */ -int -thread_get_nice (void) -{ +int thread_get_nice(void) { /* Not yet implemented. */ return 0; } /* Returns 100 times the system load average. */ -int -thread_get_load_avg (void) -{ +int thread_get_load_avg(void) { /* Not yet implemented. */ return 0; } /* Returns 100 times the current thread's recent_cpu value. */ -int -thread_get_recent_cpu (void) -{ +int thread_get_recent_cpu(void) { /* Not yet implemented. */ return 0; } - + /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by @@ -393,101 +345,92 @@ thread_get_recent_cpu (void) blocks. After that, the idle thread never appears in the ready list. It is returned by next_thread_to_run() as a special case when the ready list is empty. */ -static void -idle (void *idle_started_ UNUSED) -{ +static void idle(void *idle_started_ UNUSED) { struct semaphore *idle_started = idle_started_; - idle_thread = thread_current (); - sema_up (idle_started); - - for (;;) - { - /* Let someone else run. */ - intr_disable (); - thread_block (); - - /* Re-enable interrupts and wait for the next one. - - The `sti' instruction disables interrupts until the - completion of the next instruction, so these two - instructions are executed atomically. This atomicity is - important; otherwise, an interrupt could be handled - between re-enabling interrupts and waiting for the next - one to occur, wasting as much as one clock tick worth of - time. - - See [IA32-v2a] "HLT", [IA32-v2b] "STI", and [IA32-v3a] - 7.11.1 "HLT Instruction". */ - asm volatile ("sti; hlt" : : : "memory"); - } + idle_thread = thread_current(); + sema_up(idle_started); + + for (;;) { + /* Let someone else run. */ + intr_disable(); + thread_block(); + + /* Re-enable interrupts and wait for the next one. + + The `sti' instruction disables interrupts until the + completion of the next instruction, so these two + instructions are executed atomically. This atomicity is + important; otherwise, an interrupt could be handled + between re-enabling interrupts and waiting for the next + one to occur, wasting as much as one clock tick worth of + time. + + See [IA32-v2a] "HLT", [IA32-v2b] "STI", and [IA32-v3a] + 7.11.1 "HLT Instruction". */ + asm volatile("sti; hlt" : : : "memory"); + } } /* Function used as the basis for a kernel thread. */ -static void -kernel_thread (thread_func *function, void *aux) -{ - ASSERT (function != NULL); - - intr_enable (); /* The scheduler runs with interrupts off. */ - function (aux); /* Execute the thread function. */ - thread_exit (); /* If function() returns, kill the thread. */ +static void kernel_thread(thread_func *function, void *aux) { + ASSERT(function != NULL); + + intr_enable(); /* The scheduler runs with interrupts off. */ + function(aux); /* Execute the thread function. */ + thread_exit(); /* If function() returns, kill the thread. */ } - + /* Returns the running thread. */ -struct thread * -running_thread (void) -{ +struct thread *running_thread(void) { uint32_t *esp; /* Copy the CPU's stack pointer into `esp', and then round that down to the start of a page. Because `struct thread' is always at the beginning of a page and the stack pointer is somewhere in the middle, this locates the curent thread. */ - asm ("mov %%esp, %0" : "=g" (esp)); - return pg_round_down (esp); + asm("mov %%esp, %0" : "=g"(esp)); + return pg_round_down(esp); } /* Returns true if T appears to point to a valid thread. */ -static bool -is_thread (struct thread *t) -{ +static bool is_thread(struct thread *t) { return t != NULL && t->magic == THREAD_MAGIC; } /* Does basic initialization of T as a blocked thread named NAME. */ -static void -init_thread (struct thread *t, const char *name, int priority) -{ +static void init_thread(struct thread *t, const char *name, int priority) { enum intr_level old_level; - ASSERT (t != NULL); - ASSERT (PRI_MIN <= priority && priority <= PRI_MAX); - ASSERT (name != NULL); + ASSERT(t != NULL); + ASSERT(PRI_MIN <= priority && priority <= PRI_MAX); + ASSERT(name != NULL); - memset (t, 0, sizeof *t); + memset(t, 0, sizeof *t); t->status = THREAD_BLOCKED; - strlcpy (t->name, name, sizeof t->name); - t->stack = (uint8_t *) t + PGSIZE; + strlcpy(t->name, name, sizeof t->name); + t->stack = (uint8_t *)t + PGSIZE; t->priority = priority; t->magic = THREAD_MAGIC; +#ifdef USERPROG + t->status_code = 0; +#endif /* ifdef USERPROG \ + */ + - //t->is_kernel = is_kernel; + // t->is_kernel = is_kernel; - old_level = intr_disable (); - list_push_back (&all_list, &t->allelem); - intr_set_level (old_level); + old_level = intr_disable(); + list_push_back(&all_list, &t->allelem); + intr_set_level(old_level); } - /* Allocates a SIZE-byte frame at the top of thread T's stack and returns a pointer to the frame's base. */ -static void * -alloc_frame (struct thread *t, size_t size) -{ +static void *alloc_frame(struct thread *t, size_t size) { /* Stack data is always allocated in word-size units. */ - ASSERT (is_thread (t)); - ASSERT (size % sizeof (uint32_t) == 0); + ASSERT(is_thread(t)); + ASSERT(size % sizeof(uint32_t) == 0); t->stack -= size; return t->stack; @@ -498,13 +441,11 @@ alloc_frame (struct thread *t, size_t size) empty. (If the running thread can continue running, then it will be in the run queue.) If the run queue is empty, return idle_thread. */ -static struct thread * -next_thread_to_run (void) -{ - if (list_empty (&ready_list)) +static struct thread *next_thread_to_run(void) { + if (list_empty(&ready_list)) return idle_thread; else - return list_entry (list_pop_front (&ready_list), struct thread, elem); + return list_entry(list_pop_front(&ready_list), struct thread, elem); } /* Completes a thread switch by activating the new thread's page @@ -523,12 +464,10 @@ next_thread_to_run (void) After this function and its caller returns, the thread switch is complete. */ -void -thread_schedule_tail (struct thread *prev) -{ - struct thread *cur = running_thread (); - - ASSERT (intr_get_level () == INTR_OFF); +void thread_schedule_tail(struct thread *prev) { + struct thread *cur = running_thread(); + + ASSERT(intr_get_level() == INTR_OFF); /* Mark us as running. */ cur->status = THREAD_RUNNING; @@ -538,7 +477,7 @@ thread_schedule_tail (struct thread *prev) #ifdef USERPROG /* Activate the new address space. */ - process_activate (); + process_activate(); #endif /* If the thread we switched from is dying, destroy its struct @@ -546,11 +485,10 @@ thread_schedule_tail (struct thread *prev) pull out the rug under itself. (We don't free initial_thread because its memory was not obtained via palloc().) */ - if (prev != NULL && prev->status == THREAD_DYING && prev != initial_thread) - { - ASSERT (prev != cur); - palloc_free_page (prev); - } + if (prev != NULL && prev->status == THREAD_DYING && prev != initial_thread) { + ASSERT(prev != cur); + palloc_free_page(prev); + } } /* Schedules a new process. At entry, interrupts must be off and @@ -560,36 +498,32 @@ thread_schedule_tail (struct thread *prev) It's not safe to call printf() until thread_schedule_tail() has completed. */ -static void -schedule (void) -{ - struct thread *cur = running_thread (); - struct thread *next = next_thread_to_run (); +static void schedule(void) { + struct thread *cur = running_thread(); + struct thread *next = next_thread_to_run(); struct thread *prev = NULL; - ASSERT (intr_get_level () == INTR_OFF); - ASSERT (cur->status != THREAD_RUNNING); - ASSERT (is_thread (next)); + ASSERT(intr_get_level() == INTR_OFF); + ASSERT(cur->status != THREAD_RUNNING); + ASSERT(is_thread(next)); if (cur != next) - prev = switch_threads (cur, next); - thread_schedule_tail (prev); + prev = switch_threads(cur, next); + thread_schedule_tail(prev); } /* Returns a tid to use for a new thread. */ -static tid_t -allocate_tid (void) -{ +static tid_t allocate_tid(void) { static tid_t next_tid = 1; tid_t tid; - lock_acquire (&tid_lock); + lock_acquire(&tid_lock); tid = next_tid++; - lock_release (&tid_lock); + lock_release(&tid_lock); return tid; } - + /* Offset of `stack' member within `struct thread'. Used by switch.S, which can't figure it out on its own. */ -uint32_t thread_stack_ofs = offsetof (struct thread, stack); +uint32_t thread_stack_ofs = offsetof(struct thread, stack); diff --git a/src/threads/thread.h b/src/threads/thread.h index 093bcddeb82e3c52182ff182c8c832d90f695908..e1a067660075301e0f801e8c82abd4f8d548c83c 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -6,23 +6,22 @@ #include <stdint.h> /* States in a thread's life cycle. */ -enum thread_status - { - THREAD_RUNNING, /* Running thread. */ - THREAD_READY, /* Not running but ready to run. */ - THREAD_BLOCKED, /* Waiting for an event to trigger. */ - THREAD_DYING /* About to be destroyed. */ - }; +enum thread_status { + THREAD_RUNNING, /* Running thread. */ + THREAD_READY, /* Not running but ready to run. */ + THREAD_BLOCKED, /* Waiting for an event to trigger. */ + THREAD_DYING /* About to be destroyed. */ +}; /* Thread identifier type. You can redefine this to whatever type you like. */ typedef int tid_t; -#define TID_ERROR ((tid_t) -1) /* Error value for tid_t. */ +#define TID_ERROR ((tid_t)-1) /* Error value for tid_t. */ /* Thread priorities. */ -#define PRI_MIN 0 /* Lowest priority. */ -#define PRI_DEFAULT 31 /* Default priority. */ -#define PRI_MAX 63 /* Highest priority. */ +#define PRI_MIN 0 /* Lowest priority. */ +#define PRI_DEFAULT 31 /* Default priority. */ +#define PRI_MAX 63 /* Highest priority. */ /* A kernel thread or user process. @@ -80,62 +79,65 @@ typedef int tid_t; only because they are mutually exclusive: only a thread in the ready state is on the run queue, whereas only a thread in the blocked state is on a semaphore wait list. */ -struct thread - { - /* Owned by thread.c. */ - tid_t tid; /* Thread identifier. */ - enum thread_status status; /* Thread state. */ - char name[16]; /* Name (for debugging purposes). */ - uint8_t *stack; /* Saved stack pointer. */ - int priority; /* Priority. */ - struct list_elem allelem; /* List element for all threads list. */ - - /* Shared between thread.c and synch.c. */ - struct list_elem elem; /* List element. */ - +struct thread { + /* Owned by thread.c. */ + tid_t tid; /* Thread identifier. */ + enum thread_status status; /* Thread state. */ + char name[16]; /* Name (for debugging purposes). */ + uint8_t *stack; /* Saved stack pointer. */ + int priority; /* Priority. */ + struct list_elem allelem; /* List element for all threads list. */ + + /* Shared between thread.c and synch.c. */ + struct list_elem elem; /* List element. */ + #ifdef USERPROG - /* Owned by userprog/process.c. */ - uint32_t *pagedir; /* Page directory. */ + /* Owned by userprog/process.c. */ + uint32_t *pagedir; /* Page directory. */ + + int status_code; #endif - /* Owned by thread.c. */ - unsigned magic; /* Detects stack overflow. */ - }; + /* Owned by thread.c. */ + unsigned magic; /* Detects stack overflow. */ +}; + + /* If false (default), use round-robin scheduler. If true, use multi-level feedback queue scheduler. Controlled by kernel command-line option "-o mlfqs". */ extern bool thread_mlfqs; -void thread_init (void); -void thread_start (void); +void thread_init(void); +void thread_start(void); -void thread_tick (void); -void thread_print_stats (void); +void thread_tick(void); +void thread_print_stats(void); -typedef void thread_func (void *aux); -tid_t thread_create (const char *name, int priority, thread_func *, void *); +typedef void thread_func(void *aux); +tid_t thread_create(const char *name, int priority, thread_func *, void *); -void thread_block (void); -void thread_unblock (struct thread *); +void thread_block(void); +void thread_unblock(struct thread *); -struct thread *thread_current (void); -tid_t thread_tid (void); -const char *thread_name (void); +struct thread *thread_current(void); +tid_t thread_tid(void); +const char *thread_name(void); -void thread_exit (void) NO_RETURN; -void thread_yield (void); +void thread_exit(void) NO_RETURN; +void thread_yield(void); /* Performs some operation on thread t, given auxiliary data AUX. */ -typedef void thread_action_func (struct thread *t, void *aux); -void thread_foreach (thread_action_func *, void *); +typedef void thread_action_func(struct thread *t, void *aux); +void thread_foreach(thread_action_func *, void *); -int thread_get_priority (void); -void thread_set_priority (int); +int thread_get_priority(void); +void thread_set_priority(int); -int thread_get_nice (void); -void thread_set_nice (int); -int thread_get_recent_cpu (void); -int thread_get_load_avg (void); +int thread_get_nice(void); +void thread_set_nice(int); +int thread_get_recent_cpu(void); +int thread_get_load_avg(void); #endif /* threads/thread.h */ diff --git a/src/userprog/process.c b/src/userprog/process.c index d51339a4aff8ec7aae340ae87035ef64358853fd..d7fa990873566f8cbdf84cb60e7651695db9f5b2 100644 --- a/src/userprog/process.c +++ b/src/userprog/process.c @@ -1,13 +1,4 @@ #include "userprog/process.h" -#include <debug.h> -#include <inttypes.h> -#include <round.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "userprog/gdt.h" -#include "userprog/pagedir.h" -#include "userprog/tss.h" #include "filesys/directory.h" #include "filesys/file.h" #include "filesys/filesys.h" @@ -17,56 +8,79 @@ #include "threads/palloc.h" #include "threads/thread.h" #include "threads/vaddr.h" +#include "userprog/gdt.h" +#include "userprog/pagedir.h" +#include "userprog/tss.h" +#include <debug.h> +#include <inttypes.h> +#include <round.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> static thread_func start_process NO_RETURN; -static bool load (const char *cmdline, void (**eip) (void), void **esp); +static bool load(const char *cmdline, void (**eip)(void), void **esp, int argc, + char **argv); /* Starts a new thread running a user program loaded from FILENAME. The new thread may be scheduled (and may even exit) before process_execute() returns. Returns the new process's thread id, or TID_ERROR if the thread cannot be created. */ -tid_t -process_execute (const char *file_name) -{ +tid_t process_execute(const char *file_name) { char *fn_copy; tid_t tid; /* Make a copy of FILE_NAME. Otherwise there's a race between the caller and load(). */ - fn_copy = palloc_get_page (0); + fn_copy = palloc_get_page(0); if (fn_copy == NULL) return TID_ERROR; - strlcpy (fn_copy, file_name, PGSIZE); + strlcpy(fn_copy, file_name, PGSIZE); /* Create a new thread to execute FILE_NAME. */ - tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy); + tid = thread_create(file_name, PRI_DEFAULT, start_process, fn_copy); if (tid == TID_ERROR) - palloc_free_page (fn_copy); + palloc_free_page(fn_copy); return tid; } /* A thread function that loads a user process and starts it running. */ -static void -start_process (void *file_name_) -{ +static void start_process(void *file_name_) { char *file_name = file_name_; struct intr_frame if_; bool success; + // Run strtok_r to find correct file_name + + // Declare argument vector and argument count + char **argv[255]; + int argc = 0; // Initialize with 1 + char *token; + char *save_ptr; + // Argv[0] is the file name e.g. 'echo' in 'echo x y z' + argv[argc++] = strtok_r(file_name, " ", &save_ptr); + + // While loop to fill argument vector with arguments e.g. 'x y z' in 'echo x y + // z' + while ((token = strtok_r(NULL, " ", &save_ptr)) != NULL) { + argv[argc++] = token; + } + /* Initialize interrupt frame and load executable. */ - memset (&if_, 0, sizeof if_); + 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); - + success = load(file_name, &if_.eip, &if_.esp, argc, argv); + hex_dump(if_.esp, if_.esp, PHYS_BASE - if_.esp, true); + /* If load failed, quit. */ - palloc_free_page (file_name); - if (!success) - thread_exit (); + 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 @@ -74,8 +88,8 @@ start_process (void *file_name_) 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 (); + asm volatile("movl %0, %%esp; jmp intr_exit" : : "g"(&if_) : "memory"); + NOT_REACHED(); } /* Waits for thread TID to die and returns its exit status. If @@ -87,56 +101,50 @@ start_process (void *file_name_) This function will be implemented in problem 2-2. For now, it does nothing. */ -int -process_wait (tid_t child_tid UNUSED) -{ - // FIXME: @bgaster --- quick hack to make sure processes execute! - for(;;) ; - +int process_wait(tid_t child_tid UNUSED) { + // FIXME: @bgaster --- quick hack to make sure processes execute! + for (;;) + ; + return -1; } /* Free the current process's resources. */ -void -process_exit (void) -{ - struct thread *cur = thread_current (); +void process_exit(void) { + struct thread *cur = thread_current(); uint32_t *pd; /* Destroy the current process's page directory and switch back to the kernel-only page directory. */ pd = cur->pagedir; - if (pd != NULL) - { - /* Correct ordering here is crucial. We must set - cur->pagedir to NULL before switching page directories, - so that a timer interrupt can't switch back to the - process page directory. We must activate the base page - directory before destroying the process's page - directory, or our active page directory will be one - that's been freed (and cleared). */ - cur->pagedir = NULL; - pagedir_activate (NULL); - pagedir_destroy (pd); - } + if (pd != NULL) { + /* Correct ordering here is crucial. We must set + cur->pagedir to NULL before switching page directories, + so that a timer interrupt can't switch back to the + process page directory. We must activate the base page + directory before destroying the process's page + directory, or our active page directory will be one + that's been freed (and cleared). */ + cur->pagedir = NULL; + pagedir_activate(NULL); + pagedir_destroy(pd); + } } /* Sets up the CPU for running user code in the current thread. This function is called on every context switch. */ -void -process_activate (void) -{ - struct thread *t = thread_current (); +void process_activate(void) { + struct thread *t = thread_current(); /* Activate thread's page tables. */ - pagedir_activate (t->pagedir); + pagedir_activate(t->pagedir); /* Set thread's kernel stack for use in processing interrupts. */ - tss_update (); + tss_update(); } - + /* We load ELF binaries. The following definitions are taken from the ELF specification, [ELF1], more-or-less verbatim. */ @@ -145,75 +153,72 @@ typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off; typedef uint16_t Elf32_Half; /* For use with ELF types in printf(). */ -#define PE32Wx PRIx32 /* Print Elf32_Word in hexadecimal. */ -#define PE32Ax PRIx32 /* Print Elf32_Addr in hexadecimal. */ -#define PE32Ox PRIx32 /* Print Elf32_Off in hexadecimal. */ -#define PE32Hx PRIx16 /* Print Elf32_Half in hexadecimal. */ +#define PE32Wx PRIx32 /* Print Elf32_Word in hexadecimal. */ +#define PE32Ax PRIx32 /* Print Elf32_Addr in hexadecimal. */ +#define PE32Ox PRIx32 /* Print Elf32_Off in hexadecimal. */ +#define PE32Hx PRIx16 /* Print Elf32_Half in hexadecimal. */ /* Executable header. See [ELF1] 1-4 to 1-8. This appears at the very beginning of an ELF binary. */ -struct Elf32_Ehdr - { - unsigned char e_ident[16]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; - }; +struct Elf32_Ehdr { + unsigned char e_ident[16]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; /* Program header. See [ELF1] 2-2 to 2-4. There are e_phnum of these, starting at file offset e_phoff (see [ELF1] 1-6). */ -struct Elf32_Phdr - { - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; - }; +struct Elf32_Phdr { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; /* Values for p_type. See [ELF1] 2-3. */ -#define PT_NULL 0 /* Ignore. */ -#define PT_LOAD 1 /* Loadable segment. */ -#define PT_DYNAMIC 2 /* Dynamic linking info. */ -#define PT_INTERP 3 /* Name of dynamic loader. */ -#define PT_NOTE 4 /* Auxiliary info. */ -#define PT_SHLIB 5 /* Reserved. */ -#define PT_PHDR 6 /* Program header table. */ -#define PT_STACK 0x6474e551 /* Stack segment. */ +#define PT_NULL 0 /* Ignore. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking info. */ +#define PT_INTERP 3 /* Name of dynamic loader. */ +#define PT_NOTE 4 /* Auxiliary info. */ +#define PT_SHLIB 5 /* Reserved. */ +#define PT_PHDR 6 /* Program header table. */ +#define PT_STACK 0x6474e551 /* Stack segment. */ /* Flags for p_flags. See [ELF3] 2-3 and 2-4. */ -#define PF_X 1 /* Executable. */ -#define PF_W 2 /* Writable. */ -#define PF_R 4 /* Readable. */ +#define PF_X 1 /* Executable. */ +#define PF_W 2 /* Writable. */ +#define PF_R 4 /* Readable. */ -static bool setup_stack (void **esp); -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 bool setup_stack(void **esp, int argc, char **argv); +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. 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) -{ - struct thread *t = thread_current (); +bool load(const char *file_name, void (**eip)(void), void **esp, int argc, + char **argv) { + struct thread *t = thread_current(); struct Elf32_Ehdr ehdr; struct file *file = NULL; off_t file_ofs; @@ -221,137 +226,123 @@ load (const char *file_name, void (**eip) (void), void **esp) int i; /* Allocate and activate page directory. */ - t->pagedir = pagedir_create (); - if (t->pagedir == NULL) + t->pagedir = pagedir_create(); + if (t->pagedir == NULL) goto done; - process_activate (); + process_activate(); /* Open executable file. */ - file = filesys_open (file_name); + file = filesys_open(file_name); - if (file == NULL) - { - printf ("load: %s: open failed\n", file_name); - goto done; - } + if (file == NULL) { + printf("load: %s: open failed\n", file_name); + goto done; + } /* Read and verify executable header. */ - if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr - || memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7) - || ehdr.e_type != 2 - || ehdr.e_machine != 3 - || ehdr.e_version != 1 - || ehdr.e_phentsize != sizeof (struct Elf32_Phdr) - || ehdr.e_phnum > 1024) - { - printf ("load: %s: error loading executable\n", file_name); - goto done; - } + if (file_read(file, &ehdr, sizeof ehdr) != sizeof ehdr || + memcmp(ehdr.e_ident, "\177ELF\1\1\1", 7) || ehdr.e_type != 2 || + ehdr.e_machine != 3 || ehdr.e_version != 1 || + ehdr.e_phentsize != sizeof(struct Elf32_Phdr) || ehdr.e_phnum > 1024) { + printf("load: %s: error loading executable\n", file_name); + goto done; + } /* Read program headers. */ file_ofs = ehdr.e_phoff; - for (i = 0; i < ehdr.e_phnum; i++) - { - struct Elf32_Phdr phdr; - - if (file_ofs < 0 || file_ofs > file_length (file)) - goto done; - file_seek (file, file_ofs); - - if (file_read (file, &phdr, sizeof phdr) != sizeof phdr) - goto done; - file_ofs += sizeof phdr; - switch (phdr.p_type) - { - case PT_NULL: - case PT_NOTE: - case PT_PHDR: - case PT_STACK: - default: - /* Ignore this segment. */ - break; - case PT_DYNAMIC: - case PT_INTERP: - case PT_SHLIB: - goto done; - case PT_LOAD: - if (validate_segment (&phdr, file)) - { - bool writable = (phdr.p_flags & PF_W) != 0; - uint32_t file_page = phdr.p_offset & ~PGMASK; - uint32_t mem_page = phdr.p_vaddr & ~PGMASK; - uint32_t page_offset = phdr.p_vaddr & PGMASK; - uint32_t read_bytes, zero_bytes; - if (phdr.p_filesz > 0) - { - /* Normal segment. - Read initial part from disk and zero the rest. */ - read_bytes = page_offset + phdr.p_filesz; - zero_bytes = (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE) - - read_bytes); - } - else - { - /* Entirely zero. - Don't read anything from disk. */ - read_bytes = 0; - zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE); - } - if (!load_segment (file, file_page, (void *) mem_page, - read_bytes, zero_bytes, writable)) - goto done; - } - else - goto done; - break; + for (i = 0; i < ehdr.e_phnum; i++) { + struct Elf32_Phdr phdr; + + if (file_ofs < 0 || file_ofs > file_length(file)) + goto done; + file_seek(file, file_ofs); + + if (file_read(file, &phdr, sizeof phdr) != sizeof phdr) + goto done; + file_ofs += sizeof phdr; + switch (phdr.p_type) { + case PT_NULL: + case PT_NOTE: + case PT_PHDR: + case PT_STACK: + default: + /* Ignore this segment. */ + break; + case PT_DYNAMIC: + case PT_INTERP: + case PT_SHLIB: + goto done; + case PT_LOAD: + if (validate_segment(&phdr, file)) { + bool writable = (phdr.p_flags & PF_W) != 0; + uint32_t file_page = phdr.p_offset & ~PGMASK; + uint32_t mem_page = phdr.p_vaddr & ~PGMASK; + uint32_t page_offset = phdr.p_vaddr & PGMASK; + uint32_t read_bytes, zero_bytes; + if (phdr.p_filesz > 0) { + /* Normal segment. + Read initial part from disk and zero the rest. */ + read_bytes = page_offset + phdr.p_filesz; + zero_bytes = + (ROUND_UP(page_offset + phdr.p_memsz, PGSIZE) - read_bytes); + } else { + /* Entirely zero. + Don't read anything from disk. */ + read_bytes = 0; + zero_bytes = ROUND_UP(page_offset + phdr.p_memsz, PGSIZE); } + if (!load_segment(file, file_page, (void *)mem_page, read_bytes, + zero_bytes, writable)) + goto done; + } else + goto done; + break; } + } /* Set up stack. */ - if (!setup_stack (esp)) + if (!setup_stack(esp, argc, argv)) goto done; /* Start address. */ - *eip = (void (*) (void)) ehdr.e_entry; + *eip = (void (*)(void))ehdr.e_entry; success = true; - done: +done: /* We arrive here whether the load is successful or not. */ - file_close (file); + file_close(file); return success; } - + /* load() helpers. */ -static bool install_page (void *upage, void *kpage, bool writable); +static bool install_page(void *upage, void *kpage, bool writable); /* Checks whether PHDR describes a valid, loadable segment in FILE and returns true if so, false otherwise. */ -static bool -validate_segment (const struct Elf32_Phdr *phdr, struct file *file) -{ +static bool validate_segment(const struct Elf32_Phdr *phdr, struct file *file) { /* p_offset and p_vaddr must have the same page offset. */ - if ((phdr->p_offset & PGMASK) != (phdr->p_vaddr & PGMASK)) - return false; + if ((phdr->p_offset & PGMASK) != (phdr->p_vaddr & PGMASK)) + return false; /* p_offset must point within FILE. */ - if (phdr->p_offset > (Elf32_Off) file_length (file)) + if (phdr->p_offset > (Elf32_Off)file_length(file)) return false; /* p_memsz must be at least as big as p_filesz. */ - if (phdr->p_memsz < phdr->p_filesz) - return false; + if (phdr->p_memsz < phdr->p_filesz) + return false; /* The segment must not be empty. */ if (phdr->p_memsz == 0) return false; - + /* The virtual memory region must both start and end within the user address space range. */ - if (!is_user_vaddr ((void *) phdr->p_vaddr)) + if (!is_user_vaddr((void *)phdr->p_vaddr)) return false; - if (!is_user_vaddr ((void *) (phdr->p_vaddr + phdr->p_memsz))) + if (!is_user_vaddr((void *)(phdr->p_vaddr + phdr->p_memsz))) return false; /* The region cannot "wrap around" across the kernel virtual @@ -385,68 +376,105 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file) Return true if successful, false if a memory allocation error or disk read error occurs. */ -static bool -load_segment (struct file *file, off_t ofs, uint8_t *upage, - uint32_t read_bytes, uint32_t zero_bytes, bool writable) -{ - ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0); - ASSERT (pg_ofs (upage) == 0); - ASSERT (ofs % PGSIZE == 0); - - file_seek (file, ofs); - while (read_bytes > 0 || zero_bytes > 0) - { - /* Calculate how to fill this page. - We will read PAGE_READ_BYTES bytes from FILE - and zero the final PAGE_ZERO_BYTES bytes. */ - size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; - size_t page_zero_bytes = PGSIZE - page_read_bytes; - - /* Get a page of memory. */ - uint8_t *kpage = palloc_get_page (PAL_USER); - if (kpage == NULL) - return false; - - /* Load this page. */ - if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes) - { - palloc_free_page (kpage); - return false; - } - memset (kpage + page_read_bytes, 0, page_zero_bytes); - - /* Add the page to the process's address space. */ - if (!install_page (upage, kpage, writable)) - { - palloc_free_page (kpage); - return false; - } +static bool load_segment(struct file *file, off_t ofs, uint8_t *upage, + uint32_t read_bytes, uint32_t zero_bytes, + bool writable) { + ASSERT((read_bytes + zero_bytes) % PGSIZE == 0); + ASSERT(pg_ofs(upage) == 0); + ASSERT(ofs % PGSIZE == 0); + + file_seek(file, ofs); + while (read_bytes > 0 || zero_bytes > 0) { + /* Calculate how to fill this page. + We will read PAGE_READ_BYTES bytes from FILE + and zero the final PAGE_ZERO_BYTES bytes. */ + size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; + size_t page_zero_bytes = PGSIZE - page_read_bytes; + + /* Get a page of memory. */ + uint8_t *kpage = palloc_get_page(PAL_USER); + if (kpage == NULL) + return false; + + /* Load this page. */ + if (file_read(file, kpage, page_read_bytes) != (int)page_read_bytes) { + palloc_free_page(kpage); + return false; + } + memset(kpage + page_read_bytes, 0, page_zero_bytes); - /* Advance. */ - read_bytes -= page_read_bytes; - zero_bytes -= page_zero_bytes; - upage += PGSIZE; + /* Add the page to the process's address space. */ + if (!install_page(upage, kpage, writable)) { + palloc_free_page(kpage); + return false; } + + /* Advance. */ + read_bytes -= page_read_bytes; + zero_bytes -= page_zero_bytes; + upage += PGSIZE; + } return true; } /* Create a minimal stack by mapping a zeroed page at the top of user virtual memory. */ -static bool -setup_stack (void **esp) -{ +static bool setup_stack(void **esp, int argc, char **argv) { uint8_t *kpage; bool success = false; - kpage = palloc_get_page (PAL_USER | PAL_ZERO); - if (kpage != NULL) - { - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true); - if (success) { - *esp = PHYS_BASE; - } else - palloc_free_page (kpage); - } + kpage = palloc_get_page(PAL_USER | PAL_ZERO); + if (kpage != NULL) { + success = install_page(((uint8_t *)PHYS_BASE) - PGSIZE, kpage, true); + if (success) { + *esp = PHYS_BASE; // -12 "hack" removed as argument passing implemented + int i = argc; + //*************************** + uint32_t *arr[argc]; // Pointer to arguments in the stack + + while (--i >= 0) { + *esp = *esp - (strlen(argv[i]) + 1); // Add + 1 for null terminator + arr[i] = (uint32_t *)*esp; + // memcpy (destination, source, size); + memcpy(*esp, argv[i], strlen(argv[i]) + 1); + } + + // Word alignment using modulus + int alignment = (uint32_t)*esp % 4; + // If alignment needed move esp + if (alignment > 0) { + *esp = *esp - alignment; + // memset(* to the block of memory to fill, value to be set, number of + // bytes to be set) + memset(*esp, 0, alignment); + } + + // In C the size of each constant character e.g. 'x' is equal to 4 + // esp - 4 move position in the stack + *esp = *esp - 4; + (*(uint8_t *)(*esp)) = 0; // Add a sentinel for termination + i = argc; + + // Address pointing to each argument written to the stack + while (--i >= 0) { + *esp = *esp - 4; + (*(uint32_t **)(*esp)) = arr[i]; + } + + *esp = *esp - 4; + // Write address of argv[0] + (*(uintptr_t **)(*esp)) = (*esp + 4); + *esp = *esp - 4; + // Write the number of arguments to the stack + *(int *)(*esp) = argc; + *esp = *esp - 4; + // Write 0 for return address + (*(int *)(*esp)) = 0; + + } else + palloc_free_page(kpage); + } + return success; } @@ -459,15 +487,13 @@ setup_stack (void **esp) with palloc_get_page(). Returns true on success, false if UPAGE is already mapped or if memory allocation fails. */ -static bool -install_page (void *upage, void *kpage, bool writable) -{ - struct thread *t = thread_current (); +static bool install_page(void *upage, void *kpage, bool writable) { + struct thread *t = thread_current(); /* Verify that there's not already a page at that virtual address, then map our page there. */ - return (pagedir_get_page (t->pagedir, upage) == NULL - && pagedir_set_page (t->pagedir, upage, kpage, writable)); + return (pagedir_get_page(t->pagedir, upage) == NULL && + pagedir_set_page(t->pagedir, upage, kpage, writable)); } //-------------------------------------------------------------------- diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c index 04635159d30520fa11296dc922e622f2ad2553d5..175241685cb7ba8e78ea77616de584e7ec48ac44 100644 --- a/src/userprog/syscall.c +++ b/src/userprog/syscall.c @@ -1,21 +1,66 @@ #include "userprog/syscall.h" -#include <stdio.h> -#include <syscall-nr.h> +#include "filesys/filesys.h" +#include "lib/kernel/list.h" #include "threads/interrupt.h" +#include "threads/malloc.h" #include "threads/thread.h" +#include "userprog/process.h" +#include <stdio.h> +#include <string.h> +#include <syscall-nr.h> -static void syscall_handler (struct intr_frame *); +static void syscall_handler(struct intr_frame *); +bool create(const char *file, unsigned initial_size); +tid_t exec(const char *cmd_line); -void -syscall_init (void) -{ - intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall"); + +void syscall_init(void) { + intr_register_int(0x30, 3, INTR_ON, syscall_handler, "syscall"); } +static void syscall_handler(struct intr_frame *f) { + + // Get the syscall number from the stack + int syscall_num = *(int *)f->esp; + + switch (syscall_num) { + + case SYS_REMOVE: + // Print current syscall number + printf("Syscall_handler() - %d!\n", syscall_num); + filesys_remove(*(char **)(f->esp + 4)); + printf(*(char **)(f->esp + 4)); + break; -static void -syscall_handler (struct intr_frame *f UNUSED) -{ - printf ("system call!\n"); - thread_exit (); + case SYS_EXEC: + // Print current syscall number + printf("Syscall_handler() - %d!\n", syscall_num); + printf("SYS_CALL : EXEC \n"); + exec(*(char **)(f->esp + 4)); + break; + + case SYS_CREATE: + // Print current syscall number + printf("Syscall_handler() - %d!\n", syscall_num); + create(*(int *)(f->esp + 4), (unsigned)*(int *)(f->esp + 8)); + break; + + default: + thread_exit(); + } +} + + +tid_t exec(const char *cmd_line) { + // showing the arg/process in the command line + printf(" \ncmd_line : '%s'\n", cmd_line); + // executing whatever in cmd_line then return to the process id + tid_t pid = process_execute(cmd_line); + return pid; } + +bool create(const char *file, unsigned initial_size) { + // This creates a new file but doesn't open it + printf("File named '%s' created\n", file); + return filesys_create(file, initial_size); +} \ No newline at end of file