00001 #include "userprog/process.h"
00002
00003 #include <debug.h>
00004 #include <inttypes.h>
00005 #include <round.h>
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include "userprog/gdt.h"
00010 #include "userprog/pagedir.h"
00011 #include "userprog/tss.h"
00012 #include "filesys/directory.h"
00013 #include "filesys/file.h"
00014 #include "filesys/filesys.h"
00015 #include "threads/flags.h"
00016 #include "threads/init.h"
00017 #include "threads/interrupt.h"
00018 #include "threads/palloc.h"
00019 #include "threads/thread.h"
00020 #include "threads/vaddr.h"
00021
00022 static thread_func start_process NO_RETURN;
00023 static bool load (const char *cmdline, void (**eip) (void), void **esp);
00024
00025
00026
00027
00028
00029 tid_t
00030 process_execute (const char *file_name)
00031 {
00032 char *fn_copy;
00033 tid_t tid;
00034
00035
00036
00037 fn_copy = palloc_get_page (0);
00038 if (fn_copy == NULL)
00039 return TID_ERROR;
00040 strlcpy (fn_copy, file_name, PGSIZE);
00041
00042
00043 tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
00044 if (tid == TID_ERROR)
00045 palloc_free_page (fn_copy);
00046 return tid;
00047 }
00048
00049
00050
00051 static void
00052 start_process (void *file_name_)
00053 {
00054 char *file_name = file_name_;
00055 struct intr_frame if_;
00056 bool success;
00057
00058
00059 memset (&if_, 0, sizeof if_);
00060 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
00061 if_.cs = SEL_UCSEG;
00062 if_.eflags = FLAG_IF | FLAG_MBS;
00063 success = load (file_name, &if_.eip, &if_.esp);
00064
00065
00066 palloc_free_page (file_name);
00067 if (!success)
00068 thread_exit ();
00069
00070
00071
00072
00073
00074
00075
00076 asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory");
00077 NOT_REACHED ();
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 int
00090 process_wait (tid_t child_tid UNUSED)
00091 {
00092 return -1;
00093 }
00094
00095
00096 void
00097 process_exit (void)
00098 {
00099 struct thread *cur = thread_current ();
00100 uint32_t *pd;
00101
00102
00103
00104 pd = cur->pagedir;
00105 if (pd != NULL)
00106 {
00107
00108
00109
00110
00111
00112
00113
00114 cur->pagedir = NULL;
00115 pagedir_activate (NULL);
00116 pagedir_destroy (pd);
00117 }
00118 }
00119
00120
00121
00122
00123 void
00124 process_activate (void)
00125 {
00126 struct thread *t = thread_current ();
00127
00128
00129 pagedir_activate (t->pagedir);
00130
00131
00132
00133 tss_update ();
00134 }
00135
00136
00137
00138
00139
00140 typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
00141 typedef uint16_t Elf32_Half;
00142
00143
00144 #define PE32Wx PRIx32
00145 #define PE32Ax PRIx32
00146 #define PE32Ox PRIx32
00147 #define PE32Hx PRIx16
00148
00149
00150
00151 struct Elf32_Ehdr
00152 {
00153 unsigned char e_ident[16];
00154 Elf32_Half e_type;
00155 Elf32_Half e_machine;
00156 Elf32_Word e_version;
00157 Elf32_Addr e_entry;
00158 Elf32_Off e_phoff;
00159 Elf32_Off e_shoff;
00160 Elf32_Word e_flags;
00161 Elf32_Half e_ehsize;
00162 Elf32_Half e_phentsize;
00163 Elf32_Half e_phnum;
00164 Elf32_Half e_shentsize;
00165 Elf32_Half e_shnum;
00166 Elf32_Half e_shstrndx;
00167 };
00168
00169
00170
00171
00172 struct Elf32_Phdr
00173 {
00174 Elf32_Word p_type;
00175 Elf32_Off p_offset;
00176 Elf32_Addr p_vaddr;
00177 Elf32_Addr p_paddr;
00178 Elf32_Word p_filesz;
00179 Elf32_Word p_memsz;
00180 Elf32_Word p_flags;
00181 Elf32_Word p_align;
00182 };
00183
00184
00185 #define PT_NULL 0
00186 #define PT_LOAD 1
00187 #define PT_DYNAMIC 2
00188 #define PT_INTERP 3
00189 #define PT_NOTE 4
00190 #define PT_SHLIB 5
00191 #define PT_PHDR 6
00192 #define PT_STACK 0x6474e551
00193
00194
00195 #define PF_X 1
00196 #define PF_W 2
00197 #define PF_R 4
00198
00199 static bool setup_stack (void **esp);
00200 static bool validate_segment (const struct Elf32_Phdr *, struct file *);
00201 static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
00202 uint32_t read_bytes, uint32_t zero_bytes,
00203 bool writable);
00204
00205
00206
00207
00208
00209 bool
00210 load (const char *file_name, void (**eip) (void), void **esp)
00211 {
00212 struct thread *t = thread_current ();
00213 struct Elf32_Ehdr ehdr;
00214 struct file *file = NULL;
00215 off_t file_ofs;
00216 bool success = false;
00217 int i;
00218
00219
00220 t->pagedir = pagedir_create ();
00221 if (t->pagedir == NULL)
00222 goto done;
00223 process_activate ();
00224
00225
00226 file = filesys_open (file_name);
00227 if (file == NULL)
00228 {
00229 printf ("load: %s: open failed\n", file_name);
00230 goto done;
00231 }
00232
00233
00234 if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
00235 || memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7)
00236 || ehdr.e_type != 2
00237 || ehdr.e_machine != 3
00238 || ehdr.e_version != 1
00239 || ehdr.e_phentsize != sizeof (struct Elf32_Phdr)
00240 || ehdr.e_phnum > 1024)
00241 {
00242 printf ("load: %s: error loading executable\n", file_name);
00243 goto done;
00244 }
00245
00246
00247 file_ofs = ehdr.e_phoff;
00248 for (i = 0; i < ehdr.e_phnum; i++)
00249 {
00250 struct Elf32_Phdr phdr;
00251
00252 if (file_ofs < 0 || file_ofs > file_length (file))
00253 goto done;
00254 file_seek (file, file_ofs);
00255
00256 if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
00257 goto done;
00258 file_ofs += sizeof phdr;
00259 switch (phdr.p_type)
00260 {
00261 case PT_NULL:
00262 case PT_NOTE:
00263 case PT_PHDR:
00264 case PT_STACK:
00265 default:
00266
00267 break;
00268 case PT_DYNAMIC:
00269 case PT_INTERP:
00270 case PT_SHLIB:
00271 goto done;
00272 case PT_LOAD:
00273 if (validate_segment (&phdr, file))
00274 {
00275 bool writable = (phdr.p_flags & PF_W) != 0;
00276 uint32_t file_page = phdr.p_offset & ~PGMASK;
00277 uint32_t mem_page = phdr.p_vaddr & ~PGMASK;
00278 uint32_t page_offset = phdr.p_vaddr & PGMASK;
00279 uint32_t read_bytes, zero_bytes;
00280 if (phdr.p_filesz > 0)
00281 {
00282
00283
00284 read_bytes = page_offset + phdr.p_filesz;
00285 zero_bytes = (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE)
00286 - read_bytes);
00287 }
00288 else
00289 {
00290
00291
00292 read_bytes = 0;
00293 zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE);
00294 }
00295 if (!load_segment (file, file_page, (void *) mem_page,
00296 read_bytes, zero_bytes, writable))
00297 goto done;
00298 }
00299 else
00300 goto done;
00301 break;
00302 }
00303 }
00304
00305
00306 if (!setup_stack (esp))
00307 goto done;
00308
00309
00310 *eip = (void (*) (void)) ehdr.e_entry;
00311
00312 success = true;
00313
00314 done:
00315
00316 file_close (file);
00317 return success;
00318 }
00319
00320
00321
00322 static bool install_page (void *upage, void *kpage, bool writable);
00323
00324
00325
00326 static bool
00327 validate_segment (const struct Elf32_Phdr *phdr, struct file *file)
00328 {
00329
00330 if ((phdr->p_offset & PGMASK) != (phdr->p_vaddr & PGMASK))
00331 return false;
00332
00333
00334 if (phdr->p_offset > (Elf32_Off) file_length (file))
00335 return false;
00336
00337
00338 if (phdr->p_memsz < phdr->p_filesz)
00339 return false;
00340
00341
00342 if (phdr->p_memsz == 0)
00343 return false;
00344
00345
00346
00347 if (!is_user_vaddr ((void *) phdr->p_vaddr))
00348 return false;
00349 if (!is_user_vaddr ((void *) (phdr->p_vaddr + phdr->p_memsz)))
00350 return false;
00351
00352
00353
00354 if (phdr->p_vaddr + phdr->p_memsz < phdr->p_vaddr)
00355 return false;
00356
00357
00358
00359
00360
00361
00362 if (phdr->p_vaddr < PGSIZE)
00363 return false;
00364
00365
00366 return true;
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 static bool
00384 load_segment (struct file *file, off_t ofs, uint8_t *upage,
00385 uint32_t read_bytes, uint32_t zero_bytes, bool writable)
00386 {
00387 ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
00388 ASSERT (pg_ofs (upage) == 0);
00389 ASSERT (ofs % PGSIZE == 0);
00390
00391 file_seek (file, ofs);
00392 while (read_bytes > 0 || zero_bytes > 0)
00393 {
00394
00395
00396
00397 size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
00398 size_t page_zero_bytes = PGSIZE - page_read_bytes;
00399
00400
00401 uint8_t *kpage = palloc_get_page (PAL_USER);
00402 if (kpage == NULL)
00403 return false;
00404
00405
00406 if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes)
00407 {
00408 palloc_free_page (kpage);
00409 return false;
00410 }
00411 memset (kpage + page_read_bytes, 0, page_zero_bytes);
00412
00413
00414 if (!install_page (upage, kpage, writable))
00415 {
00416 palloc_free_page (kpage);
00417 return false;
00418 }
00419
00420
00421 read_bytes -= page_read_bytes;
00422 zero_bytes -= page_zero_bytes;
00423 upage += PGSIZE;
00424 }
00425 return true;
00426 }
00427
00428
00429
00430 static bool
00431 setup_stack (void **esp)
00432 {
00433 uint8_t *kpage;
00434 bool success = false;
00435
00436 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
00437 if (kpage != NULL)
00438 {
00439 success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
00440 if (success)
00441 *esp = PHYS_BASE;
00442 else
00443 palloc_free_page (kpage);
00444 }
00445 return success;
00446 }
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 static bool
00458 install_page (void *upage, void *kpage, bool writable)
00459 {
00460 struct thread *t = thread_current ();
00461
00462
00463
00464 return (pagedir_get_page (t->pagedir, upage) == NULL
00465 && pagedir_set_page (t->pagedir, upage, kpage, writable));
00466 }