diff --git a/src/userprog/process.c b/src/userprog/process.c index 890165a8d922983315e45ae0a1c500acfa327f27..45c2fd527cbfb828b5b33a21b51ea4998a797975 100644 --- a/src/userprog/process.c +++ b/src/userprog/process.c @@ -1,571 +1,3 @@ -Skip to content -GitLab -Menu - -sa2-alarjani -P -Pintos_Student -Project information -Repository -Issues -0 -Security & Compliance -Deployments -Packages & Registries -Analytics -Wiki -Settings - -Close sidebar -Open sidebar -sa2-alarjani -Pintos_Student -master -pintos_student -src -userprog -process.c - - - - -Update src/userprog/process.c -sa2-alarjani authored 1 day ago -a984983a -process.c -15.67 KiB -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 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 #include "userprog/process.h" #include <debug.h> #include <inttypes.h> @@ -585,8 +17,10 @@ process.c #include "threads/palloc.h" #include "threads/thread.h" #include "threads/vaddr.h" + static thread_func start_process NO_RETURN; static bool load (const char *cmdline, void (**eip) (void), void **esp); + /* 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 @@ -596,22 +30,27 @@ process_execute (const char *file_name) { char *fn_copy, *filename_, *args; 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); if (fn_copy == NULL) return TID_ERROR; strlcpy (fn_copy, file_name, PGSIZE); + int len = strlen(file_name) + 1; char file_copy[len]; strlcpy(file_copy, file_name, len); filename_ = strtok_r(file_copy, " ", &args); + /* Create a new thread to execute FILE_NAME. */ tid = thread_create (filename_, PRI_DEFAULT, start_process, fn_copy); + if (tid == TID_ERROR) palloc_free_page (fn_copy); return tid; } + /* A thread function that loads a user process and starts it running. */ static void @@ -620,17 +59,20 @@ start_process (void *file_name_) char *file_name = file_name_; struct intr_frame if_; bool success; + /* Initialize interrupt frame and load executable. */ memset (&if_, 0, sizeof if_); if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG; if_.cs = SEL_UCSEG; if_.eflags = FLAG_IF | FLAG_MBS; + success = load (file_name, &if_.eip, &if_.esp); /* If load failed, quit. */ palloc_free_page (file_name); if (!success) thread_exit (); + /* Start the user process by simulating a return from an interrupt, implemented by intr_exit (in threads/intr-stubs.S). Because intr_exit takes all of its @@ -640,12 +82,14 @@ start_process (void *file_name_) 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 it was terminated by the kernel (i.e. killed due to an exception), returns -1. If TID is invalid or if it was not a child of the calling process, or if process_wait() has already been successfully called for the given TID, returns -1 immediately, without waiting. + This function will be implemented in problem 2-2. For now, it does nothing. */ int @@ -656,13 +100,16 @@ process_wait (tid_t child_tid UNUSED) return -1; } + /* Free the current process's resources. */ void process_exit (void) { struct thread *cur = thread_current (); uint32_t *pd; + printf("%s: exit_code(%d)\n",cur->name,cur->exit_code); + /* Destroy the current process's page directory and switch back to the kernel-only page directory. */ pd = cur->pagedir; @@ -680,6 +127,7 @@ process_exit (void) pagedir_destroy (pd); } } + /* Sets up the CPU for running user code in the current thread. This function is called on every context switch. */ @@ -687,8 +135,10 @@ void process_activate (void) { struct thread *t = thread_current (); + /* Activate thread's page tables. */ pagedir_activate (t->pagedir); + /* Set thread's kernel stack for use in processing interrupts. */ tss_update (); @@ -696,14 +146,17 @@ process_activate (void) /* We load ELF binaries. The following definitions are taken from the ELF specification, [ELF1], more-or-less verbatim. */ + /* ELF types. See [ELF1] 1-2. */ 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. */ + /* Executable header. See [ELF1] 1-4 to 1-8. This appears at the very beginning of an ELF binary. */ struct Elf32_Ehdr @@ -723,6 +176,7 @@ struct Elf32_Ehdr 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). */ @@ -737,6 +191,7 @@ struct Elf32_Phdr 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. */ @@ -746,10 +201,12 @@ struct Elf32_Phdr #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. */ + static bool setup_stack (void **esp, char *filename, char *argu); static bool validate_segment (const struct Elf32_Phdr *, struct file *); static bool load_segment (struct file *file, off_t ofs, uint8_t *upage, @@ -774,18 +231,22 @@ load (const char *file_name, void (**eip) (void), void **esp) strlcpy(file_copy, file_name, len); char *args, *file_name_; file_name_ = strtok_r(file_copy, " ", &args); + /* Allocate and activate page directory. */ t->pagedir = pagedir_create (); if (t->pagedir == NULL) goto done; process_activate (); + /* Open executable file. */ file = filesys_open (file_name_); + 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) @@ -798,14 +259,17 @@ load (const char *file_name, void (**eip) (void), void **esp) 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; @@ -854,12 +318,16 @@ load (const char *file_name, void (**eip) (void), void **esp) break; } } + /* Set up stack. */ if (!setup_stack (esp, file_name_, args)) goto done; + /* Start address. */ *eip = (void (*) (void)) ehdr.e_entry; + success = true; + done: /* We arrive here whether the load is successful or not. */ file_close (file); @@ -867,7 +335,9 @@ load (const char *file_name, void (**eip) (void), void **esp) } /* load() helpers. */ + 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 @@ -876,12 +346,15 @@ 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; + /* p_offset must point within 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; + /* The segment must not be empty. */ if (phdr->p_memsz == 0) return false; @@ -892,10 +365,12 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file) return false; if (!is_user_vaddr ((void *) (phdr->p_vaddr + phdr->p_memsz))) return false; + /* The region cannot "wrap around" across the kernel virtual address space. */ if (phdr->p_vaddr + phdr->p_memsz < phdr->p_vaddr) return false; + /* Disallow mapping page 0. Not only is it a bad idea to map page 0, but if we allowed it then user code that passed a null pointer to system calls @@ -903,17 +378,23 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file) assertions in memcpy(), etc. */ if (phdr->p_vaddr < PGSIZE) return false; + /* It's okay. */ return true; } + /* Loads a segment starting at offset OFS in FILE at address UPAGE. In total, READ_BYTES + ZERO_BYTES bytes of virtual memory are initialized, as follows: + - READ_BYTES bytes at UPAGE must be read from FILE starting at offset OFS. + - ZERO_BYTES bytes at UPAGE + READ_BYTES must be zeroed. + The pages initialized by this function must be writable by the user process if WRITABLE is true, read-only otherwise. + Return true if successful, false if a memory allocation error or disk read error occurs. */ static bool @@ -923,6 +404,7 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage, 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) { @@ -931,10 +413,12 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage, 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) { @@ -942,12 +426,14 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage, 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; } + /* Advance. */ read_bytes -= page_read_bytes; zero_bytes -= page_zero_bytes; @@ -955,6 +441,7 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage, } return true; } + /* Create a minimal stack by mapping a zeroed page at the top of user virtual memory. */ static bool @@ -962,6 +449,7 @@ setup_stack (void **esp, char *filename, char *argu) { uint8_t *kpage; bool success = false; + kpage = palloc_get_page (PAL_USER | PAL_ZERO); if (kpage != NULL) { @@ -977,6 +465,7 @@ setup_stack (void **esp, char *filename, char *argu) } return success; } + /* Adds a mapping from user virtual address UPAGE to kernel virtual address KPAGE to the page table. If WRITABLE is true, the user process may modify the page; @@ -990,11 +479,13 @@ 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)); } + /*Helper function push name of file and arguments on esp stack*/ void handle_argsinstack(void **esp, char *file_name, char *args) @@ -1018,6 +509,7 @@ handle_argsinstack(void **esp, char *file_name, char *args) memcpy(*esp,argu_arr[i],arg_len); argus[arg_c - i + 1] = *esp; } + //push the name of file on esp stack int size = strlen(file_name) + 1; *esp -= size; @@ -1025,6 +517,7 @@ handle_argsinstack(void **esp, char *file_name, char *args) argus[0] = *esp; argus[arg_c + 1] = NULL; + //Add Padding to align the esp stack int pad = 4 * ((t_arg_s) / 4); *esp -= pad; @@ -1035,4 +528,5 @@ handle_argsinstack(void **esp, char *file_name, char *args) memcpy(*esp,argus,4*(arg_c + 1)); } + //--------------------------------------------------------------------