4 static int copy_shared_pages(envid_t child
);
7 // Allocate at least len bytes of physical memory for environment env,
8 // mapped at virtual address 'va' in 'dst_env's address space.
9 // Pages should be writable and zeroed.
10 // Return 0 on success, < 0 if an allocation attempt fails.
13 segment_alloc(envid_t dst_env
, uintptr_t va
, size_t len
)
15 // LAB 4: Your code here.
16 // (But only if you need it for spawn.)
17 // Refer to your Lab 3 code in kern/env.c!
23 // Shift an address from the UTEMP page to the corresponding value in the
24 // normal stack page (top address USTACKTOP).
26 static uintptr_t utemp_addr_to_stack_addr(void *ptr
)
28 uintptr_t addr
= (uintptr_t) ptr
;
29 assert(ptr
>= UTEMP
&& ptr
< (char *) UTEMP
+ PGSIZE
);
30 return USTACKTOP
- PGSIZE
+ PGOFF(addr
);
34 // Set up the initial stack page for the new child process with envid 'child'
35 // using the arguments array pointed to by 'argv',
36 // which is a null-terminated array of pointers to '\0'-terminated strings.
38 // On success, returns 0 and sets *init_esp to the initial stack pointer
39 // with which the child should start.
40 // Returns < 0 on failure.
43 init_stack(envid_t child
, const char **argv
, uintptr_t *init_esp
)
48 uintptr_t *argv_store
;
50 // Count the number of arguments (argc)
51 // and the total amount of space needed for strings (string_size).
53 for (argc
= 0; argv
[argc
] != 0; argc
++)
54 string_size
+= strlen(argv
[argc
]) + 1;
56 // Determine where to place the strings and the argv array.
57 // We set up the 'string_store' and 'argv_store' pointers to point
58 // into the temporary page at UTEMP.
59 // Later, we'll remap that page into the child environment
60 // at (USTACKTOP - PGSIZE).
62 // strings are topmost on the stack.
63 string_store
= (char *) UTEMP
+ PGSIZE
- string_size
;
65 // argv is below that. There's one argument pointer per argument, plus
67 argv_store
= (uintptr_t *) ROUNDDOWN(string_store
, 4) - (argc
+ 1);
69 // Make sure that argv, strings, and the 2 words that hold 'argc'
70 // and 'argv' themselves will all fit in a single stack page.
71 if ((void*) (argv_store
- 2) < (void*) UTEMP
)
74 // Allocate a page at UTEMP.
75 if ((r
= sys_page_alloc(0, (void*) UTEMP
, PTE_P
|PTE_U
|PTE_W
)) < 0)
78 // Store the 'argc' and 'argv' parameters themselves
79 // below 'argv_store' on the stack. These parameters will be passed
81 argv_store
[-2] = argc
;
82 argv_store
[-1] = utemp_addr_to_stack_addr(argv_store
);
85 // Copy the argument strings from 'argv' into UTEMP
86 // and initialize 'argv_store[i]' to point at argument string i
87 // in the child's address space.
88 // Then set 'argv_store[argc]' to 0 to null-terminate the args array.
89 // LAB 4: Your code here.
91 // Set *init_esp to the initial stack pointer for the child:
92 // it should point at the "argc" value stored on the stack.
93 // LAB 4: Your code here.
94 *init_esp
= USTACKTOP
;
97 // After completing the stack, map it into the child's address space
98 // and unmap it from ours!
99 if ((r
= sys_page_map(0, UTEMP
, child
, (void*) (USTACKTOP
- PGSIZE
), PTE_P
| PTE_U
| PTE_W
)) < 0)
101 if ((r
= sys_page_unmap(0, UTEMP
)) < 0)
107 sys_page_unmap(0, UTEMP
);
113 // Spawn a new user process running a specified binary.
115 // This function loads all loadable segments from an ELF binary image
116 // into the environment's user memory, starting at the appropriate
117 // virtual addresses indicated in the ELF program header.
118 // It also clears to zero any portions of these segments
119 // that are marked in the program header as being mapped
120 // but not actually present in the ELF file -- i.e., the program's bss section.
122 // This is a lot like load_elf in kern/env.c, and you can reuse a lot of the
123 // same logic! But instead of copying directly from an ELF image, you'll
124 // use the sys_program_read() system call.
126 // This function also maps one page for the program's initial stack.
127 // Command line arguments go on the stack, so it's not just an empty page;
130 // Returns the new environment's ID on success, and < 0 on error.
131 // If an error occurs, any new environment is destroyed.
134 spawn(const char *prog
, const char **argv
)
136 unsigned char elf_buf
[512];
137 struct Elf
*elf
= (struct Elf
*) &elf_buf
;
142 // LAB 5 EXERCISE: If the first character of prog is '/',
143 // look up the program using 'open' (not sys_program_lookup)
144 // and read from it using 'read' and 'seek' (not sys_program_read).
146 // Program IDs returned by sys_program_lookup are greater than
147 // or equal to PROGRAM_OFFSET (0x40000000).
148 // No file descriptors are that big, so you can use a single variable
149 // to hold either the program ID or the file descriptor number.
151 // Unfortunately, you cannot 'read' into a child address space,
152 // so you'll need to code the 'read' case differently.
154 // Also, make sure you close the file descriptor, if any,
155 // before returning from spawn().
157 // Read ELF header from the kernel's binary collection.
158 if ((progid
= sys_program_lookup(prog
, strlen(prog
))) < 0)
160 memset(elf_buf
, 0, sizeof(elf_buf
)); // ensure stack is writable
161 if (sys_program_read(0, elf_buf
, progid
, 0, sizeof(elf_buf
)) != sizeof(elf_buf
)
162 || elf
->e_magic
!= ELF_MAGIC
) {
163 cprintf("elf magic %08x want %08x\n", elf
->e_magic
, ELF_MAGIC
);
167 // Now create the child process, then load the ELF into it!
169 // - Refer to your load_elf.
170 // - You can assume that all "struct Proghdr" structures are contained
171 // in the first 512 bytes of the ELF, which you loaded already.
172 // - The virtual addresses included in ELF files might not be
173 // page-aligned. However, ELF guarantees that no two segments
174 // will load different data into the same page.
175 // (ELF also guarantees that PGOFF(ph->p_va) == PGOFF(ph->p_offset),
176 // although you won't use that fact here.)
177 // - Check out sys_env_set_trapframe and init_stack.
179 // LAB 4: Your code here.
183 // Spawn, taking command-line arguments array directly on the stack.
185 spawnl(const char *prog
, const char *arg0
, ...)
187 return spawn(prog
, &arg0
);
191 // Copy the mappings for shared pages into the child address space.
193 copy_shared_pages(envid_t child
)
197 for (va
= 0; va
< UTOP
; va
+= PGSIZE
)
198 if (!(vpd
[PDX(va
)] & PTE_P
))
199 va
= ROUNDUP(va
+ 1, PTSIZE
) - PGSIZE
;
200 else if ((vpt
[PGNUM(va
)] & (PTE_P
|PTE_SHARE
)) == (PTE_P
|PTE_SHARE
)) {
201 r
= sys_page_map(0, (void *) va
, child
, (void *) va
,
202 vpt
[PGNUM(va
)] & PTE_USER
);