main.c 15 KB

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