main.c 17 KB

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