changelog shortlog tags branches changeset file revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/main.c

revision 2323: f7c2fc5e9dd8
child 2503: e48d4208f76f
     1.1new file mode 100644
     1.2--- /dev/null
     1.3+++ b/sys/src/9/bcm/main.c
     1.4@@ -0,0 +1,597 @@
     1.5+#include "u.h"
     1.6+#include "tos.h"
     1.7+#include "../port/lib.h"
     1.8+#include "mem.h"
     1.9+#include "dat.h"
    1.10+#include "fns.h"
    1.11+
    1.12+#include "init.h"
    1.13+#include <pool.h>
    1.14+
    1.15+#include "reboot.h"
    1.16+
    1.17+/* Firmware compatibility */
    1.18+#define	Minfirmrev	326770
    1.19+#define	Minfirmdate	"22 Jul 2012"
    1.20+
    1.21+/*
    1.22+ * Where configuration info is left for the loaded programme.
    1.23+ */
    1.24+#define BOOTARGS	((char*)CONFADDR)
    1.25+#define	BOOTARGSLEN	(MACHADDR-CONFADDR)
    1.26+#define	MAXCONF		64
    1.27+#define MAXCONFLINE	160
    1.28+
    1.29+uintptr kseg0 = KZERO;
    1.30+Mach*	machaddr[MAXMACH];
    1.31+Conf	conf;
    1.32+ulong	memsize = 128*1024*1024;
    1.33+
    1.34+/*
    1.35+ * Option arguments from the command line.
    1.36+ * oargv[0] is the boot file.
    1.37+ */
    1.38+static int oargc;
    1.39+static char* oargv[20];
    1.40+static char oargb[128];
    1.41+static int oargblen;
    1.42+
    1.43+static uintptr sp;		/* XXX - must go - user stack of init proc */
    1.44+
    1.45+/* store plan9.ini contents here at least until we stash them in #ec */
    1.46+static char confname[MAXCONF][KNAMELEN];
    1.47+static char confval[MAXCONF][MAXCONFLINE];
    1.48+static int nconf;
    1.49+
    1.50+typedef struct Atag Atag;
    1.51+struct Atag {
    1.52+	u32int	size;	/* size of atag in words, including this header */
    1.53+	u32int	tag;	/* atag type */
    1.54+	union {
    1.55+		u32int	data[1];	/* actually [size-2] */
    1.56+		/* AtagMem */
    1.57+		struct {
    1.58+			u32int	size;
    1.59+			u32int	base;
    1.60+		} mem;
    1.61+		/* AtagCmdLine */
    1.62+		char	cmdline[1];	/* actually [4*(size-2)] */
    1.63+	};
    1.64+};
    1.65+
    1.66+enum {
    1.67+	AtagNone	= 0x00000000,
    1.68+	AtagCore	= 0x54410001,
    1.69+	AtagMem		= 0x54410002,
    1.70+	AtagCmdline	= 0x54410009,
    1.71+};
    1.72+
    1.73+static int
    1.74+findconf(char *name)
    1.75+{
    1.76+	int i;
    1.77+
    1.78+	for(i = 0; i < nconf; i++)
    1.79+		if(cistrcmp(confname[i], name) == 0)
    1.80+			return i;
    1.81+	return -1;
    1.82+}
    1.83+
    1.84+char*
    1.85+getconf(char *name)
    1.86+{
    1.87+	int i;
    1.88+
    1.89+	i = findconf(name);
    1.90+	if(i >= 0)
    1.91+		return confval[i];
    1.92+	return nil;
    1.93+}
    1.94+
    1.95+void
    1.96+addconf(char *name, char *val)
    1.97+{
    1.98+	int i;
    1.99+
   1.100+	i = findconf(name);
   1.101+	if(i < 0){
   1.102+		if(val == nil || nconf >= MAXCONF)
   1.103+			return;
   1.104+		i = nconf++;
   1.105+		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
   1.106+	}
   1.107+	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
   1.108+}
   1.109+
   1.110+static void
   1.111+writeconf(void)
   1.112+{
   1.113+	char *p, *q;
   1.114+	int n;
   1.115+
   1.116+	p = getconfenv();
   1.117+
   1.118+	if(waserror()) {
   1.119+		free(p);
   1.120+		nexterror();
   1.121+	}
   1.122+
   1.123+	/* convert to name=value\n format */
   1.124+	for(q=p; *q; q++) {
   1.125+		q += strlen(q);
   1.126+		*q = '=';
   1.127+		q += strlen(q);
   1.128+		*q = '\n';
   1.129+	}
   1.130+	n = q - p + 1;
   1.131+	if(n >= BOOTARGSLEN)
   1.132+		error("kernel configuration too large");
   1.133+	memmove(BOOTARGS, p, n);
   1.134+	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
   1.135+	poperror();
   1.136+	free(p);
   1.137+}
   1.138+
   1.139+static void
   1.140+plan9iniinit(char *s, int cmdline)
   1.141+{
   1.142+	char *toks[MAXCONF];
   1.143+	int i, c, n;
   1.144+	char *v;
   1.145+
   1.146+	if((c = *s) < ' ' || c >= 0x80)
   1.147+		return;
   1.148+	if(cmdline)
   1.149+		n = tokenize(s, toks, MAXCONF);
   1.150+	else
   1.151+		n = getfields(s, toks, MAXCONF, 1, "\n");
   1.152+	for(i = 0; i < n; i++){
   1.153+		if(toks[i][0] == '#')
   1.154+			continue;
   1.155+		v = strchr(toks[i], '=');
   1.156+		if(v == nil)
   1.157+			continue;
   1.158+		*v++ = '\0';
   1.159+		addconf(toks[i], v);
   1.160+	}
   1.161+}
   1.162+
   1.163+static void
   1.164+ataginit(Atag *a)
   1.165+{
   1.166+	int n;
   1.167+
   1.168+	if(a->tag != AtagCore){
   1.169+		plan9iniinit((char*)a, 0);
   1.170+		return;
   1.171+	}
   1.172+	while(a->tag != AtagNone){
   1.173+		switch(a->tag){
   1.174+		case AtagMem:
   1.175+			/* use only first bank */
   1.176+			if(conf.mem[0].limit == 0 && a->mem.size != 0){
   1.177+				memsize = a->mem.size;
   1.178+				conf.mem[0].base = a->mem.base;
   1.179+				conf.mem[0].limit = a->mem.base + memsize;
   1.180+			}
   1.181+			break;
   1.182+		case AtagCmdline:
   1.183+			n = (a->size * sizeof(u32int)) - offsetof(Atag, cmdline[0]);
   1.184+			if(a->cmdline + n < BOOTARGS + BOOTARGSLEN)
   1.185+				a->cmdline[n] = 0;
   1.186+			else
   1.187+				BOOTARGS[BOOTARGSLEN-1] = 0;
   1.188+			plan9iniinit(a->cmdline, 1);
   1.189+			break;
   1.190+		}
   1.191+		a = (Atag*)((u32int*)a + a->size);
   1.192+	}
   1.193+}
   1.194+
   1.195+void
   1.196+machinit(void)
   1.197+{
   1.198+	m->machno = 0;
   1.199+	machaddr[m->machno] = m;
   1.200+
   1.201+	m->ticks = 1;
   1.202+	m->perf.period = 1;
   1.203+
   1.204+	conf.nmach = 1;
   1.205+
   1.206+	active.machs = 1;
   1.207+	active.exiting = 0;
   1.208+
   1.209+	up = nil;
   1.210+}
   1.211+
   1.212+static void
   1.213+optionsinit(char* s)
   1.214+{
   1.215+	strecpy(oargb, oargb+sizeof(oargb), s);
   1.216+
   1.217+	oargblen = strlen(oargb);
   1.218+	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
   1.219+	oargv[oargc] = nil;
   1.220+}
   1.221+
   1.222+void
   1.223+main(void)
   1.224+{
   1.225+	extern char edata[], end[];
   1.226+	uint rev;
   1.227+
   1.228+	okay(1);
   1.229+	m = (Mach*)MACHADDR;
   1.230+	memset(edata, 0, end - edata);	/* clear bss */
   1.231+	machinit();
   1.232+	mmuinit1();
   1.233+
   1.234+	optionsinit("/boot/boot boot");
   1.235+	quotefmtinstall();
   1.236+	
   1.237+	ataginit((Atag*)BOOTARGS);
   1.238+	confinit();		/* figures out amount of memory */
   1.239+	xinit();
   1.240+	uartconsinit();
   1.241+	screeninit();
   1.242+
   1.243+	print("\nPlan 9 from Bell Labs\n");
   1.244+	rev = getfirmware();
   1.245+	print("firmware: rev %d\n", rev);
   1.246+	if(rev < Minfirmrev){
   1.247+		print("Sorry, firmware (start.elf) must be at least rev %d (%s)\n",
   1.248+			Minfirmrev, Minfirmdate);
   1.249+		for(;;)
   1.250+			;
   1.251+	}
   1.252+	trapinit();
   1.253+	clockinit();
   1.254+	printinit();
   1.255+	timersinit();
   1.256+	if(conf.monitor)
   1.257+		swcursorinit();
   1.258+	cpuidprint();
   1.259+	archreset();
   1.260+
   1.261+	procinit0();
   1.262+	initseg();
   1.263+	links();
   1.264+	chandevreset();			/* most devices are discovered here */
   1.265+	pageinit();
   1.266+	swapinit();
   1.267+	userinit();
   1.268+	schedinit();
   1.269+	assert(0);			/* shouldn't have returned */
   1.270+}
   1.271+
   1.272+/*
   1.273+ *  starting place for first process
   1.274+ */
   1.275+void
   1.276+init0(void)
   1.277+{
   1.278+	int i;
   1.279+	char buf[2*KNAMELEN];
   1.280+
   1.281+	up->nerrlab = 0;
   1.282+	coherence();
   1.283+	spllo();
   1.284+
   1.285+	/*
   1.286+	 * These are o.k. because rootinit is null.
   1.287+	 * Then early kproc's will have a root and dot.
   1.288+	 */
   1.289+	up->slash = namec("#/", Atodir, 0, 0);
   1.290+	pathclose(up->slash->path);
   1.291+	up->slash->path = newpath("/");
   1.292+	up->dot = cclone(up->slash);
   1.293+
   1.294+	chandevinit();
   1.295+
   1.296+	if(!waserror()){
   1.297+		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
   1.298+		ksetenv("terminal", buf, 0);
   1.299+		ksetenv("cputype", "arm", 0);
   1.300+		if(cpuserver)
   1.301+			ksetenv("service", "cpu", 0);
   1.302+		else
   1.303+			ksetenv("service", "terminal", 0);
   1.304+		snprint(buf, sizeof(buf), "-a %s", getethermac());
   1.305+		ksetenv("etherargs", buf, 0);
   1.306+
   1.307+		/* convert plan9.ini variables to #e and #ec */
   1.308+		for(i = 0; i < nconf; i++) {
   1.309+			ksetenv(confname[i], confval[i], 0);
   1.310+			ksetenv(confname[i], confval[i], 1);
   1.311+		}
   1.312+		poperror();
   1.313+	}
   1.314+	kproc("alarm", alarmkproc, 0);
   1.315+	touser(sp);
   1.316+	assert(0);			/* shouldn't have returned */
   1.317+}
   1.318+
   1.319+static void
   1.320+bootargs(uintptr base)
   1.321+{
   1.322+	int i;
   1.323+	ulong ssize;
   1.324+	char **av, *p;
   1.325+
   1.326+	/*
   1.327+	 * Push the boot args onto the stack.
   1.328+	 * The initial value of the user stack must be such
   1.329+	 * that the total used is larger than the maximum size
   1.330+	 * of the argument list checked in syscall.
   1.331+	 */
   1.332+	i = oargblen+1;
   1.333+	p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i));
   1.334+	memmove(p, oargb, i);
   1.335+
   1.336+	/*
   1.337+	 * Now push the argv pointers.
   1.338+	 * The code jumped to by touser in lproc.s expects arguments
   1.339+	 *	main(char* argv0, ...)
   1.340+	 * and calls
   1.341+	 * 	startboot("/boot/boot", &argv0)
   1.342+	 * not the usual (int argc, char* argv[])
   1.343+	 */
   1.344+	av = (char**)(p - (oargc+1)*sizeof(char*));
   1.345+	ssize = base + BY2PG - PTR2UINT(av);
   1.346+	for(i = 0; i < oargc; i++)
   1.347+		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
   1.348+	*av = nil;
   1.349+	sp = USTKTOP - ssize;
   1.350+}
   1.351+
   1.352+/*
   1.353+ *  create the first process
   1.354+ */
   1.355+void
   1.356+userinit(void)
   1.357+{
   1.358+	Proc *p;
   1.359+	Segment *s;
   1.360+	KMap *k;
   1.361+	Page *pg;
   1.362+
   1.363+	/* no processes yet */
   1.364+	up = nil;
   1.365+
   1.366+	p = newproc();
   1.367+	p->pgrp = newpgrp();
   1.368+	p->egrp = smalloc(sizeof(Egrp));
   1.369+	p->egrp->ref = 1;
   1.370+	p->fgrp = dupfgrp(nil);
   1.371+	p->rgrp = newrgrp();
   1.372+	p->procmode = 0640;
   1.373+
   1.374+	kstrdup(&eve, "");
   1.375+	kstrdup(&p->text, "*init*");
   1.376+	kstrdup(&p->user, eve);
   1.377+
   1.378+	/*
   1.379+	 * Kernel Stack
   1.380+	 */
   1.381+	p->sched.pc = PTR2UINT(init0);
   1.382+	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
   1.383+	p->sched.sp = STACKALIGN(p->sched.sp);
   1.384+
   1.385+	/*
   1.386+	 * User Stack
   1.387+	 *
   1.388+	 * Technically, newpage can't be called here because it
   1.389+	 * should only be called when in a user context as it may
   1.390+	 * try to sleep if there are no pages available, but that
   1.391+	 * shouldn't be the case here.
   1.392+	 */
   1.393+	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
   1.394+	s->flushme++;
   1.395+	p->seg[SSEG] = s;
   1.396+	pg = newpage(1, 0, USTKTOP-BY2PG);
   1.397+	segpage(s, pg);
   1.398+	k = kmap(pg);
   1.399+	bootargs(VA(k));
   1.400+	kunmap(k);
   1.401+
   1.402+	/*
   1.403+	 * Text
   1.404+	 */
   1.405+	s = newseg(SG_TEXT, UTZERO, 1);
   1.406+	p->seg[TSEG] = s;
   1.407+	pg = newpage(1, 0, UTZERO);
   1.408+	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
   1.409+	segpage(s, pg);
   1.410+	k = kmap(s->map[0]->pages[0]);
   1.411+	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
   1.412+	kunmap(k);
   1.413+
   1.414+	ready(p);
   1.415+}
   1.416+
   1.417+void
   1.418+confinit(void)
   1.419+{
   1.420+	int i;
   1.421+	ulong kpages;
   1.422+	uintptr pa;
   1.423+	char *p;
   1.424+
   1.425+	if(0 && (p = getconf("service")) != nil){
   1.426+		if(strcmp(p, "cpu") == 0)
   1.427+			cpuserver = 1;
   1.428+		else if(strcmp(p,"terminal") == 0)
   1.429+			cpuserver = 0;
   1.430+	}
   1.431+	if((p = getconf("*maxmem")) != nil){
   1.432+		memsize = strtoul(p, 0, 0) - PHYSDRAM;
   1.433+		if (memsize < 16*MB)		/* sanity */
   1.434+			memsize = 16*MB;
   1.435+	}
   1.436+
   1.437+	getramsize(&conf.mem[0]);
   1.438+	if(conf.mem[0].limit == 0){
   1.439+		conf.mem[0].base = PHYSDRAM;
   1.440+		conf.mem[0].limit = PHYSDRAM + memsize;
   1.441+	}else if(p != nil)
   1.442+		conf.mem[0].limit = conf.mem[0].base + memsize;
   1.443+
   1.444+	conf.npage = 0;
   1.445+	pa = PADDR(PGROUND(PTR2UINT(end)));
   1.446+
   1.447+	/*
   1.448+	 *  we assume that the kernel is at the beginning of one of the
   1.449+	 *  contiguous chunks of memory and fits therein.
   1.450+	 */
   1.451+	for(i=0; i<nelem(conf.mem); i++){
   1.452+		/* take kernel out of allocatable space */
   1.453+		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
   1.454+			conf.mem[i].base = pa;
   1.455+
   1.456+		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
   1.457+		conf.npage += conf.mem[i].npage;
   1.458+	}
   1.459+
   1.460+	conf.upages = (conf.npage*80)/100;
   1.461+	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
   1.462+
   1.463+	/* only one processor */
   1.464+	conf.nmach = 1;
   1.465+
   1.466+	/* set up other configuration parameters */
   1.467+	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
   1.468+	if(cpuserver)
   1.469+		conf.nproc *= 3;
   1.470+	if(conf.nproc > 2000)
   1.471+		conf.nproc = 2000;
   1.472+	conf.nswap = conf.npage*3;
   1.473+	conf.nswppo = 4096;
   1.474+	conf.nimage = 200;
   1.475+
   1.476+	conf.copymode = 0;		/* copy on write */
   1.477+
   1.478+	/*
   1.479+	 * Guess how much is taken by the large permanent
   1.480+	 * datastructures. Mntcache and Mntrpc are not accounted for
   1.481+	 * (probably ~300KB).
   1.482+	 */
   1.483+	kpages = conf.npage - conf.upages;
   1.484+	kpages *= BY2PG;
   1.485+	kpages -= conf.upages*sizeof(Page)
   1.486+		+ conf.nproc*sizeof(Proc)
   1.487+		+ conf.nimage*sizeof(Image)
   1.488+		+ conf.nswap
   1.489+		+ conf.nswppo*sizeof(Page);
   1.490+	mainmem->maxsize = kpages;
   1.491+	if(!cpuserver)
   1.492+		/*
   1.493+		 * give terminals lots of image memory, too; the dynamic
   1.494+		 * allocation will balance the load properly, hopefully.
   1.495+		 * be careful with 32-bit overflow.
   1.496+		 */
   1.497+		imagmem->maxsize = kpages;
   1.498+
   1.499+}
   1.500+
   1.501+static void
   1.502+shutdown(int ispanic)
   1.503+{
   1.504+	int ms, once;
   1.505+
   1.506+	lock(&active);
   1.507+	if(ispanic)
   1.508+		active.ispanic = ispanic;
   1.509+	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
   1.510+		active.ispanic = 0;
   1.511+	once = active.machs & (1<<m->machno);
   1.512+	active.machs &= ~(1<<m->machno);
   1.513+	active.exiting = 1;
   1.514+	unlock(&active);
   1.515+
   1.516+	if(once)
   1.517+		iprint("cpu%d: exiting\n", m->machno);
   1.518+	spllo();
   1.519+	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
   1.520+		delay(TK2MS(2));
   1.521+		if(active.machs == 0 && consactive() == 0)
   1.522+			break;
   1.523+	}
   1.524+	delay(1000);
   1.525+}
   1.526+
   1.527+/*
   1.528+ *  exit kernel either on a panic or user request
   1.529+ */
   1.530+void
   1.531+exit(int code)
   1.532+{
   1.533+	shutdown(code);
   1.534+	splfhi();
   1.535+	archreboot();
   1.536+}
   1.537+
   1.538+/*
   1.539+ * stub for ../omap/devether.c
   1.540+ */
   1.541+int
   1.542+isaconfig(char *class, int ctlrno, ISAConf *isa)
   1.543+{
   1.544+	USED(ctlrno);
   1.545+	USED(isa);
   1.546+	return strcmp(class, "ether") == 0;
   1.547+}
   1.548+
   1.549+/*
   1.550+ * the new kernel is already loaded at address `code'
   1.551+ * of size `size' and entry point `entry'.
   1.552+ */
   1.553+void
   1.554+reboot(void *entry, void *code, ulong size)
   1.555+{
   1.556+	void (*f)(ulong, ulong, ulong);
   1.557+
   1.558+	print("starting reboot...");
   1.559+	writeconf();
   1.560+	shutdown(0);
   1.561+
   1.562+	/*
   1.563+	 * should be the only processor running now
   1.564+	 */
   1.565+
   1.566+	print("reboot entry %#lux code %#lux size %ld\n",
   1.567+		PADDR(entry), PADDR(code), size);
   1.568+	delay(100);
   1.569+
   1.570+	/* turn off buffered serial console */
   1.571+	serialoq = nil;
   1.572+	kprintoq = nil;
   1.573+	screenputs = nil;
   1.574+
   1.575+	/* shutdown devices */
   1.576+	chandevshutdown();
   1.577+
   1.578+	/* stop the clock (and watchdog if any) */
   1.579+	clockshutdown();
   1.580+
   1.581+	splfhi();
   1.582+	intrsoff();
   1.583+
   1.584+	/* setup reboot trampoline function */
   1.585+	f = (void*)REBOOTADDR;
   1.586+	memmove(f, rebootcode, sizeof(rebootcode));
   1.587+	cacheuwbinv();
   1.588+
   1.589+	/* off we go - never to return */
   1.590+	(*f)(PADDR(entry), PADDR(code), size);
   1.591+
   1.592+	iprint("loaded kernel returned!\n");
   1.593+	delay(1000);
   1.594+	archreboot();
   1.595+}
   1.596+
   1.597+int
   1.598+cmpswap(long *addr, long old, long new)
   1.599+{
   1.600+	return cas32(addr, old, new);
   1.601+}