Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "tos.h"
3
#include "../port/lib.h"
4
#include "mem.h"
5
#include "dat.h"
6
#include "fns.h"
7
 
8
#include "init.h"
9
#include <pool.h>
10
 
11
#include "reboot.h"
12
 
13
enum {
14
	/* space for syscall args, return PC, top-of-stack struct */
15
	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
16
};
17
 
18
/* Firmware compatibility */
19
#define	Minfirmrev	326770
20
#define	Minfirmdate	"19 Aug 2013"
21
 
22
/*
23
 * Where configuration info is left for the loaded programme.
24
 */
25
#define BOOTARGS	((char*)CONFADDR)
26
#define	BOOTARGSLEN	(MACHADDR-CONFADDR)
27
#define	MAXCONF		64
28
#define MAXCONFLINE	160
29
 
30
uintptr kseg0 = KZERO;
31
Mach*	machaddr[MAXMACH];
32
Conf	conf;
33
ulong	memsize = 128*1024*1024;
34
 
35
/*
36
 * Option arguments from the command line.
37
 * oargv[0] is the boot file.
38
 */
39
static int oargc;
40
static char* oargv[20];
41
static char oargb[128];
42
static int oargblen;
43
 
44
static uintptr sp;		/* XXX - must go - user stack of init proc */
45
 
46
/* store plan9.ini contents here at least until we stash them in #ec */
47
static char confname[MAXCONF][KNAMELEN];
48
static char confval[MAXCONF][MAXCONFLINE];
49
static int nconf;
50
 
51
typedef struct Atag Atag;
52
struct Atag {
53
	u32int	size;	/* size of atag in words, including this header */
54
	u32int	tag;	/* atag type */
55
	union {
56
		u32int	data[1];	/* actually [size-2] */
57
		/* AtagMem */
58
		struct {
59
			u32int	size;
60
			u32int	base;
61
		} mem;
62
		/* AtagCmdLine */
63
		char	cmdline[1];	/* actually [4*(size-2)] */
64
	};
65
};
66
 
67
enum {
68
	AtagNone	= 0x00000000,
69
	AtagCore	= 0x54410001,
70
	AtagMem		= 0x54410002,
71
	AtagCmdline	= 0x54410009,
72
};
73
 
74
static int
75
findconf(char *name)
76
{
77
	int i;
78
 
79
	for(i = 0; i < nconf; i++)
80
		if(cistrcmp(confname[i], name) == 0)
81
			return i;
82
	return -1;
83
}
84
 
85
char*
86
getconf(char *name)
87
{
88
	int i;
89
 
90
	i = findconf(name);
91
	if(i >= 0)
92
		return confval[i];
93
	return nil;
94
}
95
 
96
void
97
addconf(char *name, char *val)
98
{
99
	int i;
100
 
101
	i = findconf(name);
102
	if(i < 0){
103
		if(val == nil || nconf >= MAXCONF)
104
			return;
105
		i = nconf++;
106
		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
107
	}
108
	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
109
}
110
 
111
static 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
static void
141
plan9iniinit(char *s, int cmdline)
142
{
143
	char *toks[MAXCONF];
144
	int i, c, n;
145
	char *v;
146
 
147
	if((c = *s) < ' ' || c >= 0x80)
148
		return;
149
	if(cmdline)
150
		n = tokenize(s, toks, MAXCONF);
151
	else
152
		n = getfields(s, toks, MAXCONF, 1, "\n");
153
	for(i = 0; i < n; i++){
154
		if(toks[i][0] == '#')
155
			continue;
156
		v = strchr(toks[i], '=');
157
		if(v == nil)
158
			continue;
159
		*v++ = '\0';
160
		addconf(toks[i], v);
161
	}
162
}
163
 
164
static void
165
ataginit(Atag *a)
166
{
167
	int n;
168
 
169
	if(a->tag != AtagCore){
170
		plan9iniinit((char*)a, 0);
171
		return;
172
	}
173
	while(a->tag != AtagNone){
174
		switch(a->tag){
175
		case AtagMem:
176
			/* use only first bank */
177
			if(conf.mem[0].limit == 0 && a->mem.size != 0){
178
				memsize = a->mem.size;
179
				conf.mem[0].base = a->mem.base;
180
				conf.mem[0].limit = a->mem.base + memsize;
181
			}
182
			break;
183
		case AtagCmdline:
184
			n = (a->size * sizeof(u32int)) - offsetof(Atag, cmdline[0]);
185
			if(a->cmdline + n < BOOTARGS + BOOTARGSLEN)
186
				a->cmdline[n] = 0;
187
			else
188
				BOOTARGS[BOOTARGSLEN-1] = 0;
189
			plan9iniinit(a->cmdline, 1);
190
			break;
191
		}
192
		a = (Atag*)((u32int*)a + a->size);
193
	}
194
}
195
 
196
void
197
machinit(void)
198
{
199
	m->machno = 0;
200
	machaddr[m->machno] = m;
201
 
202
	m->ticks = 1;
203
	m->perf.period = 1;
204
 
205
	conf.nmach = 1;
206
 
207
	active.machs = 1;
208
	active.exiting = 0;
209
 
210
	up = nil;
211
}
212
 
213
static void
214
optionsinit(char* s)
215
{
216
	strecpy(oargb, oargb+sizeof(oargb), s);
217
 
218
	oargblen = strlen(oargb);
219
	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
220
	oargv[oargc] = nil;
221
}
222
 
223
void
224
main(void)
225
{
226
	extern char edata[], end[];
227
	uint rev;
228
 
229
	okay(1);
230
	m = (Mach*)MACHADDR;
231
	memset(edata, 0, end - edata);	/* clear bss */
232
	machinit();
233
	mmuinit1();
234
 
235
	optionsinit("/boot/boot boot");
236
	quotefmtinstall();
237
 
238
	ataginit((Atag*)BOOTARGS);
239
	confinit();		/* figures out amount of memory */
240
	xinit();
241
	uartconsinit();
242
	screeninit();
243
 
244
	print("\nPlan 9 from Bell Labs\n");
245
	rev = getfirmware();
246
	print("firmware: rev %d\n", rev);
247
	if(rev < Minfirmrev){
248
		print("Sorry, firmware (start*.elf) must be at least rev %d"
249
		      " or newer than %s\n", Minfirmrev, Minfirmdate);
250
		for(;;)
251
			;
252
	}
253
	trapinit();
254
	clockinit();
255
	printinit();
256
	timersinit();
257
	if(conf.monitor)
258
		swcursorinit();
259
	cpuidprint();
260
	archreset();
261
 
262
	procinit0();
263
	initseg();
264
	links();
265
	chandevreset();			/* most devices are discovered here */
266
	pageinit();
267
	swapinit();
268
	userinit();
269
	schedinit();
270
	assert(0);			/* shouldn't have returned */
271
}
272
 
273
/*
274
 *  starting place for first process
275
 */
276
void
277
init0(void)
278
{
279
	int i;
280
	char buf[2*KNAMELEN];
281
 
282
	up->nerrlab = 0;
283
	coherence();
284
	spllo();
285
 
286
	/*
287
	 * These are o.k. because rootinit is null.
288
	 * Then early kproc's will have a root and dot.
289
	 */
290
	up->slash = namec("#/", Atodir, 0, 0);
291
	pathclose(up->slash->path);
292
	up->slash->path = newpath("/");
293
	up->dot = cclone(up->slash);
294
 
295
	chandevinit();
296
 
297
	if(!waserror()){
298
		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
299
		ksetenv("terminal", buf, 0);
300
		ksetenv("cputype", "arm", 0);
301
		if(cpuserver)
302
			ksetenv("service", "cpu", 0);
303
		else
304
			ksetenv("service", "terminal", 0);
305
		snprint(buf, sizeof(buf), "-a %s", getethermac());
306
		ksetenv("etherargs", buf, 0);
307
 
308
		/* convert plan9.ini variables to #e and #ec */
309
		for(i = 0; i < nconf; i++) {
310
			ksetenv(confname[i], confval[i], 0);
311
			ksetenv(confname[i], confval[i], 1);
312
		}
313
		poperror();
314
	}
315
	kproc("alarm", alarmkproc, 0);
316
	touser(sp);
317
	assert(0);			/* shouldn't have returned */
318
}
319
 
320
static void
321
bootargs(uintptr base)
322
{
323
	int i;
324
	ulong ssize;
325
	char **av, *p;
326
 
327
	/*
328
	 * Push the boot args onto the stack.
329
	 * The initial value of the user stack must be such
330
	 * that the total used is larger than the maximum size
331
	 * of the argument list checked in syscall.
332
	 */
333
	i = oargblen+1;
334
	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
335
	memmove(p, oargb, i);
336
 
337
	/*
338
	 * Now push the argv pointers.
339
	 * The code jumped to by touser in lproc.s expects arguments
340
	 *	main(char* argv0, ...)
341
	 * and calls
342
	 * 	startboot("/boot/boot", &argv0)
343
	 * not the usual (int argc, char* argv[])
344
	 */
345
	av = (char**)(p - (oargc+1)*sizeof(char*));
346
	ssize = base + BY2PG - PTR2UINT(av);
347
	for(i = 0; i < oargc; i++)
348
		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
349
	*av = nil;
350
	sp = USTKTOP - ssize;
351
}
352
 
353
/*
354
 *  create the first process
355
 */
356
void
357
userinit(void)
358
{
359
	Proc *p;
360
	Segment *s;
361
	KMap *k;
362
	Page *pg;
363
 
364
	/* no processes yet */
365
	up = nil;
366
 
367
	p = newproc();
368
	p->pgrp = newpgrp();
369
	p->egrp = smalloc(sizeof(Egrp));
370
	p->egrp->ref = 1;
371
	p->fgrp = dupfgrp(nil);
372
	p->rgrp = newrgrp();
373
	p->procmode = 0640;
374
 
375
	kstrdup(&eve, "");
376
	kstrdup(&p->text, "*init*");
377
	kstrdup(&p->user, eve);
378
 
379
	/*
380
	 * Kernel Stack
381
	 */
382
	p->sched.pc = PTR2UINT(init0);
383
	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
384
	p->sched.sp = STACKALIGN(p->sched.sp);
385
 
386
	/*
387
	 * User Stack
388
	 *
389
	 * Technically, newpage can't be called here because it
390
	 * should only be called when in a user context as it may
391
	 * try to sleep if there are no pages available, but that
392
	 * shouldn't be the case here.
393
	 */
394
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
395
	s->flushme++;
396
	p->seg[SSEG] = s;
397
	pg = newpage(1, 0, USTKTOP-BY2PG);
398
	segpage(s, pg);
399
	k = kmap(pg);
400
	bootargs(VA(k));
401
	kunmap(k);
402
 
403
	/*
404
	 * Text
405
	 */
406
	s = newseg(SG_TEXT, UTZERO, 1);
407
	p->seg[TSEG] = s;
408
	pg = newpage(1, 0, UTZERO);
409
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
410
	segpage(s, pg);
411
	k = kmap(s->map[0]->pages[0]);
412
	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
413
	kunmap(k);
414
 
415
	ready(p);
416
}
417
 
418
void
419
confinit(void)
420
{
421
	int i;
422
	ulong kpages;
423
	uintptr pa;
424
	char *p;
425
 
426
	if(0 && (p = getconf("service")) != nil){
427
		if(strcmp(p, "cpu") == 0)
428
			cpuserver = 1;
429
		else if(strcmp(p,"terminal") == 0)
430
			cpuserver = 0;
431
	}
432
	if((p = getconf("*maxmem")) != nil){
433
		memsize = strtoul(p, 0, 0) - PHYSDRAM;
434
		if (memsize < 16*MB)		/* sanity */
435
			memsize = 16*MB;
436
	}
437
 
438
	getramsize(&conf.mem[0]);
439
	if(conf.mem[0].limit == 0){
440
		conf.mem[0].base = PHYSDRAM;
441
		conf.mem[0].limit = PHYSDRAM + memsize;
442
	}else if(p != nil)
443
		conf.mem[0].limit = conf.mem[0].base + memsize;
444
 
445
	conf.npage = 0;
446
	pa = PADDR(PGROUND(PTR2UINT(end)));
447
 
448
	/*
449
	 *  we assume that the kernel is at the beginning of one of the
450
	 *  contiguous chunks of memory and fits therein.
451
	 */
452
	for(i=0; i<nelem(conf.mem); i++){
453
		/* take kernel out of allocatable space */
454
		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
455
			conf.mem[i].base = pa;
456
 
457
		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
458
		conf.npage += conf.mem[i].npage;
459
	}
460
 
461
	conf.upages = (conf.npage*80)/100;
462
	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
463
 
464
	/* only one processor */
465
	conf.nmach = 1;
466
 
467
	/* set up other configuration parameters */
468
	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
469
	if(cpuserver)
470
		conf.nproc *= 3;
471
	if(conf.nproc > 2000)
472
		conf.nproc = 2000;
473
	conf.nswap = conf.npage*3;
474
	conf.nswppo = 4096;
475
	conf.nimage = 200;
476
 
477
	conf.copymode = 0;		/* copy on write */
478
 
479
	/*
480
	 * Guess how much is taken by the large permanent
481
	 * datastructures. Mntcache and Mntrpc are not accounted for
482
	 * (probably ~300KB).
483
	 */
484
	kpages = conf.npage - conf.upages;
485
	kpages *= BY2PG;
486
	kpages -= conf.upages*sizeof(Page)
487
		+ conf.nproc*sizeof(Proc)
488
		+ conf.nimage*sizeof(Image)
489
		+ conf.nswap
490
		+ conf.nswppo*sizeof(Page);
491
	mainmem->maxsize = kpages;
492
	if(!cpuserver)
493
		/*
494
		 * give terminals lots of image memory, too; the dynamic
495
		 * allocation will balance the load properly, hopefully.
496
		 * be careful with 32-bit overflow.
497
		 */
498
		imagmem->maxsize = kpages;
499
 
500
}
501
 
502
static void
503
shutdown(int ispanic)
504
{
505
	int ms, once;
506
 
507
	lock(&active);
508
	if(ispanic)
509
		active.ispanic = ispanic;
510
	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
511
		active.ispanic = 0;
512
	once = active.machs & (1<<m->machno);
513
	active.machs &= ~(1<<m->machno);
514
	active.exiting = 1;
515
	unlock(&active);
516
 
517
	if(once)
518
		iprint("cpu%d: exiting\n", m->machno);
519
	spllo();
520
	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
521
		delay(TK2MS(2));
522
		if(active.machs == 0 && consactive() == 0)
523
			break;
524
	}
525
	delay(1000);
526
}
527
 
528
/*
529
 *  exit kernel either on a panic or user request
530
 */
531
void
532
exit(int code)
533
{
534
	shutdown(code);
535
	splfhi();
536
	archreboot();
537
}
538
 
539
/*
540
 * stub for ../omap/devether.c
541
 */
542
int
543
isaconfig(char *class, int ctlrno, ISAConf *isa)
544
{
545
	USED(ctlrno);
546
	USED(isa);
547
	return strcmp(class, "ether") == 0;
548
}
549
 
550
/*
551
 * the new kernel is already loaded at address `code'
552
 * of size `size' and entry point `entry'.
553
 */
554
void
555
reboot(void *entry, void *code, ulong size)
556
{
557
	void (*f)(ulong, ulong, ulong);
558
 
559
	print("starting reboot...");
560
	writeconf();
561
	shutdown(0);
562
 
563
	/*
564
	 * should be the only processor running now
565
	 */
566
 
567
	print("reboot entry %#lux code %#lux size %ld\n",
568
		PADDR(entry), PADDR(code), size);
569
	delay(100);
570
 
571
	/* turn off buffered serial console */
572
	serialoq = nil;
573
	kprintoq = nil;
574
	screenputs = nil;
575
 
576
	/* shutdown devices */
577
	chandevshutdown();
578
 
579
	/* stop the clock (and watchdog if any) */
580
	clockshutdown();
581
 
582
	splfhi();
583
	intrsoff();
584
 
585
	/* setup reboot trampoline function */
586
	f = (void*)REBOOTADDR;
587
	memmove(f, rebootcode, sizeof(rebootcode));
588
	cacheuwbinv();
589
 
590
	/* off we go - never to return */
591
	(*f)(PADDR(entry), PADDR(code), size);
592
 
593
	iprint("loaded kernel returned!\n");
594
	delay(1000);
595
	archreboot();
596
}
597
 
598
int
599
cmpswap(long *addr, long old, long new)
600
{
601
	return cas32(addr, old, new);
602
}