xref: /plan9/sys/src/9/teg2/main.c (revision 5c88beae5a9738eb333d417409242ad06a9c481a)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 
8 #include "init.h"
9 #include <pool.h>
10 #include <tos.h>
11 
12 #include "arm.h"
13 #include "reboot.h"
14 
15 /*
16  * Where configuration info is left for the loaded programme.
17  * This will turn into a structure as more is done by the boot loader
18  * (e.g. why parse the .ini file twice?).
19  * There are 3584 bytes available at CONFADDR.
20  */
21 #define BOOTARGS	((char*)CONFADDR)
22 #define	BOOTARGSLEN	(16*KiB)		/* limit in devenv.c */
23 #define	MAXCONF		64
24 #define MAXCONFLINE	160
25 
26 enum {
27 	Minmem	= 256*MB,			/* conservative default */
28 
29 	/* space for syscall args, return PC, top-of-stack struct */
30 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
31 };
32 
33 #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
34 
35 extern char bdata[], edata[], end[], etext[];
36 
37 uintptr kseg0 = KZERO;
38 Mach* machaddr[MAXMACH];
39 uchar *l2pages;
40 
41 Memcache cachel[8];		/* arm arch v7 supports 1-7 */
42 /*
43  * these are used by the cache.v7.s routines.
44  */
45 Lowmemcache *cacheconf;
46 
47 /*
48  * Option arguments from the command line.
49  * oargv[0] is the boot file.
50  * Optionsinit() is called from multiboot()
51  * or some other machine-dependent place
52  * to set it all up.
53  */
54 static int oargc;
55 static char* oargv[20];
56 static char oargb[128];
57 static int oargblen;
58 static char oenv[4096];
59 
60 static uintptr sp;		/* XXX - must go - user stack of init proc */
61 
62 int vflag;
63 int normalprint;
64 char debug[256];
65 
66 static Lock testlock;
67 
68 /* store plan9.ini contents here at least until we stash them in #ec */
69 static char confname[MAXCONF][KNAMELEN];
70 static char confval[MAXCONF][MAXCONFLINE];
71 static int nconf;
72 
73 static int
findconf(char * name)74 findconf(char *name)
75 {
76 	int i;
77 
78 	for(i = 0; i < nconf; i++)
79 		if(cistrcmp(confname[i], name) == 0)
80 			return i;
81 	return -1;
82 }
83 
84 char*
getconf(char * name)85 getconf(char *name)
86 {
87 	int i;
88 
89 	i = findconf(name);
90 	if(i >= 0)
91 		return confval[i];
92 	return nil;
93 }
94 
95 void
addconf(char * name,char * val)96 addconf(char *name, char *val)
97 {
98 	int i;
99 
100 	i = findconf(name);
101 	if(i < 0){
102 		if(val == nil || nconf >= MAXCONF)
103 			return;
104 		i = nconf++;
105 		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
106 	}
107 //	confval[i] = val;
108 	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
109 }
110 
111 static void
writeconf(void)112 writeconf(void)
113 {
114 	char *p, *q;
115 	int n;
116 
117 	p = getconfenv();
118 
119 	if(waserror()) {
120 		free(p);
121 		nexterror();
122 	}
123 
124 	/* convert to name=value\n format */
125 	for(q=p; *q; q++) {
126 		q += strlen(q);
127 		*q = '=';
128 		q += strlen(q);
129 		*q = '\n';
130 	}
131 	n = q - p + 1;
132 	if(n >= BOOTARGSLEN)
133 		error("kernel configuration too large");
134 	memmove(BOOTARGS, p, n);
135 	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
136 	poperror();
137 	free(p);
138 }
139 
140 /*
141  * assumes that we have loaded our /cfg/pxe/mac file at CONFADDR
142  * (usually 0x1000) with tftp in u-boot.  no longer uses malloc, so
143  * can be called early.
144  */
145 static void
plan9iniinit(void)146 plan9iniinit(void)
147 {
148 	char *k, *v, *next;
149 
150 	k = (char *)CONFADDR;
151 	if(!isascii(*k))
152 		return;
153 
154 	for(; k && *k != '\0'; k = next) {
155 		if (!isascii(*k))		/* sanity check */
156 			break;
157 		next = strchr(k, '\n');
158 		if (next)
159 			*next++ = '\0';
160 
161 		if (*k == '\0' || *k == '\n' || *k == '#')
162 			continue;
163 		v = strchr(k, '=');
164 		if(v == nil)
165 			continue;		/* mal-formed line */
166 		*v++ = '\0';
167 
168 		addconf(k, v);
169 	}
170 }
171 
172 static void
optionsinit(char * s)173 optionsinit(char* s)
174 {
175 	char *o;
176 
177 	strcpy(oenv, "");
178 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
179 	if(getenv("bootargs", o, o - oargb) != nil)
180 		*(o-1) = ' ';
181 
182 	oargblen = strlen(oargb);
183 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
184 	oargv[oargc] = nil;
185 }
186 
187 char*
getenv(char * name,char * buf,int n)188 getenv(char* name, char* buf, int n)
189 {
190 	char *e, *p, *q;
191 
192 	p = oenv;
193 	while(*p != 0){
194 		if((e = strchr(p, '=')) == nil)
195 			break;
196 		for(q = name; p < e; p++){
197 			if(*p != *q)
198 				break;
199 			q++;
200 		}
201 		if(p == e && *q == 0){
202 			strecpy(buf, buf+n, e+1);
203 			return buf;
204 		}
205 		p += strlen(p)+1;
206 	}
207 
208 	return nil;
209 }
210 
211 /* enable scheduling of this cpu */
212 void
machon(uint cpu)213 machon(uint cpu)
214 {
215 	ulong cpubit;
216 
217 	cpubit = 1 << cpu;
218 	lock(&active);
219 	if ((active.machs & cpubit) == 0) {	/* currently off? */
220 		conf.nmach++;
221 		active.machs |= cpubit;
222 	}
223 	unlock(&active);
224 }
225 
226 /* disable scheduling of this cpu */
227 void
machoff(uint cpu)228 machoff(uint cpu)
229 {
230 	ulong cpubit;
231 
232 	cpubit = 1 << cpu;
233 	lock(&active);
234 	if (active.machs & cpubit) {		/* currently on? */
235 		conf.nmach--;
236 		active.machs &= ~cpubit;
237 	}
238 	unlock(&active);
239 }
240 
241 void
machinit(void)242 machinit(void)
243 {
244 	Mach *m0;
245 
246 	if (m == 0) {
247 		serialputc('?');
248 		serialputc('m');
249 		serialputc('0');
250 	}
251 	if(machaddr[m->machno] != m) {
252 		serialputc('?');
253 		serialputc('m');
254 		serialputc('m');
255 	}
256 
257 	if (canlock(&testlock)) {
258 		serialputc('?');
259 		serialputc('l');
260 		panic("cpu%d: locks don't work", m->machno);
261 	}
262 
263 	m->ticks = 1;
264 	m->perf.period = 1;
265 	m0 = MACHP(0);
266 	if (m->machno != 0) {
267 		/* synchronise with cpu 0 */
268 		m->ticks = m0->ticks;
269 		m->fastclock = m0->fastclock;
270 		m->cpuhz = m0->cpuhz;
271 		m->delayloop = m0->delayloop;
272 	}
273 	if (m->machno != 0 &&
274 	    (m->fastclock == 0 || m->cpuhz == 0 || m->delayloop == 0))
275 		panic("buggered cpu 0 Mach");
276 
277 	machon(m->machno);
278 	fpoff();
279 }
280 
281 /* l.s has already zeroed Mach, which now contains our stack. */
282 void
mach0init(void)283 mach0init(void)
284 {
285 	if (m == 0) {
286 		serialputc('?');
287 		serialputc('m');
288 	}
289 	conf.nmach = 0;
290 
291 	m->machno = 0;
292 	machaddr[0] = m;
293 
294 	lock(&testlock);		/* hold this forever */
295 	machinit();
296 
297 	active.exiting = 0;
298 	l1cache->wbse(&active, sizeof active);
299 	up = nil;
300 }
301 
302 /*
303  *  count CPU's, set up their mach structures and l1 ptes.
304  *  we're running on cpu 0 and our data structures were
305  *  statically allocated.
306  */
307 void
launchinit(void)308 launchinit(void)
309 {
310 	int mach;
311 	Mach *mm;
312 	PTE *l1;
313 
314 	for(mach = 1; mach < MAXMACH; mach++){
315 		machaddr[mach] = mm = mallocalign(MACHSIZE, MACHSIZE, 0, 0);
316 		l1 = mallocalign(L1SIZE, L1SIZE, 0, 0);
317 		if(mm == nil || l1 == nil)
318 			panic("launchinit");
319 		memset(mm, 0, MACHSIZE);
320 		mm->machno = mach;
321 
322 		memmove(l1, (void *)L1, L1SIZE);  /* clone cpu0's l1 table */
323 		l1cache->wbse(l1, L1SIZE);
324 
325 		mm->mmul1 = l1;
326 		l1cache->wbse(mm, MACHSIZE);
327 	}
328 	l1cache->wbse(machaddr, sizeof machaddr);
329 	conf.nmach = 1;
330 }
331 
332 void
dump(void * vaddr,int words)333 dump(void *vaddr, int words)
334 {
335 	ulong *addr;
336 
337 	addr = vaddr;
338 	while (words-- > 0)
339 		iprint("%.8lux%c", *addr++, words % 8 == 0? '\n': ' ');
340 }
341 
342 static void
cacheinit(void)343 cacheinit(void)
344 {
345 	allcacheinfo(cachel);
346 	cacheconf = (Lowmemcache *)CACHECONF;
347 	cacheconf->l1waysh = cachel[1].waysh;
348 	cacheconf->l1setsh = cachel[1].setsh;
349 	/* on the tegra 2, l2 is unarchitected */
350 	cacheconf->l2waysh = cachel[2].waysh;
351 	cacheconf->l2setsh = cachel[2].setsh;
352 
353 	l2pl310init();
354 	allcacheson();
355 	allcache->wb();
356 }
357 
358 void
l2pageinit(void)359 l2pageinit(void)
360 {
361 	l2pages = KADDR(PHYSDRAM + DRAMSIZE - RESRVDHIMEM);
362 }
363 
364 /*
365  * at entry, l.s has set m for cpu0 and printed "Plan 9 from Be"
366  * but has not zeroed bss.
367  */
368 void
main(void)369 main(void)
370 {
371 	int cpu;
372 	static ulong vfy = 0xcafebabe;
373 
374 	up = nil;
375 	if (vfy != 0xcafebabe) {
376 		serialputc('?');
377 		serialputc('d');
378 		panic("data segment misaligned");
379 	}
380 
381 	memset(edata, 0, end - edata);
382 
383 	/*
384 	 * we can't lock until smpon has run, but we're supposed to wait
385 	 * until l1 & l2 are on.  too bad.  l1 is on, l2 will soon be.
386 	 */
387 	smpon();
388 	iprint("ll Labs ");
389 	cacheinit();
390 
391 	/*
392 	 * data segment is aligned, bss is zeroed, caches' characteristics
393 	 * are known.  begin initialisation.
394 	 */
395 	mach0init();
396 	l2pageinit();
397 	mmuinit();
398 
399 	optionsinit("/boot/boot boot");
400 	quotefmtinstall();
401 
402 	/* want plan9.ini to be able to affect memory sizing in confinit */
403 	plan9iniinit();		/* before we step on plan9.ini in low memory */
404 
405 	/* l2 looks for *l2off= in plan9.ini */
406 	l2cache->on();		/* l2->on requires locks to work, thus smpon */
407 	l2cache->info(&cachel[2]);
408 	allcache->on();
409 
410 	cortexa9cachecfg();
411 
412 	trapinit();		/* so confinit can probe memory to size it */
413 	confinit();		/* figures out amount of memory */
414 	/* xinit prints (if it can), so finish up the banner here. */
415 	delay(100);
416 	navailcpus = getncpus();
417 	iprint("(mp arm; %d cpus)\n\n", navailcpus);
418 	delay(100);
419 
420 	for (cpu = 1; cpu < navailcpus; cpu++)
421 		stopcpu(cpu);
422 
423 	xinit();
424 	irqtooearly = 0;	/* now that xinit and trapinit have run */
425 
426 	mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
427 
428 	/*
429 	 * Printinit will cause the first malloc call.
430 	 * (printinit->qopen->malloc) unless any of the
431 	 * above (like clockinit) do an irqenable, which
432 	 * will call malloc.
433 	 * If the system dies here it's probably due
434 	 * to malloc(->xalloc) not being initialised
435 	 * correctly, or the data segment is misaligned
436 	 * (it's amazing how far you can get with
437 	 * things like that completely broken).
438 	 *
439 	 * (Should be) boilerplate from here on.
440 	 */
441 
442 	archreset();			/* cfg clock signals, print cache cfg */
443 	clockinit();			/* start clocks */
444 	timersinit();
445 
446 	delay(50);			/* let uart catch up */
447 	printinit();
448 	kbdenable();
449 
450 	cpuidprint();
451 	chkmissing();
452 
453 	procinit0();
454 	initseg();
455 
456 //	dmainit();
457 	links();
458 	conf.monitor = 1;
459 //	screeninit();
460 
461 	iprint("pcireset...");
462 	pcireset();			/* this tends to hang after a reboot */
463 	iprint("ok\n");
464 
465 	chandevreset();			/* most devices are discovered here */
466 //	i8250console();			/* too early; see init0 */
467 
468 	pageinit();			/* prints "1020M memory: ⋯ */
469 	swapinit();
470 	userinit();
471 
472 	/*
473 	 * starting a cpu will eventually result in it calling schedinit,
474 	 * so everything necessary to run user processes should be set up
475 	 * before starting secondary cpus.
476 	 */
477 	launchinit();
478 	/* SMP & FW are already on when we get here; u-boot set them? */
479 	for (cpu = 1; cpu < navailcpus; cpu++)
480 		if (startcpu(cpu) < 0)
481 			panic("cpu%d didn't start", cpu);
482 	l1diag();
483 
484 	schedinit();
485 	panic("cpu%d: schedinit returned", m->machno);
486 }
487 
488 static void
shutdown(int ispanic)489 shutdown(int ispanic)
490 {
491 	int ms, once;
492 
493 	lock(&active);
494 	if(ispanic)
495 		active.ispanic = ispanic;
496 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
497 		active.ispanic = 0;
498 	once = active.machs & (1<<m->machno);
499 	/*
500 	 * setting exiting will make hzclock() on each processor call exit(0),
501 	 * which calls shutdown(0) and idles non-bootstrap cpus and returns
502 	 * on bootstrap processors (to permit a reboot).  clearing our bit
503 	 * in machs avoids calling exit(0) from hzclock() on this processor.
504 	 */
505 	active.machs &= ~(1<<m->machno);
506 	active.exiting = 1;
507 	unlock(&active);
508 
509 	if(once) {
510 		delay(m->machno*1000);		/* stagger them */
511 		iprint("cpu%d: exiting\n", m->machno);
512 	}
513 	spllo();
514 	if (m->machno == 0)
515 		ms = 5*1000;
516 	else
517 		ms = 2*1000;
518 	for(; ms > 0; ms -= TK2MS(2)){
519 		delay(TK2MS(2));
520 		if(active.machs == 0 && consactive() == 0)
521 			break;
522 	}
523 	delay(500);
524 }
525 
526 /*
527  *  exit kernel either on a panic or user request
528  */
529 void
exit(int code)530 exit(int code)
531 {
532 	shutdown(code);
533 	splhi();
534 	if (m->machno == 0)
535 		archreboot();
536 	else {
537 		intrcpushutdown();
538 		stopcpu(m->machno);
539 		for (;;)
540 			idlehands();
541 	}
542 }
543 
544 int
isaconfig(char * class,int ctlrno,ISAConf * isa)545 isaconfig(char *class, int ctlrno, ISAConf *isa)
546 {
547 	char cc[32], *p;
548 	int i;
549 
550 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
551 	p = getconf(cc);
552 	if(p == nil)
553 		return 0;
554 
555 	isa->type = "";
556 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
557 	for(i = 0; i < isa->nopt; i++){
558 		p = isa->opt[i];
559 		if(cistrncmp(p, "type=", 5) == 0)
560 			isa->type = p + 5;
561 		else if(cistrncmp(p, "port=", 5) == 0)
562 			isa->port = strtoul(p+5, &p, 0);
563 		else if(cistrncmp(p, "irq=", 4) == 0)
564 			isa->irq = strtoul(p+4, &p, 0);
565 		else if(cistrncmp(p, "dma=", 4) == 0)
566 			isa->dma = strtoul(p+4, &p, 0);
567 		else if(cistrncmp(p, "mem=", 4) == 0)
568 			isa->mem = strtoul(p+4, &p, 0);
569 		else if(cistrncmp(p, "size=", 5) == 0)
570 			isa->size = strtoul(p+5, &p, 0);
571 		else if(cistrncmp(p, "freq=", 5) == 0)
572 			isa->freq = strtoul(p+5, &p, 0);
573 	}
574 	return 1;
575 }
576 
577 /*
578  * the new kernel is already loaded at address `code'
579  * of size `size' and entry point `entry'.
580  */
581 void
reboot(void * entry,void * code,ulong size)582 reboot(void *entry, void *code, ulong size)
583 {
584 	int cpu, nmach, want, ms;
585 	void (*f)(ulong, ulong, ulong);
586 
587 	nmach = conf.nmach;
588 	writeconf();
589 
590 	/*
591 	 * the boot processor is cpu0.  execute this function on it
592 	 * so that the new kernel has the same cpu0.
593 	 */
594 	if (m->machno != 0) {
595 		procwired(up, 0);
596 		sched();
597 	}
598 	if (m->machno != 0)
599 		print("on cpu%d (not 0)!\n", m->machno);
600 
601 	/*
602 	 * the other cpus could be holding locks that will never get
603 	 * released (e.g., in the print path) if we put them into
604 	 * reset now, so force them to shutdown gracefully first.
605 	 */
606 	for (want = 0, cpu = 1; cpu < navailcpus; cpu++)
607 		want |= 1 << cpu;
608 	active.stopped = 0;
609 	shutdown(0);
610 	for (ms = 15*1000; ms > 0 && active.stopped != want; ms -= 10)
611 		delay(10);
612 	delay(20);
613 	if (active.stopped != want) {
614 		for (cpu = 1; cpu < nmach; cpu++)
615 			stopcpu(cpu);		/* make really sure */
616 		delay(20);
617 	}
618 
619 	/*
620 	 * should be the only processor running now
621 	 */
622 	pcireset();
623 //	print("reboot entry %#lux code %#lux size %ld\n",
624 //		PADDR(entry), PADDR(code), size);
625 
626 	/* turn off buffered serial console */
627 	serialoq = nil;
628 	kprintoq = nil;
629 	screenputs = nil;
630 
631 	/* shutdown devices */
632 	chandevshutdown();
633 
634 	/* call off the dog */
635 	clockshutdown();
636 
637 	splhi();
638 	intrshutdown();
639 
640 	/* setup reboot trampoline function */
641 	f = (void*)REBOOTADDR;
642 	memmove(f, rebootcode, sizeof(rebootcode));
643 	cachedwb();
644 	l2cache->wbinv();
645 	l2cache->off();
646 	cacheuwbinv();
647 
648 	/* off we go - never to return */
649 	(*f)(PADDR(entry), PADDR(code), size);
650 
651 	iprint("loaded kernel returned!\n");
652 	archreboot();
653 }
654 
655 /*
656  *  starting place for first process
657  */
658 void
init0(void)659 init0(void)
660 {
661 	int i;
662 	char buf[2*KNAMELEN];
663 
664 	up->nerrlab = 0;
665 	coherence();
666 	spllo();
667 
668 	/*
669 	 * These are o.k. because rootinit is null.
670 	 * Then early kproc's will have a root and dot.
671 	 */
672 	up->slash = namec("#/", Atodir, 0, 0);
673 	pathclose(up->slash->path);
674 	up->slash->path = newpath("/");
675 	up->dot = cclone(up->slash);
676 
677 	chandevinit();
678 	i8250console();		/* might be redundant, but harmless */
679 	if(kbdq == nil)
680 		panic("init0: nil kbdq");
681 	if(serialoq == nil)
682 		panic("init0: nil serialoq");
683 	normalprint = 1;
684 
685 	if(!waserror()){
686 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
687 		ksetenv("terminal", buf, 0);
688 		ksetenv("cputype", "arm", 0);
689 		if(cpuserver)
690 			ksetenv("service", "cpu", 0);
691 		else
692 			ksetenv("service", "terminal", 0);
693 
694 		/* convert plan9.ini variables to #e and #ec */
695 		for(i = 0; i < nconf; i++) {
696 			ksetenv(confname[i], confval[i], 0);
697 			ksetenv(confname[i], confval[i], 1);
698 		}
699 		poperror();
700 	}
701 	kproc("alarm", alarmkproc, 0);
702 //	kproc("startcpusproc", startcpusproc, nil);
703 
704 	touser(sp);
705 }
706 
707 static void
bootargs(uintptr base)708 bootargs(uintptr base)
709 {
710 	int i;
711 	ulong ssize;
712 	char **av, *p;
713 
714 	/*
715 	 * Push the boot args onto the stack.
716 	 * The initial value of the user stack must be such
717 	 * that the total used is larger than the maximum size
718 	 * of the argument list checked in syscall.
719 	 */
720 	i = oargblen+1;
721 	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
722 	memmove(p, oargb, i);
723 
724 	/*
725 	 * Now push argc and the argv pointers.
726 	 * This isn't strictly correct as the code jumped to by
727 	 * touser in init9.s calls startboot (port/initcode.c) which
728 	 * expects arguments
729 	 * 	startboot(char *argv0, char **argv)
730 	 * not the usual (int argc, char* argv[]), but argv0 is
731 	 * unused so it doesn't matter (at the moment...).
732 	 */
733 	av = (char**)(p - (oargc+2)*sizeof(char*));
734 	ssize = base + BY2PG - PTR2UINT(av);
735 	*av++ = (char*)oargc;
736 	for(i = 0; i < oargc; i++)
737 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
738 	*av = nil;
739 
740 	/*
741 	 * Leave space for the return PC of the
742 	 * caller of initcode.
743 	 */
744 	sp = USTKTOP - ssize - sizeof(void*);
745 }
746 
747 /*
748  *  create the first process
749  */
750 void
userinit(void)751 userinit(void)
752 {
753 	Proc *p;
754 	Segment *s;
755 	KMap *k;
756 	Page *pg;
757 
758 	/* no processes yet */
759 	up = nil;
760 
761 	p = newproc();
762 	p->pgrp = newpgrp();
763 	p->egrp = smalloc(sizeof(Egrp));
764 	p->egrp->ref = 1;
765 	p->fgrp = dupfgrp(nil);
766 	p->rgrp = newrgrp();
767 	p->procmode = 0640;
768 
769 	kstrdup(&eve, "");
770 	kstrdup(&p->text, "*init*");
771 	kstrdup(&p->user, eve);
772 
773 	/*
774 	 * Kernel Stack
775 	 */
776 	p->sched.pc = PTR2UINT(init0);
777 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
778 	p->sched.sp = STACKALIGN(p->sched.sp);
779 
780 	/*
781 	 * User Stack
782 	 *
783 	 * Technically, newpage can't be called here because it
784 	 * should only be called when in a user context as it may
785 	 * try to sleep if there are no pages available, but that
786 	 * shouldn't be the case here.
787 	 */
788 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
789 	s->flushme++;
790 	p->seg[SSEG] = s;
791 	pg = newpage(1, 0, USTKTOP-BY2PG);
792 	segpage(s, pg);
793 	k = kmap(pg);
794 	bootargs(VA(k));
795 	kunmap(k);
796 
797 	/*
798 	 * Text
799 	 */
800 	s = newseg(SG_TEXT, UTZERO, 1);
801 	p->seg[TSEG] = s;
802 	pg = newpage(1, 0, UTZERO);
803 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
804 	segpage(s, pg);
805 	k = kmap(s->map[0]->pages[0]);
806 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
807 	kunmap(k);
808 
809 	ready(p);
810 }
811 
812 Conf conf;			/* XXX - must go - gag */
813 
814 Confmem tsmem[nelem(conf.mem)] = {
815 	/*
816 	 * Memory available to Plan 9:
817 	 */
818 	{ .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
819 };
820 ulong memsize = DRAMSIZE;
821 
822 static int
gotmem(uintptr sz)823 gotmem(uintptr sz)
824 {
825 	uintptr addr;
826 
827 	/* back off a little from the end */
828 	addr = (uintptr)KADDR(PHYSDRAM + sz - BY2WD);
829 	if (probeaddr(addr) >= 0) {	/* didn't trap? memory present */
830 		memsize = sz;
831 		return 0;
832 	}
833 	return -1;
834 }
835 
836 void
confinit(void)837 confinit(void)
838 {
839 	int i;
840 	ulong kpages;
841 	uintptr pa;
842 	char *p;
843 
844 	/*
845 	 * Copy the physical memory configuration to Conf.mem.
846 	 */
847 	if(nelem(tsmem) > nelem(conf.mem)){
848 		iprint("memory configuration botch\n");
849 		exit(1);
850 	}
851 	if(0 && (p = getconf("*maxmem")) != nil) {
852 		memsize = strtoul(p, 0, 0) - PHYSDRAM;
853 		if (memsize < 16*MB)		/* sanity */
854 			memsize = 16*MB;
855 	}
856 
857 	/*
858 	 * see if all that memory exists; if not, find out how much does.
859 	 * trapinit must have been called first.
860 	 */
861 	if (gotmem(memsize - RESRVDHIMEM) < 0)
862 		panic("can't find 1GB of memory");
863 
864 	tsmem[0].limit = PHYSDRAM + memsize;
865 	memmove(conf.mem, tsmem, sizeof(tsmem));
866 
867 	conf.npage = 0;
868 	pa = PADDR(PGROUND(PTR2UINT(end)));
869 
870 	/*
871 	 *  we assume that the kernel is at the beginning of one of the
872 	 *  contiguous chunks of memory and fits therein.
873 	 */
874 	for(i=0; i<nelem(conf.mem); i++){
875 		/* take kernel out of allocatable space */
876 		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
877 			conf.mem[i].base = pa;
878 
879 		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
880 		conf.npage += conf.mem[i].npage;
881 	}
882 
883 	conf.upages = (conf.npage*80)/100;
884 	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
885 
886 	/* set up other configuration parameters */
887 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
888 	if(cpuserver)
889 		conf.nproc *= 3;
890 	if(conf.nproc > 2000)
891 		conf.nproc = 2000;
892 	conf.nswap = conf.npage*3;
893 	conf.nswppo = 4096;
894 	conf.nimage = 200;
895 
896 	/*
897 	 * it's simpler on mp systems to take page-faults early,
898 	 * on reference, rather than later, on write, which might
899 	 * require tlb shootdowns.
900 	 */
901 	conf.copymode = 1;		/* copy on reference */
902 
903 	/*
904 	 * Guess how much is taken by the large permanent
905 	 * datastructures. Mntcache and Mntrpc are not accounted for
906 	 * (probably ~300KB).
907 	 */
908 	kpages = conf.npage - conf.upages;
909 	kpages *= BY2PG;
910 	kpages -= conf.upages*sizeof(Page)
911 		+ conf.nproc*sizeof(Proc)
912 		+ conf.nimage*sizeof(Image)
913 		+ conf.nswap
914 		+ conf.nswppo*sizeof(Page);
915 	mainmem->maxsize = kpages;
916 	if(!cpuserver)
917 		/*
918 		 * give terminals lots of image memory, too; the dynamic
919 		 * allocation will balance the load properly, hopefully.
920 		 * be careful with 32-bit overflow.
921 		 */
922 		imagmem->maxsize = kpages;
923 
924 //	archconfinit();
925 }
926 
927 int
cmpswap(long * addr,long old,long new)928 cmpswap(long *addr, long old, long new)
929 {
930 	return cas((int *)addr, old, new);
931 }
932 
933 void
advertwfi(void)934 advertwfi(void)			/* advertise my wfi status */
935 {
936 	ilock(&active);
937 	active.wfi |= 1 << m->machno;
938 	iunlock(&active);
939 }
940 
941 void
unadvertwfi(void)942 unadvertwfi(void)		/* do not advertise my wfi status */
943 {
944 	ilock(&active);
945 	active.wfi &= ~(1 << m->machno);
946 	iunlock(&active);
947 }
948 
949 void
idlehands(void)950 idlehands(void)
951 {
952 #ifdef use_ipi
953 	int advertised;
954 
955 	/* don't go into wfi until my local timer is ticking */
956 	if (m->ticks <= 1)
957 		return;
958 
959 	advertised = 0;
960 	m->inidlehands++;
961 	/* avoid recursion via ilock, advertise iff this cpu is initialised */
962 	if (m->inidlehands == 1 && m->syscall > 0) {
963 		advertwfi();
964 		advertised = 1;
965 	}
966 
967 	wfi();
968 
969 	if (advertised)
970 		unadvertwfi();
971 	m->inidlehands--;
972 #endif
973 }
974 
975 void
wakewfi(void)976 wakewfi(void)
977 {
978 #ifdef use_ipi
979 	uint cpu;
980 
981 	/*
982 	 * find any cpu other than me currently in wfi.
983 	 * need not be exact.
984 	 */
985 	cpu = BI2BY*BY2WD - 1 - clz(active.wfi & ~(1 << m->machno));
986 	if (cpu < MAXMACH)
987 		intrcpu(cpu);
988 #endif
989 }
990