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