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