xref: /plan9-contrib/sys/src/9/kw/main.c (revision 25fc69938fdecc61cd09e795cbe2d2f72f1082b1)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 
7 #include "init.h"
8 #include "arm.h"
9 #include <pool.h>
10 
11 #include "reboot.h"
12 
13 uintptr kseg0 = KZERO;
14 Mach* machaddr[MAXMACH];
15 
16 /*
17  * Option arguments from the command line.
18  * oargv[0] is the boot file.
19  * Optionsinit() is called from multiboot()
20  * or some other machine-dependent place
21  * to set it all up.
22  */
23 static int oargc;
24 static char* oargv[20];
25 static char oargb[128];
26 static int oargblen;
27 static char oenv[4096];
28 
29 static uintptr sp;		/* XXX - must go - user stack of init proc */
30 
31 int vflag;
32 char debug[256];
33 
34 static void
35 optionsinit(char* s)
36 {
37 	char *o;
38 #ifdef USE_FLASH
39 	uintptr va;
40 	char *p;
41 
42 	va = 0xf0000000;
43 	if(mmukmap(va, PHYSFLASH, 1*MiB) != 0){
44 		o = oenv;
45 		for(p = (char*)(va+256*KiB+4); *p != 0; p += strlen(p)+1)
46 			o = strecpy(o, oenv+sizeof(oenv), p)+1;
47 		mmukunmap(va, PHYSFLASH, 1*MiB);
48 	}
49 #else
50 	strcpy(oenv, "ethaddr=00:50:43:01:c4:9e");	// TODO
51 #endif
52 
53 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
54 	if(getenv("bootargs", o, o - oargb) != nil)
55 		*(o-1) = ' ';
56 
57 	oargblen = strlen(oargb);
58 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
59 	oargv[oargc] = nil;
60 }
61 
62 char*
63 getenv(char* name, char* buf, int n)
64 {
65 	char *e, *p, *q;
66 
67 	p = oenv;
68 	while(*p != 0){
69 		if((e = strchr(p, '=')) == nil)
70 			break;
71 		for(q = name; p < e; p++){
72 			if(*p != *q)
73 				break;
74 			q++;
75 		}
76 		if(p == e && *q == 0){
77 			strecpy(buf, buf+n, e+1);
78 			return buf;
79 		}
80 		p += strlen(p)+1;
81 	}
82 
83 	return nil;
84 }
85 
86 #include "io.h"
87 
88 typedef struct Spiregs Spiregs;
89 struct Spiregs {
90 	ulong	ictl;		/* interface ctl */
91 	ulong	icfg;		/* interface config */
92 	ulong	out;		/* data out */
93 	ulong	in;		/* data in */
94 	ulong	ic;		/* interrupt cause */
95 	ulong	im;		/* interrupt mask */
96 	ulong	_pad[2];
97 	ulong	dwrcfg;		/* direct write config */
98 	ulong	dwrhdr;		/* direct write header */
99 };
100 
101 enum {
102 	/* ictl bits */
103 	Csnact	= 1<<0,		/* serial memory activated */
104 
105 	/* icfg bits */
106 	Bytelen	= 1<<5,		/* 2^(this_bit) bytes per transfer */
107 	Dirrdcmd= 1<<10,	/* flag: fast read */
108 };
109 
110 static void
111 dumpbytes(uchar *bp, long max)
112 {
113 	iprint("%#p: ", bp);
114 	for (; max > 0; max--)
115 		iprint("%02.2ux ", *bp++);
116 	iprint("...\n");
117 }
118 
119 vlong	probeaddr(uintptr);
120 
121 // linux sez environment is in nand, 128K at offset 0x40000
122 static void
123 spiprobe(void)
124 {
125 	Spiregs *rp = (Spiregs *)AddrSpi;
126 
127 	l2cacheon();
128 
129 	rp->ictl |= Csnact;
130 	coherence();
131 	rp->icfg |= Dirrdcmd | 3<<8;	/* fast reads, 4-byte addresses */
132 	rp->icfg &= ~Bytelen;		/* one-byte reads */
133 	coherence();
134 
135 	print("spi flash at %#ux: memory reads enabled\n", PHYSSPIFLASH);
136 #ifdef AMBITIOUS
137 	uchar *p, *ep, *np;
138 
139 	p = (uchar *)PHYSSPIFLASH;
140 	ep = p + FLASHSIZE - 64;
141 iprint("scan: ");
142 	for (; p < ep - 1; p++) {
143 iprint("%#p of %,ld bytes...", p, ep - p);
144 		np = memchr(p, 'e', ep - p);
145 		if (np == nil)
146 			break;
147 		p = np;
148 		if (*p == 'e' && memcmp(p, "ethaddr", 7) == 0)
149 			break;
150 	}
151 	dumpbytes(p, 64);
152 #endif
153 }
154 
155 void	archconsole(void);
156 
157 /*
158  * this low-level printing stuff is ugly,
159  * but there appears to be no other way to
160  * print until after #t is populated.
161  */
162 
163 #define wave(c) { \
164 	coherence(); \
165 	while ((*(ulong *)(PHYSCONS+4*5) & (1<<5)) == 0) /* (x->lsr&LSRthre)==0? */ \
166 		; \
167 	*(ulong *)PHYSCONS = (c); \
168 	coherence(); \
169 }
170 
171 /*
172  * entered from l.s with mmu enabled.
173  *
174  * we may have to realign the data segment; apparently 5l -H0 -R4096
175  * does not pad the text segment.  on the other hand, we may have been
176  * loaded by another kernel.
177  *
178  * be careful not to touch the data segment until we know it's aligned.
179  */
180 void
181 main(Mach* mach)
182 {
183 	extern char bdata[], edata[], end[], etext[];
184 	static ulong vfy = 0xcafebabe;
185 
186 	m = mach;
187 	if (vfy != 0xcafebabe)
188 		memmove(bdata, etext, edata - bdata);
189 	if (vfy != 0xcafebabe) {
190 		wave('?');
191 		panic("misaligned data segment");
192 	}
193 	memset(edata, 0, end - edata);		/* zero bss */
194 	vfy = 0;
195 
196 wave('9');
197 	machinit();
198 	archreset();
199 	mmuinit();
200 
201 	optionsinit("/boot/boot boot");
202 	quotefmtinstall();
203 	archconsole();
204 wave('\n');
205 
206 	confinit();
207 	xinit();
208 wave('\r');
209 
210 	/*
211 	 * Printinit will cause the first malloc call.
212 	 * (printinit->qopen->malloc) unless any of the
213 	 * above (like clockintr) do an irqenable, which
214 	 * will call malloc.
215 	 * If the system dies here it's probably due
216 	 * to malloc(->xalloc) not being initialised
217 	 * correctly, or the data segment is misaligned
218 	 * (it's amazing how far you can get with
219 	 * things like that completely broken).
220 	 *
221 	 * (Should be) boilerplate from here on.
222 	 */
223 	trapinit();
224 	clockinit();
225 
226 	printinit();
227 	/* only now can we print */
228 	uartkirkwoodconsole();
229 	archconfinit();
230 	cpuidprint();
231 	timersinit();
232 
233 	procinit0();
234 	initseg();
235 	links();
236 	chandevreset();
237 
238 	spiprobe();
239 
240 	pageinit();
241 	swapinit();
242 	userinit();
243 	schedinit();
244 }
245 
246 void
247 cpuidprint(void)
248 {
249 	char name[64];
250 
251 	cputype2name(name, sizeof name);
252 	print("cpu%d: %lldMHz ARM %s\n", m->machno, m->cpuhz/1000000, name);
253 }
254 
255 void
256 machinit(void)
257 {
258 	memset(m, 0, sizeof(Mach));
259 	m->machno = 0;
260 	machaddr[m->machno] = m;
261 
262 	m->ticks = 1;
263 	m->perf.period = 1;
264 
265 	conf.nmach = 1;
266 
267 	active.machs = 1;
268 	active.exiting = 0;
269 
270 	up = nil;
271 }
272 
273 static void
274 shutdown(int ispanic)
275 {
276 	int ms, once;
277 
278 	lock(&active);
279 	if(ispanic)
280 		active.ispanic = ispanic;
281 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
282 		active.ispanic = 0;
283 	once = active.machs & (1<<m->machno);
284 	active.machs &= ~(1<<m->machno);
285 	active.exiting = 1;
286 	unlock(&active);
287 
288 	if(once)
289 		iprint("cpu%d: exiting\n", m->machno);
290 	spllo();
291 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
292 		delay(TK2MS(2));
293 		if(active.machs == 0 && consactive() == 0)
294 			break;
295 	}
296 	delay(1000);
297 }
298 
299 /*
300  *  exit kernel either on a panic or user request
301  */
302 void
303 exit(int code)
304 {
305 	shutdown(code);
306 	splhi();
307 	archreboot();
308 }
309 
310 /*
311  * the new kernel is already loaded at address `code'
312  * of size `size' and entry point `entry'.
313  */
314 void
315 reboot(void *entry, void *code, ulong size)
316 {
317 	void (*f)(ulong, ulong, ulong);
318 
319 	iprint("starting reboot...");
320 //	writeconf();
321 	shutdown(0);
322 
323 	/*
324 	 * should be the only processor running now
325 	 */
326 
327 	print("shutting down...\n");
328 	delay(200);
329 
330 	/* turn off buffered serial console */
331 	serialoq = nil;
332 
333 	/* shutdown devices */
334 	devtabshutdown();
335 
336 	/* call off the dog */
337 	clockshutdown();
338 
339 	splhi();
340 
341 	/* setup reboot trampoline function */
342 	f = (void*)REBOOTADDR;
343 	memmove(f, rebootcode, sizeof(rebootcode));
344 	coherence();
345 	dcflushall();
346 	icflushall();
347 
348 	print("rebooting...");
349 	iprint("entry %#lux code %#lux size %ld\n",
350 		PADDR(entry), PADDR(code), size);
351 	delay(100);		/* wait for uart to quiesce */
352 
353 	/* off we go - never to return */
354 	coherence();
355 	dcflushall();
356 	icflushall();
357 	(*f)(PADDR(entry), PADDR(code), size);
358 
359 	iprint("loaded kernel returned!\n");
360 	delay(1000);
361 	archreboot();
362 }
363 
364 /*
365  *  starting place for first process
366  */
367 void
368 init0(void)
369 {
370 	char buf[2*KNAMELEN];
371 
372 	assert(up != nil);
373 	up->nerrlab = 0;
374 	coherence();
375 	spllo();
376 
377 	/*
378 	 * These are o.k. because rootinit is null.
379 	 * Then early kproc's will have a root and dot.
380 	 */
381 	up->slash = namec("#/", Atodir, 0, 0);
382 	pathclose(up->slash->path);
383 	up->slash->path = newpath("/");
384 	up->dot = cclone(up->slash);
385 
386 	devtabinit();
387 
388 	if(!waserror()){
389 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
390 		ksetenv("terminal", buf, 0);
391 		ksetenv("cputype", "arm", 0);
392 		if(cpuserver)
393 			ksetenv("service", "cpu", 0);
394 		else
395 			ksetenv("service", "terminal", 0);
396 
397 		/* sheevaplug configuration */
398 		ksetenv("nvram", "/boot/nvram", 0);
399 		ksetenv("nvroff", "0", 0);
400 		ksetenv("nvrlen", "512", 0);
401 		ksetenv("nobootprompt", "tcp", 0);
402 
403 		poperror();
404 	}
405 	kproc("alarm", alarmkproc, 0);
406 
407 	touser(sp);
408 }
409 
410 static void
411 bootargs(uintptr base)
412 {
413 	int i;
414 	ulong ssize;
415 	char **av, *p;
416 
417 	/*
418 	 * Push the boot args onto the stack.
419 	 * The initial value of the user stack must be such
420 	 * that the total used is larger than the maximum size
421 	 * of the argument list checked in syscall.
422 	 */
423 	i = oargblen+1;
424 	p = UINT2PTR(STACKALIGN(base + PGSIZE - sizeof(up->s.args) - i));
425 	memmove(p, oargb, i);
426 
427 	/*
428 	 * Now push argc and the argv pointers.
429 	 * This isn't strictly correct as the code jumped to by
430 	 * touser in init9.s calls startboot (port/initcode.c) which
431 	 * expects arguments
432 	 * 	startboot(char *argv0, char **argv)
433 	 * not the usual (int argc, char* argv[]), but argv0 is
434 	 * unused so it doesn't matter (at the moment...).
435 	 */
436 	av = (char**)(p - (oargc+2)*sizeof(char*));
437 	ssize = base + PGSIZE - PTR2UINT(av);
438 	*av++ = (char*)oargc;
439 	for(i = 0; i < oargc; i++)
440 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
441 	*av = nil;
442 
443 	/*
444 	 * Leave space for the return PC of the
445 	 * caller of initcode.
446 	 */
447 	sp = USTKTOP - ssize - sizeof(void*);
448 }
449 
450 /*
451  *  create the first process
452  */
453 void
454 userinit(void)
455 {
456 	Proc *p;
457 	Segment *s;
458 	KMap *k;
459 	Page *pg;
460 
461 	/* no processes yet */
462 	up = nil;
463 
464 	p = newproc();
465 	p->pgrp = newpgrp();
466 	p->egrp = smalloc(sizeof(Egrp));
467 	p->egrp->ref = 1;
468 	p->fgrp = dupfgrp(nil);
469 	p->rgrp = newrgrp();
470 	p->procmode = 0640;
471 
472 	kstrdup(&eve, "");
473 	kstrdup(&p->text, "*init*");
474 	kstrdup(&p->user, eve);
475 
476 	/*
477 	 * Kernel Stack
478 	 */
479 	p->sched.pc = PTR2UINT(init0);
480 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
481 	p->sched.sp = STACKALIGN(p->sched.sp);
482 
483 	/*
484 	 * User Stack
485 	 *
486 	 * Technically, newpage can't be called here because it
487 	 * should only be called when in a user context as it may
488 	 * try to sleep if there are no pages available, but that
489 	 * shouldn't be the case here.
490 	 */
491 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
492 	p->seg[SSEG] = s;
493 	pg = newpage(1, 0, USTKTOP-BY2PG);
494 	segpage(s, pg);
495 	k = kmap(pg);
496 	bootargs(VA(k));
497 	kunmap(k);
498 
499 	/*
500 	 * Text
501 	 */
502 	s = newseg(SG_TEXT, UTZERO, 1);
503 	s->flushme++;
504 	p->seg[TSEG] = s;
505 	pg = newpage(1, 0, UTZERO);
506 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
507 	segpage(s, pg);
508 	k = kmap(s->map[0]->pages[0]);
509 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
510 	kunmap(k);
511 
512 	ready(p);
513 }
514 
515 Conf conf;			/* XXX - must go - gag */
516 
517 Confmem sheevamem[] = {
518 	/*
519 	 * Memory available to Plan 9:
520 	 */
521 	{ .base = 0x00000000, .limit = 512*1024*1024, },
522 };
523 
524 void
525 confinit(void)
526 {
527 	int i;
528 	ulong kpages;
529 	uintptr pa;
530 
531 	/*
532 	 * Copy the physical memory configuration to Conf.mem.
533 	 * The physical memory configuration will be used later
534 	 * to check against what the the Pico Array wants.
535 	 */
536 	if(nelem(sheevamem) > nelem(conf.mem)){
537 		iprint("memory configuration botch\n");
538 		exit(1);
539 	}
540 	memmove(conf.mem, sheevamem, sizeof(sheevamem));
541 
542 	conf.npage = 0;
543 	pa = PADDR(PGROUND(PTR2UINT(end)));
544 
545 	/*
546 	 *  we assume that the kernel is at the beginning of one of the
547 	 *  contiguous chunks of memory and fits therein.
548 	 */
549 	for(i=0; i<nelem(conf.mem); i++){
550 		/* take kernel out of allocatable space */
551 		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
552 			conf.mem[i].base = pa;
553 
554 		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
555 		conf.npage += conf.mem[i].npage;
556 	}
557 
558 	conf.upages = (conf.npage*90)/100;
559 	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
560 
561 	/* only one processor */
562 	conf.nmach = 1;
563 
564 	/* set up other configuration parameters */
565 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
566 	if(cpuserver)
567 		conf.nproc *= 3;
568 	if(conf.nproc > 2000)
569 		conf.nproc = 2000;
570 	conf.nswap = conf.npage*3;
571 	conf.nswppo = 4096;
572 	conf.nimage = 200;
573 
574 	conf.copymode = 0;		/* copy on write */
575 
576 	/*
577 	 * Guess how much is taken by the large permanent
578 	 * datastructures. Mntcache and Mntrpc are not accounted for
579 	 * (probably ~300KB).
580 	 */
581 	kpages = conf.npage - conf.upages;
582 	kpages *= BY2PG;
583 	kpages -= conf.upages*sizeof(Page)
584 		+ conf.nproc*sizeof(Proc)
585 		+ conf.nimage*sizeof(Image)
586 		+ conf.nswap
587 		+ conf.nswppo*sizeof(Page);
588 	mainmem->maxsize = kpages;
589 	if(!cpuserver)
590 		/*
591 		 * give terminals lots of image memory, too; the dynamic
592 		 * allocation will balance the load properly, hopefully.
593 		 * be careful with 32-bit overflow.
594 		 */
595 		imagmem->maxsize = kpages;
596 }
597 
598 char*
599 getconf(char *)
600 {
601 	return nil;
602 }
603 
604 int
605 cmpswap(long *addr, long old, long new)
606 {
607 	return cas32(addr, old, new);
608 }
609