xref: /plan9/sys/src/9/ppc/main.c (revision 4de34a7edde43207e841ec91ecd12e6cf5f5ebe7)
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	"tos.h"
10 
11 #define	MAXCONF		64
12 
13 typedef struct Plan9ini Plan9ini;
14 struct Plan9ini
15 {
16 	char	*name;
17 	char	*val;
18 };
19 
20 char *plan9inistr;
21 Plan9ini plan9ini[MAXCONF];
22 int nconf;
23 
24 Conf conf;
25 FPsave initfp;
26 Lock testlock;
27 
28 static void plan9iniinit(void);
29 
30 char *
cpuid(void)31 cpuid(void)
32 {
33 	char *id;
34 
35 	id = "unknown PowerPC";
36 	switch(m->cputype) {
37 	case 8:
38 		id = "PowerPC 750";
39 		break;
40 	case 9:
41 		id = "PowerPC 604e";
42 		break;
43 	case 0x81:
44 		id = "PowerPC 8260";
45 		break;
46 	case 0x8081:
47 		id = "PowerPC 826xA";
48 		break;
49 	default:
50 		break;
51 	}
52 	return id;
53 }
54 
55 void
cpuidprint(void)56 cpuidprint(void)
57 {
58 	print("cpu0: %s, rev 0x%lux, cpu hz %lld, bus hz %ld\n",
59 		cpuid(), getpvr()&0xffff, m->cpuhz, m->bushz);
60 }
61 
62 void
main(void)63 main(void)
64 {
65 	memset(edata, 0, (ulong)end-(ulong)edata);
66 	conf.nmach = 1;
67 	machinit();
68 	confinit();
69 	xinit();
70 	trapinit();
71 	mmuinit();
72 	plan9iniinit();
73 	hwintrinit();
74 	clockinit();
75 	timerinit();
76 	console();
77 	quotefmtinstall();
78 	printinit();
79 	cpuidprint();
80 	print("\nPlan 9 from Bell Labs\n");
81 	procinit0();
82 	initseg();
83 	timersinit();
84 	links();
85 	chandevreset();
86 	pageinit();
87 	swapinit();
88 	sharedseginit();
89 	fpsave(&initfp);
90 	initfp.fpscr = 0;
91 	userinit();
92 	schedinit();
93 }
94 
95 char*
getconf(char * name)96 getconf(char *name)
97 {
98 	int i;
99 
100 	for(i = 0; i < nconf; i++)
101 		if(cistrcmp(name, plan9ini[i].name) == 0)
102 			return plan9ini[i].val;
103 	return nil;
104 }
105 
106 static void
plan9iniinit(void)107 plan9iniinit(void)
108 {
109 	long i;
110 	int c;
111 	char *cp, line[MAXCONF], *p, *q;
112 
113 	/*
114 	 *  parse configuration args from dos file plan9.ini
115 	 */
116 
117 	cp = plan9inistr;
118 	for(i = 0; i < MAXCONF; i++){
119 		/*
120 		 * Strip out '\r', change '\t' -> ' ', test for 0xff which is end of file
121 		 */
122 		p = line;
123 		for(q = cp; c = (uchar)*q; q++){
124 			if(c == '\r')
125 				continue;
126 			if(c == '\t')
127 				c = ' ';
128 			if(c == 0xff || c == '\n')
129 				break;
130 			*p++ = c;
131 		}
132 		*p = 0;
133 		if (*line == 0)
134 			break;
135 		if(*line != '#' && (cp = strchr(line, '='))){
136 			*cp++ = '\0';
137 			kstrdup(&plan9ini[nconf].name, line);
138 			kstrdup(&plan9ini[nconf].val, cp);
139 			nconf++;
140 		}
141 		if (c == 0xff)
142 			break;
143 
144 		cp = q + 1;
145 	}
146 }
147 
148 void
init0(void)149 init0(void)
150 {
151 //	char **p, *q, name[KNAMELEN];
152 	int i;
153 	char buf[2*KNAMELEN];
154 
155 	up->nerrlab = 0;
156 	spllo();
157 
158 	/*
159 	 * These are o.k. because rootinit is null.
160 	 * Then early kproc's will have a root and dot.
161 	 */
162 	up->slash = namec("#/", Atodir, 0, 0);
163 	pathclose(up->slash->path);
164 	up->slash->path = newpath("/");
165 	up->dot = cclone(up->slash);
166 
167 	chandevinit();
168 
169 	if(!waserror()){
170 		snprint(buf, sizeof(buf), "power %s mtx", conffile);
171 		ksetenv("terminal", buf, 0);
172 		ksetenv("cputype", "power", 0);
173 		if(cpuserver)
174 			ksetenv("service", "cpu", 0);
175 		else
176 			ksetenv("service", "terminal", 0);
177 
178 		for(i = 0; i < nconf; i++){
179 			if(plan9ini[i].name[0] != '*')
180 				ksetenv(plan9ini[i].name, plan9ini[i].val, 0);
181 			ksetenv(plan9ini[i].name, plan9ini[i].val, 1);
182 		}
183 		poperror();
184 	}
185 	kproc("alarm", alarmkproc, 0);
186 	kproc("mmusweep", mmusweep, 0);
187 	touser((void*)(USTKTOP-sizeof(Tos)));
188 }
189 
190 void
userinit(void)191 userinit(void)
192 {
193 	Proc *p;
194 	Segment *s;
195 	KMap *k;
196 	Page *pg;
197 
198 	p = newproc();
199 	p->pgrp = newpgrp();
200 	p->egrp = smalloc(sizeof(Egrp));
201 	p->egrp->ref = 1;
202 	p->fgrp = dupfgrp(nil);
203 	p->rgrp = newrgrp();
204 	p->procmode = 0640;
205 
206 	kstrdup(&eve, "");
207 	kstrdup(&p->text, "*init*");
208 	kstrdup(&p->user, eve);
209 
210 	p->fpstate = FPinit;
211 
212 	/*
213 	 *  Stack
214 	 *
215 	 * N.B. The -12 for the stack pointer is important.
216 	 *	4 bytes for gotolabel's return PC
217 	 */
218 	p->sched.pc = (ulong)init0;
219 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
220 
221 	/*
222 	 * User Stack
223 	 */
224 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
225 	p->seg[SSEG] = s;
226 	pg = newpage(1, 0, USTKTOP-BY2PG);
227 	segpage(s, pg);
228 
229 	/*
230 	 * Text
231 	 */
232 	s = newseg(SG_TEXT, UTZERO, 1);
233 	s->flushme++;
234 	p->seg[TSEG] = s;
235 	pg = newpage(1, 0, UTZERO);
236 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
237 	segpage(s, pg);
238 	k = kmap(s->map[0]->pages[0]);
239 	memmove((ulong*)VA(k), initcode, sizeof initcode);
240 	kunmap(k);
241 
242 	ready(p);
243 }
244 
245 void
exit(int ispanic)246 exit(int ispanic)
247 {
248 	int ms, once;
249 
250 	lock(&active);
251 	if(ispanic)
252 		active.ispanic = ispanic;
253 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
254 		active.ispanic = 0;
255 	once = active.machs & (1<<m->machno);
256 	active.machs &= ~(1<<m->machno);
257 	active.exiting = 1;
258 	unlock(&active);
259 
260 	if(once)
261 		print("cpu%d: exiting\n", m->machno);
262 	spllo();
263 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
264 		delay(TK2MS(2));
265 		if(active.machs == 0 && consactive() == 0)
266 			break;
267 	}
268 
269 	if(active.ispanic && m->machno == 0){
270 		if(cpuserver)
271 			delay(10000);
272 		else if(conf.monitor)
273 			for(;;);
274 	}
275 	else
276 		delay(1000);
277 
278 }
279 
280 /*
281  *  set up floating point for a new process
282  */
283 void
procsetup(Proc * p)284 procsetup(Proc *p)
285 {
286 	p->fpstate = FPinit;
287 }
288 
289 void
procrestore(Proc * p)290 procrestore(Proc *p)
291 {
292 	uvlong t;
293 
294 	if(p->kp)
295 		return;
296 	cycles(&t);
297 	p->pcycles -= t;
298 }
299 
300 /*
301  *  Save the mach dependent part of the process state.
302  */
303 void
procsave(Proc * p)304 procsave(Proc *p)
305 {
306 	uvlong t;
307 
308 	cycles(&t);
309 	p->pcycles += t;
310 	if(p->fpstate == FPactive){
311 		if(p->state != Moribund)
312 			fpsave(&up->fpsave);
313 		p->fpstate = FPinactive;
314 	}
315 }
316 
317 void
confinit(void)318 confinit(void)
319 {
320 	char *p;
321 	int userpcnt;
322 	ulong pa, kpages;
323 	/* passed in from ROM monitor: */
324 
325 	if(p = getconf("*kernelpercent"))
326 		userpcnt = 100 - strtol(p, 0, 0);
327 	else
328 		userpcnt = 0;
329 
330 	pa = PGROUND(PADDR(end));
331 
332 	/* Blast Board specific */
333 	conf.mem[0].npage = (MEM1SIZE - pa)/BY2PG;
334 	conf.mem[0].base = pa;
335 
336 	conf.mem[1].npage = MEM2SIZE/BY2PG;
337 	conf.mem[1].base = MEM2BASE;
338 
339 	conf.npage = conf.mem[0].npage + conf.mem[1].npage;
340 
341 	conf.nmach = 1;
342 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
343 	if(cpuserver)
344 		conf.nproc *= 3;
345 	if(conf.nproc > 2000)
346 		conf.nproc = 2000;
347 	conf.nimage = 200;
348 	conf.nswap = conf.nproc*80;
349 	conf.nswppo = 4096;
350 	conf.copymode = 0;			/* copy on write */
351 
352 	if(cpuserver) {
353 		if(userpcnt < 10)
354 			userpcnt = 70;
355 		kpages = conf.npage - (conf.npage*userpcnt)/100;
356 
357 		/*
358 		 * Hack for the big boys. Only good while physmem < 4GB.
359 		 * Give the kernel a max. of 16MB + enough to allocate the
360 		 * page pool.
361 		 * This is an overestimate as conf.upages < conf.npages.
362 		 * The patch of nimage is a band-aid, scanning the whole
363 		 * page list in imagereclaim just takes too long.
364 		 */
365 		if(kpages > (16*MB + conf.npage*sizeof(Page))/BY2PG){
366 			kpages = (16*MB + conf.npage*sizeof(Page))/BY2PG;
367 			conf.nimage = 2000;
368 			kpages += (conf.nproc*KSTACK)/BY2PG;
369 		}
370 	} else {
371 		if(userpcnt < 10) {
372 			if(conf.npage*BY2PG < 16*MB)
373 				userpcnt = 40;
374 			else
375 				userpcnt = 60;
376 		}
377 		kpages = conf.npage - (conf.npage*userpcnt)/100;
378 
379 		/*
380 		 * Make sure terminals with low memory get at least
381 		 * 4MB on the first Image chunk allocation.
382 		 */
383 		if(conf.npage*BY2PG < 16*MB)
384 			imagmem->minarena = 4*1024*1024;
385 	}
386 	conf.upages = conf.npage - kpages;
387 	conf.ialloc = (kpages/2)*BY2PG;
388 
389 	/*
390 	 * Guess how much is taken by the large permanent
391 	 * datastructures. Mntcache and Mntrpc are not accounted for
392 	 * (probably ~300KB).
393 	 */
394 	kpages *= BY2PG;
395 	kpages -= conf.upages*sizeof(Page)
396 		+ conf.nproc*sizeof(Proc)
397 		+ conf.nimage*sizeof(Image)
398 		+ conf.nswap
399 		+ conf.nswppo*sizeof(Page);
400 	mainmem->maxsize = kpages;
401 	if(!cpuserver){
402 		/*
403 		 * give terminals lots of image memory, too; the dynamic
404 		 * allocation will balance the load properly, hopefully.
405 		 * be careful with 32-bit overflow.
406 		 */
407 		imagmem->maxsize = kpages;
408 	}
409 
410 //	conf.monitor = 1;	/* BUG */
411 }
412 
413 static int
getcfields(char * lp,char ** fields,int n,char * sep)414 getcfields(char* lp, char** fields, int n, char* sep)
415 {
416 	int i;
417 
418 	for(i = 0; lp && *lp && i < n; i++){
419 		while(*lp && strchr(sep, *lp) != 0)
420 			*lp++ = 0;
421 		if(*lp == 0)
422 			break;
423 		fields[i] = lp;
424 		while(*lp && strchr(sep, *lp) == 0){
425 			if(*lp == '\\' && *(lp+1) == '\n')
426 				*lp++ = ' ';
427 			lp++;
428 		}
429 	}
430 
431 	return i;
432 }
433 
434 int
isaconfig(char * class,int ctlrno,ISAConf * isa)435 isaconfig(char *class, int ctlrno, ISAConf *isa)
436 {
437 	int i;
438 	char cc[KNAMELEN], *p;
439 
440 	sprint(cc, "%s%d", class, ctlrno);
441 
442 	p = getconf(cc);
443 	if(p == 0)
444 		return 0;
445 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
446 	for(i = 0; i < isa->nopt; i++){
447 		p = isa->opt[i];
448 		if(cistrncmp(p, "type=", 5) == 0)
449 			isa->type = p + 5;
450 		else if(cistrncmp(p, "port=", 5) == 0)
451 			isa->port = strtoul(p+5, &p, 0);
452 		else if(cistrncmp(p, "irq=", 4) == 0)
453 			isa->irq = strtoul(p+4, &p, 0);
454 		else if(cistrncmp(p, "dma=", 4) == 0)
455 			isa->dma = strtoul(p+4, &p, 0);
456 		else if(cistrncmp(p, "mem=", 4) == 0)
457 			isa->mem = strtoul(p+4, &p, 0);
458 		else if(cistrncmp(p, "size=", 5) == 0)
459 			isa->size = strtoul(p+5, &p, 0);
460 		else if(cistrncmp(p, "freq=", 5) == 0)
461 			isa->freq = strtoul(p+5, &p, 0);
462 	}
463 	return 1;
464 }
465 
466 int
cistrcmp(char * a,char * b)467 cistrcmp(char *a, char *b)
468 {
469 	int ac, bc;
470 
471 	for(;;){
472 		ac = *a++;
473 		bc = *b++;
474 
475 		if(ac >= 'A' && ac <= 'Z')
476 			ac = 'a' + (ac - 'A');
477 		if(bc >= 'A' && bc <= 'Z')
478 			bc = 'a' + (bc - 'A');
479 		ac -= bc;
480 		if(ac)
481 			return ac;
482 		if(bc == 0)
483 			break;
484 	}
485 	return 0;
486 }
487 
488 int
cistrncmp(char * a,char * b,int n)489 cistrncmp(char *a, char *b, int n)
490 {
491 	unsigned ac, bc;
492 
493 	while(n > 0){
494 		ac = *a++;
495 		bc = *b++;
496 		n--;
497 
498 		if(ac >= 'A' && ac <= 'Z')
499 			ac = 'a' + (ac - 'A');
500 		if(bc >= 'A' && bc <= 'Z')
501 			bc = 'a' + (bc - 'A');
502 
503 		ac -= bc;
504 		if(ac)
505 			return ac;
506 		if(bc == 0)
507 			break;
508 	}
509 
510 	return 0;
511 }
512