// Set up the initial stack page for the new child process with envid 'child' // using the arguments array pointed to by 'argv', // which is a null-terminated array of pointers to null-terminated strings. // // On success, returns 0 and sets *init_esp // to the initial stack pointer with which the child should start. // Returns < 0 on failure. static int init_stack(envid_t child, const char **argv, uintptr_t *init_esp) { size_t string_size; int argc, i, r; char *string_store; uintptr_t *argv_store; // Count the number of arguments (argc) // and the total amount of space needed for strings (string_size). string_size = 0; for (argc = 0; argv[argc] != 0; argc++) string_size += strlen(argv[argc]) + 1; // Determine where to place the strings and the argv array. // Set up pointers into the temporary page 'UTEMP'; we'll map a page // there later, then remap that page into the child environment // at (USTACKTOP - PGSIZE). // strings is the topmost thing on the stack. string_store = (char*) UTEMP + PGSIZE - string_size; // argv is below that. There's one argument pointer per argument, plus // a null pointer. argv_store = (uintptr_t*) (ROUNDDOWN(string_store, 4) - 4 * (argc + 1)); // Make sure that argv, strings, and the 2 words that hold 'argc' // and 'argv' themselves will all fit in a single stack page. if ((void*) (argv_store - 2) < (void*) UTEMP) return -E_NO_MEM; // Allocate the single stack page at UTEMP. if ((r = sys_page_alloc(0, (void*) UTEMP, PTE_P|PTE_U|PTE_W)) < 0) return r; for (i = 0; i < argc; i++) { argv_store[i] = UTEMP2USTACK(string_store); strcpy(string_store, argv[i]); string_store += strlen(argv[i]) + 1; } argv_store[argc] = 0; assert(string_store == (char*)UTEMP + PGSIZE); argv_store[-1] = UTEMP2USTACK(argv_store); argv_store[-2] = argc; *init_esp = UTEMP2USTACK(&argv_store[-2]); // After completing the stack, map it into the child's address space // and unmap it from ours! if ((r = sys_page_map(0, UTEMP, child, (void*) (USTACKTOP - PGSIZE), PTE_P | PTE_U | PTE_W)) < 0) goto error; if ((r = sys_page_unmap(0, UTEMP)) < 0) goto error; return 0; error: sys_page_unmap(0, UTEMP); return r; }
// Set up the initial stack page for the new child process with envid 'child' // using the arguments array pointed to by 'argv', // which is a null-terminated array of pointers to null-terminated strings. // // On success, returns 0 and sets *init_esp // to the initial stack pointer with which the child should start. // Returns < 0 on failure. static int init_stack(envid_t child, const char **argv, uintptr_t *init_esp) { size_t string_size; int argc, i, r; char *string_store; uintptr_t *argv_store; // Count the number of arguments (argc) // and the total amount of space needed for strings (string_size). string_size = 0; for (argc = 0; argv[argc] != 0; argc++) string_size += strlen(argv[argc]) + 1; // Determine where to place the strings and the argv array. // Set up pointers into the temporary page 'UTEMP'; we'll map a page // there later, then remap that page into the child environment // at (USTACKTOP - PGSIZE). // strings is the topmost thing on the stack. string_store = (char*) UTEMP + PGSIZE - string_size; // argv is below that. There's one argument pointer per argument, plus // a null pointer. argv_store = (uintptr_t*) (ROUNDDOWN(string_store, 4) - 4 * (argc + 1)); // Make sure that argv, strings, and the 2 words that hold 'argc' // and 'argv' themselves will all fit in a single stack page. if ((void*) (argv_store - 2) < (void*) UTEMP) return -E_NO_MEM; // Allocate the single stack page at UTEMP. if ((r = sys_page_alloc(0, (void*) UTEMP, PTE_P|PTE_U|PTE_W)) < 0) return r; // * Initialize 'argv_store[i]' to point to argument string i, // for all 0 <= i < argc. // Also, copy the argument strings from 'argv' into the // newly-allocated stack page. // // * Set 'argv_store[argc]' to 0 to null-terminate the args array. // // * Push two more words onto the child's stack below 'args', // containing the argc and argv parameters to be passed // to the child's umain() function. // argv should be below argc on the stack. // (Again, argv should use an address valid in the child's // environment.) // // * Set *init_esp to the initial stack pointer for the child, // (Again, use an address valid in the child's environment.) for (i = 0; i < argc; i++) { argv_store[i] = UTEMP2USTACK(string_store); strcpy(string_store, argv[i]); string_store += strlen(argv[i]) + 1; } argv_store[argc] = 0; assert(string_store == (char*)UTEMP + PGSIZE); argv_store[-1] = UTEMP2USTACK(argv_store); argv_store[-2] = argc; *init_esp = UTEMP2USTACK(&argv_store[-2]); // After completing the stack, map it into the child's address space // and unmap it from ours! if ((r = sys_page_map(0, UTEMP, child, (void*) (USTACKTOP - PGSIZE), PTE_P | PTE_U | PTE_W)) < 0) goto error; if ((r = sys_page_unmap(0, UTEMP)) < 0) goto error; return 0; error: sys_page_unmap(0, UTEMP); return r; }
// Set up the initial stack page for the new child process with envid 'child' // using the arguments array pointed to by 'argv', // which is a null-terminated array of pointers to '\0'-terminated strings. // // On success, returns 0 and sets *init_esp // to the initial stack pointer with which the child should start. // Returns < 0 on failure. static int init_stack(envid_t child, const char **argv, uintptr_t *init_esp) { size_t string_size; int argc, i, r; char *string_store; uintptr_t *argv_store; // Count the number of arguments (argc) // and the total amount of space needed for strings (string_size). string_size = 0; for (argc = 0; argv[argc] != 0; argc++) string_size += strlen(argv[argc]) + 1; // Determine where to place the strings and the argv array. // We set up the 'string_store' and 'argv_store' pointers to point // into the temporary page at UTEMP. // Later, we'll remap that page into the child environment // at (USTACKTOP - PGSIZE). // strings is the topmost thing on the stack. string_store = (char *) UTEMP + PGSIZE - string_size; // argv is below that. There's one argument pointer per argument, plus // a null pointer. argv_store = (uintptr_t*) (round_down(string_store, 4) - 4 * (argc + 1)); // Make sure that argv, strings, and the 2 words that hold 'argc' // and 'argv' themselves will all fit in a single stack page. if ((void*) (argv_store - 2) < (void*) UTEMP) return -E_NO_MEM; // Allocate a page at UTEMP. if ((r = sys_page_alloc(0, (void*) UTEMP, PTE_P|PTE_U|PTE_W)) < 0) return r; // Replace this with your code to: // // * Initialize 'argv_store[i]' to point to argument string i, // for all 0 <= i < argc. // Also, copy the argument strings from 'argv' into the // newly-allocated stack page. // Hint: Copy the argument strings into string_store. // Hint: Make sure that argv_store uses addresses valid in the // CHILD'S environment! The string_store variable itself // points into page UTEMP, but the child environment will have // this page mapped at USTACKTOP - PGSIZE. Check out the // utemp_addr_to_ustack_addr function defined above. // for(i = 0; i < argc; i++){ argv_store[i] = UTEMP2USTACK(string_store); strcpy(string_store,argv[i]); string_store += strlen(argv[i])+1; } // * Set 'argv_store[argc]' to 0 to null-terminate the args array. // argv_store[argc] = 0; // * Push two more words onto the child's stack below 'args', // containing the argc and argv parameters to be passed // to the child's umain() function. // argv should be below argc on the stack. // (Again, argv should use an address valid in the child's // environment.) // argv_store[-1] = UTEMP2USTACK(argv_store); argv_store[-2] = argc; // * Set *init_esp to the initial stack pointer for the child, // (Again, use an address valid in the child's environment.) // // LAB 4: Your code here. //*init_esp = USTACKTOP; // Change this! *init_esp = UTEMP2USTACK(argv_store-2); // After completing the stack, map it into the child's address space // and unmap it from ours! if ((r = sys_page_map(0, (void*) UTEMP, child, (void*) (USTACKTOP - PGSIZE), PTE_P | PTE_U | PTE_W)) < 0) goto error; if ((r = sys_page_unmap(0, (void*) UTEMP)) < 0) goto error; return 0; error: sys_page_unmap(0, (void*) UTEMP); return r; }