xref: /plan9-contrib/sys/src/9k/k10/main.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 
7 #include "io.h"
8 
9 #include "init.h"
10 
11 extern void crapoptions(void);	/* XXX - must go */
12 extern void confsetenv(void);	/* XXX - must go */
13 
14 static uintptr sp;		/* XXX - must go - user stack of init proc */
15 
16 uintptr kseg0 = KZERO;
17 Sys* sys = nil;
18 usize sizeofSys = sizeof(Sys);
19 
20 /*
21  * Option arguments from the command line.
22  * oargv[0] is the boot file.
23  * Optionsinit() is called from multiboot() to
24  * set it all up.
25  */
26 static int oargc;
27 static char* oargv[20];
28 static char oargb[128];
29 static int oargblen;
30 
31 char dbgflg[256];
32 static int vflag = 0;
33 
34 void
optionsinit(char * s)35 optionsinit(char* s)
36 {
37 	oargblen = strecpy(oargb, oargb+sizeof(oargb), s) - oargb;
38 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
39 	oargv[oargc] = nil;
40 }
41 
42 static void
options(int argc,char * argv[])43 options(int argc, char* argv[])
44 {
45 	char *p;
46 	int n, o;
47 
48 	/*
49 	 * Process flags.
50 	 * Flags [A-Za-z] may be optionally followed by
51 	 * an integer level between 1 and 127 inclusive
52 	 * (no space between flag and level).
53 	 * '--' ends flag processing.
54 	 */
55 	while(--argc > 0 && (*++argv)[0] == '-' && (*argv)[1] != '-'){
56 		while(o = *++argv[0]){
57 			if(!(o >= 'A' && o <= 'Z') && !(o >= 'a' && o <= 'z'))
58 				continue;
59 			n = strtol(argv[0]+1, &p, 0);
60 			if(p == argv[0]+1 || n < 1 || n > 127)
61 				n = 1;
62 			argv[0] = p-1;
63 			dbgflg[o] = n;
64 		}
65 	}
66 	vflag = dbgflg['v'];
67 }
68 
69 void
squidboy(int apicno)70 squidboy(int apicno)
71 {
72 	vlong hz;
73 
74 	sys->machptr[m->machno] = m;
75 
76 	/*
77 	 * Need something for initial delays
78 	 * until a timebase is worked out.
79 	 */
80 	m->cpuhz = 2000000000ll;
81 	m->cpumhz = 2000;
82 	m->perf.period = 1;
83 
84 	DBG("Hello Squidboy %d %d\n", apicno, m->machno);
85 
86 	vsvminit(MACHSTKSZ);
87 
88 	/*
89 	 * Beware the Curse of The Non-Interruptable Were-Temporary.
90 	 */
91 	hz = archhz();
92 	if(hz == 0)
93 		ndnr();
94 	m->cpuhz = hz;
95 	m->cpumhz = hz/1000000ll;
96 
97 	mmuinit();
98 	if(!apiconline())
99 		ndnr();
100 
101 	fpuinit();
102 
103 	/*
104 	 * Handshake with sipi to let it
105 	 * know the Startup IPI succeeded.
106 	 */
107 	m->splpc = 0;
108 
109 	/*
110 	 * Handshake with main to proceed with initialisation.
111 	 */
112 	while(sys->epoch == 0)
113 		;
114 	wrmsr(0x10, sys->epoch);
115 	m->rdtsc = rdtsc();
116 
117 	DBG("mach %d is go %#p %#p %#p\n", m->machno, m, m->pml4->va, &apicno);
118 	switch(m->mode){
119 	default:
120 //		vsvminit(MACHSTKSZ);
121 
122 		timersinit();
123 
124 		/*
125 		 * Cannot allow interrupts while waiting for online,
126 		 * if this were a real O/S, it would perhaps allow a clock
127 		 * interrupt to call the scheduler, and that would
128 		 * be a mistake.
129 		 * Could perhaps use MONITOR/MWAIT here to drop the energy
130 		 * used by the spinning core.
131 		 */
132 		while(!m->online)
133 			pause();
134 		apictimerenable();
135 		apictprput(0);
136 
137 		DBG("mach%d: online color %d\n", m->machno, m->color);
138 		schedinit();
139 		break;
140 	}
141 	panic("squidboy returns (type %d)", m->mode);
142 }
143 
144 void
main(u32int ax,u32int bx)145 main(u32int ax, u32int bx)
146 {
147 	int i;
148 	vlong hz;
149 
150 	memset(edata, 0, end - edata);
151 
152 	/*
153 	 * ilock via i8250enable via i8250console
154 	 * needs m->machno, sys->machptr[] set, and
155 	 * also 'up' set to nil.
156 	 */
157 	cgapost(sizeof(uintptr)*8);
158 	memset(m, 0, sizeof(Mach));
159 	m->machno = 0;
160 	m->online = 1;
161 	sys->machptr[m->machno] = &sys->mach;
162 	m->stack = PTR2UINT(sys->machstk);
163 	m->vsvm = sys->vsvmpage;
164 	sys->nmach = 1;
165 	sys->nonline = 1;
166 	sys->copymode = 0;			/* COW */
167 	up = nil;
168 
169 	asminit();
170 	multiboot(ax, bx, 0);
171 	options(oargc, oargv);
172 	crapoptions();
173 
174 	/*
175 	 * Need something for initial delays
176 	 * until a timebase is worked out.
177 	 */
178 	m->cpuhz = 2000000000ll;
179 	m->cpumhz = 2000;
180 
181 	cgainit();
182 	i8250console("0");
183 	consputs = cgaconsputs;
184 
185 	vsvminit(MACHSTKSZ);
186 
187 	active.machs = 1;
188 	active.exiting = 0;
189 
190 	fmtinit();
191 	print("\nPlan 9\n");
192 	if(vflag){
193 		print("&ax = %#p, ax = %#ux, bx = %#ux\n", &ax, ax, bx);
194 		multiboot(ax, bx, vflag);
195 	}
196 
197 	m->perf.period = 1;
198 	if((hz = archhz()) != 0ll){
199 		m->cpuhz = hz;
200 		m->cpumhz = hz/1000000ll;
201 	}
202 
203 	/*
204 	 * Mmuinit before meminit because it
205 	 * makes mappings and
206 	 * flushes the TLB via m->pml4->pa.
207 	 */
208 	mmuinit();
209 
210 	ioinit();
211 	kbdinit();
212 
213 	meminit();
214 	archinit();
215 	mallocinit();
216 	umeminit();
217 	trapinit();
218 
219 	/*
220 	 * Printinit will cause the first malloc
221 	 * call to happen (printinit->qopen->malloc).
222 	 * If the system dies here it's probably due
223 	 * to malloc not being initialised
224 	 * correctly, or the data segment is misaligned
225 	 * (it's amazing how far you can get with
226 	 * things like that completely broken).
227 	 */
228 	printinit();
229 
230 	/*
231 	 * This is necessary with GRUB and QEMU.
232 	 * Without it an interrupt can occur at a weird vector,
233 	 * because the vector base is likely different, causing
234 	 * havoc. Do it before any APIC initialisation.
235 	 */
236 	i8259init(IdtPIC);
237 
238 	acpiinit();
239 	mpsinit();
240 	apiconline();
241 	intrenable(IdtTIMER, apictimerintr, 0, -1, "APIC timer");
242 	apictimerenable();
243 	apictprput(0);
244 
245 	timersinit();
246 	kbdenable();
247 	fpuinit();
248 	psinit();
249 	initimage();
250 	links();
251 	devtabreset();
252 	pageinit();
253 	userinit();
254 	if(!dbgflg['S'])
255 		sipi();
256 
257 	sys->epoch = rdtsc();
258 	wrmsr(0x10, sys->epoch);
259 	m->rdtsc = rdtsc();
260 
261 	/*
262 	 * Release the hounds.
263 	 */
264 	for(i = 1; i < MACHMAX; i++){
265 		if(sys->machptr[i] == nil)
266 			continue;
267 
268 		sys->nonline++;
269 		lock(&active);			/* GAK */
270 		active.machs |= 1<<i;		/* GAK */
271 		unlock(&active);		/* GAK */
272 
273 		sys->machptr[i]->color = corecolor(i);
274 		if(sys->machptr[i]->color < 0)
275 			sys->machptr[i]->color = 0;
276 		sys->machptr[i]->online = 1;
277 	}
278 	schedinit();
279 }
280 
281 void
init0(void)282 init0(void)
283 {
284 	char buf[2*KNAMELEN];
285 
286 	up->nerrlab = 0;
287 
288 //	if(consuart == nil)
289 //		i8250console("0");
290 	spllo();
291 
292 	/*
293 	 * These are o.k. because rootinit is null.
294 	 * Then early kproc's will have a root and dot.
295 	 */
296 	up->slash = namec("#/", Atodir, 0, 0);
297 	pathclose(up->slash->path);
298 	up->slash->path = newpath("/");
299 	up->dot = cclone(up->slash);
300 
301 	devtabinit();
302 
303 	if(!waserror()){
304 		snprint(buf, sizeof(buf), "%s %s", "AMD64", conffile);
305 		ksetenv("terminal", buf, 0);
306 		ksetenv("cputype", "amd64", 0);
307 		if(cpuserver)
308 			ksetenv("service", "cpu", 0);
309 		else
310 			ksetenv("service", "terminal", 0);
311 		confsetenv();
312 		poperror();
313 	}
314 	kproc("alarm", alarmkproc, 0);
315 	touser(sp);
316 }
317 
318 void
bootargs(uintptr base)319 bootargs(uintptr base)
320 {
321 	int i;
322 	ulong ssize;
323 	char **av, *p;
324 
325 	/*
326 	 * Push the boot args onto the stack.
327 	 * Make sure the validaddr check in syscall won't fail
328 	 * because there are fewer than the maximum number of
329 	 * args by subtracting sizeof(up->arg).
330 	 */
331 	i = oargblen+1;
332 	p = UINT2PTR(STACKALIGN(base + PGSZ - sizeof(up->arg) - i));
333 	memmove(p, oargb, i);
334 
335 	/*
336 	 * Now push argc and the argv pointers.
337 	 * This isn't strictly correct as the code jumped to by
338 	 * touser in init9.[cs] calls startboot (port/initcode.c) which
339 	 * expects arguments
340 	 * 	startboot(char* argv0, char* argv[])
341 	 * not the usual (int argc, char* argv[]), but argv0 is
342 	 * unused so it doesn't matter (at the moment...).
343 	 */
344 	av = (char**)(p - (oargc+2)*sizeof(char*));
345 	ssize = base + PGSZ - PTR2UINT(av);
346 	*av++ = (char*)oargc;
347 	for(i = 0; i < oargc; i++)
348 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - PGSZ);
349 	*av = nil;
350 
351 	sp = USTKTOP - ssize;
352 }
353 
354 void
userinit(void)355 userinit(void)
356 {
357 	Proc *p;
358 	Segment *s;
359 	KMap *k;
360 	Page *pg;
361 
362 	p = newproc();
363 	p->pgrp = newpgrp();
364 	p->egrp = smalloc(sizeof(Egrp));
365 	p->egrp->ref = 1;
366 	p->fgrp = dupfgrp(nil);
367 	p->rgrp = newrgrp();
368 	p->procmode = 0640;
369 
370 	kstrdup(&eve, "");
371 	kstrdup(&p->text, "*init*");
372 	kstrdup(&p->user, eve);
373 
374 	/*
375 	 * Kernel Stack
376 	 *
377 	 * N.B. make sure there's enough space for syscall to check
378 	 *	for valid args and
379 	 *	space for gotolabel's return PC
380 	 * AMD64 stack must be quad-aligned.
381 	 */
382 	p->sched.pc = PTR2UINT(init0);
383 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->arg)-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, USTKTOP);
395 	p->seg[SSEG] = s;
396 	pg = newpage(1, s, USTKTOP-segpgsize(s), PGSHFT, -1, 0);
397 	segpage(s, pg);
398 	k = kmap(pg);
399 	bootargs(VA(k));
400 	kunmap(k);
401 
402 	/*
403 	 * Text
404 	 */
405 	s = newseg(SG_TEXT, UTZERO, UTZERO+PGSZ);
406 	s->flushme++;
407 	p->seg[TSEG] = s;
408 	pg = newpage(1, s, UTZERO, PGSHFT, -1, 0);
409 	mmucachectl(pg, PG_TXTFLUSH);
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 static void
shutdown(int ispanic)419 shutdown(int ispanic)
420 {
421 	int ms, once;
422 
423 	lock(&active);
424 	if(ispanic)
425 		active.ispanic = ispanic;
426 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
427 		active.ispanic = 0;
428 	once = active.machs & (1<<m->machno);
429 	active.machs &= ~(1<<m->machno);
430 	active.exiting = 1;
431 	unlock(&active);
432 
433 	if(once)
434 		iprint("cpu%d: exiting\n", m->machno);
435 	spllo();
436 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
437 		delay(TK2MS(2));
438 		if(active.machs == 0 && consactive() == 0)
439 			break;
440 	}
441 
442 //#ifdef notdef
443 	if(active.ispanic && m->machno == 0){
444 		if(cpuserver)
445 			delay(30000);
446 		else
447 			for(;;)
448 				halt();
449 	}
450 	else
451 //#endif /* notdef */
452 		delay(1000);
453 }
454 
455 void
reboot(void *,void *,long)456 reboot(void*, void*, long)
457 {
458 	panic("reboot");
459 }
460 
461 void
exit(int ispanic)462 exit(int ispanic)
463 {
464 	shutdown(ispanic);
465 	archreset();
466 }
467