main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "init.h"
  15. #include "apic.h"
  16. #include "io.h"
  17. #include "amd64.h"
  18. #undef DBG
  19. #define DBG iprint
  20. Conf conf; /* XXX - must go - gag */
  21. static uintptr_t sp; /* XXX - must go - user stack of init proc */
  22. /* Next time you see a system with cores/sockets running at different clock rates, on x86,
  23. * let me know. AFAIK, it no longer happens. So the BSP hz is good for the AP hz.
  24. */
  25. int64_t hz;
  26. uintptr_t kseg0 = KZERO;
  27. Sys* sys = nil;
  28. usize sizeofSys = sizeof(Sys);
  29. Mach *entrym;
  30. /*
  31. * Option arguments from the command line.
  32. * oargv[0] is the boot file.
  33. * Optionsinit() is called from multiboot() to
  34. * set it all up.
  35. */
  36. static int64_t oargc;
  37. static char* oargv[20];
  38. static char oargb[128];
  39. static int oargblen;
  40. static int maxcores = 1024; /* max # of cores given as an argument */
  41. static int numtcs = 32; /* initial # of TCs */
  42. char dbgflg[256];
  43. static int vflag = 1;
  44. int nosmp = 0;
  45. void
  46. optionsinit(char* s)
  47. {
  48. oargblen = strecpy(oargb, oargb+sizeof(oargb), s) - oargb;
  49. oargc = tokenize(oargb, oargv, nelem(oargv)-1);
  50. oargv[oargc] = nil;
  51. }
  52. static void
  53. options(int argc, char* argv[])
  54. {
  55. char *p;
  56. int n, o;
  57. /*
  58. * Process flags.
  59. * Flags [A-Za-z] may be optionally followed by
  60. * an integer level between 1 and 127 inclusive
  61. * (no space between flag and level).
  62. * '--' ends flag processing.
  63. */
  64. while(--argc > 0 && (*++argv)[0] == '-' && (*argv)[1] != '-'){
  65. while(o = *++argv[0]){
  66. if(!(o >= 'A' && o <= 'Z') && !(o >= 'a' && o <= 'z'))
  67. continue;
  68. n = strtol(argv[0]+1, &p, 0);
  69. if(p == argv[0]+1 || n < 1 || n > 127)
  70. n = 1;
  71. argv[0] = p-1;
  72. dbgflg[o] = n;
  73. }
  74. }
  75. vflag = dbgflg['v'];
  76. if(argc > 0){
  77. maxcores = strtol(argv[0], 0, 0);
  78. argc--;
  79. argv++;
  80. }
  81. if(argc > 0){
  82. numtcs = strtol(argv[0], 0, 0);
  83. //argc--;
  84. //argv++;
  85. }
  86. // hack.
  87. nosmp = dbgflg['n'];
  88. }
  89. void
  90. squidboy(int apicno, Mach *m)
  91. {
  92. // FIX QEMU. extern int64_t hz;
  93. int64_t hz;
  94. sys->machptr[machp()->machno] = m;
  95. /*
  96. * Need something for initial delays
  97. * until a timebase is worked out.
  98. */
  99. m->cpuhz = 2000000000ll;
  100. m->cpumhz = 2000;
  101. m->perf.period = 1;
  102. m->nixtype = NIXAC;
  103. // no NIXAC for now.
  104. m->nixtype = NIXTC;
  105. // NOTE: you can't do ANYTHING here before vsvminit.
  106. // PRINT WILL PANIC. So wait.
  107. vsvminit(MACHSTKSZ, m->nixtype, m);
  108. DBG("Hello Squidboy %d %d\n", apicno, machp()->machno);
  109. /*
  110. * Beware the Curse of The Non-Interruptable Were-Temporary.
  111. */
  112. // see comment in main.c. This is a 1990s thing. hz = archhz();
  113. // except qemu won't work unless we do this. Sigh.
  114. hz = archhz();
  115. if(hz == 0)
  116. ndnr();
  117. m->cpuhz = hz;
  118. m->cyclefreq = hz;
  119. m->cpumhz = hz/1000000ll;
  120. mmuinit();
  121. if(!apiconline())
  122. ndnr();
  123. fpuinit();
  124. acmodeset(m->nixtype);
  125. m->splpc = 0;
  126. m->online = 1;
  127. /*
  128. * CAUTION: no time sync done, etc.
  129. */
  130. DBG("Wait for the thunderbirds!\n");
  131. while(!active.thunderbirdsarego)
  132. ;
  133. wrmsr(0x10, sys->epoch);
  134. m->rdtsc = rdtsc();
  135. print("cpu%d color %d role %s tsc %lld\n",
  136. machp()->machno, corecolor(machp()->machno), rolename[m->nixtype], m->rdtsc);
  137. switch(m->nixtype){
  138. case NIXAC:
  139. acmmuswitch();
  140. acinit();
  141. adec(&active.nbooting);
  142. ainc(&active.nonline); /* this was commented out */
  143. acsched();
  144. panic("squidboy");
  145. break;
  146. case NIXTC:
  147. /*
  148. * We only need the idt and syscall entry point actually.
  149. * At boot time the boot processor might set our role after
  150. * we have decided to become an AC.
  151. */
  152. vsvminit(MACHSTKSZ, NIXTC, m);
  153. /*
  154. * Enable the timer interrupt.
  155. */
  156. apictimerenab();
  157. apicpri(0);
  158. timersinit();
  159. adec(&active.nbooting);
  160. ainc(&active.nonline);
  161. schedinit();
  162. break;
  163. }
  164. panic("squidboy returns (type %d)", m->nixtype);
  165. }
  166. static void
  167. testiccs(void)
  168. {
  169. int i;
  170. Mach *mp;
  171. extern void testicc(int);
  172. /* setup arguments for all */
  173. for(i = 0; i < MACHMAX; i++)
  174. if((mp = sys->machptr[i]) != nil && mp->online && mp->nixtype == NIXAC)
  175. testicc(i);
  176. print("bootcore: all cores done\n");
  177. }
  178. /*
  179. * Rendezvous with other cores. Set roles for those that came
  180. * up online, and wait until they are initialized.
  181. * Sync TSC with them.
  182. * We assume other processors that could boot had time to
  183. * set online to 1 by now.
  184. */
  185. static void
  186. nixsquids(void)
  187. {
  188. Proc *up = machp()->externup;
  189. Mach *mp;
  190. int i;
  191. uint64_t now, start;
  192. for(i = 1; i < MACHMAX; i++)
  193. if((mp = sys->machptr[i]) != nil && mp->online){
  194. /*
  195. * Inter-core calls. A ensure *mp->iccall and mp->icargs
  196. * go into different cache lines.
  197. */
  198. mp->icc = mallocalign(sizeof *m->icc, ICCLNSZ, 0, 0);
  199. mp->icc->fn = nil;
  200. if(i < numtcs){
  201. sys->nmach++;
  202. mp->nixtype = NIXTC;
  203. sys->nc[NIXTC]++;
  204. }else
  205. sys->nc[NIXAC]++;
  206. ainc(&active.nbooting);
  207. }
  208. sys->epoch = rdtsc();
  209. mfence();
  210. wrmsr(0x10, sys->epoch);
  211. m->rdtsc = rdtsc();
  212. active.thunderbirdsarego = 1;
  213. start = fastticks2us(fastticks(nil));
  214. do{
  215. now = fastticks2us(fastticks(nil));
  216. }while(active.nbooting > 0 && now - start < 1000000)
  217. ;
  218. if(active.nbooting > 0)
  219. print("cpu0: %d cores couldn't start\n", active.nbooting);
  220. active.nbooting = 0;
  221. }
  222. void
  223. DONE(void)
  224. {
  225. print("DONE\n");
  226. prflush();
  227. delay(10000);
  228. ndnr();
  229. }
  230. void
  231. HERE(void)
  232. {
  233. print("here\n");
  234. prflush();
  235. delay(5000);
  236. }
  237. /* The old plan 9 standby ... wave ... */
  238. /* Keep to debug trap.c */
  239. void wave(int c)
  240. {
  241. outb(0x3f8, c);
  242. }
  243. void hi(char *s)
  244. {
  245. if (! s)
  246. s = "<NULL>";
  247. while (*s)
  248. wave(*s++);
  249. }
  250. /*
  251. * for gdb:
  252. * call this anywhere in your code.
  253. * die("yourturn with gdb\n");
  254. * gdb 9k
  255. * target remote localhost:1234
  256. * display/i $pc
  257. * set staydead = 0
  258. * stepi, and debug.
  259. * note, you can always resume after a die. Just set staydead = 0
  260. */
  261. int staydead = 1;
  262. void die(char *s)
  263. {
  264. wave('d');
  265. wave('i');
  266. wave('e');
  267. wave(':');
  268. hi(s);
  269. while(staydead);
  270. staydead = 1;
  271. }
  272. /*
  273. void bmemset(void *p)
  274. {
  275. __asm__ __volatile__("1: jmp 1b");
  276. }
  277. void put8(uint8_t c)
  278. {
  279. char x[] = "0123456789abcdef";
  280. wave(x[c>>4]);
  281. wave(x[c&0xf]);
  282. }
  283. void put16(uint16_t s)
  284. {
  285. put8(s>>8);
  286. put8(s);
  287. }
  288. void put32(uint32_t u)
  289. {
  290. put16(u>>16);
  291. put16(u);
  292. }
  293. void put64(uint64_t v)
  294. {
  295. put32(v>>32);
  296. put32(v);
  297. }
  298. */
  299. void debugtouser(void *va)
  300. {
  301. Proc *up = machp()->externup;
  302. uintptr_t uva = (uintptr_t) va;
  303. PTE *pte, *pml4;
  304. pml4 = UINT2PTR(machp()->pml4->va);
  305. mmuwalk(pml4, uva, 0, &pte, nil);
  306. iprint("va %p m %p m>pml4 %p machp()->pml4->va %p pml4 %p PTE 0x%lx\n", va,
  307. m, machp()->pml4, machp()->pml4->va, (void *)pml4, *pte);
  308. }
  309. /*
  310. void badcall(uint64_t where, uint64_t what)
  311. {
  312. hi("Bad call from function "); put64(where); hi(" to "); put64(what); hi("\n");
  313. while (1)
  314. ;
  315. }
  316. */
  317. void errstr(char *s, int i) {
  318. panic("errstr");
  319. }
  320. static int x = 0x123456;
  321. /* tear down the identity map we created in assembly. ONLY do this after all the
  322. * APs have started up (and you know they've done so. But you must do it BEFORE
  323. * you create address spaces for procs, i.e. userinit()
  324. */
  325. static void
  326. teardownidmap(Mach *m)
  327. {
  328. int i;
  329. uintptr_t va = 0;
  330. PTE *p;
  331. /* loop on the level 2 because we should not assume we know
  332. * how many there are But stop after 1G no matter what, and
  333. * report if there were that many, as that is odd.
  334. */
  335. for(i = 0; i < 512; i++, va += BIGPGSZ) {
  336. if (mmuwalk(UINT2PTR(machp()->pml4->va), va, 1, &p, nil) != 1)
  337. break;
  338. if (! *p)
  339. break;
  340. iprint("teardown: va %p, pte %p\n", (void *)va, p);
  341. *p = 0;
  342. }
  343. iprint("Teardown: zapped %d PML1 entries\n", i);
  344. for(i = 2; i < 4; i++) {
  345. if (mmuwalk(UINT2PTR(machp()->pml4->va), 0, i, &p, nil) != i) {
  346. iprint("weird; 0 not mapped at %d\n", i);
  347. continue;
  348. }
  349. iprint("teardown: zap %p at level %d\n", p, i);
  350. if (p)
  351. *p = 0;
  352. }
  353. }
  354. void
  355. main(uint32_t mbmagic, uint32_t mbaddress)
  356. {
  357. Mach *m = entrym;
  358. /* when we get here, entrym is set to core0 mach. */
  359. sys->machptr[machp()->machno] = m;
  360. // Very special case for BSP only. Too many things
  361. // assume this is set.
  362. wrmsr(GSbase, PTR2UINT(&sys->machptr[machp()->machno]));
  363. if (machp() != m)
  364. panic("m and machp() are different!!\n");
  365. assert(sizeof(Mach) <= PGSZ);
  366. /*
  367. * Check that our data is on the right boundaries.
  368. * This works because the immediate value is in code.
  369. */
  370. if (x != 0x123456)
  371. panic("Data is not set up correctly\n");
  372. memset(edata, 0, end - edata);
  373. m = (void *) (KZERO + 1048576 + 11*4096);
  374. sys = (void *) (KZERO + 1048576);
  375. /*
  376. * ilock via i8250enable via i8250console
  377. * needs machp()->machno, sys->machptr[] set, and
  378. * also 'up' set to nil.
  379. */
  380. cgapost(sizeof(uintptr_t)*8);
  381. memset(m, 0, sizeof(Mach));
  382. machp()->machno = 0;
  383. m->online = 1;
  384. m->nixtype = NIXTC;
  385. sys->machptr[machp()->machno] = &sys->mach;
  386. m->stack = PTR2UINT(sys->machstk);
  387. m->vsvm = sys->vsvmpage;
  388. up = (void *)0;
  389. active.nonline = 1;
  390. active.exiting = 0;
  391. active.nbooting = 0;
  392. asminit();
  393. multiboot(mbmagic, mbaddress, 0);
  394. options(oargc, oargv);
  395. /*
  396. * Need something for initial delays
  397. * until a timebase is worked out.
  398. */
  399. m->cpuhz = 2000000000ll;
  400. m->cpumhz = 2000;
  401. cgainit();
  402. i8250console("0");
  403. consputs = cgaconsputs;
  404. /* It all ends here. */
  405. vsvminit(MACHSTKSZ, NIXTC, m);
  406. if (machp() != m)
  407. panic("After vsvminit, m and machp() are different");
  408. fmtinit();
  409. print("\nHarvey\n");
  410. sys->nmach = 1;
  411. if(1){
  412. multiboot(mbmagic, mbaddress, 1);
  413. }
  414. m->perf.period = 1;
  415. if((hz = archhz()) != 0ll){
  416. m->cpuhz = hz;
  417. m->cyclefreq = hz;
  418. m->cpumhz = hz/1000000ll;
  419. }
  420. iprint("archhz returns 0x%lld\n", hz);
  421. /*
  422. * Mmuinit before meminit because it
  423. * flushes the TLB via machp()->pml4->pa.
  424. */
  425. mmuinit();
  426. ioinit();
  427. kbdinit();
  428. meminit();
  429. confinit();
  430. archinit();
  431. mallocinit();
  432. /* test malloc. It's easier to find out it's broken here,
  433. * not deep in some call chain.
  434. * See next note.
  435. *
  436. void *v = malloc(1234);
  437. hi("v "); put64((uint64_t)v); hi("\n");
  438. free(v);
  439. hi("free ok\n");
  440. */
  441. /*
  442. * Acpiinit will cause the first malloc
  443. * call to happen.
  444. * If the system dies here it's probably due
  445. * to malloc not being initialised
  446. * correctly, or the data segment is misaligned
  447. * (it's amazing how far you can get with
  448. * things like that completely broken).
  449. */
  450. if (0){ acpiinit(); hi(" acpiinit();\n");}
  451. umeminit();
  452. trapinit();
  453. printinit();
  454. /*
  455. * This is necessary with GRUB and QEMU.
  456. * Without it an interrupt can occur at a weird vector,
  457. * because the vector base is likely different, causing
  458. * havoc. Do it before any APIC initialisation.
  459. */
  460. i8259init(32);
  461. procinit0();
  462. mpsinit(maxcores);
  463. apiconline();
  464. /* Forcing to single core if desired */
  465. if(!nosmp) {
  466. sipi();
  467. }
  468. teardownidmap(m);
  469. timersinit();
  470. kbdenable();
  471. fpuinit();
  472. psinit(conf.nproc);
  473. initimage();
  474. links();
  475. devtabreset();
  476. pageinit();
  477. swapinit();
  478. userinit();
  479. /* Forcing to single core if desired */
  480. if(!nosmp) {
  481. nixsquids();
  482. testiccs();
  483. }
  484. print("schedinit...\n");
  485. schedinit();
  486. }
  487. void
  488. init0(void)
  489. {
  490. Proc *up = machp()->externup;
  491. char buf[2*KNAMELEN];
  492. up->nerrlab = 0;
  493. /*
  494. * if(consuart == nil)
  495. * i8250console("0");
  496. */
  497. spllo();
  498. /*
  499. * These are o.k. because rootinit is null.
  500. * Then early kproc's will have a root and dot.
  501. */
  502. up->slash = namec("#/", Atodir, 0, 0);
  503. pathclose(up->slash->path);
  504. up->slash->path = newpath("/");
  505. up->dot = cclone(up->slash);
  506. devtabinit();
  507. if(!waserror()){
  508. snprint(buf, sizeof(buf), "%s %s", "AMD64", conffile);
  509. ksetenv("terminal", buf, 0);
  510. ksetenv("cputype", "amd64", 0);
  511. if(cpuserver)
  512. ksetenv("service", "cpu", 0);
  513. else
  514. ksetenv("service", "terminal", 0);
  515. ksetenv("pgsz", "2097152", 0);
  516. // no longer. confsetenv();
  517. poperror();
  518. }
  519. kproc("alarm", alarmkproc, 0);
  520. debugtouser((void *)UTZERO);
  521. touser(sp);
  522. }
  523. void
  524. bootargs(uintptr_t base)
  525. {
  526. int i;
  527. uint32_t ssize;
  528. char **av, *p;
  529. /*
  530. * Push the boot args onto the stack.
  531. * Make sure the validaddr check in syscall won't fail
  532. * because there are fewer than the maximum number of
  533. * args by subtracting sizeof(up->arg).
  534. */
  535. i = oargblen+1;
  536. p = UINT2PTR(STACKALIGN(base + BIGPGSZ - sizeof(entryup->arg) - i));
  537. memmove(p, oargb, i);
  538. /*
  539. * Now push argc and the argv pointers.
  540. * This isn't strictly correct as the code jumped to by
  541. * touser in init9.[cs] calls startboot (port/initcode.c) which
  542. * expects arguments
  543. * startboot(char* argv0, char* argv[])
  544. * not the usual (int argc, char* argv[]), but argv0 is
  545. * unused so it doesn't matter (at the moment...).
  546. */
  547. av = (char**)(p - (oargc+2)*sizeof(char*));
  548. ssize = base + BIGPGSZ - PTR2UINT(av);
  549. *av++ = (char*)oargc;
  550. for(i = 0; i < oargc; i++)
  551. *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BIGPGSZ);
  552. *av = nil;
  553. sp = USTKTOP - ssize;
  554. }
  555. void
  556. userinit(void)
  557. {
  558. Proc *up = machp()->externup;
  559. Proc *p;
  560. Segment *s;
  561. KMap *k;
  562. Page *pg;
  563. p = newproc();
  564. p->pgrp = newpgrp();
  565. p->egrp = smalloc(sizeof(Egrp));
  566. p->egrp->ref = 1;
  567. p->fgrp = dupfgrp(nil);
  568. p->rgrp = newrgrp();
  569. p->procmode = 0640;
  570. kstrdup(&eve, "");
  571. kstrdup(&p->text, "*init*");
  572. kstrdup(&p->user, eve);
  573. /*
  574. * Kernel Stack
  575. *
  576. * N.B. make sure there's enough space for syscall to check
  577. * for valid args and
  578. * space for gotolabel's return PC
  579. * AMD64 stack must be quad-aligned.
  580. */
  581. p->sched.pc = PTR2UINT(init0);
  582. p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->arg)-sizeof(uintptr_t));
  583. p->sched.sp = STACKALIGN(p->sched.sp);
  584. /*
  585. * User Stack
  586. *
  587. * Technically, newpage can't be called here because it
  588. * should only be called when in a user context as it may
  589. * try to sleep if there are no pages available, but that
  590. * shouldn't be the case here.
  591. */
  592. s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/ BIGPGSZ);
  593. p->seg[SSEG] = s;
  594. pg = newpage(1, 0, USTKTOP-BIGPGSZ, BIGPGSZ, -1);
  595. segpage(s, pg);
  596. k = kmap(pg);
  597. bootargs(VA(k));
  598. kunmap(k);
  599. /*
  600. * Text
  601. */
  602. s = newseg(SG_TEXT, UTZERO, 1);
  603. s->flushme++;
  604. p->seg[TSEG] = s;
  605. pg = newpage(1, 0, UTZERO, BIGPGSZ, -1);
  606. memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
  607. segpage(s, pg);
  608. k = kmap(s->map[0]->pages[0]);
  609. //memmove(UINT2PTR(VA(k)), initcode, sizeof(initcode));
  610. memmove(UINT2PTR(VA(k)), init_code_out, sizeof(init_code_out));
  611. kunmap(k);
  612. /*
  613. * Data
  614. */
  615. s = newseg(SG_DATA, UTZERO + BIGPGSZ, 1);
  616. s->flushme++;
  617. p->seg[DSEG] = s;
  618. pg = newpage(1, 0, UTZERO + BIGPGSZ, BIGPGSZ, -1);
  619. memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
  620. segpage(s, pg);
  621. k = kmap(s->map[0]->pages[0]);
  622. //memmove(UINT2PTR(VA(k)), initcode, sizeof(initcode));
  623. memmove(UINT2PTR(VA(k)), init_data_out, sizeof(init_data_out));
  624. kunmap(k);
  625. ready(p);
  626. }
  627. void
  628. confinit(void)
  629. {
  630. int i;
  631. conf.npage = 0;
  632. for(i=0; i<nelem(conf.mem); i++)
  633. conf.npage += conf.mem[i].npage;
  634. conf.nproc = 1000;
  635. conf.nimage = 200;
  636. }
  637. static void
  638. shutdown(int ispanic)
  639. {
  640. Proc *up = machp()->externup;
  641. int ms, once;
  642. lock(&active);
  643. if(ispanic)
  644. active.ispanic = ispanic;
  645. else if(machp()->machno == 0 && m->online == 0)
  646. active.ispanic = 0;
  647. once = m->online;
  648. m->online = 0;
  649. adec(&active.nonline);
  650. active.exiting = 1;
  651. unlock(&active);
  652. if(once)
  653. iprint("cpu%d: exiting\n", machp()->machno);
  654. spllo();
  655. for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
  656. delay(TK2MS(2));
  657. if(active.nonline == 0 && consactive() == 0)
  658. break;
  659. }
  660. if(active.ispanic && machp()->machno == 0){
  661. if(cpuserver)
  662. delay(30000);
  663. else
  664. for(;;)
  665. halt();
  666. }
  667. else
  668. delay(1000);
  669. }
  670. void
  671. reboot(void* v, void* w, int32_t i)
  672. {
  673. panic("Somebody called reboot()");
  674. }
  675. void
  676. exit(int ispanic)
  677. {
  678. shutdown(ispanic);
  679. archreset();
  680. }