diff --git a/src/userprog/process.c b/src/userprog/process.c index ea068069855a3e108656de97f08df7057d037e13..e0f44086d4f4b6b53d10aafe4fae0993b4308a0d 100644 --- a/src/userprog/process.c +++ b/src/userprog/process.c @@ -19,9 +19,9 @@ #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 *cmdline, void (**eip)(void), void **esp); static void argument_pushing(char **parse, int count, void **esp); -# define WORD_SIZE 4 +#define WORD_SIZE 4 /* Starts a new thread running a user program loaded from FILENAME. The new thread may be scheduled (and may even exit) @@ -30,64 +30,71 @@ static void argument_pushing(char **parse, int count, void **esp); tid_t process_execute(const char *file_name) { - char *file_copy; - char *ptr; - tid_t tid; - - /* Make a copy of command line. Otherwise there's a race between the caller and load(). */ - file_copy = palloc_get_page(0); - if (file_copy == NULL) - return TID_ERROR; - strlcpy(file_copy, file_name, PGSIZE); - - /* Extract file_name from command line. */ - file_name = strtok_r(file_name, " ", &ptr); - - /* Create a new thread to execute FILE_NAME. */ - tid = thread_create(file_name, PRI_DEFAULT, start_process, file_copy); - - if (tid == TID_ERROR) - { - palloc_free_page(file_copy); - } - return tid; + char *file_copy; + tid_t tid; + char *ptr = NULL; + int file_name_length = strlen(file_name) + 1; + char program[file_name_length]; + + /* Make a copy of command line. Otherwise there's a race between the caller and load(). */ + file_copy = palloc_get_page(0); + if (file_copy == NULL) + return TID_ERROR; + strlcpy(file_copy, file_name, PGSIZE); + + /* Parse first argument as program name */ + strlcpy(program, file_name, file_name_length); + strtok_r(program, " ", &ptr); + printf("\nProgram name: %s\n\n", program) ; + + /* Create a new thread to execute FILE_NAME. */ + tid = thread_create(file_name, PRI_DEFAULT, start_process, file_copy); + + if (tid == TID_ERROR) + { + palloc_free_page(file_copy); + } + return tid; } /* A thread function that loads a user process and starts it running. */ static void -start_process (void *file_name_) +start_process(void *file_name_) { char *file_name = file_name_; struct intr_frame if_; bool success; - char* temp[50]; - char* token; - char* ptr; + char *parse[250]; + char *token; + char *ptr; int count = 0; - + for (token = strtok_r(file_name, " ", &ptr); token != NULL; - token = strtok_r(NULL, " ", &ptr)) + token = strtok_r(NULL, " ", &ptr)) { - temp[count++] = token; + parse[count] = token; + count++; + printf("\nTokenized Argument: %s\n", parse[count - 1]); } + printf("\nNumber of tokenized Arguments : %d\n", count); /* 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(parse[0], &if_.eip, &if_.esp); - argument_pushing(&temp, count, &if_.esp); + argument_pushing(&parse, count, &if_.esp); 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 @@ -95,8 +102,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 @@ -109,55 +116,55 @@ 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) +process_wait(tid_t child_tid UNUSED) { - // FIXME: @bgaster --- quick hack to make sure processes execute! - for(;;) ; - + // FIXME: @bgaster --- quick hack to make sure processes execute! + for (;;); + return -1; } /* Free the current process's resources. */ -void -process_exit (void) +void +process_exit(void) { - struct thread *cur = thread_current (); + 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) +process_activate(void) { - struct thread *t = thread_current (); + 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. */ @@ -166,75 +173,75 @@ 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; - }; +{ + 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; - }; +{ + 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, char * cmdline); -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); +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) +load(const char *file_name, void (**eip)(void), void **esp) { - struct thread *t = thread_current (); + struct thread *t = thread_current(); struct Elf32_Ehdr ehdr; struct file *file = NULL; off_t file_ofs; @@ -242,122 +249,115 @@ 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; + 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_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) + 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) { - 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; + /* 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)) 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) +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)) + 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. */ @@ -367,12 +367,12 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file) /* 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 @@ -407,173 +407,123 @@ 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) +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); + 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) + 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) { - /* 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; - } + 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; } /* References: J,Choi(2014), pintos. Available from: https://github.com/wookayin/pintos [accessed on 23/11/22]*/ static void -argument_pushing (char** parse, int argc, void **esp) +argument_pushing(char **parse, int count, void **esp) { - /* Increment Counter */ - int i; - int len=0; - int argv_addr[argc]; - for (i = 0; i < argc; i++) { - len = strlen(parse[i]) + 1; - *esp -= len; - memcpy(*esp, parse[i], len); - argv_addr[i] = (int) *esp; + int i, j; + int length = 0; // Argument length + int parse0_address; // First Argument's Adress + int address[count]; // Argument adress + + /*Push arguments to stack one by one*/ + for (i = count - 1; i > -1; i--) + { + for (j = strlen(parse[i]); j > -1; j--) + { + *esp = *esp - 1; + **(char **)esp = parse[i][j]; + length++; /*Count length of arguments we pushed*/ + } + /*Store address of argument*/ + address[i] = *(unsigned int *)esp; + printf("\nAdress of %d 's argument: %d\n", i + 1, address[i]); } + printf("\nNumber of arguments pushed onto stack: %d\n", length); + /* Word Allignment*/ - *esp = (int)*esp & 0xfffffffc; + for (i = 0; i < 4 - (length % 4); i++) + { + *esp = *esp - 1; + **(uint8_t **)esp = 0; + } - /* Last null*/ + /* Last argument needs to be NULL*/ *esp -= 4; - *(int*)*esp = 0; + **(char ***)esp = 0; - /* Use argvs to set **esp */ - for (i = argc - 1; i >= 0; i--) { + /*Push argument adress - Use counter to set **esp */ + for (i = count - 1; i >= 0; i--) + { *esp -= 4; - *(int*)*esp = argv_addr[i]; + **(char ***)esp = address[i]; } /* Set **argv*/ + parse0_address = *(unsigned int *)esp; *esp -= 4; - *(int*)*esp = (int)*esp + 4; + **(char ***)esp = (char *)parse0_address; - /* Set argc*/ + /* Set counter*/ *esp -= 4; - *(int*)*esp = argc; + *(int *)*esp = count; - /* Set ret*/ - *esp-=4; - *(int*)*esp = 0; + /*Fake Adress - Set ret*/ + *esp -= 4; + *(int *)*esp = 0; } /* 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) { 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); - } - char *token, *temp_ptr; - - char * flname_cp = malloc(strlen(file_name)+1); - strlcpy (flname_cp, file_name, strlen(file_name)+1); - - - /* argc calculation*/ - enum intr_level old_level = intr_disable(); - int argc=1; - /* Is the last char a space? - Only one space in the end*/ - bool is_lastchar_space=false; - for(int j=0;j!=strlen(file_name); j++){ - if(file_name[j] == ' '){ - if(!is_lastchar_space) - argc++; - is_lastchar_space=true; - } - else - is_lastchar_space=false; - } - intr_set_level (old_level); - - - int *argv = calloc(argc,sizeof(int)); - - int i; - token = strtok_r (file_name, " ", &temp_ptr); - for (i=0; ; i++){ - if(token){ - *esp -= strlen(token) + 1; - memcpy(*esp,token,strlen(token) + 1); - argv[i]=*esp; - token = strtok_r (NULL, " ", &temp_ptr); - }else{ - break; - } - } - - /* Word alignment*/ - *esp -= ((unsigned)*esp % WORD_SIZE); - - /* Null ptr sentinel: null at argv[argc]*/ - *esp-=sizeof(int); - - /* Push address*/ - for(i=argc-1;i>=0;i--) + kpage = palloc_get_page(PAL_USER | PAL_ZERO); + if (kpage != NULL) { - *esp-=sizeof(int); - memcpy(*esp,&argv[i],sizeof(int)); + success = install_page(((uint8_t *)PHYS_BASE) - PGSIZE, kpage, true); + if (success) + *esp = PHYS_BASE; + else + palloc_free_page(kpage); } - - /* Push argv address*/ - int tmp = *esp; - *esp-=sizeof(int); - memcpy(*esp,&tmp,sizeof(int)); - - /* Push argc*/ - *esp-=sizeof(int); - memcpy(*esp,&argc,sizeof(int)); - - /* Return address*/ - *esp-=sizeof(int); - memcpy(*esp,&argv[argc],sizeof(int)); - - free(flname_cp); - free(argv); return success; } @@ -587,14 +537,13 @@ setup_stack (void **esp) 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) +install_page(void *upage, void *kpage, bool writable) { - struct thread *t = thread_current (); + 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/process.h b/src/userprog/process.h index 688cd2a37fd2c1bd7fdcb417f834026a25fa4945..6dc39e41c99c450b487be78a2352fb0f0c39881d 100644 --- a/src/userprog/process.h +++ b/src/userprog/process.h @@ -3,6 +3,10 @@ #include "threads/thread.h" +typedef int pit_t; +#define PID_ERROR ((pid_t)-1) +#define PID_INITIALIZING ((pid_t) -2) + tid_t process_execute (const char *file_name); int process_wait (tid_t); void process_exit (void); diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c index 04635159d30520fa11296dc922e622f2ad2553d5..b4522f8e95a127cf2c25a573285a3bb217ec9bbb 100644 --- a/src/userprog/syscall.c +++ b/src/userprog/syscall.c @@ -1,4 +1,5 @@ #include "userprog/syscall.h" +#include <stdbool.h> #include <stdio.h> #include <syscall-nr.h> #include "threads/interrupt.h" @@ -6,16 +7,149 @@ static void syscall_handler (struct intr_frame *); +/*System call initializer*/ void syscall_init (void) { intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall"); } - +/*Handler for system commands.*/ static void syscall_handler (struct intr_frame *f UNUSED) { - printf ("system call!\n"); - thread_exit (); + /* References: J,Choi(2014), pintos. Available from: https://github.com/wookayin/pintos [accessed on 27/11/22]*/ + int syscall_number; + ASSERT( sizeof(syscall_number) == 4 ); /*assuming x86*/ + + /*The system call number is in the 32-bit word at the caller's stack pointer.*/ + read(f->esp, &syscall_number, sizeof(syscall_number)); + + /*Store the esp, which is needed in the page fault handler.*/ + thread_current()->current_esp = f->esp; + + switch (syscall_number) { + case SYS_HALT: // 0 + { + /*Terminate PintOS*/ + syscall_halt(); + break; + } + case SYS_WAIT: // 2 + { + tid_t tid; + /*Get argument*/ + read(f->esp + 4, &tid, sizeof(tid_t)); + /*Wait for child process*/ + f->eax = syscall_wait(tid); + break; + } + + case SYS_CREATE: // 3 + { + const char* file_name; + unsigned initial_size; + + /*Get file name and size*/ + read(f->esp + 4, &file_name, sizeof(file_name)); + read(f->esp + 8, &initial_size, sizeof(initial_size)); + + /*Create file*/ + f->eax = syscall_create(file_name, initial_size); + break; + } + + case SYS_REMOVE: // 4 + { + const char* file_name; + bool return_code; + + /*Get file name*/ + read(f->esp + 4, &file_name, sizeof(file_name)); + + /*Remove file*/ + f->eax = syscall_remove(file_name); + break; + } + /* Unimplemented system calls */ + default: + printf("ERROR: system call ( %d ) has not implemented!\n", syscall_number); + + /* Terminate. */ + syscall_exit(-1); + break; + } +} + + +/********SYSTEMCALLS********/ + +/* Halt */ +void syscall_halt(void) { + shutdown_power_off(); /* From shutdown.h */ +} + +/* Exit */ +void syscall_exit(int status) { + struct thread *current_process=thread_current(); + current_process->process_exit_status = status; + + printf("%s: exit(%d)\n",current_process->name,status); + + thread_exit(); +} + +/* Wait */ +int syscall_wait(tid_t tid) +{ + return process_wait(tid); +} + +/* Create File */ +bool syscall_create(const char* file_name, unsigned initial_size) { + bool if_created = false; + if( filesys_create(file_name, initial_size)==true){ + if_created = true; + } + return if_created; +} + +/* Remove File */ +bool syscall_remove(const char* file_name) { + bool if_removed = false; + if( filesys_remove(file_name)==true){ + if_removed = true; + } + return if_removed; +} + + +/****OTHER FUNCTIONS****/ +static int read(void *src, void *dst, size_t bytes) +{ + int32_t value; + size_t i; + for (i = 0; i < bytes; i++) + { + value = get_user(src + i); + if (value == -1) // segfault or invalid memory access + fail_invalid_access(); + + *(char *)(dst + i) = value & 0xff; + } + return (int)bytes; +} +/* Reads a byte at user virtual address UADDR. + UADDR must be below PHYS_BASE. + Returns the byte value if successful, -1 if a segfault + occurred. */ +static int +get_user (const uint8_t *uaddr) +{ + if(!is_user_vaddr(uaddr)) + return -1; + int result; + asm ("movl $1f, %0; movzbl %1, %0; 1:" + : "=&a" (result) : "m" (*uaddr)); + return result; } diff --git a/src/userprog/syscall.h b/src/userprog/syscall.h index 90590967a9f96f9ea359d15c672b815dfb4379cb..4d30d0a80bdb162a372668138916fe1ab1658126 100644 --- a/src/userprog/syscall.h +++ b/src/userprog/syscall.h @@ -1,6 +1,18 @@ #ifndef USERPROG_SYSCALL_H #define USERPROG_SYSCALL_H +#include "threads/thread.h" +#include <stdbool.h> +#include <stddef.h> + void syscall_init (void); +void syscall_halt(void); +void syscall_exit(int status); +int syscall_wait(tid_t tid); +bool syscall_create(const char* file_name, unsigned initial_size); +bool syscall_remove(const char* file_name); + +static int read(void *src, void *dst, size_t bytes); +static int get_user (const uint8_t *uaddr); #endif /* userprog/syscall.h */