#include        "u.h"
#include        "../port/lib.h"
#include        "mem.h"
#include        "dat.h"
#include        "fns.h"
#include        "../port/error.h"

/*
* The initcode array contains the binary text of the first
* user process. Its job is to invoke the exec system call
* for /boot/boot.
* Initcode does not link with standard plan9 libc _main()
* trampoline due to size constrains. Instead it is linked
* with a small machine specific trampoline init9.s that
* only sets the base address register and passes arguments
* to startboot() (see port/initcode.c).
*/
#include        "initcode.i"

/*
* The first process kernel process starts here.
*/
static void
proc0(void*)
{
       KMap *k;
       Page *p;

       spllo();

       up->pgrp = newpgrp();
       up->egrp = smalloc(sizeof(Egrp));
       up->egrp->ref = 1;
       up->fgrp = dupfgrp(nil);
       up->rgrp = newrgrp();

       /*
        * These are o.k. because rootinit is null.
        * Then early kproc's will have a root and dot.
        */
       up->slash = namec("#/", Atodir, 0, 0);
       pathclose(up->slash->path);
       up->slash->path = newpath("/");
       up->dot = cclone(up->slash);

       /*
        * Setup Text and Stack segments for initcode.
        */
       up->seg[SSEG] = newseg(SG_STACK | SG_NOEXEC, USTKTOP-USTKSIZE, USTKSIZE / BY2PG);
       up->seg[TSEG] = newseg(SG_TEXT | SG_RONLY, UTZERO, 1);
       p = newpage(1, 0, UTZERO);
       k = kmap(p);
       memmove((void*)VA(k), initcode, sizeof(initcode));
       kunmap(k);
       p->txtflush = ~0;
       segpage(up->seg[TSEG], p);
       up->seg[TSEG]->flushme = 1;

       /*
        * Become a user process.
        */
       up->kp = 0;
       up->noswap = 0;
       up->privatemem = 0;
       procpriority(up, PriNormal, 0);
       procsetup(up);

       flushmmu();

       /*
        * init0():
        *      call chandevinit()
        *      setup environment variables
        *      prepare the stack for initcode
        *      switch to usermode to run initcode
        */
       init0();

       /* init0 will never return */
       panic("init0");
}

void
userinit(void)
{
       up = nil;
       kstrdup(&eve, "");
       kproc("*init*", proc0, nil);
}