main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. #include "init.h"
  9. #include "pool.h"
  10. #include "reboot.h"
  11. #include "mp.h"
  12. Mach *m;
  13. /*
  14. * Where configuration info is left for the loaded programme.
  15. * This will turn into a structure as more is done by the boot loader
  16. * (e.g. why parse the .ini file twice?).
  17. * There are 3584 bytes available at CONFADDR.
  18. */
  19. #define BOOTLINE ((char*)CONFADDR)
  20. #define BOOTLINELEN 64
  21. #define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
  22. #define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
  23. #define MAXCONF 64
  24. char bootdisk[KNAMELEN];
  25. Conf conf;
  26. char *confname[MAXCONF];
  27. char *confval[MAXCONF];
  28. int nconf;
  29. uchar *sp; /* user stack of init proc */
  30. int delaylink;
  31. static void
  32. options(void)
  33. {
  34. long i, n;
  35. char *cp, *line[MAXCONF], *p, *q;
  36. /*
  37. * parse configuration args from dos file plan9.ini
  38. */
  39. cp = BOOTARGS; /* where b.com leaves its config */
  40. cp[BOOTARGSLEN-1] = 0;
  41. /*
  42. * Strip out '\r', change '\t' -> ' '.
  43. */
  44. p = cp;
  45. for(q = cp; *q; q++){
  46. if(*q == '\r')
  47. continue;
  48. if(*q == '\t')
  49. *q = ' ';
  50. *p++ = *q;
  51. }
  52. *p = 0;
  53. n = getfields(cp, line, MAXCONF, 1, "\n");
  54. for(i = 0; i < n; i++){
  55. if(*line[i] == '#')
  56. continue;
  57. cp = strchr(line[i], '=');
  58. if(cp == nil)
  59. continue;
  60. *cp++ = '\0';
  61. confname[nconf] = line[i];
  62. confval[nconf] = cp;
  63. nconf++;
  64. }
  65. }
  66. extern void mmuinit0(void);
  67. extern void (*i8237alloc)(void);
  68. void
  69. main(void)
  70. {
  71. mach0init();
  72. options();
  73. ioinit();
  74. i8250console();
  75. quotefmtinstall();
  76. screeninit();
  77. print("\nPlan 9\n");
  78. trapinit0();
  79. mmuinit0();
  80. kbdinit();
  81. i8253init();
  82. cpuidentify();
  83. meminit();
  84. confinit();
  85. archinit();
  86. xinit();
  87. if(i8237alloc != nil)
  88. i8237alloc();
  89. trapinit();
  90. printinit();
  91. cpuidprint();
  92. mmuinit();
  93. if(arch->intrinit) /* launches other processors on an mp */
  94. arch->intrinit();
  95. timersinit();
  96. mathinit();
  97. kbdenable();
  98. if(arch->clockenable)
  99. arch->clockenable();
  100. procinit0();
  101. initseg();
  102. if(delaylink){
  103. bootlinks();
  104. pcimatch(0, 0, 0);
  105. }else
  106. links();
  107. conf.monitor = 1;
  108. chandevreset();
  109. pageinit();
  110. i8253link();
  111. swapinit();
  112. userinit();
  113. active.thunderbirdsarego = 1;
  114. schedinit();
  115. }
  116. void
  117. mach0init(void)
  118. {
  119. conf.nmach = 1;
  120. MACHP(0) = (Mach*)CPU0MACH;
  121. m->pdb = (ulong*)CPU0PDB;
  122. m->gdt = (Segdesc*)CPU0GDT;
  123. machinit();
  124. active.machs = 1;
  125. active.exiting = 0;
  126. }
  127. void
  128. machinit(void)
  129. {
  130. int machno;
  131. ulong *pdb;
  132. Segdesc *gdt;
  133. machno = m->machno;
  134. pdb = m->pdb;
  135. gdt = m->gdt;
  136. memset(m, 0, sizeof(Mach));
  137. m->machno = machno;
  138. m->pdb = pdb;
  139. m->gdt = gdt;
  140. m->perf.period = 1;
  141. /*
  142. * For polled uart output at boot, need
  143. * a default delay constant. 100000 should
  144. * be enough for a while. Cpuidentify will
  145. * calculate the real value later.
  146. */
  147. m->loopconst = 100000;
  148. }
  149. void
  150. init0(void)
  151. {
  152. int i;
  153. char buf[2*KNAMELEN];
  154. up->nerrlab = 0;
  155. spllo();
  156. /*
  157. * These are o.k. because rootinit is null.
  158. * Then early kproc's will have a root and dot.
  159. */
  160. up->slash = namec("#/", Atodir, 0, 0);
  161. pathclose(up->slash->path);
  162. up->slash->path = newpath("/");
  163. up->dot = cclone(up->slash);
  164. chandevinit();
  165. if(!waserror()){
  166. snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
  167. ksetenv("terminal", buf, 0);
  168. ksetenv("cputype", "386", 0);
  169. if(cpuserver)
  170. ksetenv("service", "cpu", 0);
  171. else
  172. ksetenv("service", "terminal", 0);
  173. for(i = 0; i < nconf; i++){
  174. if(confname[i][0] != '*')
  175. ksetenv(confname[i], confval[i], 0);
  176. ksetenv(confname[i], confval[i], 1);
  177. }
  178. poperror();
  179. }
  180. kproc("alarm", alarmkproc, 0);
  181. touser(sp);
  182. }
  183. void
  184. userinit(void)
  185. {
  186. void *v;
  187. Proc *p;
  188. Segment *s;
  189. Page *pg;
  190. p = newproc();
  191. p->pgrp = newpgrp();
  192. p->egrp = smalloc(sizeof(Egrp));
  193. p->egrp->ref = 1;
  194. p->fgrp = dupfgrp(nil);
  195. p->rgrp = newrgrp();
  196. p->procmode = 0640;
  197. kstrdup(&eve, "");
  198. kstrdup(&p->text, "*init*");
  199. kstrdup(&p->user, eve);
  200. p->fpstate = FPinit;
  201. fpoff();
  202. /*
  203. * Kernel Stack
  204. *
  205. * N.B. make sure there's enough space for syscall to check
  206. * for valid args and
  207. * 4 bytes for gotolabel's return PC
  208. */
  209. p->sched.pc = (ulong)init0;
  210. p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
  211. /*
  212. * User Stack
  213. *
  214. * N.B. cannot call newpage() with clear=1, because pc kmap
  215. * requires up != nil. use tmpmap instead.
  216. */
  217. s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
  218. p->seg[SSEG] = s;
  219. pg = newpage(0, 0, USTKTOP-BY2PG);
  220. v = tmpmap(pg);
  221. memset(v, 0, BY2PG);
  222. segpage(s, pg);
  223. bootargs(v);
  224. tmpunmap(v);
  225. /*
  226. * Text
  227. */
  228. s = newseg(SG_TEXT, UTZERO, 1);
  229. s->flushme++;
  230. p->seg[TSEG] = s;
  231. pg = newpage(0, 0, UTZERO);
  232. memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
  233. segpage(s, pg);
  234. v = tmpmap(pg);
  235. memset(v, 0, BY2PG);
  236. memmove(v, initcode, sizeof initcode);
  237. tmpunmap(v);
  238. ready(p);
  239. }
  240. uchar *
  241. pusharg(char *p)
  242. {
  243. int n;
  244. n = strlen(p)+1;
  245. sp -= n;
  246. memmove(sp, p, n);
  247. return sp;
  248. }
  249. void
  250. bootargs(void *base)
  251. {
  252. int i, ac;
  253. uchar *av[32];
  254. uchar **lsp;
  255. char *cp = BOOTLINE;
  256. char buf[64];
  257. sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD;
  258. ac = 0;
  259. av[ac++] = pusharg("/386/9dos");
  260. /* when boot is changed to only use rc, this code can go away */
  261. cp[BOOTLINELEN-1] = 0;
  262. buf[0] = 0;
  263. if(strncmp(cp, "fd", 2) == 0){
  264. sprint(buf, "local!#f/fd%lddisk", strtol(cp+2, 0, 0));
  265. av[ac++] = pusharg(buf);
  266. } else if(strncmp(cp, "sd", 2) == 0){
  267. sprint(buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3));
  268. av[ac++] = pusharg(buf);
  269. } else if(strncmp(cp, "ether", 5) == 0)
  270. av[ac++] = pusharg("-n");
  271. /* 4 byte word align stack */
  272. sp = (uchar*)((ulong)sp & ~3);
  273. /* build argc, argv on stack */
  274. sp -= (ac+1)*sizeof(sp);
  275. lsp = (uchar**)sp;
  276. for(i = 0; i < ac; i++)
  277. *lsp++ = av[i] + ((USTKTOP - BY2PG) - (ulong)base);
  278. *lsp = 0;
  279. sp += (USTKTOP - BY2PG) - (ulong)base - sizeof(ulong);
  280. }
  281. char*
  282. getconf(char *name)
  283. {
  284. int i;
  285. for(i = 0; i < nconf; i++)
  286. if(cistrcmp(confname[i], name) == 0)
  287. return confval[i];
  288. return 0;
  289. }
  290. static void
  291. writeconf(void)
  292. {
  293. char *p, *q;
  294. int n;
  295. p = getconfenv();
  296. if(waserror()) {
  297. free(p);
  298. nexterror();
  299. }
  300. /* convert to name=value\n format */
  301. for(q=p; *q; q++) {
  302. q += strlen(q);
  303. *q = '=';
  304. q += strlen(q);
  305. *q = '\n';
  306. }
  307. n = q - p + 1;
  308. if(n >= BOOTARGSLEN)
  309. error("kernel configuration too large");
  310. memset(BOOTLINE, 0, BOOTLINELEN);
  311. memmove(BOOTARGS, p, n);
  312. poperror();
  313. free(p);
  314. }
  315. void
  316. confinit(void)
  317. {
  318. char *p;
  319. int i, userpcnt;
  320. ulong kpages;
  321. if(p = getconf("*kernelpercent"))
  322. userpcnt = 100 - strtol(p, 0, 0);
  323. else
  324. userpcnt = 0;
  325. conf.npage = 0;
  326. for(i=0; i<nelem(conf.mem); i++)
  327. conf.npage += conf.mem[i].npage;
  328. conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
  329. if(cpuserver)
  330. conf.nproc *= 3;
  331. if(conf.nproc > 2000)
  332. conf.nproc = 2000;
  333. conf.nimage = 200;
  334. conf.nswap = conf.nproc*80;
  335. conf.nswppo = 4096;
  336. if(cpuserver) {
  337. if(userpcnt < 10)
  338. userpcnt = 70;
  339. kpages = conf.npage - (conf.npage*userpcnt)/100;
  340. /*
  341. * Hack for the big boys. Only good while physmem < 4GB.
  342. * Give the kernel fixed max + enough to allocate the
  343. * page pool.
  344. * This is an overestimate as conf.upages < conf.npages.
  345. * The patch of nimage is a band-aid, scanning the whole
  346. * page list in imagereclaim just takes too long.
  347. */
  348. if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
  349. kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
  350. conf.nimage = 2000;
  351. kpages += (conf.nproc*KSTACK)/BY2PG;
  352. }
  353. } else {
  354. if(userpcnt < 10) {
  355. if(conf.npage*BY2PG < 16*MB)
  356. userpcnt = 40;
  357. else
  358. userpcnt = 60;
  359. }
  360. kpages = conf.npage - (conf.npage*userpcnt)/100;
  361. /*
  362. * Make sure terminals with low memory get at least
  363. * 4MB on the first Image chunk allocation.
  364. */
  365. if(conf.npage*BY2PG < 16*MB)
  366. imagmem->minarena = 4*1024*1024;
  367. }
  368. /*
  369. * can't go past the end of virtual memory
  370. * (ulong)-KZERO is 2^32 - KZERO
  371. */
  372. if(kpages > ((ulong)-KZERO)/BY2PG)
  373. kpages = ((ulong)-KZERO)/BY2PG;
  374. conf.upages = conf.npage - kpages;
  375. conf.ialloc = (kpages/2)*BY2PG;
  376. /*
  377. * Guess how much is taken by the large permanent
  378. * datastructures. Mntcache and Mntrpc are not accounted for
  379. * (probably ~300KB).
  380. */
  381. kpages *= BY2PG;
  382. kpages -= conf.upages*sizeof(Page)
  383. + conf.nproc*sizeof(Proc)
  384. + conf.nimage*sizeof(Image)
  385. + conf.nswap
  386. + conf.nswppo*sizeof(Page);
  387. mainmem->maxsize = kpages;
  388. if(!cpuserver){
  389. /*
  390. * give terminals lots of image memory, too; the dynamic
  391. * allocation will balance the load properly, hopefully.
  392. * be careful with 32-bit overflow.
  393. */
  394. imagmem->maxsize = kpages;
  395. }
  396. }
  397. static char* mathmsg[] =
  398. {
  399. nil, /* handled below */
  400. "denormalized operand",
  401. "division by zero",
  402. "numeric overflow",
  403. "numeric underflow",
  404. "precision loss",
  405. };
  406. static void
  407. mathnote(void)
  408. {
  409. int i;
  410. ulong status;
  411. char *msg, note[ERRMAX];
  412. status = up->fpsave.status;
  413. /*
  414. * Some attention should probably be paid here to the
  415. * exception masks and error summary.
  416. */
  417. msg = "unknown exception";
  418. for(i = 1; i <= 5; i++){
  419. if(!((1<<i) & status))
  420. continue;
  421. msg = mathmsg[i];
  422. break;
  423. }
  424. if(status & 0x01){
  425. if(status & 0x40){
  426. if(status & 0x200)
  427. msg = "stack overflow";
  428. else
  429. msg = "stack underflow";
  430. }else
  431. msg = "invalid operation";
  432. }
  433. snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
  434. msg, up->fpsave.pc, status);
  435. postnote(up, 1, note, NDebug);
  436. }
  437. /*
  438. * math coprocessor error
  439. */
  440. static void
  441. matherror(Ureg *ur, void*)
  442. {
  443. /*
  444. * a write cycle to port 0xF0 clears the interrupt latch attached
  445. * to the error# line from the 387
  446. */
  447. if(!(m->cpuiddx & 0x01))
  448. outb(0xF0, 0xFF);
  449. /*
  450. * save floating point state to check out error
  451. */
  452. fpenv(&up->fpsave);
  453. mathnote();
  454. if((ur->pc & 0xf0000000) == KZERO)
  455. panic("fp: status %ux fppc=0x%lux pc=0x%lux",
  456. up->fpsave.status, up->fpsave.pc, ur->pc);
  457. }
  458. /*
  459. * math coprocessor emulation fault
  460. */
  461. static void
  462. mathemu(Ureg *ureg, void*)
  463. {
  464. if(up->fpstate & FPillegal){
  465. /* someone did floating point in a note handler */
  466. postnote(up, 1, "sys: floating point in note handler", NDebug);
  467. return;
  468. }
  469. switch(up->fpstate){
  470. case FPinit:
  471. fpinit();
  472. up->fpstate = FPactive;
  473. break;
  474. case FPinactive:
  475. /*
  476. * Before restoring the state, check for any pending
  477. * exceptions, there's no way to restore the state without
  478. * generating an unmasked exception.
  479. * More attention should probably be paid here to the
  480. * exception masks and error summary.
  481. */
  482. if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
  483. mathnote();
  484. break;
  485. }
  486. fprestore(&up->fpsave);
  487. up->fpstate = FPactive;
  488. break;
  489. case FPactive:
  490. panic("math emu pid %ld %s pc 0x%lux",
  491. up->pid, up->text, ureg->pc);
  492. break;
  493. }
  494. }
  495. /*
  496. * math coprocessor segment overrun
  497. */
  498. static void
  499. mathover(Ureg*, void*)
  500. {
  501. pexit("math overrun", 0);
  502. }
  503. void
  504. mathinit(void)
  505. {
  506. trapenable(VectorCERR, matherror, 0, "matherror");
  507. if(X86FAMILY(m->cpuidax) == 3)
  508. intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
  509. trapenable(VectorCNA, mathemu, 0, "mathemu");
  510. trapenable(VectorCSO, mathover, 0, "mathover");
  511. }
  512. /*
  513. * set up floating point for a new process
  514. */
  515. void
  516. procsetup(Proc*p)
  517. {
  518. p->fpstate = FPinit;
  519. fpoff();
  520. }
  521. void
  522. procrestore(Proc *p)
  523. {
  524. uvlong t;
  525. if(p->kp)
  526. return;
  527. cycles(&t);
  528. p->pcycles -= t;
  529. }
  530. /*
  531. * Save the mach dependent part of the process state.
  532. */
  533. void
  534. procsave(Proc *p)
  535. {
  536. uvlong t;
  537. cycles(&t);
  538. p->pcycles += t;
  539. if(p->fpstate == FPactive){
  540. if(p->state == Moribund)
  541. fpclear();
  542. else{
  543. /*
  544. * Fpsave() stores without handling pending
  545. * unmasked exeptions. Postnote() can't be called
  546. * here as sleep() already has up->rlock, so
  547. * the handling of pending exceptions is delayed
  548. * until the process runs again and generates an
  549. * emulation fault to activate the FPU.
  550. */
  551. fpsave(&p->fpsave);
  552. }
  553. p->fpstate = FPinactive;
  554. }
  555. /*
  556. * While this processor is in the scheduler, the process could run
  557. * on another processor and exit, returning the page tables to
  558. * the free list where they could be reallocated and overwritten.
  559. * When this processor eventually has to get an entry from the
  560. * trashed page tables it will crash.
  561. *
  562. * If there's only one processor, this can't happen.
  563. * You might think it would be a win not to do this in that case,
  564. * especially on VMware, but it turns out not to matter.
  565. */
  566. mmuflushtlb(PADDR(m->pdb));
  567. }
  568. static void
  569. shutdown(int ispanic)
  570. {
  571. int ms, once;
  572. lock(&active);
  573. if(ispanic)
  574. active.ispanic = ispanic;
  575. else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
  576. active.ispanic = 0;
  577. once = active.machs & (1<<m->machno);
  578. /*
  579. * setting exiting will make hzclock() on each processor call exit(0),
  580. * which calls shutdown(0) and arch->reset(), which on mp systems is
  581. * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap
  582. * processors (to permit a reboot). clearing our bit in machs avoids
  583. * calling exit(0) from hzclock() on this processor.
  584. */
  585. active.machs &= ~(1<<m->machno);
  586. active.exiting = 1;
  587. unlock(&active);
  588. if(once)
  589. iprint("cpu%d: exiting\n", m->machno);
  590. /* wait for any other processors to shutdown */
  591. spllo();
  592. for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
  593. delay(TK2MS(2));
  594. if(active.machs == 0 && consactive() == 0)
  595. break;
  596. }
  597. if(active.ispanic){
  598. if(!cpuserver)
  599. for(;;)
  600. halt();
  601. if(getconf("*debug"))
  602. delay(5*60*1000);
  603. else
  604. delay(10000);
  605. }else
  606. delay(1000);
  607. }
  608. void
  609. reboot(void *entry, void *code, ulong size)
  610. {
  611. void (*f)(ulong, ulong, ulong);
  612. ulong *pdb;
  613. writeconf();
  614. /*
  615. * the boot processor is cpu0. execute this function on it
  616. * so that the new kernel has the same cpu0. this only matters
  617. * because the hardware has a notion of which processor was the
  618. * boot processor and we look at it at start up.
  619. */
  620. if (m->machno != 0) {
  621. procwired(up, 0);
  622. sched();
  623. }
  624. if(conf.nmach > 1) {
  625. /*
  626. * the other cpus could be holding locks that will never get
  627. * released (e.g., in the print path) if we put them into
  628. * reset now, so force them to shutdown gracefully first.
  629. */
  630. lock(&active);
  631. active.rebooting = 1;
  632. unlock(&active);
  633. shutdown(0);
  634. if(arch->resetothers)
  635. arch->resetothers();
  636. delay(20);
  637. }
  638. /*
  639. * should be the only processor running now
  640. */
  641. active.machs = 0;
  642. if (m->machno != 0)
  643. print("on cpu%d (not 0)!\n", m->machno);
  644. print("shutting down...\n");
  645. delay(200);
  646. splhi();
  647. /* turn off buffered serial console */
  648. serialoq = nil;
  649. /* shutdown devices */
  650. chandevshutdown();
  651. arch->introff();
  652. /*
  653. * Modify the machine page table to directly map the low 4MB of memory
  654. * This allows the reboot code to turn off the page mapping
  655. */
  656. pdb = m->pdb;
  657. pdb[PDX(0)] = pdb[PDX(KZERO)];
  658. mmuflushtlb(PADDR(pdb));
  659. /* setup reboot trampoline function */
  660. f = (void*)REBOOTADDR;
  661. memmove(f, rebootcode, sizeof(rebootcode));
  662. print("rebooting...\n");
  663. /* off we go - never to return */
  664. coherence();
  665. (*f)(PADDR(entry), PADDR(code), size);
  666. }
  667. void
  668. exit(int ispanic)
  669. {
  670. shutdown(ispanic);
  671. arch->reset();
  672. }
  673. int
  674. isaconfig(char *class, int ctlrno, ISAConf *isa)
  675. {
  676. char cc[32], *p;
  677. int i;
  678. snprint(cc, sizeof cc, "%s%d", class, ctlrno);
  679. p = getconf(cc);
  680. if(p == nil)
  681. return 0;
  682. isa->type = "";
  683. isa->nopt = tokenize(p, isa->opt, NISAOPT);
  684. for(i = 0; i < isa->nopt; i++){
  685. p = isa->opt[i];
  686. if(cistrncmp(p, "type=", 5) == 0)
  687. isa->type = p + 5;
  688. else if(cistrncmp(p, "port=", 5) == 0)
  689. isa->port = strtoul(p+5, &p, 0);
  690. else if(cistrncmp(p, "irq=", 4) == 0)
  691. isa->irq = strtoul(p+4, &p, 0);
  692. else if(cistrncmp(p, "dma=", 4) == 0)
  693. isa->dma = strtoul(p+4, &p, 0);
  694. else if(cistrncmp(p, "mem=", 4) == 0)
  695. isa->mem = strtoul(p+4, &p, 0);
  696. else if(cistrncmp(p, "size=", 5) == 0)
  697. isa->size = strtoul(p+5, &p, 0);
  698. else if(cistrncmp(p, "freq=", 5) == 0)
  699. isa->freq = strtoul(p+5, &p, 0);
  700. }
  701. return 1;
  702. }
  703. int
  704. cistrcmp(char *a, char *b)
  705. {
  706. int ac, bc;
  707. for(;;){
  708. ac = *a++;
  709. bc = *b++;
  710. if(ac >= 'A' && ac <= 'Z')
  711. ac = 'a' + (ac - 'A');
  712. if(bc >= 'A' && bc <= 'Z')
  713. bc = 'a' + (bc - 'A');
  714. ac -= bc;
  715. if(ac)
  716. return ac;
  717. if(bc == 0)
  718. break;
  719. }
  720. return 0;
  721. }
  722. int
  723. cistrncmp(char *a, char *b, int n)
  724. {
  725. unsigned ac, bc;
  726. while(n > 0){
  727. ac = *a++;
  728. bc = *b++;
  729. n--;
  730. if(ac >= 'A' && ac <= 'Z')
  731. ac = 'a' + (ac - 'A');
  732. if(bc >= 'A' && bc <= 'Z')
  733. bc = 'a' + (bc - 'A');
  734. ac -= bc;
  735. if(ac)
  736. return ac;
  737. if(bc == 0)
  738. break;
  739. }
  740. return 0;
  741. }
  742. int less_power_slower;
  743. /*
  744. * put the processor in the halt state if we've no processes to run.
  745. * an interrupt will get us going again.
  746. */
  747. void
  748. idlehands(void)
  749. {
  750. /*
  751. * we used to halt only on single-core setups. halting in an smp system
  752. * can result in a startup latency for processes that become ready.
  753. * if less_power_slower is true, we care more about saving energy
  754. * than reducing this latency.
  755. */
  756. if(conf.nmach == 1 || less_power_slower)
  757. halt();
  758. }