main.c 14 KB

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