main.c 16 KB

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