xref: /plan9/sys/src/9/rb/main.c (revision 23a969667fc2f16f64e45b0a4135d6dd31daef7a)
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 #include	"init.h"
8 #include	"pool.h"
9 #include	"../ip/ip.h"
10 #include	<tos.h>
11 #include	<bootexec.h>
12 #include	"reboot.h"
13 
14 enum {
15 	/* space for syscall args, return PC, top-of-stack struct */
16 	Stkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
17 };
18 
19 typedef struct mipsexec Mipsexec;
20 
21 /*
22  * Option arguments from the command line.
23  * oargv[0] is the boot file.
24  */
25 static int oargc;
26 static char* oargv[20];
27 static char oargb[128];
28 static int oargblen;
29 
30 static uintptr sp;		/* XXX - must go - user stack of init proc */
31 
32 /*
33  * software tlb simulation
34  */
35 static Softtlb stlb[MAXMACH][STLBSIZE];
36 
37 Conf	conf;
38 FPsave	initfp;
39 
40 int normalprint;
41 
42 char *
getconf(char *)43 getconf(char *)
44 {
45 	return nil;	/* stub */
46 }
47 
48 static void
optionsinit(char * s)49 optionsinit(char* s)
50 {
51 	strecpy(oargb, oargb+sizeof(oargb), s);
52 
53 	oargblen = strlen(oargb);
54 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
55 	oargv[oargc] = nil;
56 }
57 
58 static void
prcpuid(void)59 prcpuid(void)
60 {
61 	ulong cpuid, cfg1;
62 	char *cpu;
63 
64 	cpuid = prid();
65 	if (((cpuid>>16) & MASK(8)) == 0)		/* vendor */
66 		cpu = "old mips";
67 	else if (((cpuid>>16) & MASK(8)) == 1)
68 		switch ((cpuid>>8) & MASK(8)) {		/* processor */
69 		case 0x93:
70 			cpu = "mips 24k";
71 			break;
72 		case 0x96:
73 			cpu = "mips 24ke";
74 			break;
75 		default:
76 			cpu = "mips";
77 			break;
78 		}
79 	else
80 		cpu = "other mips";
81 	delay(20);
82 	print("cpu%d: %ldMHz %s %se v%ld.%ld rev %ld, ",
83 		m->machno, m->hz / Mhz, cpu, getconfig() & (1<<15)? "b": "l",
84 		(cpuid>>5) & MASK(3), (cpuid>>2) & MASK(3), cpuid & MASK(2));
85 	delay(200);
86 	cfg1 = getconfig1();
87 	print("%s fpu\n", (cfg1 & 1? "has": "no"));
88 	print("cpu%d: %ld tlb entries, using %dK pages\n", m->machno,
89 		((cfg1>>25) & MASK(6)) + 1, BY2PG/1024);
90 	delay(50);
91 	print("cpu%d: l1 i cache: %d sets 4 ways 32 bytes/line\n", m->machno,
92 		64 << ((cfg1>>22) & MASK(3)));
93 	delay(50);
94 	print("cpu%d: l1 d cache: %d sets 4 ways 32 bytes/line\n", m->machno,
95 		64 << ((cfg1>>13) & MASK(3)));
96 	delay(500);
97 	if (0)
98 		print("cpu%d: cycle counter res = %ld\n",
99 			m->machno, gethwreg3());
100 }
101 
102 static void
fmtinit(void)103 fmtinit(void)
104 {
105 	printinit();
106 	quotefmtinstall();
107 	/* ipreset installs these when chandevreset runs */
108 	fmtinstall('i', eipfmt);
109 	fmtinstall('I', eipfmt);
110 	fmtinstall('E', eipfmt);
111 	fmtinstall('V', eipfmt);
112 	fmtinstall('M', eipfmt);
113 }
114 
115 static int
ckpagemask(ulong mask,ulong size)116 ckpagemask(ulong mask, ulong size)
117 {
118 	int s;
119 	ulong pm;
120 
121 	s = splhi();
122 	setpagemask(mask);
123 	pm = getpagemask();
124 	splx(s);
125 	if(pm != mask){
126 		iprint("page size %ldK not supported on this cpu; "
127 			"mask %#lux read back as %#lux\n", size/1024, mask, pm);
128 		return -1;
129 	}
130 	return 0;
131 }
132 
133 /* called from rebootcmd() */
134 int
parsemipsboothdr(Chan * c,ulong magic,Execvals * evp)135 parsemipsboothdr(Chan *c, ulong magic, Execvals *evp)
136 {
137 	long extra;
138 	Mipsexec me;
139 
140 	/*
141 	 * BOOT_MAGIC is sometimes defined like this:
142 	 * #define BOOT_MAGIC	(0x160<<16) || magic == ((0x160<<16)|3)
143 	 * so we can only use it in a fairly stylized manner.
144 	 */
145 	if(magic == BOOT_MAGIC) {
146 		c->offset = 0;			/* back up */
147 		readn(c, &me, sizeof me);
148 		/* if binary is -H1, read an extra long */
149 		if (l2be(me.amagic) == 0407 && me.nscns == 0)
150 			readn(c, &extra, sizeof extra);
151 		evp->entry = l2be(me.mentry);
152 		evp->textsize = l2be(me.tsize);
153 		evp->datasize = l2be(me.dsize);
154 		return 0;
155 	} else
156 		return -1;
157 }
158 
159 void
main(void)160 main(void)
161 {
162 	stopwdog();			/* tranquilise the dog */
163 	optionsinit("/boot/boot boot");
164 	confinit();
165 	savefpregs(&initfp);
166 
167 	machinit();			/* calls clockinit */
168 	active.exiting = 0;
169 	active.machs = 1;
170 
171 	kmapinit();
172 	xinit();
173 
174 	timersinit();
175 	fmtinit();
176 	vecinit();
177 
178 	normalprint = 1;
179 	print("\nPlan 9\n");
180 	prcpuid();
181 	if (PTECACHABILITY == PTENONCOHERWT)
182 		print("caches configured as write-through\n");
183 	if (0)
184 		xsummary();
185 
186 	ckpagemask(PGSZ, BY2PG);
187 	tlbinit();
188 	machwire();
189 	pageinit();
190 	procinit0();
191 	initseg();
192 	links();
193 	chandevreset();
194 
195 	swapinit();
196 	userinit();
197 	sicwdog();
198 	parseboothdr = parsemipsboothdr;
199 	schedinit();
200 	panic("schedinit returned");
201 }
202 
203 /*
204  *  initialize a processor's mach structure.  each processor does this
205  *  for itself.
206  */
207 void
machinit(void)208 machinit(void)
209 {
210 	/* Ensure CU1 is off */
211 	clrfpintr();
212 
213 	m->stb = &stlb[m->machno][0];
214 
215 	clockinit();
216 }
217 
218 /*
219  *  setup MIPS trap vectors
220  */
221 void
vecinit(void)222 vecinit(void)
223 {
224 	memmove((ulong*)UTLBMISS, (ulong*)vector0, 0x80);
225 	memmove((ulong*)XEXCEPTION, (ulong*)vector0, 0x80);
226 	memmove((ulong*)CACHETRAP, (ulong*)vector100, 0x80);
227 	memmove((ulong*)EXCEPTION, (ulong*)vector180, 0x80);
228 	memmove((ulong*)(KSEG0+0x200), (ulong*)vector180, 0x80);
229 	icflush((ulong*)UTLBMISS, 4*1024);
230 
231 	setstatus(getstatus() & ~BEV);
232 }
233 
234 void
init0(void)235 init0(void)
236 {
237 	char buf[128];
238 
239 	up->nerrlab = 0;
240 
241 	spllo();
242 
243 	/*
244 	 * These are o.k. because rootinit is null.
245 	 * Then early kproc's will have a root and dot.
246 	 */
247 	up->slash = namec("#/", Atodir, 0, 0);
248 	pathclose(up->slash->path);
249 	up->slash->path = newpath("/");
250 	up->dot = cclone(up->slash);
251 
252 	chandevinit();
253 
254 	if(!waserror()){
255 		ksetenv("cputype", "mips", 0);
256 		snprint(buf, sizeof buf, "mips %s rb450g", conffile);
257 		ksetenv("terminal", buf, 0);
258 		if(cpuserver)
259 			ksetenv("service", "cpu", 0);
260 		else
261 			ksetenv("service", "terminal", 0);
262 		/*
263 		 * we don't have a good way to read our cfg file in
264 		 * RouterBOOT, so set the configuration here.
265 		 */
266 		ksetenv("nobootprompt", "tcp", 0);
267 		ksetenv("nvram", "/boot/nvram", 0);
268 		poperror();
269 	}
270 	kproc("alarm", alarmkproc, 0);
271 	i8250console();
272 	touser(sp);
273 }
274 
275 FPsave	initfp;
276 
277 static void
bootargs(uintptr base)278 bootargs(uintptr base)
279 {
280 	int i;
281 	ulong ssize;
282 	char **av, *p;
283 
284 	/*
285 	 * Push the boot args onto the stack.
286 	 * The initial value of the user stack must be such
287 	 * that the total used is larger than the maximum size
288 	 * of the argument list checked in syscall.
289 	 */
290 	i = oargblen+1;
291 	p = UINT2PTR(STACKALIGN(base + BY2PG - Stkheadroom - i));
292 	memmove(p, oargb, i);
293 
294 	/*
295 	 * Now push the argv pointers.
296 	 * The code jumped to by touser in lproc.s expects arguments
297 	 *	main(char* argv0, ...)
298 	 * and calls
299 	 * 	startboot("/boot/boot", &argv0)
300 	 * not the usual (int argc, char* argv[])
301 	 */
302 	av = (char**)(p - (oargc+1)*sizeof(char*));
303 	ssize = base + BY2PG - PTR2UINT(av);
304 	for(i = 0; i < oargc; i++)
305 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
306 	*av = nil;
307 	sp = USTKTOP - ssize;
308 }
309 
310 void
userinit(void)311 userinit(void)
312 {
313 	Proc *p;
314 	KMap *k;
315 	Page *pg;
316 	Segment *s;
317 
318 	p = newproc();
319 	p->pgrp = newpgrp();
320 	p->egrp = smalloc(sizeof(Egrp));
321 	p->egrp->ref = 1;
322 	p->fgrp = dupfgrp(nil);
323 	p->rgrp = newrgrp();
324 	p->procmode = 0640;
325 
326 	kstrdup(&eve, "");
327 	kstrdup(&p->text, "*init*");
328 	kstrdup(&p->user, eve);
329 
330 	p->fpstate = FPinit;
331 	p->fpsave.fpstatus = initfp.fpstatus;
332 
333 	/*
334 	 * Kernel Stack
335 	 */
336 	p->sched.pc = (ulong)init0;
337 	p->sched.sp = (ulong)p->kstack+KSTACK-Stkheadroom;
338 	p->sched.sp = STACKALIGN(p->sched.sp);
339 
340 	/*
341 	 * User Stack
342 	 *
343 	 * Technically, newpage can't be called here because it
344 	 * should only be called when in a user context as it may
345 	 * try to sleep if there are no pages available, but that
346 	 * shouldn't be the case here.
347 	 */
348 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
349 	p->seg[SSEG] = s;
350 	pg = newpage(1, 0, USTKTOP-BY2PG);
351 	segpage(s, pg);
352 	k = kmap(pg);
353 	bootargs(VA(k));
354 	kunmap(k);
355 
356 	/*
357 	 * Text
358 	 */
359 	s = newseg(SG_TEXT, UTZERO, 1);
360 	s->flushme++;
361 	p->seg[TSEG] = s;
362 	pg = newpage(1, 0, UTZERO);
363 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
364 	segpage(s, pg);
365 	k = kmap(s->map[0]->pages[0]);
366 	memset((void *)VA(k), 0, BY2PG);
367 	memmove((ulong*)VA(k), initcode, sizeof initcode);
368 	kunmap(k);
369 
370 	ready(p);
371 }
372 
373 void
procrestore(Proc * p)374 procrestore(Proc *p)
375 {
376 	uvlong t;
377 
378 	if(p->kp)
379 		return;
380 	cycles(&t);
381 	p->pcycles -= t;
382 }
383 
384 /*
385  *  Save the mach dependent part of the process state.
386  */
387 void
procsave(Proc * p)388 procsave(Proc *p)
389 {
390 	uvlong t;
391 
392 	cycles(&t);
393 	p->pcycles += t;
394 	/* no fpu, so no fp state to save */
395 }
396 
397 static void
writeconf(void)398 writeconf(void)
399 {
400 	char *p, *q;
401 	int n;
402 
403 	p = getconfenv();
404 
405 	if(waserror()) {
406 		free(p);
407 		nexterror();
408 	}
409 
410 	/* convert to name=value\n format */
411 	for(q=p; *q; q++) {
412 		q += strlen(q);
413 		*q = '=';
414 		q += strlen(q);
415 		*q = '\n';
416 	}
417 	n = q - p + 1;
418 #ifdef BOOTARGS_EXIST
419 	if(n >= BOOTARGSLEN)
420 		error("kernel configuration too large");
421 	memmove(BOOTARGS, p, n);
422 	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
423 #endif
424 	USED(n);
425 	poperror();
426 	free(p);
427 }
428 
429 static void
shutdown(int ispanic)430 shutdown(int ispanic)
431 {
432 	int ms, once;
433 
434 	ilock(&active);
435 	if(ispanic)
436 		active.ispanic = ispanic;
437 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
438 		active.ispanic = 0;
439 	once = active.machs & (1<<m->machno);
440 	/*
441 	 * setting exiting will make hzclock() on each processor call exit(0),
442 	 * which calls shutdown(0) and idles non-bootstrap cpus and returns
443 	 * on bootstrap processors (to permit a reboot).  clearing our bit
444 	 * in machs avoids calling exit(0) from hzclock() on this processor.
445 	 */
446 	active.machs &= ~(1<<m->machno);
447 	active.exiting = 1;
448 	iunlock(&active);
449 
450 	if(once) {
451 		delay(m->machno*1000);		/* stagger them */
452 		iprint("cpu%d: exiting\n", m->machno);
453 	}
454 	spllo();
455 	ms = MAXMACH * 1000;
456 	for(; ms > 0; ms -= TK2MS(2)){
457 		delay(TK2MS(2));
458 		if(active.machs == 0 && consactive() == 0)
459 			break;
460 	}
461 	delay(100);
462 }
463 
464 /*
465  * the new kernel is already loaded at address `code'
466  * of size `size' and entry point `entry'.
467  */
468 void
reboot(void * entry,void * code,ulong size)469 reboot(void *entry, void *code, ulong size)
470 {
471 	void (*f)(ulong, ulong, ulong);
472 
473 	writeconf();
474 
475 	/*
476 	 * the boot processor is cpu0.  execute this function on it
477 	 * so that the new kernel has the same cpu0.
478 	 */
479 	if (m->machno != 0) {
480 		procwired(up, 0);
481 		sched();
482 	}
483 	if (m->machno != 0)
484 		print("on cpu%d (not 0)!\n", m->machno);
485 
486 	shutdown(0);
487 
488 	/*
489 	 * should be the only processor running now
490 	 */
491 //	iprint("reboot: entry %#p code %#p size %ld\n", entry, code, size);
492 //	iprint("code[0] = %#lux\n", *(ulong *)code);
493 
494 	/* turn off buffered serial console */
495 	serialoq = nil;
496 	kprintoq = nil;
497 	screenputs = nil;
498 
499 	/* shutdown devices */
500 	chandevshutdown();
501 
502 	/* call off the dog */
503 	clockshutdown();
504 
505 	splhi();
506 	intrshutdown();
507 
508 	/* is the watchdog tied into the usb machinery? */
509 //	*Reset |= Rstusbohcidll | Rstusbhost | Rstusbphy;
510 //		Rstge0mac | Rstge0phy |
511 //		Rstge1mac | Rstge1phy;
512 
513 	/* setup reboot trampoline function */
514 	f = (void*)REBOOTADDR;
515 	memmove(f, rebootcode, sizeof(rebootcode));
516 	icflush(f, sizeof(rebootcode));
517 
518 	setstatus(BEV);		/* also, kernel mode, no interrupts */
519 	coherence();
520 
521 	/* off we go - never to return */
522 	(*f)((ulong)entry, (ulong)code, size);
523 
524 	panic("loaded kernel returned!");
525 }
526 
527 void
exit(int type)528 exit(int type)
529 {
530 	int timer;
531 	void (*fnp)(void);
532 
533 	stopwdog();
534 
535 	delay(1000);
536 	lock(&active);
537 	active.machs &= ~(1<<m->machno);
538 	active.exiting = 1;
539 	unlock(&active);
540 	spllo();
541 
542 	print("cpu %d exiting\n", m->machno);
543 	timer = 0;
544 	while(active.machs || consactive()) {
545 		if(timer++ > 400)
546 			break;
547 		delay(10);
548 	}
549 	delay(1000);
550 	splhi();
551 	USED(type);
552 
553 	setstatus(BEV);
554 	coherence();
555 
556 	iprint("exit: awaiting reset\n");
557 	wdogreset();			/* wake the dog with v. short timeout */
558 
559 //	*Reset |= Rstfullchip;
560 //	*Reset |= Rstcpucold;
561 
562 	delay(1000);			/* await a reset */
563 
564 	iprint("exit: jumping to rom\n");
565 	fnp = (void (*)(void))ROM;
566 	(*fnp)();
567 
568 	iprint("exit: looping\n");
569 	for (;;)
570 		;
571 }
572 
573 void
idlehands(void)574 idlehands(void)
575 {
576 	stopwdog();
577 	idle();
578 	sicwdog();			/* wake the dog */
579 }
580 
581 void
confinit(void)582 confinit(void)
583 {
584 	ulong kpages, ktop;
585 
586 	/*
587 	 *  divide memory twixt user pages and kernel.
588 	 */
589 	conf.mem[0].base = ktop = PADDR(PGROUND((ulong)end));
590 	/* fixed memory on routerboard */
591 	conf.mem[0].npage = MEMSIZE/BY2PG - ktop/BY2PG;
592 	conf.npage = conf.mem[0].npage;
593 	conf.nuart = 1;
594 
595 	kpages = conf.npage - (conf.npage*80)/100;
596 	if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
597 		kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
598 		kpages += (conf.nproc*KSTACK)/BY2PG;
599 	}
600 	conf.upages = conf.npage - kpages;
601 	conf.ialloc = (kpages/2)*BY2PG;
602 
603 	kpages *= BY2PG;
604 	kpages -= conf.upages*sizeof(Page)
605 		+ conf.nproc*sizeof(Proc)
606 		+ conf.nimage*sizeof(Image)
607 		+ conf.nswap
608 		+ conf.nswppo*sizeof(Page);
609 	mainmem->maxsize = kpages;
610 
611 	/*
612 	 *  set up CPU's mach structure
613 	 *  cpu0's was zeroed in l.s and our stack is in Mach, so don't zero it.
614 	 */
615 	m->machno = 0;
616 	m->speed = 680;			/* initial guess at MHz, for rb450g */
617 	m->hz = m->speed * Mhz;
618 	conf.nmach = 1;
619 
620 	/* set up other configuration parameters */
621 	conf.nproc = 2000;
622 	conf.nswap = 262144;
623 	conf.nswppo = 4096;
624 	conf.nimage = 200;
625 
626 	conf.copymode = 0;		/* copy on write */
627 }
628