* same with xv6
[mascara-docs.git] / i386 / ucla / src / lab5 / lib / spawn.c
blobe3580c6c9c5acea45e87558551b8cc4751ba49e2
1 #include <inc/lib.h>
2 #include <inc/elf.h>
4 static int copy_shared_pages(envid_t child);
6 //
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.
12 static int
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!
18 return -E_FAULT;
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.
42 static int
43 init_stack(envid_t child, const char **argv, uintptr_t *init_esp)
45 size_t string_size;
46 int argc, i, r;
47 char *string_store;
48 uintptr_t *argv_store;
50 // Count the number of arguments (argc)
51 // and the total amount of space needed for strings (string_size).
52 string_size = 0;
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
66 // a null pointer.
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)
72 return -E_NO_MEM;
74 // Allocate a page at UTEMP.
75 if ((r = sys_page_alloc(0, (void*) UTEMP, PTE_P|PTE_U|PTE_W)) < 0)
76 return r;
78 // Store the 'argc' and 'argv' parameters themselves
79 // below 'argv_store' on the stack. These parameters will be passed
80 // to umain().
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)
100 goto error;
101 if ((r = sys_page_unmap(0, UTEMP)) < 0)
102 goto error;
104 return 0;
106 error:
107 sys_page_unmap(0, UTEMP);
108 return r;
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;
128 // see init_stack.
130 // Returns the new environment's ID on success, and < 0 on error.
131 // If an error occurs, any new environment is destroyed.
133 envid_t
134 spawn(const char *prog, const char **argv)
136 unsigned char elf_buf[512];
137 struct Elf *elf = (struct Elf *) &elf_buf;
139 int progid, i, r;
140 struct Proghdr *ph;
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)
159 return progid;
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);
164 return -E_NOT_EXEC;
167 // Now create the child process, then load the ELF into it!
168 // Hints:
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.
180 return -E_NOT_EXEC;
183 // Spawn, taking command-line arguments array directly on the stack.
184 envid_t
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.
192 static int
193 copy_shared_pages(envid_t child)
195 uintptr_t va;
196 int r;
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);
203 if (r < 0)
204 return r;
206 return 0;