+static thread_func execute_thread 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 before
+ addrspace_execute() returns.*/
+tid_t
+addrspace_execute (const char *filename)
+{
+ char *fn_copy;
+ tid_t tid;
+
+ /* Make a copy of FILENAME.
+ Otherwise there's a race between the caller and load(). */
+ fn_copy = palloc_get (0);
+ if (fn_copy == NULL)
+ return TID_ERROR;
+ strlcpy (fn_copy, filename, PGSIZE);
+
+ /* Create a new thread to execute FILENAME. */
+ tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
+ if (tid == TID_ERROR)
+ palloc_free (fn_copy);
+ return tid;
+}
+
+/* A thread function that loads a user process and starts it
+ running. */
+static void
+execute_thread (void *filename_)
+{
+ char *filename = filename_;
+ struct intr_frame if_;
+ bool success;
+
+ /* Initialize interrupt frame and load executable. */
+ memset (&if_, 0, sizeof if_);
+ if_.es = SEL_UDSEG;
+ if_.ds = SEL_UDSEG;
+ if_.cs = SEL_UCSEG;
+ if_.eflags = FLAG_IF | FLAG_MBS;
+ if_.ss = SEL_UDSEG;
+ success = load (filename, &if_.eip, &if_.esp);
+
+ /* If load failed, quit. */
+ palloc_free (filename);
+ if (!success)
+ thread_exit ();
+
+ /* Switch page tables. */
+ addrspace_activate ();
+
+ /* Start the user process by simulating a return from an
+ interrupt, implemented by intr_exit (in
+ threads/intr-stubs.pl). Because intr_exit takes all of its
+ arguments on the stack in the form of a `struct intr_frame',
+ we just point the stack pointer (%esp) to our stack frame
+ and jump to it. */
+ asm ("mov %0, %%esp\n"
+ "jmp intr_exit\n"
+ : /* no outputs */
+ : "g" (&if_));
+ NOT_REACHED ();
+}
+\f