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