示例#1
0
文件: proc.c 项目: LuaDist/lua-apr
int lua_apr_proc_fork(lua_State *L)
{
  lua_apr_proc *process = proc_alloc(L, NULL);
  apr_status_t status = apr_proc_fork(&process->handle, process->memory_pool);
  if (status != APR_INCHILD && status != APR_INPARENT)
    return push_error_status(L, status);
  lua_pushstring(L, status == APR_INPARENT ? "parent" : "child");
  return 2;
}
示例#2
0
static VALUE
proc_dup(VALUE self)
{
    VALUE procval = proc_alloc(rb_cProc);
    rb_proc_t *src, *dst;
    GetProcPtr(self, src);
    GetProcPtr(procval, dst);

    dst->block = src->block;
    dst->envval = src->envval;
    dst->safe_level = dst->safe_level;
    dst->special_cref_stack = src->special_cref_stack;
    
    return procval;
}
示例#3
0
ft_error_t ft_proc_init_from_pid(ft_proc_t** proc, ft_pid_t pid)
{
  ft_proc_t* p;

  *proc = 0;
  
  /* hu ;) */
  if (pid == getpid())
    return FT_ERR_BADPROC;

  p = proc_alloc();
  p->pid = pid;
  ft_proc_init_swdep(p);
  *proc = p;
  return FT_ERR_SUCCESS;
}
示例#4
0
ft_error_t ft_proc_init_from_av(ft_proc_t** proc, char** av, char** env)
{
  ft_proc_t* p;
  int pfather[2];
  int pchild[2];
  char buf;

  *proc = 0;
  p = proc_alloc();
  p->child = true;

  pipe(pfather);
  pipe(pchild);

  p->pid = fork();
  if (p->pid == 0)
    {
      /* Close unecessary fds */
      close(pchild[1]);
      close(pfather[0]);

      /* Set tracing mode */
      ft_proc_traceme(p);

      /* Tell our father we can be traced */
      close(pfather[1]);

      /* Wait for the father */
      read(pchild[0], &buf, sizeof(char));
      close(pchild[0]);

      /* Execute */
      execve(av[0], av, env);
      perror("execve");
      exit(-1);
    }

  p->ipcfd = pchild[1];
  ft_proc_init_swdep(p);
  close(pchild[0]);
  close(pfather[1]);
  read(pfather[0], &buf, sizeof(buf));
  close(pfather[0]);

  *proc = p;
  return FT_ERR_SUCCESS;
}
示例#5
0
VALUE
rb_proc_alloc(void)
{
    return proc_alloc(rb_cProc);
}
示例#6
0
文件: proc.c 项目: LuaDist/lua-apr
int lua_apr_proc_create(lua_State *L)
{
  proc_alloc(L, luaL_checkstring(L, 1));
  return 1;
}
示例#7
0
static void
do_put(trapframe *tf, uint32_t cmd)
{
	proc *curr = proc_cur();
  spinlock_acquire(&curr->lock);

  uint32_t child_index = tf->regs.edx;
  uint8_t node_number  = child_index >> 8 & 0xff;  // First 8 bits are the node number
  uint8_t child_number = child_index & 0xff;// The last 8 bits for child number

  // cprintf("node %d put: dest node: %d, child: %d, home node: %d\n", 
  //   net_node, node_number, child_number, RRNODE(curr->home));

  // When migrating, make sure to adjust eip! => entry == 0
  // Trying to migrate home and this is not its home
  if(node_number == 0) {
    node_number = RRNODE(curr->home);
  }
  if (net_node != node_number) {
    // cprintf("sys_put: %p migrating to %d\n", curr, RRNODE(curr->home));
    spinlock_release(&curr->lock);
    net_migrate(tf, node_number, 0);
  }

  proc *child = curr->child[child_number];

  if(!child) 
    child = proc_alloc(curr, child_number);
  if(child->state != PROC_STOP)
    proc_wait(curr, child, tf);
  
  spinlock_release(&curr->lock);

  // cprintf("do_put: current proc: %p, cpu_cur proc: %p\n", curr, cpu_cur()->proc);
	if(cmd & SYS_REGS) {
		usercopy(tf, 0, &child->sv, tf->regs.ebx, sizeof(procstate));
    child->sv.tf.ds = CPU_GDT_UDATA | 3;
		child->sv.tf.es = CPU_GDT_UDATA | 3;
		child->sv.tf.cs = CPU_GDT_UCODE | 3;
		child->sv.tf.ss = CPU_GDT_UDATA | 3;
		child->sv.tf.eflags &= FL_USER;
		child->sv.tf.eflags |= FL_IF;
  }
  uint32_t dest = tf->regs.edi; //syscall.h
  uint32_t size = tf->regs.ecx;
  uint32_t src = tf->regs.esi;

  if(cmd & SYS_MEMOP) {
    int op = cmd & SYS_MEMOP;
    // Check if the destination range is okay
    if(dest < VM_USERLO || dest > VM_USERHI || dest + size > VM_USERHI)
        systrap(tf, T_GPFLT, 0);
    if(op == SYS_COPY) {
      // we have to check the source too
      if(src < VM_USERLO || src > VM_USERHI || src + size > VM_USERHI)
          systrap(tf, T_GPFLT, 0);
      pmap_copy(curr->pdir, src, child->pdir, dest, size);
    } else
      pmap_remove(child->pdir, dest, size);
  }

	if(cmd & SYS_PERM)
		pmap_setperm(child->pdir, dest, size, cmd & SYS_RW);

	if(cmd & SYS_SNAP)
    // copy pdir to rpdir
    pmap_copy(child->pdir, VM_USERLO, child->rpdir, VM_USERLO, VM_USERHI-VM_USERLO);

	if(cmd & SYS_START)
		proc_ready(child);

	trap_return(tf);	// syscall completed
}
示例#8
0
/*
 * General fork call.  Note that another LWP in the process may call exec()
 * or exit() while we are forking.  It's safe to continue here, because
 * neither operation will complete until all LWPs have exited the process.
 */
int
fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize,
    void (*func)(void *), void *arg, register_t *retval,
    struct proc **rnewprocp)
{
	struct proc	*p1, *p2, *parent;
	struct plimit   *p1_lim;
	uid_t		uid;
	struct lwp	*l2;
	int		count;
	vaddr_t		uaddr;
	int		tnprocs;
	int		tracefork;
	int		error = 0;

	p1 = l1->l_proc;
	uid = kauth_cred_getuid(l1->l_cred);
	tnprocs = atomic_inc_uint_nv(&nprocs);

	/*
	 * Although process entries are dynamically created, we still keep
	 * a global limit on the maximum number we will create.
	 */
	if (__predict_false(tnprocs >= maxproc))
		error = -1;
	else
		error = kauth_authorize_process(l1->l_cred,
		    KAUTH_PROCESS_FORK, p1, KAUTH_ARG(tnprocs), NULL, NULL);

	if (error) {
		static struct timeval lasttfm;
		atomic_dec_uint(&nprocs);
		if (ratecheck(&lasttfm, &fork_tfmrate))
			tablefull("proc", "increase kern.maxproc or NPROC");
		if (forkfsleep)
			kpause("forkmx", false, forkfsleep, NULL);
		return EAGAIN;
	}

	/*
	 * Enforce limits.
	 */
	count = chgproccnt(uid, 1);
	if (__predict_false(count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur)) {
		if (kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_RLIMIT,
		    p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS),
		    &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) != 0) {
			(void)chgproccnt(uid, -1);
			atomic_dec_uint(&nprocs);
			if (forkfsleep)
				kpause("forkulim", false, forkfsleep, NULL);
			return EAGAIN;
		}
	}

	/*
	 * Allocate virtual address space for the U-area now, while it
	 * is still easy to abort the fork operation if we're out of
	 * kernel virtual address space.
	 */
	uaddr = uvm_uarea_alloc();
	if (__predict_false(uaddr == 0)) {
		(void)chgproccnt(uid, -1);
		atomic_dec_uint(&nprocs);
		return ENOMEM;
	}

	/*
	 * We are now committed to the fork.  From here on, we may
	 * block on resources, but resource allocation may NOT fail.
	 */

	/* Allocate new proc. */
	p2 = proc_alloc();

	/*
	 * Make a proc table entry for the new process.
	 * Start by zeroing the section of proc that is zero-initialized,
	 * then copy the section that is copied directly from the parent.
	 */
	memset(&p2->p_startzero, 0,
	    (unsigned) ((char *)&p2->p_endzero - (char *)&p2->p_startzero));
	memcpy(&p2->p_startcopy, &p1->p_startcopy,
	    (unsigned) ((char *)&p2->p_endcopy - (char *)&p2->p_startcopy));

	TAILQ_INIT(&p2->p_sigpend.sp_info);

	LIST_INIT(&p2->p_lwps);
	LIST_INIT(&p2->p_sigwaiters);

	/*
	 * Duplicate sub-structures as needed.
	 * Increase reference counts on shared objects.
	 * Inherit flags we want to keep.  The flags related to SIGCHLD
	 * handling are important in order to keep a consistent behaviour
	 * for the child after the fork.  If we are a 32-bit process, the
	 * child will be too.
	 */
	p2->p_flag =
	    p1->p_flag & (PK_SUGID | PK_NOCLDWAIT | PK_CLDSIGIGN | PK_32);
	p2->p_emul = p1->p_emul;
	p2->p_execsw = p1->p_execsw;

	if (flags & FORK_SYSTEM) {
		/*
		 * Mark it as a system process.  Set P_NOCLDWAIT so that
		 * children are reparented to init(8) when they exit.
		 * init(8) can easily wait them out for us.
		 */
		p2->p_flag |= (PK_SYSTEM | PK_NOCLDWAIT);
	}

	mutex_init(&p2->p_stmutex, MUTEX_DEFAULT, IPL_HIGH);
	mutex_init(&p2->p_auxlock, MUTEX_DEFAULT, IPL_NONE);
	rw_init(&p2->p_reflock);
	cv_init(&p2->p_waitcv, "wait");
	cv_init(&p2->p_lwpcv, "lwpwait");

	/*
	 * Share a lock between the processes if they are to share signal
	 * state: we must synchronize access to it.
	 */
	if (flags & FORK_SHARESIGS) {
		p2->p_lock = p1->p_lock;
		mutex_obj_hold(p1->p_lock);
	} else
		p2->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);

	kauth_proc_fork(p1, p2);

	p2->p_raslist = NULL;
#if defined(__HAVE_RAS)
	ras_fork(p1, p2);
#endif

	/* bump references to the text vnode (for procfs) */
	p2->p_textvp = p1->p_textvp;
	if (p2->p_textvp)
		vref(p2->p_textvp);

	if (flags & FORK_SHAREFILES)
		fd_share(p2);
	else if (flags & FORK_CLEANFILES)
		p2->p_fd = fd_init(NULL);
	else
		p2->p_fd = fd_copy();

	/* XXX racy */
	p2->p_mqueue_cnt = p1->p_mqueue_cnt;

	if (flags & FORK_SHARECWD)
		cwdshare(p2);
	else
		p2->p_cwdi = cwdinit();

	/*
	 * Note: p_limit (rlimit stuff) is copy-on-write, so normally
	 * we just need increase pl_refcnt.
	 */
	p1_lim = p1->p_limit;
	if (!p1_lim->pl_writeable) {
		lim_addref(p1_lim);
		p2->p_limit = p1_lim;
	} else {
		p2->p_limit = lim_copy(p1_lim);
	}

	if (flags & FORK_PPWAIT) {
		/* Mark ourselves as waiting for a child. */
		l1->l_pflag |= LP_VFORKWAIT;
		p2->p_lflag = PL_PPWAIT;
		p2->p_vforklwp = l1;
	} else {
		p2->p_lflag = 0;
	}
	p2->p_sflag = 0;
	p2->p_slflag = 0;
	parent = (flags & FORK_NOWAIT) ? initproc : p1;
	p2->p_pptr = parent;
	p2->p_ppid = parent->p_pid;
	LIST_INIT(&p2->p_children);

	p2->p_aio = NULL;

#ifdef KTRACE
	/*
	 * Copy traceflag and tracefile if enabled.
	 * If not inherited, these were zeroed above.
	 */
	if (p1->p_traceflag & KTRFAC_INHERIT) {
		mutex_enter(&ktrace_lock);
		p2->p_traceflag = p1->p_traceflag;
		if ((p2->p_tracep = p1->p_tracep) != NULL)
			ktradref(p2);
		mutex_exit(&ktrace_lock);
	}
#endif

	/*
	 * Create signal actions for the child process.
	 */
	p2->p_sigacts = sigactsinit(p1, flags & FORK_SHARESIGS);
	mutex_enter(p1->p_lock);
	p2->p_sflag |=
	    (p1->p_sflag & (PS_STOPFORK | PS_STOPEXEC | PS_NOCLDSTOP));
	sched_proc_fork(p1, p2);
	mutex_exit(p1->p_lock);

	p2->p_stflag = p1->p_stflag;

	/*
	 * p_stats.
	 * Copy parts of p_stats, and zero out the rest.
	 */
	p2->p_stats = pstatscopy(p1->p_stats);

	/*
	 * Set up the new process address space.
	 */
	uvm_proc_fork(p1, p2, (flags & FORK_SHAREVM) ? true : false);

	/*
	 * Finish creating the child process.
	 * It will return through a different path later.
	 */
	lwp_create(l1, p2, uaddr, (flags & FORK_PPWAIT) ? LWP_VFORK : 0,
	    stack, stacksize, (func != NULL) ? func : child_return, arg, &l2,
	    l1->l_class);

	/*
	 * Inherit l_private from the parent.
	 * Note that we cannot use lwp_setprivate() here since that
	 * also sets the CPU TLS register, which is incorrect if the
	 * process has changed that without letting the kernel know.
	 */
	l2->l_private = l1->l_private;

	/*
	 * If emulation has a process fork hook, call it now.
	 */
	if (p2->p_emul->e_proc_fork)
		(*p2->p_emul->e_proc_fork)(p2, l1, flags);

	/*
	 * ...and finally, any other random fork hooks that subsystems
	 * might have registered.
	 */
	doforkhooks(p2, p1);

	SDT_PROBE(proc,,,create, p2, p1, flags, 0, 0);

	/*
	 * It's now safe for the scheduler and other processes to see the
	 * child process.
	 */
	mutex_enter(proc_lock);

	if (p1->p_session->s_ttyvp != NULL && p1->p_lflag & PL_CONTROLT)
		p2->p_lflag |= PL_CONTROLT;

	LIST_INSERT_HEAD(&parent->p_children, p2, p_sibling);
	p2->p_exitsig = exitsig;		/* signal for parent on exit */

	/*
	 * We don't want to tracefork vfork()ed processes because they
	 * will not receive the SIGTRAP until it is too late.
	 */
	tracefork = (p1->p_slflag & (PSL_TRACEFORK|PSL_TRACED)) ==
	    (PSL_TRACEFORK|PSL_TRACED) && (flags && FORK_PPWAIT) == 0;
	if (tracefork) {
		p2->p_slflag |= PSL_TRACED;
		p2->p_opptr = p2->p_pptr;
		if (p2->p_pptr != p1->p_pptr) {
			struct proc *parent1 = p2->p_pptr;

			if (parent1->p_lock < p2->p_lock) {
				if (!mutex_tryenter(parent1->p_lock)) {
					mutex_exit(p2->p_lock);
					mutex_enter(parent1->p_lock);
				}
			} else if (parent1->p_lock > p2->p_lock) {
				mutex_enter(parent1->p_lock);
			}
			parent1->p_slflag |= PSL_CHTRACED;
			proc_reparent(p2, p1->p_pptr);
			if (parent1->p_lock != p2->p_lock)
				mutex_exit(parent1->p_lock);
		}

		/*
		 * Set ptrace status.
		 */
		p1->p_fpid = p2->p_pid;
		p2->p_fpid = p1->p_pid;
	}

	LIST_INSERT_AFTER(p1, p2, p_pglist);
	LIST_INSERT_HEAD(&allproc, p2, p_list);

	p2->p_trace_enabled = trace_is_enabled(p2);
#ifdef __HAVE_SYSCALL_INTERN
	(*p2->p_emul->e_syscall_intern)(p2);
#endif

	/*
	 * Update stats now that we know the fork was successful.
	 */
	uvmexp.forks++;
	if (flags & FORK_PPWAIT)
		uvmexp.forks_ppwait++;
	if (flags & FORK_SHAREVM)
		uvmexp.forks_sharevm++;

	/*
	 * Pass a pointer to the new process to the caller.
	 */
	if (rnewprocp != NULL)
		*rnewprocp = p2;

	if (ktrpoint(KTR_EMUL))
		p2->p_traceflag |= KTRFAC_TRC_EMUL;

	/*
	 * Notify any interested parties about the new process.
	 */
	if (!SLIST_EMPTY(&p1->p_klist)) {
		mutex_exit(proc_lock);
		KNOTE(&p1->p_klist, NOTE_FORK | p2->p_pid);
		mutex_enter(proc_lock);
	}

	/*
	 * Make child runnable, set start time, and add to run queue except
	 * if the parent requested the child to start in SSTOP state.
	 */
	mutex_enter(p2->p_lock);

	/*
	 * Start profiling.
	 */
	if ((p2->p_stflag & PST_PROFIL) != 0) {
		mutex_spin_enter(&p2->p_stmutex);
		startprofclock(p2);
		mutex_spin_exit(&p2->p_stmutex);
	}

	getmicrotime(&p2->p_stats->p_start);
	p2->p_acflag = AFORK;
	lwp_lock(l2);
	KASSERT(p2->p_nrlwps == 1);
	if (p2->p_sflag & PS_STOPFORK) {
		struct schedstate_percpu *spc = &l2->l_cpu->ci_schedstate;
		p2->p_nrlwps = 0;
		p2->p_stat = SSTOP;
		p2->p_waited = 0;
		p1->p_nstopchild++;
		l2->l_stat = LSSTOP;
		KASSERT(l2->l_wchan == NULL);
		lwp_unlock_to(l2, spc->spc_lwplock);
	} else {
		p2->p_nrlwps = 1;
		p2->p_stat = SACTIVE;
		l2->l_stat = LSRUN;
		sched_enqueue(l2, false);
		lwp_unlock(l2);
	}

	/*
	 * Return child pid to parent process,
	 * marking us as parent via retval[1].
	 */
	if (retval != NULL) {
		retval[0] = p2->p_pid;
		retval[1] = 0;
	}
	mutex_exit(p2->p_lock);

	/*
	 * Preserve synchronization semantics of vfork.  If waiting for
	 * child to exec or exit, sleep until it clears LP_VFORKWAIT.
	 */
#if 0
	while (l1->l_pflag & LP_VFORKWAIT) {
		cv_wait(&l1->l_waitcv, proc_lock);
	}
#else
	while (p2->p_lflag & PL_PPWAIT)
		cv_wait(&p1->p_waitcv, proc_lock);
#endif

	/*
	 * Let the parent know that we are tracing its child.
	 */
	if (tracefork) {
		ksiginfo_t ksi;

		KSI_INIT_EMPTY(&ksi);
		ksi.ksi_signo = SIGTRAP;
		ksi.ksi_lid = l1->l_lid;
		kpsignal(p1, &ksi, NULL);
	}
	mutex_exit(proc_lock);

	return 0;
}
示例#9
0
static void
do_put(trapframe *tf, uint32_t cmd)
{
  proc *p = proc_cur();
  assert(p->state == PROC_RUN && p->runcpu == cpu_cur());
  cprintf("PUT proc %x eip %x esp %x cmd %x\n", p, tf->eip, tf->esp, cmd);

  spinlock_acquire(&p->lock);

  // Find the named child process; create if it doesn't exist
  uint32_t cn = tf->regs.edx & 0xff;
  proc *cp = p->child[cn];
  if (!cp) {
    cp = proc_alloc(p, cn);
    if (!cp)  // XX handle more gracefully
      panic("sys_put: no memory for child");
  }

  // Synchronize with child if necessary.
  if (cp->state != PROC_STOP)
    proc_wait(p, cp, tf);

  // Since the child is now stopped, it's ours to control;
  // we no longer need our process lock -
  // and we don't want to be holding it if usercopy() below aborts.
  spinlock_release(&p->lock);

  // Put child's general register state
  if (cmd & SYS_REGS) {
    int len = offsetof(procstate, fx);  // just integer regs
    if (cmd & SYS_FPU) len = sizeof(procstate); // whole shebang

  usercopy(tf,0,&cp->sv, tf->regs.ebx, len);
    // Copy user's trapframe into child process
    procstate *cs = (procstate*) tf->regs.ebx;
    memcpy(&cp->sv, cs, len);

    // Make sure process uses user-mode segments and eflag settings
    cp->sv.tf.ds = CPU_GDT_UDATA | 3;
    cp->sv.tf.es = CPU_GDT_UDATA | 3;
    cp->sv.tf.cs = CPU_GDT_UCODE | 3;
    cp->sv.tf.ss = CPU_GDT_UDATA | 3;
    cp->sv.tf.eflags &= FL_USER;
    cp->sv.tf.eflags |= FL_IF;  // enable interrupts
  }
	uint32_t sva = tf->regs.esi;
	uint32_t dva = tf->regs.edi;
	uint32_t size = tf->regs.ecx;
	switch (cmd & SYS_MEMOP) {
	case 0:	// no memory operation
		break;
	case SYS_COPY:
		// validate source region
		if (PTOFF(sva) || PTOFF(size)
				|| sva < VM_USERLO || sva > VM_USERHI
				|| size > VM_USERHI-sva)
			systrap(tf, T_GPFLT, 0);
		// fall thru...
	case SYS_ZERO:
		// validate destination region
		if (PTOFF(dva) || PTOFF(size)
				|| dva < VM_USERLO || dva > VM_USERHI
				|| size > VM_USERHI-dva)
			systrap(tf, T_GPFLT, 0);

		switch (cmd & SYS_MEMOP) {
		case SYS_ZERO:	// zero memory and clear permissions
			pmap_remove(cp->pdir, dva, size);
			break;
		case SYS_COPY:	// copy from local src to dest in child
			pmap_copy(p->pdir, sva, cp->pdir, dva, size);
			break;
		}
		break;
	default:
		systrap(tf, T_GPFLT, 0);
	}

	if (cmd & SYS_PERM) {
		// validate destination region
		if (PGOFF(dva) || PGOFF(size)
				|| dva < VM_USERLO || dva > VM_USERHI
				|| size > VM_USERHI-dva)
			systrap(tf, T_GPFLT, 0);
		if (!pmap_setperm(cp->pdir, dva, size, cmd & SYS_RW))
			panic("pmap_put: no memory to set permissions");
	}

	if (cmd & SYS_SNAP)	// Snapshot child's state
		pmap_copy(cp->pdir, VM_USERLO, cp->rpdir, VM_USERLO,
				VM_USERHI-VM_USERLO);

  // Start the child if requested
  if (cmd & SYS_START)
    proc_ready(cp);

  trap_return(tf);  // syscall completed
}
示例#10
0
文件: init.c 项目: EddieSpencer/pios
// Called first from entry.S on the bootstrap processor,
// and later from boot/bootother.S on all other processors.
// As a rule, "init" functions in PIOS are called once on EACH processor.
void
init(void)
{
	extern char start[], edata[], end[];

	// Before anything else, complete the ELF loading process.
	// Clear all uninitialized global data (BSS) in our program,
	// ensuring that all static/global variables start out zero.
	if (cpu_onboot())
		memset(edata, 0, end - edata);

	// Initialize the console.
	// Can't call cprintf until after we do this!
	cons_init();

  	extern uint8_t _binary_obj_boot_bootother_start[],
    	_binary_obj_boot_bootother_size[];

  	uint8_t *code = (uint8_t*)lowmem_bootother_vec;
  	memmove(code, _binary_obj_boot_bootother_start, (uint32_t) _binary_obj_boot_bootother_size);

	// Lab 1: test cprintf and debug_trace
	cprintf("1234 decimal is %o octal!\n", 1234);
	debug_check();

	// Initialize and load the bootstrap CPU's GDT, TSS, and IDT.
	cpu_init();
	trap_init();

	// Physical memory detection/initialization.
	// Can't call mem_alloc until after we do this!
	mem_init();

	// Lab 2: check spinlock implementation
	if (cpu_onboot())
		spinlock_check();

	// Initialize the paged virtual memory system.
	pmap_init();

	// Find and start other processors in a multiprocessor system
	mp_init();		// Find info about processors in system
	pic_init();		// setup the legacy PIC (mainly to disable it)
	ioapic_init();		// prepare to handle external device interrupts
	lapic_init();		// setup this CPU's local APIC
	cpu_bootothers();	// Get other processors started
//	cprintf("CPU %d (%s) has booted\n", cpu_cur()->id,
//		cpu_onboot() ? "BP" : "AP");

	file_init();		// Create root directory and console I/O files

	// Lab 4: uncomment this when you can handle IRQ_SERIAL and IRQ_KBD.
	//cons_intenable();	// Let the console start producing interrupts

	// Initialize the process management code.
	proc_init();
	// Initialize the process management code.
	proc_init();


	if(!cpu_onboot())
		proc_sched();
 	proc *root = proc_root = proc_alloc(NULL,0);
  
  	elfhdr *ehs = (elfhdr *)ROOTEXE_START;
  	assert(ehs->e_magic == ELF_MAGIC);

  	proghdr *phs = (proghdr *) ((void *) ehs + ehs->e_phoff);
  	proghdr *ep = phs + ehs->e_phnum;

  	for (; phs < ep; phs++)
	{
    		if (phs->p_type != ELF_PROG_LOAD)
      		continue;

    		void *fa = (void *) ehs + ROUNDDOWN(phs->p_offset, PAGESIZE);
    		uint32_t va = ROUNDDOWN(phs->p_va, PAGESIZE);
    		uint32_t zva = phs->p_va + phs->p_filesz;
    		uint32_t eva = ROUNDUP(phs->p_va + phs->p_memsz, PAGESIZE);

    		uint32_t perm = SYS_READ | PTE_P | PTE_U;
    		if(phs->p_flags & ELF_PROG_FLAG_WRITE) perm |= SYS_WRITE | PTE_W;

    		for (; va < eva; va += PAGESIZE, fa += PAGESIZE) 
		{
    			pageinfo *pi = mem_alloc(); assert(pi != NULL);
      			if(va < ROUNDDOWN(zva, PAGESIZE))
        			memmove(mem_pi2ptr(pi), fa, PAGESIZE);
      			else if (va < zva && phs->p_filesz)
			{
      				memset(mem_pi2ptr(pi),0, PAGESIZE);
      				memmove(mem_pi2ptr(pi), fa, zva-va);
      			} 
			else
        			memset(mem_pi2ptr(pi), 0, PAGESIZE);

      			pte_t *pte = pmap_insert(root->pdir, pi, va, perm);
      			assert(pte != NULL);
      		}
      }

      root->sv.tf.eip = ehs->e_entry;
      root->sv.tf.eflags |= FL_IF;

      pageinfo *pi = mem_alloc(); assert(pi != NULL);
      pte_t *pte = pmap_insert(root->pdir, pi, VM_STACKHI-PAGESIZE,
      SYS_READ | SYS_WRITE | PTE_P | PTE_U | PTE_W);

      assert(pte != NULL);
      root->sv.tf.esp = VM_STACKHI;

      proc_ready(root);
      proc_sched();
	// Initialize the I/O system.

	// Lab 1: change this so it enters user() in user mode,
	// running on the user_stack declared above,
	// instead of just calling user() directly.
	user(); // FIXME: Maybe get rid of this
}