13de6a9c0SDavid du Colombier #include "u.h"
23de6a9c0SDavid du Colombier #include "../port/lib.h"
33de6a9c0SDavid du Colombier #include "mem.h"
43de6a9c0SDavid du Colombier #include "dat.h"
53de6a9c0SDavid du Colombier #include "fns.h"
63de6a9c0SDavid du Colombier #include "io.h"
73de6a9c0SDavid du Colombier
83de6a9c0SDavid du Colombier #include "init.h"
93de6a9c0SDavid du Colombier #include <pool.h>
1023a96966SDavid du Colombier #include <tos.h>
113de6a9c0SDavid du Colombier
123de6a9c0SDavid du Colombier #include "arm.h"
133de6a9c0SDavid du Colombier #include "reboot.h"
143de6a9c0SDavid du Colombier
153de6a9c0SDavid du Colombier /*
163de6a9c0SDavid du Colombier * Where configuration info is left for the loaded programme.
173de6a9c0SDavid du Colombier * This will turn into a structure as more is done by the boot loader
183de6a9c0SDavid du Colombier * (e.g. why parse the .ini file twice?).
193de6a9c0SDavid du Colombier * There are 3584 bytes available at CONFADDR.
203de6a9c0SDavid du Colombier */
213de6a9c0SDavid du Colombier #define BOOTARGS ((char*)CONFADDR)
223de6a9c0SDavid du Colombier #define BOOTARGSLEN (16*KiB) /* limit in devenv.c */
233de6a9c0SDavid du Colombier #define MAXCONF 64
243de6a9c0SDavid du Colombier #define MAXCONFLINE 160
253de6a9c0SDavid du Colombier
263de6a9c0SDavid du Colombier enum {
273de6a9c0SDavid du Colombier Minmem = 256*MB, /* conservative default */
2823a96966SDavid du Colombier
2923a96966SDavid du Colombier /* space for syscall args, return PC, top-of-stack struct */
3023a96966SDavid du Colombier Ustkheadroom = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
313de6a9c0SDavid du Colombier };
323de6a9c0SDavid du Colombier
333de6a9c0SDavid du Colombier #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
343de6a9c0SDavid du Colombier
353de6a9c0SDavid du Colombier extern char bdata[], edata[], end[], etext[];
363de6a9c0SDavid du Colombier
373de6a9c0SDavid du Colombier uintptr kseg0 = KZERO;
383de6a9c0SDavid du Colombier Mach* machaddr[MAXMACH];
393de6a9c0SDavid du Colombier uchar *l2pages;
403de6a9c0SDavid du Colombier
413de6a9c0SDavid du Colombier Memcache cachel[8]; /* arm arch v7 supports 1-7 */
423de6a9c0SDavid du Colombier /*
433de6a9c0SDavid du Colombier * these are used by the cache.v7.s routines.
443de6a9c0SDavid du Colombier */
453de6a9c0SDavid du Colombier Lowmemcache *cacheconf;
463de6a9c0SDavid du Colombier
473de6a9c0SDavid du Colombier /*
483de6a9c0SDavid du Colombier * Option arguments from the command line.
493de6a9c0SDavid du Colombier * oargv[0] is the boot file.
503de6a9c0SDavid du Colombier * Optionsinit() is called from multiboot()
513de6a9c0SDavid du Colombier * or some other machine-dependent place
523de6a9c0SDavid du Colombier * to set it all up.
533de6a9c0SDavid du Colombier */
543de6a9c0SDavid du Colombier static int oargc;
553de6a9c0SDavid du Colombier static char* oargv[20];
563de6a9c0SDavid du Colombier static char oargb[128];
573de6a9c0SDavid du Colombier static int oargblen;
583de6a9c0SDavid du Colombier static char oenv[4096];
593de6a9c0SDavid du Colombier
603de6a9c0SDavid du Colombier static uintptr sp; /* XXX - must go - user stack of init proc */
613de6a9c0SDavid du Colombier
623de6a9c0SDavid du Colombier int vflag;
633de6a9c0SDavid du Colombier int normalprint;
643de6a9c0SDavid du Colombier char debug[256];
653de6a9c0SDavid du Colombier
663de6a9c0SDavid du Colombier static Lock testlock;
673de6a9c0SDavid du Colombier
683de6a9c0SDavid du Colombier /* store plan9.ini contents here at least until we stash them in #ec */
693de6a9c0SDavid du Colombier static char confname[MAXCONF][KNAMELEN];
703de6a9c0SDavid du Colombier static char confval[MAXCONF][MAXCONFLINE];
713de6a9c0SDavid du Colombier static int nconf;
723de6a9c0SDavid du Colombier
733de6a9c0SDavid du Colombier static int
findconf(char * name)743de6a9c0SDavid du Colombier findconf(char *name)
753de6a9c0SDavid du Colombier {
763de6a9c0SDavid du Colombier int i;
773de6a9c0SDavid du Colombier
783de6a9c0SDavid du Colombier for(i = 0; i < nconf; i++)
793de6a9c0SDavid du Colombier if(cistrcmp(confname[i], name) == 0)
803de6a9c0SDavid du Colombier return i;
813de6a9c0SDavid du Colombier return -1;
823de6a9c0SDavid du Colombier }
833de6a9c0SDavid du Colombier
843de6a9c0SDavid du Colombier char*
getconf(char * name)853de6a9c0SDavid du Colombier getconf(char *name)
863de6a9c0SDavid du Colombier {
873de6a9c0SDavid du Colombier int i;
883de6a9c0SDavid du Colombier
893de6a9c0SDavid du Colombier i = findconf(name);
903de6a9c0SDavid du Colombier if(i >= 0)
913de6a9c0SDavid du Colombier return confval[i];
923de6a9c0SDavid du Colombier return nil;
933de6a9c0SDavid du Colombier }
943de6a9c0SDavid du Colombier
953de6a9c0SDavid du Colombier void
addconf(char * name,char * val)963de6a9c0SDavid du Colombier addconf(char *name, char *val)
973de6a9c0SDavid du Colombier {
983de6a9c0SDavid du Colombier int i;
993de6a9c0SDavid du Colombier
1003de6a9c0SDavid du Colombier i = findconf(name);
1013de6a9c0SDavid du Colombier if(i < 0){
1023de6a9c0SDavid du Colombier if(val == nil || nconf >= MAXCONF)
1033de6a9c0SDavid du Colombier return;
1043de6a9c0SDavid du Colombier i = nconf++;
1053de6a9c0SDavid du Colombier strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
1063de6a9c0SDavid du Colombier }
1073de6a9c0SDavid du Colombier // confval[i] = val;
1083de6a9c0SDavid du Colombier strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
1093de6a9c0SDavid du Colombier }
1103de6a9c0SDavid du Colombier
1113de6a9c0SDavid du Colombier static void
writeconf(void)1123de6a9c0SDavid du Colombier writeconf(void)
1133de6a9c0SDavid du Colombier {
1143de6a9c0SDavid du Colombier char *p, *q;
1153de6a9c0SDavid du Colombier int n;
1163de6a9c0SDavid du Colombier
1173de6a9c0SDavid du Colombier p = getconfenv();
1183de6a9c0SDavid du Colombier
1193de6a9c0SDavid du Colombier if(waserror()) {
1203de6a9c0SDavid du Colombier free(p);
1213de6a9c0SDavid du Colombier nexterror();
1223de6a9c0SDavid du Colombier }
1233de6a9c0SDavid du Colombier
1243de6a9c0SDavid du Colombier /* convert to name=value\n format */
1253de6a9c0SDavid du Colombier for(q=p; *q; q++) {
1263de6a9c0SDavid du Colombier q += strlen(q);
1273de6a9c0SDavid du Colombier *q = '=';
1283de6a9c0SDavid du Colombier q += strlen(q);
1293de6a9c0SDavid du Colombier *q = '\n';
1303de6a9c0SDavid du Colombier }
1313de6a9c0SDavid du Colombier n = q - p + 1;
1323de6a9c0SDavid du Colombier if(n >= BOOTARGSLEN)
1333de6a9c0SDavid du Colombier error("kernel configuration too large");
1343de6a9c0SDavid du Colombier memmove(BOOTARGS, p, n);
1353de6a9c0SDavid du Colombier memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
1363de6a9c0SDavid du Colombier poperror();
1373de6a9c0SDavid du Colombier free(p);
1383de6a9c0SDavid du Colombier }
1393de6a9c0SDavid du Colombier
1403de6a9c0SDavid du Colombier /*
1413de6a9c0SDavid du Colombier * assumes that we have loaded our /cfg/pxe/mac file at CONFADDR
1423de6a9c0SDavid du Colombier * (usually 0x1000) with tftp in u-boot. no longer uses malloc, so
1433de6a9c0SDavid du Colombier * can be called early.
1443de6a9c0SDavid du Colombier */
1453de6a9c0SDavid du Colombier static void
plan9iniinit(void)1463de6a9c0SDavid du Colombier plan9iniinit(void)
1473de6a9c0SDavid du Colombier {
1483de6a9c0SDavid du Colombier char *k, *v, *next;
1493de6a9c0SDavid du Colombier
1503de6a9c0SDavid du Colombier k = (char *)CONFADDR;
1513de6a9c0SDavid du Colombier if(!isascii(*k))
1523de6a9c0SDavid du Colombier return;
1533de6a9c0SDavid du Colombier
1543de6a9c0SDavid du Colombier for(; k && *k != '\0'; k = next) {
1553de6a9c0SDavid du Colombier if (!isascii(*k)) /* sanity check */
1563de6a9c0SDavid du Colombier break;
1573de6a9c0SDavid du Colombier next = strchr(k, '\n');
1583de6a9c0SDavid du Colombier if (next)
1593de6a9c0SDavid du Colombier *next++ = '\0';
1603de6a9c0SDavid du Colombier
1613de6a9c0SDavid du Colombier if (*k == '\0' || *k == '\n' || *k == '#')
1623de6a9c0SDavid du Colombier continue;
1633de6a9c0SDavid du Colombier v = strchr(k, '=');
1643de6a9c0SDavid du Colombier if(v == nil)
1653de6a9c0SDavid du Colombier continue; /* mal-formed line */
1663de6a9c0SDavid du Colombier *v++ = '\0';
1673de6a9c0SDavid du Colombier
1683de6a9c0SDavid du Colombier addconf(k, v);
1693de6a9c0SDavid du Colombier }
1703de6a9c0SDavid du Colombier }
1713de6a9c0SDavid du Colombier
1723de6a9c0SDavid du Colombier static void
optionsinit(char * s)1733de6a9c0SDavid du Colombier optionsinit(char* s)
1743de6a9c0SDavid du Colombier {
1753de6a9c0SDavid du Colombier char *o;
1763de6a9c0SDavid du Colombier
1773de6a9c0SDavid du Colombier strcpy(oenv, "");
1783de6a9c0SDavid du Colombier o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
1793de6a9c0SDavid du Colombier if(getenv("bootargs", o, o - oargb) != nil)
1803de6a9c0SDavid du Colombier *(o-1) = ' ';
1813de6a9c0SDavid du Colombier
1823de6a9c0SDavid du Colombier oargblen = strlen(oargb);
1833de6a9c0SDavid du Colombier oargc = tokenize(oargb, oargv, nelem(oargv)-1);
1843de6a9c0SDavid du Colombier oargv[oargc] = nil;
1853de6a9c0SDavid du Colombier }
1863de6a9c0SDavid du Colombier
1873de6a9c0SDavid du Colombier char*
getenv(char * name,char * buf,int n)1883de6a9c0SDavid du Colombier getenv(char* name, char* buf, int n)
1893de6a9c0SDavid du Colombier {
1903de6a9c0SDavid du Colombier char *e, *p, *q;
1913de6a9c0SDavid du Colombier
1923de6a9c0SDavid du Colombier p = oenv;
1933de6a9c0SDavid du Colombier while(*p != 0){
1943de6a9c0SDavid du Colombier if((e = strchr(p, '=')) == nil)
1953de6a9c0SDavid du Colombier break;
1963de6a9c0SDavid du Colombier for(q = name; p < e; p++){
1973de6a9c0SDavid du Colombier if(*p != *q)
1983de6a9c0SDavid du Colombier break;
1993de6a9c0SDavid du Colombier q++;
2003de6a9c0SDavid du Colombier }
2013de6a9c0SDavid du Colombier if(p == e && *q == 0){
2023de6a9c0SDavid du Colombier strecpy(buf, buf+n, e+1);
2033de6a9c0SDavid du Colombier return buf;
2043de6a9c0SDavid du Colombier }
2053de6a9c0SDavid du Colombier p += strlen(p)+1;
2063de6a9c0SDavid du Colombier }
2073de6a9c0SDavid du Colombier
2083de6a9c0SDavid du Colombier return nil;
2093de6a9c0SDavid du Colombier }
2103de6a9c0SDavid du Colombier
2113de6a9c0SDavid du Colombier /* enable scheduling of this cpu */
2123de6a9c0SDavid du Colombier void
machon(uint cpu)2133de6a9c0SDavid du Colombier machon(uint cpu)
2143de6a9c0SDavid du Colombier {
2153de6a9c0SDavid du Colombier ulong cpubit;
2163de6a9c0SDavid du Colombier
2173de6a9c0SDavid du Colombier cpubit = 1 << cpu;
2183de6a9c0SDavid du Colombier lock(&active);
2193de6a9c0SDavid du Colombier if ((active.machs & cpubit) == 0) { /* currently off? */
2203de6a9c0SDavid du Colombier conf.nmach++;
2213de6a9c0SDavid du Colombier active.machs |= cpubit;
2223de6a9c0SDavid du Colombier }
2233de6a9c0SDavid du Colombier unlock(&active);
2243de6a9c0SDavid du Colombier }
2253de6a9c0SDavid du Colombier
2263de6a9c0SDavid du Colombier /* disable scheduling of this cpu */
2273de6a9c0SDavid du Colombier void
machoff(uint cpu)2283de6a9c0SDavid du Colombier machoff(uint cpu)
2293de6a9c0SDavid du Colombier {
2303de6a9c0SDavid du Colombier ulong cpubit;
2313de6a9c0SDavid du Colombier
2323de6a9c0SDavid du Colombier cpubit = 1 << cpu;
2333de6a9c0SDavid du Colombier lock(&active);
2343de6a9c0SDavid du Colombier if (active.machs & cpubit) { /* currently on? */
2353de6a9c0SDavid du Colombier conf.nmach--;
2363de6a9c0SDavid du Colombier active.machs &= ~cpubit;
2373de6a9c0SDavid du Colombier }
2383de6a9c0SDavid du Colombier unlock(&active);
2393de6a9c0SDavid du Colombier }
2403de6a9c0SDavid du Colombier
2413de6a9c0SDavid du Colombier void
machinit(void)2423de6a9c0SDavid du Colombier machinit(void)
2433de6a9c0SDavid du Colombier {
2443de6a9c0SDavid du Colombier Mach *m0;
2453de6a9c0SDavid du Colombier
2463de6a9c0SDavid du Colombier if (m == 0) {
2473de6a9c0SDavid du Colombier serialputc('?');
2483de6a9c0SDavid du Colombier serialputc('m');
2493de6a9c0SDavid du Colombier serialputc('0');
2503de6a9c0SDavid du Colombier }
2513de6a9c0SDavid du Colombier if(machaddr[m->machno] != m) {
2523de6a9c0SDavid du Colombier serialputc('?');
2533de6a9c0SDavid du Colombier serialputc('m');
2543de6a9c0SDavid du Colombier serialputc('m');
2553de6a9c0SDavid du Colombier }
2563de6a9c0SDavid du Colombier
2573de6a9c0SDavid du Colombier if (canlock(&testlock)) {
2583de6a9c0SDavid du Colombier serialputc('?');
2593de6a9c0SDavid du Colombier serialputc('l');
2603de6a9c0SDavid du Colombier panic("cpu%d: locks don't work", m->machno);
2613de6a9c0SDavid du Colombier }
2623de6a9c0SDavid du Colombier
2633de6a9c0SDavid du Colombier m->ticks = 1;
2643de6a9c0SDavid du Colombier m->perf.period = 1;
2653de6a9c0SDavid du Colombier m0 = MACHP(0);
2663de6a9c0SDavid du Colombier if (m->machno != 0) {
2673de6a9c0SDavid du Colombier /* synchronise with cpu 0 */
2683de6a9c0SDavid du Colombier m->ticks = m0->ticks;
2693de6a9c0SDavid du Colombier m->fastclock = m0->fastclock;
2703de6a9c0SDavid du Colombier m->cpuhz = m0->cpuhz;
2713de6a9c0SDavid du Colombier m->delayloop = m0->delayloop;
2723de6a9c0SDavid du Colombier }
2733de6a9c0SDavid du Colombier if (m->machno != 0 &&
2743de6a9c0SDavid du Colombier (m->fastclock == 0 || m->cpuhz == 0 || m->delayloop == 0))
2753de6a9c0SDavid du Colombier panic("buggered cpu 0 Mach");
2763de6a9c0SDavid du Colombier
2773de6a9c0SDavid du Colombier machon(m->machno);
2783de6a9c0SDavid du Colombier fpoff();
2793de6a9c0SDavid du Colombier }
2803de6a9c0SDavid du Colombier
2813de6a9c0SDavid du Colombier /* l.s has already zeroed Mach, which now contains our stack. */
2823de6a9c0SDavid du Colombier void
mach0init(void)2833de6a9c0SDavid du Colombier mach0init(void)
2843de6a9c0SDavid du Colombier {
2853de6a9c0SDavid du Colombier if (m == 0) {
2863de6a9c0SDavid du Colombier serialputc('?');
2873de6a9c0SDavid du Colombier serialputc('m');
2883de6a9c0SDavid du Colombier }
2893de6a9c0SDavid du Colombier conf.nmach = 0;
2903de6a9c0SDavid du Colombier
2913de6a9c0SDavid du Colombier m->machno = 0;
2923de6a9c0SDavid du Colombier machaddr[0] = m;
2933de6a9c0SDavid du Colombier
2943de6a9c0SDavid du Colombier lock(&testlock); /* hold this forever */
2953de6a9c0SDavid du Colombier machinit();
2963de6a9c0SDavid du Colombier
2973de6a9c0SDavid du Colombier active.exiting = 0;
2983de6a9c0SDavid du Colombier l1cache->wbse(&active, sizeof active);
2993de6a9c0SDavid du Colombier up = nil;
3003de6a9c0SDavid du Colombier }
3013de6a9c0SDavid du Colombier
3023de6a9c0SDavid du Colombier /*
3033de6a9c0SDavid du Colombier * count CPU's, set up their mach structures and l1 ptes.
3043de6a9c0SDavid du Colombier * we're running on cpu 0 and our data structures were
3053de6a9c0SDavid du Colombier * statically allocated.
3063de6a9c0SDavid du Colombier */
3073de6a9c0SDavid du Colombier void
launchinit(void)3083de6a9c0SDavid du Colombier launchinit(void)
3093de6a9c0SDavid du Colombier {
3103de6a9c0SDavid du Colombier int mach;
3113de6a9c0SDavid du Colombier Mach *mm;
3123de6a9c0SDavid du Colombier PTE *l1;
3133de6a9c0SDavid du Colombier
3143de6a9c0SDavid du Colombier for(mach = 1; mach < MAXMACH; mach++){
3153de6a9c0SDavid du Colombier machaddr[mach] = mm = mallocalign(MACHSIZE, MACHSIZE, 0, 0);
3163de6a9c0SDavid du Colombier l1 = mallocalign(L1SIZE, L1SIZE, 0, 0);
3173de6a9c0SDavid du Colombier if(mm == nil || l1 == nil)
3183de6a9c0SDavid du Colombier panic("launchinit");
3193de6a9c0SDavid du Colombier memset(mm, 0, MACHSIZE);
3203de6a9c0SDavid du Colombier mm->machno = mach;
3213de6a9c0SDavid du Colombier
3223de6a9c0SDavid du Colombier memmove(l1, (void *)L1, L1SIZE); /* clone cpu0's l1 table */
3233de6a9c0SDavid du Colombier l1cache->wbse(l1, L1SIZE);
3243de6a9c0SDavid du Colombier
3253de6a9c0SDavid du Colombier mm->mmul1 = l1;
3263de6a9c0SDavid du Colombier l1cache->wbse(mm, MACHSIZE);
3273de6a9c0SDavid du Colombier }
3283de6a9c0SDavid du Colombier l1cache->wbse(machaddr, sizeof machaddr);
3293de6a9c0SDavid du Colombier conf.nmach = 1;
3303de6a9c0SDavid du Colombier }
3313de6a9c0SDavid du Colombier
3323de6a9c0SDavid du Colombier void
dump(void * vaddr,int words)3333de6a9c0SDavid du Colombier dump(void *vaddr, int words)
3343de6a9c0SDavid du Colombier {
3353de6a9c0SDavid du Colombier ulong *addr;
3363de6a9c0SDavid du Colombier
3373de6a9c0SDavid du Colombier addr = vaddr;
3383de6a9c0SDavid du Colombier while (words-- > 0)
3393de6a9c0SDavid du Colombier iprint("%.8lux%c", *addr++, words % 8 == 0? '\n': ' ');
3403de6a9c0SDavid du Colombier }
3413de6a9c0SDavid du Colombier
3423de6a9c0SDavid du Colombier static void
cacheinit(void)3433de6a9c0SDavid du Colombier cacheinit(void)
3443de6a9c0SDavid du Colombier {
3453de6a9c0SDavid du Colombier allcacheinfo(cachel);
3463de6a9c0SDavid du Colombier cacheconf = (Lowmemcache *)CACHECONF;
3473de6a9c0SDavid du Colombier cacheconf->l1waysh = cachel[1].waysh;
3483de6a9c0SDavid du Colombier cacheconf->l1setsh = cachel[1].setsh;
3493de6a9c0SDavid du Colombier /* on the tegra 2, l2 is unarchitected */
3503de6a9c0SDavid du Colombier cacheconf->l2waysh = cachel[2].waysh;
3513de6a9c0SDavid du Colombier cacheconf->l2setsh = cachel[2].setsh;
3523de6a9c0SDavid du Colombier
3533de6a9c0SDavid du Colombier l2pl310init();
3543de6a9c0SDavid du Colombier allcacheson();
3553de6a9c0SDavid du Colombier allcache->wb();
3563de6a9c0SDavid du Colombier }
3573de6a9c0SDavid du Colombier
3583de6a9c0SDavid du Colombier void
l2pageinit(void)3593de6a9c0SDavid du Colombier l2pageinit(void)
3603de6a9c0SDavid du Colombier {
3613de6a9c0SDavid du Colombier l2pages = KADDR(PHYSDRAM + DRAMSIZE - RESRVDHIMEM);
3623de6a9c0SDavid du Colombier }
3633de6a9c0SDavid du Colombier
3643de6a9c0SDavid du Colombier /*
3653de6a9c0SDavid du Colombier * at entry, l.s has set m for cpu0 and printed "Plan 9 from Be"
3663de6a9c0SDavid du Colombier * but has not zeroed bss.
3673de6a9c0SDavid du Colombier */
3683de6a9c0SDavid du Colombier void
main(void)3693de6a9c0SDavid du Colombier main(void)
3703de6a9c0SDavid du Colombier {
3713de6a9c0SDavid du Colombier int cpu;
3723de6a9c0SDavid du Colombier static ulong vfy = 0xcafebabe;
3733de6a9c0SDavid du Colombier
3743de6a9c0SDavid du Colombier up = nil;
3753de6a9c0SDavid du Colombier if (vfy != 0xcafebabe) {
3763de6a9c0SDavid du Colombier serialputc('?');
3773de6a9c0SDavid du Colombier serialputc('d');
3783de6a9c0SDavid du Colombier panic("data segment misaligned");
3793de6a9c0SDavid du Colombier }
3803de6a9c0SDavid du Colombier
3813de6a9c0SDavid du Colombier memset(edata, 0, end - edata);
3823de6a9c0SDavid du Colombier
3833de6a9c0SDavid du Colombier /*
3843de6a9c0SDavid du Colombier * we can't lock until smpon has run, but we're supposed to wait
3853de6a9c0SDavid du Colombier * until l1 & l2 are on. too bad. l1 is on, l2 will soon be.
3863de6a9c0SDavid du Colombier */
3873de6a9c0SDavid du Colombier smpon();
3883de6a9c0SDavid du Colombier iprint("ll Labs ");
3893de6a9c0SDavid du Colombier cacheinit();
3903de6a9c0SDavid du Colombier
3913de6a9c0SDavid du Colombier /*
3923de6a9c0SDavid du Colombier * data segment is aligned, bss is zeroed, caches' characteristics
3933de6a9c0SDavid du Colombier * are known. begin initialisation.
3943de6a9c0SDavid du Colombier */
3953de6a9c0SDavid du Colombier mach0init();
3963de6a9c0SDavid du Colombier l2pageinit();
3973de6a9c0SDavid du Colombier mmuinit();
3983de6a9c0SDavid du Colombier
3993de6a9c0SDavid du Colombier optionsinit("/boot/boot boot");
4003de6a9c0SDavid du Colombier quotefmtinstall();
4013de6a9c0SDavid du Colombier
4023de6a9c0SDavid du Colombier /* want plan9.ini to be able to affect memory sizing in confinit */
4033de6a9c0SDavid du Colombier plan9iniinit(); /* before we step on plan9.ini in low memory */
4043de6a9c0SDavid du Colombier
4053de6a9c0SDavid du Colombier /* l2 looks for *l2off= in plan9.ini */
4063de6a9c0SDavid du Colombier l2cache->on(); /* l2->on requires locks to work, thus smpon */
4073de6a9c0SDavid du Colombier l2cache->info(&cachel[2]);
4083de6a9c0SDavid du Colombier allcache->on();
4093de6a9c0SDavid du Colombier
4103de6a9c0SDavid du Colombier cortexa9cachecfg();
4113de6a9c0SDavid du Colombier
4123de6a9c0SDavid du Colombier trapinit(); /* so confinit can probe memory to size it */
4133de6a9c0SDavid du Colombier confinit(); /* figures out amount of memory */
4143de6a9c0SDavid du Colombier /* xinit prints (if it can), so finish up the banner here. */
4153de6a9c0SDavid du Colombier delay(100);
4163de6a9c0SDavid du Colombier navailcpus = getncpus();
4173de6a9c0SDavid du Colombier iprint("(mp arm; %d cpus)\n\n", navailcpus);
4183de6a9c0SDavid du Colombier delay(100);
4193de6a9c0SDavid du Colombier
4203de6a9c0SDavid du Colombier for (cpu = 1; cpu < navailcpus; cpu++)
4213de6a9c0SDavid du Colombier stopcpu(cpu);
4223de6a9c0SDavid du Colombier
4233de6a9c0SDavid du Colombier xinit();
4243de6a9c0SDavid du Colombier irqtooearly = 0; /* now that xinit and trapinit have run */
4253de6a9c0SDavid du Colombier
4263de6a9c0SDavid du Colombier mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
4273de6a9c0SDavid du Colombier
4283de6a9c0SDavid du Colombier /*
4293de6a9c0SDavid du Colombier * Printinit will cause the first malloc call.
4303de6a9c0SDavid du Colombier * (printinit->qopen->malloc) unless any of the
4313de6a9c0SDavid du Colombier * above (like clockinit) do an irqenable, which
4323de6a9c0SDavid du Colombier * will call malloc.
4333de6a9c0SDavid du Colombier * If the system dies here it's probably due
4343de6a9c0SDavid du Colombier * to malloc(->xalloc) not being initialised
4353de6a9c0SDavid du Colombier * correctly, or the data segment is misaligned
4363de6a9c0SDavid du Colombier * (it's amazing how far you can get with
4373de6a9c0SDavid du Colombier * things like that completely broken).
4383de6a9c0SDavid du Colombier *
4393de6a9c0SDavid du Colombier * (Should be) boilerplate from here on.
4403de6a9c0SDavid du Colombier */
4413de6a9c0SDavid du Colombier
4423de6a9c0SDavid du Colombier archreset(); /* cfg clock signals, print cache cfg */
4433de6a9c0SDavid du Colombier clockinit(); /* start clocks */
4443de6a9c0SDavid du Colombier timersinit();
4453de6a9c0SDavid du Colombier
4463de6a9c0SDavid du Colombier delay(50); /* let uart catch up */
4473de6a9c0SDavid du Colombier printinit();
4483de6a9c0SDavid du Colombier kbdenable();
4493de6a9c0SDavid du Colombier
4503de6a9c0SDavid du Colombier cpuidprint();
4513de6a9c0SDavid du Colombier chkmissing();
4523de6a9c0SDavid du Colombier
4533de6a9c0SDavid du Colombier procinit0();
4543de6a9c0SDavid du Colombier initseg();
4553de6a9c0SDavid du Colombier
4563de6a9c0SDavid du Colombier // dmainit();
4573de6a9c0SDavid du Colombier links();
4583de6a9c0SDavid du Colombier conf.monitor = 1;
4593de6a9c0SDavid du Colombier // screeninit();
4603de6a9c0SDavid du Colombier
4613de6a9c0SDavid du Colombier iprint("pcireset...");
4623de6a9c0SDavid du Colombier pcireset(); /* this tends to hang after a reboot */
4633de6a9c0SDavid du Colombier iprint("ok\n");
4643de6a9c0SDavid du Colombier
4653de6a9c0SDavid du Colombier chandevreset(); /* most devices are discovered here */
4663de6a9c0SDavid du Colombier // i8250console(); /* too early; see init0 */
4673de6a9c0SDavid du Colombier
4683de6a9c0SDavid du Colombier pageinit(); /* prints "1020M memory: ⋯ */
4693de6a9c0SDavid du Colombier swapinit();
4703de6a9c0SDavid du Colombier userinit();
4713de6a9c0SDavid du Colombier
4723de6a9c0SDavid du Colombier /*
4733de6a9c0SDavid du Colombier * starting a cpu will eventually result in it calling schedinit,
4743de6a9c0SDavid du Colombier * so everything necessary to run user processes should be set up
4753de6a9c0SDavid du Colombier * before starting secondary cpus.
4763de6a9c0SDavid du Colombier */
4773de6a9c0SDavid du Colombier launchinit();
4783de6a9c0SDavid du Colombier /* SMP & FW are already on when we get here; u-boot set them? */
4793de6a9c0SDavid du Colombier for (cpu = 1; cpu < navailcpus; cpu++)
4803de6a9c0SDavid du Colombier if (startcpu(cpu) < 0)
4813de6a9c0SDavid du Colombier panic("cpu%d didn't start", cpu);
4823de6a9c0SDavid du Colombier l1diag();
4833de6a9c0SDavid du Colombier
4843de6a9c0SDavid du Colombier schedinit();
4853de6a9c0SDavid du Colombier panic("cpu%d: schedinit returned", m->machno);
4863de6a9c0SDavid du Colombier }
4873de6a9c0SDavid du Colombier
4883de6a9c0SDavid du Colombier static void
shutdown(int ispanic)4893de6a9c0SDavid du Colombier shutdown(int ispanic)
4903de6a9c0SDavid du Colombier {
4913de6a9c0SDavid du Colombier int ms, once;
4923de6a9c0SDavid du Colombier
4933de6a9c0SDavid du Colombier lock(&active);
4943de6a9c0SDavid du Colombier if(ispanic)
4953de6a9c0SDavid du Colombier active.ispanic = ispanic;
4963de6a9c0SDavid du Colombier else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
4973de6a9c0SDavid du Colombier active.ispanic = 0;
4983de6a9c0SDavid du Colombier once = active.machs & (1<<m->machno);
4993de6a9c0SDavid du Colombier /*
5003de6a9c0SDavid du Colombier * setting exiting will make hzclock() on each processor call exit(0),
5013de6a9c0SDavid du Colombier * which calls shutdown(0) and idles non-bootstrap cpus and returns
5023de6a9c0SDavid du Colombier * on bootstrap processors (to permit a reboot). clearing our bit
5033de6a9c0SDavid du Colombier * in machs avoids calling exit(0) from hzclock() on this processor.
5043de6a9c0SDavid du Colombier */
5053de6a9c0SDavid du Colombier active.machs &= ~(1<<m->machno);
5063de6a9c0SDavid du Colombier active.exiting = 1;
5073de6a9c0SDavid du Colombier unlock(&active);
5083de6a9c0SDavid du Colombier
5093de6a9c0SDavid du Colombier if(once) {
5103de6a9c0SDavid du Colombier delay(m->machno*1000); /* stagger them */
5113de6a9c0SDavid du Colombier iprint("cpu%d: exiting\n", m->machno);
5123de6a9c0SDavid du Colombier }
5133de6a9c0SDavid du Colombier spllo();
5143de6a9c0SDavid du Colombier if (m->machno == 0)
5153de6a9c0SDavid du Colombier ms = 5*1000;
5163de6a9c0SDavid du Colombier else
5173de6a9c0SDavid du Colombier ms = 2*1000;
5183de6a9c0SDavid du Colombier for(; ms > 0; ms -= TK2MS(2)){
5193de6a9c0SDavid du Colombier delay(TK2MS(2));
5203de6a9c0SDavid du Colombier if(active.machs == 0 && consactive() == 0)
5213de6a9c0SDavid du Colombier break;
5223de6a9c0SDavid du Colombier }
5233de6a9c0SDavid du Colombier delay(500);
5243de6a9c0SDavid du Colombier }
5253de6a9c0SDavid du Colombier
5263de6a9c0SDavid du Colombier /*
5273de6a9c0SDavid du Colombier * exit kernel either on a panic or user request
5283de6a9c0SDavid du Colombier */
5293de6a9c0SDavid du Colombier void
exit(int code)5303de6a9c0SDavid du Colombier exit(int code)
5313de6a9c0SDavid du Colombier {
5323de6a9c0SDavid du Colombier shutdown(code);
5333de6a9c0SDavid du Colombier splhi();
5343de6a9c0SDavid du Colombier if (m->machno == 0)
5353de6a9c0SDavid du Colombier archreboot();
5363de6a9c0SDavid du Colombier else {
5373de6a9c0SDavid du Colombier intrcpushutdown();
5383de6a9c0SDavid du Colombier stopcpu(m->machno);
5393de6a9c0SDavid du Colombier for (;;)
5403de6a9c0SDavid du Colombier idlehands();
5413de6a9c0SDavid du Colombier }
5423de6a9c0SDavid du Colombier }
5433de6a9c0SDavid du Colombier
5443de6a9c0SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)5453de6a9c0SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
5463de6a9c0SDavid du Colombier {
5473de6a9c0SDavid du Colombier char cc[32], *p;
5483de6a9c0SDavid du Colombier int i;
5493de6a9c0SDavid du Colombier
5503de6a9c0SDavid du Colombier snprint(cc, sizeof cc, "%s%d", class, ctlrno);
5513de6a9c0SDavid du Colombier p = getconf(cc);
5523de6a9c0SDavid du Colombier if(p == nil)
5533de6a9c0SDavid du Colombier return 0;
5543de6a9c0SDavid du Colombier
5553de6a9c0SDavid du Colombier isa->type = "";
5563de6a9c0SDavid du Colombier isa->nopt = tokenize(p, isa->opt, NISAOPT);
5573de6a9c0SDavid du Colombier for(i = 0; i < isa->nopt; i++){
5583de6a9c0SDavid du Colombier p = isa->opt[i];
5593de6a9c0SDavid du Colombier if(cistrncmp(p, "type=", 5) == 0)
5603de6a9c0SDavid du Colombier isa->type = p + 5;
5613de6a9c0SDavid du Colombier else if(cistrncmp(p, "port=", 5) == 0)
5623de6a9c0SDavid du Colombier isa->port = strtoul(p+5, &p, 0);
5633de6a9c0SDavid du Colombier else if(cistrncmp(p, "irq=", 4) == 0)
5643de6a9c0SDavid du Colombier isa->irq = strtoul(p+4, &p, 0);
5653de6a9c0SDavid du Colombier else if(cistrncmp(p, "dma=", 4) == 0)
5663de6a9c0SDavid du Colombier isa->dma = strtoul(p+4, &p, 0);
5673de6a9c0SDavid du Colombier else if(cistrncmp(p, "mem=", 4) == 0)
5683de6a9c0SDavid du Colombier isa->mem = strtoul(p+4, &p, 0);
5693de6a9c0SDavid du Colombier else if(cistrncmp(p, "size=", 5) == 0)
5703de6a9c0SDavid du Colombier isa->size = strtoul(p+5, &p, 0);
5713de6a9c0SDavid du Colombier else if(cistrncmp(p, "freq=", 5) == 0)
5723de6a9c0SDavid du Colombier isa->freq = strtoul(p+5, &p, 0);
5733de6a9c0SDavid du Colombier }
5743de6a9c0SDavid du Colombier return 1;
5753de6a9c0SDavid du Colombier }
5763de6a9c0SDavid du Colombier
5773de6a9c0SDavid du Colombier /*
5783de6a9c0SDavid du Colombier * the new kernel is already loaded at address `code'
5793de6a9c0SDavid du Colombier * of size `size' and entry point `entry'.
5803de6a9c0SDavid du Colombier */
5813de6a9c0SDavid du Colombier void
reboot(void * entry,void * code,ulong size)5823de6a9c0SDavid du Colombier reboot(void *entry, void *code, ulong size)
5833de6a9c0SDavid du Colombier {
5843de6a9c0SDavid du Colombier int cpu, nmach, want, ms;
5853de6a9c0SDavid du Colombier void (*f)(ulong, ulong, ulong);
5863de6a9c0SDavid du Colombier
5873de6a9c0SDavid du Colombier nmach = conf.nmach;
5883de6a9c0SDavid du Colombier writeconf();
5893de6a9c0SDavid du Colombier
5903de6a9c0SDavid du Colombier /*
5913de6a9c0SDavid du Colombier * the boot processor is cpu0. execute this function on it
5923de6a9c0SDavid du Colombier * so that the new kernel has the same cpu0.
5933de6a9c0SDavid du Colombier */
5943de6a9c0SDavid du Colombier if (m->machno != 0) {
5953de6a9c0SDavid du Colombier procwired(up, 0);
5963de6a9c0SDavid du Colombier sched();
5973de6a9c0SDavid du Colombier }
5983de6a9c0SDavid du Colombier if (m->machno != 0)
5993de6a9c0SDavid du Colombier print("on cpu%d (not 0)!\n", m->machno);
6003de6a9c0SDavid du Colombier
6013de6a9c0SDavid du Colombier /*
6023de6a9c0SDavid du Colombier * the other cpus could be holding locks that will never get
6033de6a9c0SDavid du Colombier * released (e.g., in the print path) if we put them into
6043de6a9c0SDavid du Colombier * reset now, so force them to shutdown gracefully first.
6053de6a9c0SDavid du Colombier */
6063de6a9c0SDavid du Colombier for (want = 0, cpu = 1; cpu < navailcpus; cpu++)
6073de6a9c0SDavid du Colombier want |= 1 << cpu;
6083de6a9c0SDavid du Colombier active.stopped = 0;
6093de6a9c0SDavid du Colombier shutdown(0);
6103de6a9c0SDavid du Colombier for (ms = 15*1000; ms > 0 && active.stopped != want; ms -= 10)
6113de6a9c0SDavid du Colombier delay(10);
6123de6a9c0SDavid du Colombier delay(20);
6133de6a9c0SDavid du Colombier if (active.stopped != want) {
6143de6a9c0SDavid du Colombier for (cpu = 1; cpu < nmach; cpu++)
6153de6a9c0SDavid du Colombier stopcpu(cpu); /* make really sure */
6163de6a9c0SDavid du Colombier delay(20);
6173de6a9c0SDavid du Colombier }
6183de6a9c0SDavid du Colombier
6193de6a9c0SDavid du Colombier /*
6203de6a9c0SDavid du Colombier * should be the only processor running now
6213de6a9c0SDavid du Colombier */
6223de6a9c0SDavid du Colombier pcireset();
6233de6a9c0SDavid du Colombier // print("reboot entry %#lux code %#lux size %ld\n",
6243de6a9c0SDavid du Colombier // PADDR(entry), PADDR(code), size);
6253de6a9c0SDavid du Colombier
6263de6a9c0SDavid du Colombier /* turn off buffered serial console */
6273de6a9c0SDavid du Colombier serialoq = nil;
6283de6a9c0SDavid du Colombier kprintoq = nil;
6293de6a9c0SDavid du Colombier screenputs = nil;
6303de6a9c0SDavid du Colombier
6313de6a9c0SDavid du Colombier /* shutdown devices */
6323de6a9c0SDavid du Colombier chandevshutdown();
6333de6a9c0SDavid du Colombier
6343de6a9c0SDavid du Colombier /* call off the dog */
6353de6a9c0SDavid du Colombier clockshutdown();
6363de6a9c0SDavid du Colombier
6373de6a9c0SDavid du Colombier splhi();
6383de6a9c0SDavid du Colombier intrshutdown();
6393de6a9c0SDavid du Colombier
6403de6a9c0SDavid du Colombier /* setup reboot trampoline function */
6413de6a9c0SDavid du Colombier f = (void*)REBOOTADDR;
6423de6a9c0SDavid du Colombier memmove(f, rebootcode, sizeof(rebootcode));
6433de6a9c0SDavid du Colombier cachedwb();
6443de6a9c0SDavid du Colombier l2cache->wbinv();
6453de6a9c0SDavid du Colombier l2cache->off();
6463de6a9c0SDavid du Colombier cacheuwbinv();
6473de6a9c0SDavid du Colombier
6483de6a9c0SDavid du Colombier /* off we go - never to return */
6493de6a9c0SDavid du Colombier (*f)(PADDR(entry), PADDR(code), size);
6503de6a9c0SDavid du Colombier
6513de6a9c0SDavid du Colombier iprint("loaded kernel returned!\n");
6523de6a9c0SDavid du Colombier archreboot();
6533de6a9c0SDavid du Colombier }
6543de6a9c0SDavid du Colombier
6553de6a9c0SDavid du Colombier /*
6563de6a9c0SDavid du Colombier * starting place for first process
6573de6a9c0SDavid du Colombier */
6583de6a9c0SDavid du Colombier void
init0(void)6593de6a9c0SDavid du Colombier init0(void)
6603de6a9c0SDavid du Colombier {
6613de6a9c0SDavid du Colombier int i;
6623de6a9c0SDavid du Colombier char buf[2*KNAMELEN];
6633de6a9c0SDavid du Colombier
6643de6a9c0SDavid du Colombier up->nerrlab = 0;
6653de6a9c0SDavid du Colombier coherence();
6663de6a9c0SDavid du Colombier spllo();
6673de6a9c0SDavid du Colombier
6683de6a9c0SDavid du Colombier /*
6693de6a9c0SDavid du Colombier * These are o.k. because rootinit is null.
6703de6a9c0SDavid du Colombier * Then early kproc's will have a root and dot.
6713de6a9c0SDavid du Colombier */
6723de6a9c0SDavid du Colombier up->slash = namec("#/", Atodir, 0, 0);
6733de6a9c0SDavid du Colombier pathclose(up->slash->path);
6743de6a9c0SDavid du Colombier up->slash->path = newpath("/");
6753de6a9c0SDavid du Colombier up->dot = cclone(up->slash);
6763de6a9c0SDavid du Colombier
6773de6a9c0SDavid du Colombier chandevinit();
6783de6a9c0SDavid du Colombier i8250console(); /* might be redundant, but harmless */
6793de6a9c0SDavid du Colombier if(kbdq == nil)
6803de6a9c0SDavid du Colombier panic("init0: nil kbdq");
6813de6a9c0SDavid du Colombier if(serialoq == nil)
6823de6a9c0SDavid du Colombier panic("init0: nil serialoq");
6833de6a9c0SDavid du Colombier normalprint = 1;
6843de6a9c0SDavid du Colombier
6853de6a9c0SDavid du Colombier if(!waserror()){
6863de6a9c0SDavid du Colombier snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
6873de6a9c0SDavid du Colombier ksetenv("terminal", buf, 0);
6883de6a9c0SDavid du Colombier ksetenv("cputype", "arm", 0);
6893de6a9c0SDavid du Colombier if(cpuserver)
6903de6a9c0SDavid du Colombier ksetenv("service", "cpu", 0);
6913de6a9c0SDavid du Colombier else
6923de6a9c0SDavid du Colombier ksetenv("service", "terminal", 0);
6933de6a9c0SDavid du Colombier
6943de6a9c0SDavid du Colombier /* convert plan9.ini variables to #e and #ec */
6953de6a9c0SDavid du Colombier for(i = 0; i < nconf; i++) {
6963de6a9c0SDavid du Colombier ksetenv(confname[i], confval[i], 0);
6973de6a9c0SDavid du Colombier ksetenv(confname[i], confval[i], 1);
6983de6a9c0SDavid du Colombier }
6993de6a9c0SDavid du Colombier poperror();
7003de6a9c0SDavid du Colombier }
7013de6a9c0SDavid du Colombier kproc("alarm", alarmkproc, 0);
7023de6a9c0SDavid du Colombier // kproc("startcpusproc", startcpusproc, nil);
7033de6a9c0SDavid du Colombier
7043de6a9c0SDavid du Colombier touser(sp);
7053de6a9c0SDavid du Colombier }
7063de6a9c0SDavid du Colombier
7073de6a9c0SDavid du Colombier static void
bootargs(uintptr base)7083de6a9c0SDavid du Colombier bootargs(uintptr base)
7093de6a9c0SDavid du Colombier {
7103de6a9c0SDavid du Colombier int i;
7113de6a9c0SDavid du Colombier ulong ssize;
7123de6a9c0SDavid du Colombier char **av, *p;
7133de6a9c0SDavid du Colombier
7143de6a9c0SDavid du Colombier /*
7153de6a9c0SDavid du Colombier * Push the boot args onto the stack.
7163de6a9c0SDavid du Colombier * The initial value of the user stack must be such
7173de6a9c0SDavid du Colombier * that the total used is larger than the maximum size
7183de6a9c0SDavid du Colombier * of the argument list checked in syscall.
7193de6a9c0SDavid du Colombier */
7203de6a9c0SDavid du Colombier i = oargblen+1;
721*5c88beaeSDavid du Colombier p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
7223de6a9c0SDavid du Colombier memmove(p, oargb, i);
7233de6a9c0SDavid du Colombier
7243de6a9c0SDavid du Colombier /*
7253de6a9c0SDavid du Colombier * Now push argc and the argv pointers.
7263de6a9c0SDavid du Colombier * This isn't strictly correct as the code jumped to by
7273de6a9c0SDavid du Colombier * touser in init9.s calls startboot (port/initcode.c) which
7283de6a9c0SDavid du Colombier * expects arguments
7293de6a9c0SDavid du Colombier * startboot(char *argv0, char **argv)
7303de6a9c0SDavid du Colombier * not the usual (int argc, char* argv[]), but argv0 is
7313de6a9c0SDavid du Colombier * unused so it doesn't matter (at the moment...).
7323de6a9c0SDavid du Colombier */
7333de6a9c0SDavid du Colombier av = (char**)(p - (oargc+2)*sizeof(char*));
7343de6a9c0SDavid du Colombier ssize = base + BY2PG - PTR2UINT(av);
7353de6a9c0SDavid du Colombier *av++ = (char*)oargc;
7363de6a9c0SDavid du Colombier for(i = 0; i < oargc; i++)
7373de6a9c0SDavid du Colombier *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
7383de6a9c0SDavid du Colombier *av = nil;
7393de6a9c0SDavid du Colombier
7403de6a9c0SDavid du Colombier /*
7413de6a9c0SDavid du Colombier * Leave space for the return PC of the
7423de6a9c0SDavid du Colombier * caller of initcode.
7433de6a9c0SDavid du Colombier */
7443de6a9c0SDavid du Colombier sp = USTKTOP - ssize - sizeof(void*);
7453de6a9c0SDavid du Colombier }
7463de6a9c0SDavid du Colombier
7473de6a9c0SDavid du Colombier /*
7483de6a9c0SDavid du Colombier * create the first process
7493de6a9c0SDavid du Colombier */
7503de6a9c0SDavid du Colombier void
userinit(void)7513de6a9c0SDavid du Colombier userinit(void)
7523de6a9c0SDavid du Colombier {
7533de6a9c0SDavid du Colombier Proc *p;
7543de6a9c0SDavid du Colombier Segment *s;
7553de6a9c0SDavid du Colombier KMap *k;
7563de6a9c0SDavid du Colombier Page *pg;
7573de6a9c0SDavid du Colombier
7583de6a9c0SDavid du Colombier /* no processes yet */
7593de6a9c0SDavid du Colombier up = nil;
7603de6a9c0SDavid du Colombier
7613de6a9c0SDavid du Colombier p = newproc();
7623de6a9c0SDavid du Colombier p->pgrp = newpgrp();
7633de6a9c0SDavid du Colombier p->egrp = smalloc(sizeof(Egrp));
7643de6a9c0SDavid du Colombier p->egrp->ref = 1;
7653de6a9c0SDavid du Colombier p->fgrp = dupfgrp(nil);
7663de6a9c0SDavid du Colombier p->rgrp = newrgrp();
7673de6a9c0SDavid du Colombier p->procmode = 0640;
7683de6a9c0SDavid du Colombier
7693de6a9c0SDavid du Colombier kstrdup(&eve, "");
7703de6a9c0SDavid du Colombier kstrdup(&p->text, "*init*");
7713de6a9c0SDavid du Colombier kstrdup(&p->user, eve);
7723de6a9c0SDavid du Colombier
7733de6a9c0SDavid du Colombier /*
7743de6a9c0SDavid du Colombier * Kernel Stack
7753de6a9c0SDavid du Colombier */
7763de6a9c0SDavid du Colombier p->sched.pc = PTR2UINT(init0);
7773de6a9c0SDavid du Colombier p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
7783de6a9c0SDavid du Colombier p->sched.sp = STACKALIGN(p->sched.sp);
7793de6a9c0SDavid du Colombier
7803de6a9c0SDavid du Colombier /*
7813de6a9c0SDavid du Colombier * User Stack
7823de6a9c0SDavid du Colombier *
7833de6a9c0SDavid du Colombier * Technically, newpage can't be called here because it
7843de6a9c0SDavid du Colombier * should only be called when in a user context as it may
7853de6a9c0SDavid du Colombier * try to sleep if there are no pages available, but that
7863de6a9c0SDavid du Colombier * shouldn't be the case here.
7873de6a9c0SDavid du Colombier */
7883de6a9c0SDavid du Colombier s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
7893de6a9c0SDavid du Colombier s->flushme++;
7903de6a9c0SDavid du Colombier p->seg[SSEG] = s;
7913de6a9c0SDavid du Colombier pg = newpage(1, 0, USTKTOP-BY2PG);
7923de6a9c0SDavid du Colombier segpage(s, pg);
7933de6a9c0SDavid du Colombier k = kmap(pg);
7943de6a9c0SDavid du Colombier bootargs(VA(k));
7953de6a9c0SDavid du Colombier kunmap(k);
7963de6a9c0SDavid du Colombier
7973de6a9c0SDavid du Colombier /*
7983de6a9c0SDavid du Colombier * Text
7993de6a9c0SDavid du Colombier */
8003de6a9c0SDavid du Colombier s = newseg(SG_TEXT, UTZERO, 1);
8013de6a9c0SDavid du Colombier p->seg[TSEG] = s;
8023de6a9c0SDavid du Colombier pg = newpage(1, 0, UTZERO);
8033de6a9c0SDavid du Colombier memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
8043de6a9c0SDavid du Colombier segpage(s, pg);
8053de6a9c0SDavid du Colombier k = kmap(s->map[0]->pages[0]);
8063de6a9c0SDavid du Colombier memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
8073de6a9c0SDavid du Colombier kunmap(k);
8083de6a9c0SDavid du Colombier
8093de6a9c0SDavid du Colombier ready(p);
8103de6a9c0SDavid du Colombier }
8113de6a9c0SDavid du Colombier
8123de6a9c0SDavid du Colombier Conf conf; /* XXX - must go - gag */
8133de6a9c0SDavid du Colombier
8143de6a9c0SDavid du Colombier Confmem tsmem[nelem(conf.mem)] = {
8153de6a9c0SDavid du Colombier /*
8163de6a9c0SDavid du Colombier * Memory available to Plan 9:
8173de6a9c0SDavid du Colombier */
8183de6a9c0SDavid du Colombier { .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
8193de6a9c0SDavid du Colombier };
8203de6a9c0SDavid du Colombier ulong memsize = DRAMSIZE;
8213de6a9c0SDavid du Colombier
8223de6a9c0SDavid du Colombier static int
gotmem(uintptr sz)8233de6a9c0SDavid du Colombier gotmem(uintptr sz)
8243de6a9c0SDavid du Colombier {
8253de6a9c0SDavid du Colombier uintptr addr;
8263de6a9c0SDavid du Colombier
8273de6a9c0SDavid du Colombier /* back off a little from the end */
8283de6a9c0SDavid du Colombier addr = (uintptr)KADDR(PHYSDRAM + sz - BY2WD);
8293de6a9c0SDavid du Colombier if (probeaddr(addr) >= 0) { /* didn't trap? memory present */
8303de6a9c0SDavid du Colombier memsize = sz;
8313de6a9c0SDavid du Colombier return 0;
8323de6a9c0SDavid du Colombier }
8333de6a9c0SDavid du Colombier return -1;
8343de6a9c0SDavid du Colombier }
8353de6a9c0SDavid du Colombier
8363de6a9c0SDavid du Colombier void
confinit(void)8373de6a9c0SDavid du Colombier confinit(void)
8383de6a9c0SDavid du Colombier {
8393de6a9c0SDavid du Colombier int i;
8403de6a9c0SDavid du Colombier ulong kpages;
8413de6a9c0SDavid du Colombier uintptr pa;
8423de6a9c0SDavid du Colombier char *p;
8433de6a9c0SDavid du Colombier
8443de6a9c0SDavid du Colombier /*
8453de6a9c0SDavid du Colombier * Copy the physical memory configuration to Conf.mem.
8463de6a9c0SDavid du Colombier */
8473de6a9c0SDavid du Colombier if(nelem(tsmem) > nelem(conf.mem)){
8483de6a9c0SDavid du Colombier iprint("memory configuration botch\n");
8493de6a9c0SDavid du Colombier exit(1);
8503de6a9c0SDavid du Colombier }
8513de6a9c0SDavid du Colombier if(0 && (p = getconf("*maxmem")) != nil) {
8523de6a9c0SDavid du Colombier memsize = strtoul(p, 0, 0) - PHYSDRAM;
8533de6a9c0SDavid du Colombier if (memsize < 16*MB) /* sanity */
8543de6a9c0SDavid du Colombier memsize = 16*MB;
8553de6a9c0SDavid du Colombier }
8563de6a9c0SDavid du Colombier
8573de6a9c0SDavid du Colombier /*
8583de6a9c0SDavid du Colombier * see if all that memory exists; if not, find out how much does.
8593de6a9c0SDavid du Colombier * trapinit must have been called first.
8603de6a9c0SDavid du Colombier */
8613de6a9c0SDavid du Colombier if (gotmem(memsize - RESRVDHIMEM) < 0)
8623de6a9c0SDavid du Colombier panic("can't find 1GB of memory");
8633de6a9c0SDavid du Colombier
8643de6a9c0SDavid du Colombier tsmem[0].limit = PHYSDRAM + memsize;
8653de6a9c0SDavid du Colombier memmove(conf.mem, tsmem, sizeof(tsmem));
8663de6a9c0SDavid du Colombier
8673de6a9c0SDavid du Colombier conf.npage = 0;
8683de6a9c0SDavid du Colombier pa = PADDR(PGROUND(PTR2UINT(end)));
8693de6a9c0SDavid du Colombier
8703de6a9c0SDavid du Colombier /*
8713de6a9c0SDavid du Colombier * we assume that the kernel is at the beginning of one of the
8723de6a9c0SDavid du Colombier * contiguous chunks of memory and fits therein.
8733de6a9c0SDavid du Colombier */
8743de6a9c0SDavid du Colombier for(i=0; i<nelem(conf.mem); i++){
8753de6a9c0SDavid du Colombier /* take kernel out of allocatable space */
8763de6a9c0SDavid du Colombier if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
8773de6a9c0SDavid du Colombier conf.mem[i].base = pa;
8783de6a9c0SDavid du Colombier
8793de6a9c0SDavid du Colombier conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
8803de6a9c0SDavid du Colombier conf.npage += conf.mem[i].npage;
8813de6a9c0SDavid du Colombier }
8823de6a9c0SDavid du Colombier
8833de6a9c0SDavid du Colombier conf.upages = (conf.npage*80)/100;
8843de6a9c0SDavid du Colombier conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
8853de6a9c0SDavid du Colombier
8863de6a9c0SDavid du Colombier /* set up other configuration parameters */
8873de6a9c0SDavid du Colombier conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
8883de6a9c0SDavid du Colombier if(cpuserver)
8893de6a9c0SDavid du Colombier conf.nproc *= 3;
8903de6a9c0SDavid du Colombier if(conf.nproc > 2000)
8913de6a9c0SDavid du Colombier conf.nproc = 2000;
8923de6a9c0SDavid du Colombier conf.nswap = conf.npage*3;
8933de6a9c0SDavid du Colombier conf.nswppo = 4096;
8943de6a9c0SDavid du Colombier conf.nimage = 200;
8953de6a9c0SDavid du Colombier
8963de6a9c0SDavid du Colombier /*
8973de6a9c0SDavid du Colombier * it's simpler on mp systems to take page-faults early,
8983de6a9c0SDavid du Colombier * on reference, rather than later, on write, which might
8993de6a9c0SDavid du Colombier * require tlb shootdowns.
9003de6a9c0SDavid du Colombier */
9013de6a9c0SDavid du Colombier conf.copymode = 1; /* copy on reference */
9023de6a9c0SDavid du Colombier
9033de6a9c0SDavid du Colombier /*
9043de6a9c0SDavid du Colombier * Guess how much is taken by the large permanent
9053de6a9c0SDavid du Colombier * datastructures. Mntcache and Mntrpc are not accounted for
9063de6a9c0SDavid du Colombier * (probably ~300KB).
9073de6a9c0SDavid du Colombier */
9083de6a9c0SDavid du Colombier kpages = conf.npage - conf.upages;
9093de6a9c0SDavid du Colombier kpages *= BY2PG;
9103de6a9c0SDavid du Colombier kpages -= conf.upages*sizeof(Page)
9113de6a9c0SDavid du Colombier + conf.nproc*sizeof(Proc)
9123de6a9c0SDavid du Colombier + conf.nimage*sizeof(Image)
9133de6a9c0SDavid du Colombier + conf.nswap
9143de6a9c0SDavid du Colombier + conf.nswppo*sizeof(Page);
9153de6a9c0SDavid du Colombier mainmem->maxsize = kpages;
9163de6a9c0SDavid du Colombier if(!cpuserver)
9173de6a9c0SDavid du Colombier /*
9183de6a9c0SDavid du Colombier * give terminals lots of image memory, too; the dynamic
9193de6a9c0SDavid du Colombier * allocation will balance the load properly, hopefully.
9203de6a9c0SDavid du Colombier * be careful with 32-bit overflow.
9213de6a9c0SDavid du Colombier */
9223de6a9c0SDavid du Colombier imagmem->maxsize = kpages;
9233de6a9c0SDavid du Colombier
9243de6a9c0SDavid du Colombier // archconfinit();
9253de6a9c0SDavid du Colombier }
9263de6a9c0SDavid du Colombier
9273de6a9c0SDavid du Colombier int
cmpswap(long * addr,long old,long new)9283de6a9c0SDavid du Colombier cmpswap(long *addr, long old, long new)
9293de6a9c0SDavid du Colombier {
9303de6a9c0SDavid du Colombier return cas((int *)addr, old, new);
9313de6a9c0SDavid du Colombier }
9323de6a9c0SDavid du Colombier
9333de6a9c0SDavid du Colombier void
advertwfi(void)9343de6a9c0SDavid du Colombier advertwfi(void) /* advertise my wfi status */
9353de6a9c0SDavid du Colombier {
9363de6a9c0SDavid du Colombier ilock(&active);
9373de6a9c0SDavid du Colombier active.wfi |= 1 << m->machno;
9383de6a9c0SDavid du Colombier iunlock(&active);
9393de6a9c0SDavid du Colombier }
9403de6a9c0SDavid du Colombier
9413de6a9c0SDavid du Colombier void
unadvertwfi(void)9423de6a9c0SDavid du Colombier unadvertwfi(void) /* do not advertise my wfi status */
9433de6a9c0SDavid du Colombier {
9443de6a9c0SDavid du Colombier ilock(&active);
9453de6a9c0SDavid du Colombier active.wfi &= ~(1 << m->machno);
9463de6a9c0SDavid du Colombier iunlock(&active);
9473de6a9c0SDavid du Colombier }
9483de6a9c0SDavid du Colombier
9493de6a9c0SDavid du Colombier void
idlehands(void)9503de6a9c0SDavid du Colombier idlehands(void)
9513de6a9c0SDavid du Colombier {
9523de6a9c0SDavid du Colombier #ifdef use_ipi
9533de6a9c0SDavid du Colombier int advertised;
9543de6a9c0SDavid du Colombier
9553de6a9c0SDavid du Colombier /* don't go into wfi until my local timer is ticking */
9563de6a9c0SDavid du Colombier if (m->ticks <= 1)
9573de6a9c0SDavid du Colombier return;
9583de6a9c0SDavid du Colombier
9593de6a9c0SDavid du Colombier advertised = 0;
9603de6a9c0SDavid du Colombier m->inidlehands++;
9613de6a9c0SDavid du Colombier /* avoid recursion via ilock, advertise iff this cpu is initialised */
9623de6a9c0SDavid du Colombier if (m->inidlehands == 1 && m->syscall > 0) {
9633de6a9c0SDavid du Colombier advertwfi();
9643de6a9c0SDavid du Colombier advertised = 1;
9653de6a9c0SDavid du Colombier }
9663de6a9c0SDavid du Colombier
9673de6a9c0SDavid du Colombier wfi();
9683de6a9c0SDavid du Colombier
9693de6a9c0SDavid du Colombier if (advertised)
9703de6a9c0SDavid du Colombier unadvertwfi();
9713de6a9c0SDavid du Colombier m->inidlehands--;
9723de6a9c0SDavid du Colombier #endif
9733de6a9c0SDavid du Colombier }
9743de6a9c0SDavid du Colombier
9753de6a9c0SDavid du Colombier void
wakewfi(void)9763de6a9c0SDavid du Colombier wakewfi(void)
9773de6a9c0SDavid du Colombier {
9783de6a9c0SDavid du Colombier #ifdef use_ipi
9793de6a9c0SDavid du Colombier uint cpu;
9803de6a9c0SDavid du Colombier
9813de6a9c0SDavid du Colombier /*
9823de6a9c0SDavid du Colombier * find any cpu other than me currently in wfi.
9833de6a9c0SDavid du Colombier * need not be exact.
9843de6a9c0SDavid du Colombier */
9853de6a9c0SDavid du Colombier cpu = BI2BY*BY2WD - 1 - clz(active.wfi & ~(1 << m->machno));
9863de6a9c0SDavid du Colombier if (cpu < MAXMACH)
9873de6a9c0SDavid du Colombier intrcpu(cpu);
9883de6a9c0SDavid du Colombier #endif
9893de6a9c0SDavid du Colombier }
990