18e32b400SDavid du Colombier #include "u.h"
28e32b400SDavid du Colombier #include "../port/lib.h"
38e32b400SDavid du Colombier #include "mem.h"
48e32b400SDavid du Colombier #include "dat.h"
58e32b400SDavid du Colombier #include "fns.h"
68e32b400SDavid du Colombier #include "io.h"
78e32b400SDavid du Colombier
88e32b400SDavid du Colombier #include "init.h"
98e32b400SDavid du Colombier #include <pool.h>
10*23a96966SDavid du Colombier #include <tos.h>
118e32b400SDavid du Colombier
128e32b400SDavid du Colombier #include "reboot.h"
138e32b400SDavid du Colombier
148e32b400SDavid du Colombier /*
158e32b400SDavid du Colombier * Where configuration info is left for the loaded programme.
168e32b400SDavid du Colombier * This will turn into a structure as more is done by the boot loader
178e32b400SDavid du Colombier * (e.g. why parse the .ini file twice?).
188e32b400SDavid du Colombier * There are 3584 bytes available at CONFADDR.
198e32b400SDavid du Colombier */
208e32b400SDavid du Colombier #define BOOTARGS ((char*)CONFADDR)
218e32b400SDavid du Colombier #define BOOTARGSLEN (16*KiB) /* limit in devenv.c */
228e32b400SDavid du Colombier #define MAXCONF 64
238e32b400SDavid du Colombier #define MAXCONFLINE 160
248e32b400SDavid du Colombier
25add6b5c5SDavid du Colombier enum {
26add6b5c5SDavid du Colombier Minmem = 256*MB, /* conservative default */
27*23a96966SDavid du Colombier
28*23a96966SDavid du Colombier /* space for syscall args, return PC, top-of-stack struct */
29*23a96966SDavid du Colombier Ustkheadroom = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
30add6b5c5SDavid du Colombier };
31add6b5c5SDavid du Colombier
32*23a96966SDavid du Colombier
338e32b400SDavid du Colombier #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
348e32b400SDavid du Colombier
358e32b400SDavid du Colombier uintptr kseg0 = KZERO;
368e32b400SDavid du Colombier Mach* machaddr[MAXMACH];
378e32b400SDavid du Colombier
388e32b400SDavid du Colombier /*
398e32b400SDavid du Colombier * Option arguments from the command line.
408e32b400SDavid du Colombier * oargv[0] is the boot file.
418e32b400SDavid du Colombier * Optionsinit() is called from multiboot()
428e32b400SDavid du Colombier * or some other machine-dependent place
438e32b400SDavid du Colombier * to set it all up.
448e32b400SDavid du Colombier */
458e32b400SDavid du Colombier static int oargc;
468e32b400SDavid du Colombier static char* oargv[20];
478e32b400SDavid du Colombier static char oargb[128];
488e32b400SDavid du Colombier static int oargblen;
498e32b400SDavid du Colombier static char oenv[4096];
508e32b400SDavid du Colombier
518e32b400SDavid du Colombier static uintptr sp; /* XXX - must go - user stack of init proc */
528e32b400SDavid du Colombier
538e32b400SDavid du Colombier int vflag;
548e32b400SDavid du Colombier int normalprint;
558e32b400SDavid du Colombier char debug[256];
568e32b400SDavid du Colombier
578e32b400SDavid du Colombier /* store plan9.ini contents here at least until we stash them in #ec */
588e32b400SDavid du Colombier static char confname[MAXCONF][KNAMELEN];
598e32b400SDavid du Colombier static char confval[MAXCONF][MAXCONFLINE];
608e32b400SDavid du Colombier static int nconf;
618e32b400SDavid du Colombier
628e32b400SDavid du Colombier static int
findconf(char * name)638e32b400SDavid du Colombier findconf(char *name)
648e32b400SDavid du Colombier {
658e32b400SDavid du Colombier int i;
668e32b400SDavid du Colombier
678e32b400SDavid du Colombier for(i = 0; i < nconf; i++)
688e32b400SDavid du Colombier if(cistrcmp(confname[i], name) == 0)
698e32b400SDavid du Colombier return i;
708e32b400SDavid du Colombier return -1;
718e32b400SDavid du Colombier }
728e32b400SDavid du Colombier
738e32b400SDavid du Colombier char*
getconf(char * name)748e32b400SDavid du Colombier getconf(char *name)
758e32b400SDavid du Colombier {
768e32b400SDavid du Colombier int i;
778e32b400SDavid du Colombier
788e32b400SDavid du Colombier i = findconf(name);
798e32b400SDavid du Colombier if(i >= 0)
808e32b400SDavid du Colombier return confval[i];
818e32b400SDavid du Colombier return nil;
828e32b400SDavid du Colombier }
838e32b400SDavid du Colombier
848e32b400SDavid du Colombier void
addconf(char * name,char * val)858e32b400SDavid du Colombier addconf(char *name, char *val)
868e32b400SDavid du Colombier {
878e32b400SDavid du Colombier int i;
888e32b400SDavid du Colombier
898e32b400SDavid du Colombier i = findconf(name);
908e32b400SDavid du Colombier if(i < 0){
918e32b400SDavid du Colombier if(val == nil || nconf >= MAXCONF)
928e32b400SDavid du Colombier return;
938e32b400SDavid du Colombier i = nconf++;
948e32b400SDavid du Colombier strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
958e32b400SDavid du Colombier }
968e32b400SDavid du Colombier // confval[i] = val;
978e32b400SDavid du Colombier strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
988e32b400SDavid du Colombier }
998e32b400SDavid du Colombier
1008e32b400SDavid du Colombier static void
writeconf(void)1018e32b400SDavid du Colombier writeconf(void)
1028e32b400SDavid du Colombier {
1038e32b400SDavid du Colombier char *p, *q;
1048e32b400SDavid du Colombier int n;
1058e32b400SDavid du Colombier
1068e32b400SDavid du Colombier p = getconfenv();
1078e32b400SDavid du Colombier
1088e32b400SDavid du Colombier if(waserror()) {
1098e32b400SDavid du Colombier free(p);
1108e32b400SDavid du Colombier nexterror();
1118e32b400SDavid du Colombier }
1128e32b400SDavid du Colombier
1138e32b400SDavid du Colombier /* convert to name=value\n format */
1148e32b400SDavid du Colombier for(q=p; *q; q++) {
1158e32b400SDavid du Colombier q += strlen(q);
1168e32b400SDavid du Colombier *q = '=';
1178e32b400SDavid du Colombier q += strlen(q);
1188e32b400SDavid du Colombier *q = '\n';
1198e32b400SDavid du Colombier }
1208e32b400SDavid du Colombier n = q - p + 1;
1218e32b400SDavid du Colombier if(n >= BOOTARGSLEN)
1228e32b400SDavid du Colombier error("kernel configuration too large");
1238e32b400SDavid du Colombier memmove(BOOTARGS, p, n);
12493631029SDavid du Colombier memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
1258e32b400SDavid du Colombier poperror();
1268e32b400SDavid du Colombier free(p);
1278e32b400SDavid du Colombier }
1288e32b400SDavid du Colombier
1298e32b400SDavid du Colombier /*
1308e32b400SDavid du Colombier * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
1318e32b400SDavid du Colombier * tftp in u-boot. no longer uses malloc, so can be called early.
1328e32b400SDavid du Colombier */
1338e32b400SDavid du Colombier static void
plan9iniinit(void)1348e32b400SDavid du Colombier plan9iniinit(void)
1358e32b400SDavid du Colombier {
1368e32b400SDavid du Colombier char *k, *v, *next;
1378e32b400SDavid du Colombier
1388e32b400SDavid du Colombier k = (char *)CONFADDR;
1398e32b400SDavid du Colombier if(!isascii(*k))
1408e32b400SDavid du Colombier return;
1418e32b400SDavid du Colombier
1428e32b400SDavid du Colombier for(; k && *k != '\0'; k = next) {
1438e32b400SDavid du Colombier if (!isascii(*k)) /* sanity check */
1448e32b400SDavid du Colombier break;
1458e32b400SDavid du Colombier next = strchr(k, '\n');
1468e32b400SDavid du Colombier if (next)
1478e32b400SDavid du Colombier *next++ = '\0';
1488e32b400SDavid du Colombier
1498e32b400SDavid du Colombier if (*k == '\0' || *k == '\n' || *k == '#')
1508e32b400SDavid du Colombier continue;
1518e32b400SDavid du Colombier v = strchr(k, '=');
1528e32b400SDavid du Colombier if(v == nil)
1538e32b400SDavid du Colombier continue; /* mal-formed line */
1548e32b400SDavid du Colombier *v++ = '\0';
1558e32b400SDavid du Colombier
1568e32b400SDavid du Colombier addconf(k, v);
1578e32b400SDavid du Colombier }
1588e32b400SDavid du Colombier }
1598e32b400SDavid du Colombier
1608e32b400SDavid du Colombier static void
optionsinit(char * s)1618e32b400SDavid du Colombier optionsinit(char* s)
1628e32b400SDavid du Colombier {
1638e32b400SDavid du Colombier char *o;
1648e32b400SDavid du Colombier
1658e32b400SDavid du Colombier strcpy(oenv, "");
1668e32b400SDavid du Colombier o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
1678e32b400SDavid du Colombier if(getenv("bootargs", o, o - oargb) != nil)
1688e32b400SDavid du Colombier *(o-1) = ' ';
1698e32b400SDavid du Colombier
1708e32b400SDavid du Colombier oargblen = strlen(oargb);
1718e32b400SDavid du Colombier oargc = tokenize(oargb, oargv, nelem(oargv)-1);
1728e32b400SDavid du Colombier oargv[oargc] = nil;
1738e32b400SDavid du Colombier }
1748e32b400SDavid du Colombier
1758e32b400SDavid du Colombier char*
getenv(char * name,char * buf,int n)1768e32b400SDavid du Colombier getenv(char* name, char* buf, int n)
1778e32b400SDavid du Colombier {
1788e32b400SDavid du Colombier char *e, *p, *q;
1798e32b400SDavid du Colombier
1808e32b400SDavid du Colombier p = oenv;
1818e32b400SDavid du Colombier while(*p != 0){
1828e32b400SDavid du Colombier if((e = strchr(p, '=')) == nil)
1838e32b400SDavid du Colombier break;
1848e32b400SDavid du Colombier for(q = name; p < e; p++){
1858e32b400SDavid du Colombier if(*p != *q)
1868e32b400SDavid du Colombier break;
1878e32b400SDavid du Colombier q++;
1888e32b400SDavid du Colombier }
1898e32b400SDavid du Colombier if(p == e && *q == 0){
1908e32b400SDavid du Colombier strecpy(buf, buf+n, e+1);
1918e32b400SDavid du Colombier return buf;
1928e32b400SDavid du Colombier }
1938e32b400SDavid du Colombier p += strlen(p)+1;
1948e32b400SDavid du Colombier }
1958e32b400SDavid du Colombier
1968e32b400SDavid du Colombier return nil;
1978e32b400SDavid du Colombier }
1988e32b400SDavid du Colombier
1998e32b400SDavid du Colombier void
main(void)2008e32b400SDavid du Colombier main(void)
2018e32b400SDavid du Colombier {
2028e32b400SDavid du Colombier // int i;
2038e32b400SDavid du Colombier extern char bdata[], edata[], end[], etext[];
2048e32b400SDavid du Colombier static ulong vfy = 0xcafebabe;
2058e32b400SDavid du Colombier
2068e32b400SDavid du Colombier /* l.s has already printed "Plan 9 from Be" */
2078e32b400SDavid du Colombier // m = mach; /* now done in l.s */
2088e32b400SDavid du Colombier
2098e32b400SDavid du Colombier /* realign data seg; apparently -H0 -R4096 does not pad the text seg */
2108e32b400SDavid du Colombier if (vfy != 0xcafebabe) {
2118e32b400SDavid du Colombier // wave('<'); wave('-');
2128e32b400SDavid du Colombier memmove(bdata, etext, edata - bdata);
2138e32b400SDavid du Colombier }
2148e32b400SDavid du Colombier /*
2158e32b400SDavid du Colombier * once data segment is in place, always zero bss since we may
2168e32b400SDavid du Colombier * have been loaded by another Plan 9 kernel.
2178e32b400SDavid du Colombier */
2188e32b400SDavid du Colombier memset(edata, 0, end - edata); /* zero BSS */
2198e32b400SDavid du Colombier cacheuwbinv();
2208e32b400SDavid du Colombier l2cacheuwbinv();
2218e32b400SDavid du Colombier
2228e32b400SDavid du Colombier if (vfy != 0xcafebabe)
2238e32b400SDavid du Colombier panic("data segment misaligned");
2248e32b400SDavid du Colombier vfy = 0;
2258e32b400SDavid du Colombier
2268e32b400SDavid du Colombier wave('l');
2278e32b400SDavid du Colombier machinit();
2288e32b400SDavid du Colombier mmuinit();
2298e32b400SDavid du Colombier
2308e32b400SDavid du Colombier optionsinit("/boot/boot boot");
2318e32b400SDavid du Colombier quotefmtinstall();
2328e32b400SDavid du Colombier
2338e32b400SDavid du Colombier /* want plan9.ini to be able to affect memory sizing in confinit */
2348e32b400SDavid du Colombier plan9iniinit(); /* before we step on plan9.ini in low memory */
2358e32b400SDavid du Colombier
236add6b5c5SDavid du Colombier trapinit(); /* so confinit can probe memory to size it */
237add6b5c5SDavid du Colombier confinit(); /* figures out amount of memory */
2388e32b400SDavid du Colombier /* xinit prints (if it can), so finish up the banner here. */
23993631029SDavid du Colombier delay(500);
2408e32b400SDavid du Colombier iprint("l Labs\n\n");
24193631029SDavid du Colombier delay(500);
2428e32b400SDavid du Colombier xinit();
2438e32b400SDavid du Colombier
244add6b5c5SDavid du Colombier mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
245add6b5c5SDavid du Colombier
2468e32b400SDavid du Colombier /*
2478e32b400SDavid du Colombier * Printinit will cause the first malloc call.
2488e32b400SDavid du Colombier * (printinit->qopen->malloc) unless any of the
2498e32b400SDavid du Colombier * above (like clockinit) do an irqenable, which
2508e32b400SDavid du Colombier * will call malloc.
2518e32b400SDavid du Colombier * If the system dies here it's probably due
2528e32b400SDavid du Colombier * to malloc(->xalloc) not being initialised
2538e32b400SDavid du Colombier * correctly, or the data segment is misaligned
2548e32b400SDavid du Colombier * (it's amazing how far you can get with
2558e32b400SDavid du Colombier * things like that completely broken).
2568e32b400SDavid du Colombier *
2578e32b400SDavid du Colombier * (Should be) boilerplate from here on.
2588e32b400SDavid du Colombier */
2598e32b400SDavid du Colombier
26093631029SDavid du Colombier archreset(); /* configure clock signals */
2618e32b400SDavid du Colombier clockinit(); /* start clocks */
2628e32b400SDavid du Colombier timersinit();
2638e32b400SDavid du Colombier watchdoginit();
2648e32b400SDavid du Colombier
26593631029SDavid du Colombier delay(250); /* let uart catch up */
2668e32b400SDavid du Colombier printinit();
26793631029SDavid du Colombier kbdenable();
2688bfb44c2SDavid du Colombier
2698bfb44c2SDavid du Colombier cpuidprint();
2708bfb44c2SDavid du Colombier // chkmissing();
2718e32b400SDavid du Colombier
2728e32b400SDavid du Colombier procinit0();
2738e32b400SDavid du Colombier initseg();
2748e32b400SDavid du Colombier
2758e32b400SDavid du Colombier dmainit();
2768e32b400SDavid du Colombier links();
27793631029SDavid du Colombier conf.monitor = 1;
27893631029SDavid du Colombier screeninit();
27993631029SDavid du Colombier chandevreset(); /* most devices are discovered here */
28093631029SDavid du Colombier
28193631029SDavid du Colombier // i8250console(); /* too early; see init0 */
2828e32b400SDavid du Colombier
2838e32b400SDavid du Colombier pageinit();
2848e32b400SDavid du Colombier swapinit();
2858e32b400SDavid du Colombier userinit();
2868e32b400SDavid du Colombier schedinit();
2878e32b400SDavid du Colombier }
2888e32b400SDavid du Colombier
2898e32b400SDavid du Colombier void
machinit(void)2908e32b400SDavid du Colombier machinit(void)
2918e32b400SDavid du Colombier {
2928e32b400SDavid du Colombier if (m == 0)
2938e32b400SDavid du Colombier wave('?');
2948e32b400SDavid du Colombier // memset(m, 0, sizeof(Mach)); /* done by l.s, now contains stack */
2958e32b400SDavid du Colombier m->machno = 0;
2968e32b400SDavid du Colombier machaddr[m->machno] = m;
2978e32b400SDavid du Colombier
2988e32b400SDavid du Colombier m->ticks = 1;
2998e32b400SDavid du Colombier m->perf.period = 1;
3008e32b400SDavid du Colombier
3018e32b400SDavid du Colombier conf.nmach = 1;
3028e32b400SDavid du Colombier
3038e32b400SDavid du Colombier active.machs = 1;
3048e32b400SDavid du Colombier active.exiting = 0;
3058e32b400SDavid du Colombier
3068e32b400SDavid du Colombier up = nil;
3078e32b400SDavid du Colombier }
3088e32b400SDavid du Colombier
3098e32b400SDavid du Colombier static void
shutdown(int ispanic)3108e32b400SDavid du Colombier shutdown(int ispanic)
3118e32b400SDavid du Colombier {
3128e32b400SDavid du Colombier int ms, once;
3138e32b400SDavid du Colombier
3148e32b400SDavid du Colombier lock(&active);
3158e32b400SDavid du Colombier if(ispanic)
3168e32b400SDavid du Colombier active.ispanic = ispanic;
3178e32b400SDavid du Colombier else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
3188e32b400SDavid du Colombier active.ispanic = 0;
3198e32b400SDavid du Colombier once = active.machs & (1<<m->machno);
3208e32b400SDavid du Colombier active.machs &= ~(1<<m->machno);
3218e32b400SDavid du Colombier active.exiting = 1;
3228e32b400SDavid du Colombier unlock(&active);
3238e32b400SDavid du Colombier
3248e32b400SDavid du Colombier if(once)
3258e32b400SDavid du Colombier iprint("cpu%d: exiting\n", m->machno);
3268e32b400SDavid du Colombier spllo();
3278e32b400SDavid du Colombier for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
3288e32b400SDavid du Colombier delay(TK2MS(2));
3298e32b400SDavid du Colombier if(active.machs == 0 && consactive() == 0)
3308e32b400SDavid du Colombier break;
3318e32b400SDavid du Colombier }
3328e32b400SDavid du Colombier delay(1000);
3338e32b400SDavid du Colombier }
3348e32b400SDavid du Colombier
3358e32b400SDavid du Colombier /*
3368e32b400SDavid du Colombier * exit kernel either on a panic or user request
3378e32b400SDavid du Colombier */
3388e32b400SDavid du Colombier void
exit(int code)3398e32b400SDavid du Colombier exit(int code)
3408e32b400SDavid du Colombier {
3418e32b400SDavid du Colombier shutdown(code);
3428e32b400SDavid du Colombier splhi();
3438e32b400SDavid du Colombier archreboot();
3448e32b400SDavid du Colombier }
3458e32b400SDavid du Colombier
3468e32b400SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)3478e32b400SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
3488e32b400SDavid du Colombier {
3498e32b400SDavid du Colombier char cc[32], *p;
3508e32b400SDavid du Colombier int i;
3518e32b400SDavid du Colombier
3528e32b400SDavid du Colombier snprint(cc, sizeof cc, "%s%d", class, ctlrno);
3538e32b400SDavid du Colombier p = getconf(cc);
3548e32b400SDavid du Colombier if(p == nil)
3558e32b400SDavid du Colombier return 0;
3568e32b400SDavid du Colombier
3578e32b400SDavid du Colombier isa->type = "";
3588e32b400SDavid du Colombier isa->nopt = tokenize(p, isa->opt, NISAOPT);
3598e32b400SDavid du Colombier for(i = 0; i < isa->nopt; i++){
3608e32b400SDavid du Colombier p = isa->opt[i];
3618e32b400SDavid du Colombier if(cistrncmp(p, "type=", 5) == 0)
3628e32b400SDavid du Colombier isa->type = p + 5;
3638e32b400SDavid du Colombier else if(cistrncmp(p, "port=", 5) == 0)
3648e32b400SDavid du Colombier isa->port = strtoul(p+5, &p, 0);
3658e32b400SDavid du Colombier else if(cistrncmp(p, "irq=", 4) == 0)
3668e32b400SDavid du Colombier isa->irq = strtoul(p+4, &p, 0);
3678e32b400SDavid du Colombier else if(cistrncmp(p, "dma=", 4) == 0)
3688e32b400SDavid du Colombier isa->dma = strtoul(p+4, &p, 0);
3698e32b400SDavid du Colombier else if(cistrncmp(p, "mem=", 4) == 0)
3708e32b400SDavid du Colombier isa->mem = strtoul(p+4, &p, 0);
3718e32b400SDavid du Colombier else if(cistrncmp(p, "size=", 5) == 0)
3728e32b400SDavid du Colombier isa->size = strtoul(p+5, &p, 0);
3738e32b400SDavid du Colombier else if(cistrncmp(p, "freq=", 5) == 0)
3748e32b400SDavid du Colombier isa->freq = strtoul(p+5, &p, 0);
3758e32b400SDavid du Colombier }
3768e32b400SDavid du Colombier return 1;
3778e32b400SDavid du Colombier }
3788e32b400SDavid du Colombier
3798e32b400SDavid du Colombier /*
3808e32b400SDavid du Colombier * the new kernel is already loaded at address `code'
3818e32b400SDavid du Colombier * of size `size' and entry point `entry'.
3828e32b400SDavid du Colombier */
3838e32b400SDavid du Colombier void
reboot(void * entry,void * code,ulong size)3848e32b400SDavid du Colombier reboot(void *entry, void *code, ulong size)
3858e32b400SDavid du Colombier {
3868e32b400SDavid du Colombier void (*f)(ulong, ulong, ulong);
3878e32b400SDavid du Colombier
3888e32b400SDavid du Colombier print("starting reboot...");
3898e32b400SDavid du Colombier writeconf();
3908e32b400SDavid du Colombier shutdown(0);
3918e32b400SDavid du Colombier
3928e32b400SDavid du Colombier /*
3938e32b400SDavid du Colombier * should be the only processor running now
3948e32b400SDavid du Colombier */
3958e32b400SDavid du Colombier
3968e32b400SDavid du Colombier print("reboot entry %#lux code %#lux size %ld\n",
3978e32b400SDavid du Colombier PADDR(entry), PADDR(code), size);
3988e32b400SDavid du Colombier delay(100);
3998e32b400SDavid du Colombier
4008e32b400SDavid du Colombier /* turn off buffered serial console */
4018e32b400SDavid du Colombier serialoq = nil;
4028e32b400SDavid du Colombier kprintoq = nil;
4038e32b400SDavid du Colombier screenputs = nil;
4048e32b400SDavid du Colombier
4058e32b400SDavid du Colombier /* shutdown devices */
4068e32b400SDavid du Colombier chandevshutdown();
4078e32b400SDavid du Colombier
4088e32b400SDavid du Colombier /* call off the dog */
4098e32b400SDavid du Colombier clockshutdown();
4108e32b400SDavid du Colombier
4118e32b400SDavid du Colombier splhi();
4128e32b400SDavid du Colombier intrsoff();
4138e32b400SDavid du Colombier
4148e32b400SDavid du Colombier /* setup reboot trampoline function */
4158e32b400SDavid du Colombier f = (void*)REBOOTADDR;
4168e32b400SDavid du Colombier memmove(f, rebootcode, sizeof(rebootcode));
4178e32b400SDavid du Colombier cacheuwbinv();
4188e32b400SDavid du Colombier l2cacheuwbinv();
4198e32b400SDavid du Colombier
4208e32b400SDavid du Colombier /* off we go - never to return */
4218e32b400SDavid du Colombier (*f)(PADDR(entry), PADDR(code), size);
4228e32b400SDavid du Colombier
4238e32b400SDavid du Colombier iprint("loaded kernel returned!\n");
4248e32b400SDavid du Colombier delay(1000);
4258e32b400SDavid du Colombier archreboot();
4268e32b400SDavid du Colombier }
4278e32b400SDavid du Colombier
4288e32b400SDavid du Colombier /*
4298e32b400SDavid du Colombier * starting place for first process
4308e32b400SDavid du Colombier */
4318e32b400SDavid du Colombier void
init0(void)4328e32b400SDavid du Colombier init0(void)
4338e32b400SDavid du Colombier {
4348e32b400SDavid du Colombier int i;
4358e32b400SDavid du Colombier char buf[2*KNAMELEN];
4368e32b400SDavid du Colombier
4378e32b400SDavid du Colombier up->nerrlab = 0;
4388e32b400SDavid du Colombier coherence();
4398e32b400SDavid du Colombier spllo();
4408e32b400SDavid du Colombier
4418e32b400SDavid du Colombier /*
4428e32b400SDavid du Colombier * These are o.k. because rootinit is null.
4438e32b400SDavid du Colombier * Then early kproc's will have a root and dot.
4448e32b400SDavid du Colombier */
4458e32b400SDavid du Colombier up->slash = namec("#/", Atodir, 0, 0);
4468e32b400SDavid du Colombier pathclose(up->slash->path);
4478e32b400SDavid du Colombier up->slash->path = newpath("/");
4488e32b400SDavid du Colombier up->dot = cclone(up->slash);
4498e32b400SDavid du Colombier
4508e32b400SDavid du Colombier dmatest(); /* needs `up' set, so can't do it earlier */
4518e32b400SDavid du Colombier chandevinit();
45293631029SDavid du Colombier i8250console(); /* might be redundant, but harmless */
45393631029SDavid du Colombier if(kbdq == nil)
45493631029SDavid du Colombier panic("init0: nil kbdq");
45593631029SDavid du Colombier if(serialoq == nil)
45693631029SDavid du Colombier panic("init0: nil serialoq");
457bacfa46cSDavid du Colombier normalprint = 1;
4588e32b400SDavid du Colombier
4598e32b400SDavid du Colombier if(!waserror()){
4608e32b400SDavid du Colombier snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
4618e32b400SDavid du Colombier ksetenv("terminal", buf, 0);
4628e32b400SDavid du Colombier ksetenv("cputype", "arm", 0);
4638e32b400SDavid du Colombier if(cpuserver)
4648e32b400SDavid du Colombier ksetenv("service", "cpu", 0);
4658e32b400SDavid du Colombier else
4668e32b400SDavid du Colombier ksetenv("service", "terminal", 0);
4678e32b400SDavid du Colombier
4688e32b400SDavid du Colombier /* convert plan9.ini variables to #e and #ec */
4698e32b400SDavid du Colombier for(i = 0; i < nconf; i++) {
4708e32b400SDavid du Colombier ksetenv(confname[i], confval[i], 0);
4718e32b400SDavid du Colombier ksetenv(confname[i], confval[i], 1);
4728e32b400SDavid du Colombier }
4738e32b400SDavid du Colombier poperror();
4748e32b400SDavid du Colombier }
4758e32b400SDavid du Colombier kproc("alarm", alarmkproc, 0);
4768e32b400SDavid du Colombier touser(sp);
4778e32b400SDavid du Colombier }
4788e32b400SDavid du Colombier
4798e32b400SDavid du Colombier static void
bootargs(uintptr base)4808e32b400SDavid du Colombier bootargs(uintptr base)
4818e32b400SDavid du Colombier {
4828e32b400SDavid du Colombier int i;
4838e32b400SDavid du Colombier ulong ssize;
4848e32b400SDavid du Colombier char **av, *p;
4858e32b400SDavid du Colombier
4868e32b400SDavid du Colombier /*
4878e32b400SDavid du Colombier * Push the boot args onto the stack.
4888e32b400SDavid du Colombier * The initial value of the user stack must be such
4898e32b400SDavid du Colombier * that the total used is larger than the maximum size
4908e32b400SDavid du Colombier * of the argument list checked in syscall.
4918e32b400SDavid du Colombier */
4928e32b400SDavid du Colombier i = oargblen+1;
493*23a96966SDavid du Colombier p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
4948e32b400SDavid du Colombier memmove(p, oargb, i);
4958e32b400SDavid du Colombier
4968e32b400SDavid du Colombier /*
4978e32b400SDavid du Colombier * Now push argc and the argv pointers.
4988e32b400SDavid du Colombier * This isn't strictly correct as the code jumped to by
4998e32b400SDavid du Colombier * touser in init9.s calls startboot (port/initcode.c) which
5008e32b400SDavid du Colombier * expects arguments
5018e32b400SDavid du Colombier * startboot(char *argv0, char **argv)
5028e32b400SDavid du Colombier * not the usual (int argc, char* argv[]), but argv0 is
5038e32b400SDavid du Colombier * unused so it doesn't matter (at the moment...).
5048e32b400SDavid du Colombier */
5058e32b400SDavid du Colombier av = (char**)(p - (oargc+2)*sizeof(char*));
506b1c4f505SDavid du Colombier ssize = base + BY2PG - PTR2UINT(av);
5078e32b400SDavid du Colombier *av++ = (char*)oargc;
5088e32b400SDavid du Colombier for(i = 0; i < oargc; i++)
5098e32b400SDavid du Colombier *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
5108e32b400SDavid du Colombier *av = nil;
5118e32b400SDavid du Colombier
5128e32b400SDavid du Colombier /*
5138e32b400SDavid du Colombier * Leave space for the return PC of the
5148e32b400SDavid du Colombier * caller of initcode.
5158e32b400SDavid du Colombier */
5168e32b400SDavid du Colombier sp = USTKTOP - ssize - sizeof(void*);
5178e32b400SDavid du Colombier }
5188e32b400SDavid du Colombier
5198e32b400SDavid du Colombier /*
5208e32b400SDavid du Colombier * create the first process
5218e32b400SDavid du Colombier */
5228e32b400SDavid du Colombier void
userinit(void)5238e32b400SDavid du Colombier userinit(void)
5248e32b400SDavid du Colombier {
5258e32b400SDavid du Colombier Proc *p;
5268e32b400SDavid du Colombier Segment *s;
5278e32b400SDavid du Colombier KMap *k;
5288e32b400SDavid du Colombier Page *pg;
5298e32b400SDavid du Colombier
5308e32b400SDavid du Colombier /* no processes yet */
5318e32b400SDavid du Colombier up = nil;
5328e32b400SDavid du Colombier
5338e32b400SDavid du Colombier p = newproc();
5348e32b400SDavid du Colombier p->pgrp = newpgrp();
5358e32b400SDavid du Colombier p->egrp = smalloc(sizeof(Egrp));
5368e32b400SDavid du Colombier p->egrp->ref = 1;
5378e32b400SDavid du Colombier p->fgrp = dupfgrp(nil);
5388e32b400SDavid du Colombier p->rgrp = newrgrp();
5398e32b400SDavid du Colombier p->procmode = 0640;
5408e32b400SDavid du Colombier
5418e32b400SDavid du Colombier kstrdup(&eve, "");
5428e32b400SDavid du Colombier kstrdup(&p->text, "*init*");
5438e32b400SDavid du Colombier kstrdup(&p->user, eve);
5448e32b400SDavid du Colombier
5458e32b400SDavid du Colombier /*
5468e32b400SDavid du Colombier * Kernel Stack
5478e32b400SDavid du Colombier */
5488e32b400SDavid du Colombier p->sched.pc = PTR2UINT(init0);
5498e32b400SDavid du Colombier p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
5508e32b400SDavid du Colombier p->sched.sp = STACKALIGN(p->sched.sp);
5518e32b400SDavid du Colombier
5528e32b400SDavid du Colombier /*
5538e32b400SDavid du Colombier * User Stack
5548e32b400SDavid du Colombier *
5558e32b400SDavid du Colombier * Technically, newpage can't be called here because it
5568e32b400SDavid du Colombier * should only be called when in a user context as it may
5578e32b400SDavid du Colombier * try to sleep if there are no pages available, but that
5588e32b400SDavid du Colombier * shouldn't be the case here.
5598e32b400SDavid du Colombier */
5608e32b400SDavid du Colombier s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
5618e32b400SDavid du Colombier s->flushme++;
5628e32b400SDavid du Colombier p->seg[SSEG] = s;
5638e32b400SDavid du Colombier pg = newpage(1, 0, USTKTOP-BY2PG);
5648e32b400SDavid du Colombier segpage(s, pg);
5658e32b400SDavid du Colombier k = kmap(pg);
5668e32b400SDavid du Colombier bootargs(VA(k));
5678e32b400SDavid du Colombier kunmap(k);
5688e32b400SDavid du Colombier
5698e32b400SDavid du Colombier /*
5708e32b400SDavid du Colombier * Text
5718e32b400SDavid du Colombier */
5728e32b400SDavid du Colombier s = newseg(SG_TEXT, UTZERO, 1);
5738e32b400SDavid du Colombier p->seg[TSEG] = s;
5748e32b400SDavid du Colombier pg = newpage(1, 0, UTZERO);
5758e32b400SDavid du Colombier memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
5768e32b400SDavid du Colombier segpage(s, pg);
5778e32b400SDavid du Colombier k = kmap(s->map[0]->pages[0]);
5788e32b400SDavid du Colombier memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
5798e32b400SDavid du Colombier kunmap(k);
5808e32b400SDavid du Colombier
5818e32b400SDavid du Colombier ready(p);
5828e32b400SDavid du Colombier }
5838e32b400SDavid du Colombier
5848e32b400SDavid du Colombier Conf conf; /* XXX - must go - gag */
5858e32b400SDavid du Colombier
5868e32b400SDavid du Colombier Confmem omapmem[nelem(conf.mem)] = {
5878e32b400SDavid du Colombier /*
5888e32b400SDavid du Colombier * Memory available to Plan 9:
5898e32b400SDavid du Colombier */
590add6b5c5SDavid du Colombier { .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
5918e32b400SDavid du Colombier };
592add6b5c5SDavid du Colombier ulong memsize = Minmem;
593add6b5c5SDavid du Colombier
594add6b5c5SDavid du Colombier static int
gotmem(uintptr sz)595add6b5c5SDavid du Colombier gotmem(uintptr sz)
596add6b5c5SDavid du Colombier {
597add6b5c5SDavid du Colombier uintptr addr;
598add6b5c5SDavid du Colombier
599add6b5c5SDavid du Colombier addr = PHYSDRAM + sz - BY2WD;
600add6b5c5SDavid du Colombier mmuidmap(addr, 1);
601add6b5c5SDavid du Colombier if (probeaddr(addr) >= 0) {
602add6b5c5SDavid du Colombier memsize = sz;
603add6b5c5SDavid du Colombier return 0;
604add6b5c5SDavid du Colombier }
605add6b5c5SDavid du Colombier return -1;
606add6b5c5SDavid du Colombier }
6078e32b400SDavid du Colombier
6088e32b400SDavid du Colombier void
confinit(void)6098e32b400SDavid du Colombier confinit(void)
6108e32b400SDavid du Colombier {
6118e32b400SDavid du Colombier int i;
6128e32b400SDavid du Colombier ulong kpages;
6138e32b400SDavid du Colombier uintptr pa;
6148e32b400SDavid du Colombier char *p;
6158e32b400SDavid du Colombier
6168e32b400SDavid du Colombier /*
6178e32b400SDavid du Colombier * Copy the physical memory configuration to Conf.mem.
6188e32b400SDavid du Colombier */
6198e32b400SDavid du Colombier if(nelem(omapmem) > nelem(conf.mem)){
6208e32b400SDavid du Colombier iprint("memory configuration botch\n");
6218e32b400SDavid du Colombier exit(1);
6228e32b400SDavid du Colombier }
6238e32b400SDavid du Colombier if((p = getconf("*maxmem")) != nil) {
6248e32b400SDavid du Colombier memsize = strtoul(p, 0, 0) - PHYSDRAM;
6258e32b400SDavid du Colombier if (memsize < 16*MB) /* sanity */
6268e32b400SDavid du Colombier memsize = 16*MB;
6278e32b400SDavid du Colombier }
6288e32b400SDavid du Colombier
629add6b5c5SDavid du Colombier /*
630add6b5c5SDavid du Colombier * see if all that memory exists; if not, find out how much does.
631add6b5c5SDavid du Colombier * trapinit must have been called first.
632add6b5c5SDavid du Colombier */
633add6b5c5SDavid du Colombier if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
634add6b5c5SDavid du Colombier iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
635add6b5c5SDavid du Colombier memsize = Minmem;
636add6b5c5SDavid du Colombier }
637add6b5c5SDavid du Colombier
6388e32b400SDavid du Colombier omapmem[0].limit = PHYSDRAM + memsize;
6398e32b400SDavid du Colombier memmove(conf.mem, omapmem, sizeof(omapmem));
6408e32b400SDavid du Colombier
6418e32b400SDavid du Colombier conf.npage = 0;
6428e32b400SDavid du Colombier pa = PADDR(PGROUND(PTR2UINT(end)));
6438e32b400SDavid du Colombier
6448e32b400SDavid du Colombier /*
6458e32b400SDavid du Colombier * we assume that the kernel is at the beginning of one of the
6468e32b400SDavid du Colombier * contiguous chunks of memory and fits therein.
6478e32b400SDavid du Colombier */
6488e32b400SDavid du Colombier for(i=0; i<nelem(conf.mem); i++){
6498e32b400SDavid du Colombier /* take kernel out of allocatable space */
6508e32b400SDavid du Colombier if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
6518e32b400SDavid du Colombier conf.mem[i].base = pa;
6528e32b400SDavid du Colombier
6538e32b400SDavid du Colombier conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
6548e32b400SDavid du Colombier conf.npage += conf.mem[i].npage;
6558e32b400SDavid du Colombier }
6568e32b400SDavid du Colombier
6578e32b400SDavid du Colombier conf.upages = (conf.npage*80)/100;
6588e32b400SDavid du Colombier conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
6598e32b400SDavid du Colombier
6608e32b400SDavid du Colombier /* only one processor */
6618e32b400SDavid du Colombier conf.nmach = 1;
6628e32b400SDavid du Colombier
6638e32b400SDavid du Colombier /* set up other configuration parameters */
6648e32b400SDavid du Colombier conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
6658e32b400SDavid du Colombier if(cpuserver)
6668e32b400SDavid du Colombier conf.nproc *= 3;
6678e32b400SDavid du Colombier if(conf.nproc > 2000)
6688e32b400SDavid du Colombier conf.nproc = 2000;
6698e32b400SDavid du Colombier conf.nswap = conf.npage*3;
6708e32b400SDavid du Colombier conf.nswppo = 4096;
6718e32b400SDavid du Colombier conf.nimage = 200;
6728e32b400SDavid du Colombier
6738e32b400SDavid du Colombier conf.copymode = 0; /* copy on write */
6748e32b400SDavid du Colombier
6758e32b400SDavid du Colombier /*
6768e32b400SDavid du Colombier * Guess how much is taken by the large permanent
6778e32b400SDavid du Colombier * datastructures. Mntcache and Mntrpc are not accounted for
6788e32b400SDavid du Colombier * (probably ~300KB).
6798e32b400SDavid du Colombier */
6808e32b400SDavid du Colombier kpages = conf.npage - conf.upages;
6818e32b400SDavid du Colombier kpages *= BY2PG;
6828e32b400SDavid du Colombier kpages -= conf.upages*sizeof(Page)
6838e32b400SDavid du Colombier + conf.nproc*sizeof(Proc)
6848e32b400SDavid du Colombier + conf.nimage*sizeof(Image)
6858e32b400SDavid du Colombier + conf.nswap
6868e32b400SDavid du Colombier + conf.nswppo*sizeof(Page);
6878e32b400SDavid du Colombier mainmem->maxsize = kpages;
6888e32b400SDavid du Colombier if(!cpuserver)
6898e32b400SDavid du Colombier /*
6908e32b400SDavid du Colombier * give terminals lots of image memory, too; the dynamic
6918e32b400SDavid du Colombier * allocation will balance the load properly, hopefully.
6928e32b400SDavid du Colombier * be careful with 32-bit overflow.
6938e32b400SDavid du Colombier */
6948e32b400SDavid du Colombier imagmem->maxsize = kpages;
6958e32b400SDavid du Colombier
6968e32b400SDavid du Colombier // archconfinit();
6978e32b400SDavid du Colombier }
6988e32b400SDavid du Colombier
6998e32b400SDavid du Colombier int
cmpswap(long * addr,long old,long new)7008e32b400SDavid du Colombier cmpswap(long *addr, long old, long new)
7018e32b400SDavid du Colombier {
7028e32b400SDavid du Colombier return cas32(addr, old, new);
7038e32b400SDavid du Colombier }
704