load.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "sd.h"
  8. #include "fs.h"
  9. /*
  10. * "cache" must be in this list so that 9load will pass the definition of
  11. * the cache partition into the kernel so that the disk named by the `cfs'
  12. * variable in plan9.ini can be seen in all circumstances before termrc
  13. * sets up all the disk partitions. In particular, if it's on an odd-ball
  14. * disk like sd10 rather than sdC0, this is needed.
  15. * "nvram" is for the benefit of AoE clients.
  16. */
  17. static char *diskparts[] = {
  18. "dos", "plan9", "9fat", "fs", "data", "cdboot", "cache", "nvram", 0
  19. };
  20. static char *etherparts[] = { "*", 0 };
  21. static char *diskinis[] = {
  22. "plan9/plan9.ini",
  23. "plan9.ini",
  24. 0
  25. };
  26. static char *etherinis[] = {
  27. "/cfg/pxe/%E",
  28. 0
  29. };
  30. /* ordering: devbios must be called before devsd calls sdbios */
  31. Type types[] = {
  32. { Tfloppy,
  33. Fini|Ffs,
  34. floppyinit, floppyinitdev,
  35. floppygetfspart, 0, floppyboot,
  36. floppyprintdevs,
  37. diskparts,
  38. diskinis,
  39. },
  40. { Tether,
  41. Fini|Fbootp,
  42. etherinit, etherinitdev,
  43. pxegetfspart, 0, bootpboot,
  44. etherprintdevs,
  45. etherparts,
  46. etherinis,
  47. },
  48. { Tbios,
  49. Fini|Ffs,
  50. biosinit, biosinitdev,
  51. biosgetfspart, nil, biosboot,
  52. biosprintdevs,
  53. diskparts,
  54. diskinis,
  55. },
  56. { Tcd,
  57. Fini|Ffs,
  58. cdinit, sdinitdev,
  59. sdgetfspart, sdaddconf, sdboot,
  60. sdprintdevs,
  61. diskparts,
  62. diskinis,
  63. },
  64. { Tsd,
  65. Fini|Ffs,
  66. sdinit, sdinitdev,
  67. sdgetfspart, sdaddconf, sdboot,
  68. sdprintdevs,
  69. diskparts,
  70. diskinis,
  71. },
  72. { Tnil,
  73. 0,
  74. nil, nil, nil, nil, nil, nil,
  75. nil,
  76. nil,
  77. 0,
  78. nil,
  79. },
  80. };
  81. static char *typenm[] = {
  82. [Tnil] "nil",
  83. [Tfloppy] "floppy",
  84. [Tsd] "sd",
  85. [Tether] "ether",
  86. [Tcd] "cd",
  87. [Tbios] "bios",
  88. };
  89. extern SDifc sdataifc;
  90. extern SDifc sdiahciifc;
  91. extern SDifc sdaoeifc;
  92. extern SDifc sdbiosifc;
  93. extern SDifc sdmylexifc;
  94. extern SDifc sd53c8xxifc;
  95. SDifc* sdifc[] = {
  96. &sdataifc,
  97. &sdiahciifc,
  98. &sdmylexifc,
  99. &sd53c8xxifc,
  100. &sdbiosifc,
  101. &sdaoeifc,
  102. nil,
  103. };
  104. typedef struct Mode Mode;
  105. enum {
  106. Maxdev = 7,
  107. Dany = -1,
  108. Nmedia = 16,
  109. Nini = 10,
  110. };
  111. enum { /* mode */
  112. Mauto = 0x00,
  113. Mlocal = 0x01,
  114. Manual = 0x02,
  115. NMode = 0x03,
  116. };
  117. typedef struct Medium Medium;
  118. struct Medium {
  119. Type* type;
  120. int flag;
  121. int dev;
  122. char name[NAMELEN];
  123. Fs *inifs;
  124. char *part;
  125. char *ini;
  126. Medium* next;
  127. };
  128. typedef struct Mode {
  129. char* name;
  130. int mode;
  131. } Mode;
  132. static Medium media[Nmedia];
  133. static Medium *curmedium = media;
  134. static Mode modes[NMode+1] = {
  135. [Mauto] { "auto", Mauto, },
  136. [Mlocal] { "local", Mlocal, },
  137. [Manual] { "manual", Manual, },
  138. };
  139. char **ini;
  140. int scsi0port;
  141. char *defaultpartition;
  142. int biosload; /* is it safe to probe the bios? */
  143. int iniread;
  144. int debugload;
  145. int vga;
  146. char *persist;
  147. static char *
  148. typename(int type)
  149. {
  150. if (type < 0 || type >= nelem(typenm) || typenm[type] == nil)
  151. return "**gok**";
  152. return typenm[type];
  153. }
  154. static Medium*
  155. parse(char *line, char **file)
  156. {
  157. char *p;
  158. Type *tp;
  159. Medium *mp;
  160. if(p = strchr(line, '!')) {
  161. *p++ = 0;
  162. *file = p;
  163. } else
  164. *file = "";
  165. for(tp = types; tp->type != Tnil; tp++)
  166. for(mp = tp->media; mp; mp = mp->next)
  167. if(strcmp(mp->name, line) == 0)
  168. return mp;
  169. if(p)
  170. *--p = '!';
  171. return nil;
  172. }
  173. static int
  174. boot(Medium *mp, char *file)
  175. {
  176. Type *tp;
  177. Medium *xmp;
  178. static int didaddconf;
  179. Boot b;
  180. memset(&b, 0, sizeof b);
  181. b.state = INITKERNEL;
  182. if(didaddconf == 0) {
  183. didaddconf = 1;
  184. for(tp = types; tp->type != Tnil; tp++)
  185. if(tp->addconf)
  186. for(xmp = tp->media; xmp; xmp = xmp->next)
  187. (*tp->addconf)(xmp->dev);
  188. }
  189. sprint(BOOTLINE, "%s!%s", mp->name, file);
  190. // print("booting %s!%s\n", mp->name, file);
  191. return (*mp->type->boot)(mp->dev, file, &b);
  192. }
  193. static Medium*
  194. allocm(Type *tp)
  195. {
  196. Medium **l;
  197. if(curmedium >= &media[Nmedia])
  198. return 0;
  199. for(l = &tp->media; *l; l = &(*l)->next)
  200. ;
  201. *l = curmedium++;
  202. return *l;
  203. }
  204. Medium*
  205. probe(int type, int flag, int dev)
  206. {
  207. Type *tp;
  208. int i;
  209. Medium *mp;
  210. File f;
  211. Fs *fs;
  212. char **partp;
  213. for(tp = types; tp->type != Tnil; tp++){
  214. if(type != Tany && type != tp->type)
  215. continue;
  216. if(flag != Fnone){
  217. for(mp = tp->media; mp; mp = mp->next){
  218. if((flag & mp->flag) && (dev == Dany || dev == mp->dev))
  219. return mp;
  220. }
  221. }
  222. if (debugload)
  223. print("probing %s...", typename(tp->type));
  224. if((tp->flag & Fprobe) == 0){
  225. tp->flag |= Fprobe;
  226. tp->mask = (*tp->init)();
  227. }
  228. for(i = 0; tp->mask; i++){
  229. if((tp->mask & (1<<i)) == 0)
  230. continue;
  231. tp->mask &= ~(1<<i);
  232. if((mp = allocm(tp)) == 0)
  233. continue;
  234. mp->dev = i;
  235. mp->flag = tp->flag;
  236. mp->type = tp;
  237. (*tp->initdev)(i, mp->name);
  238. if(mp->flag & Fini){
  239. mp->flag &= ~Fini;
  240. for(partp = tp->parts; *partp; partp++){
  241. if((fs = (*tp->getfspart)(i, *partp, 0)) == nil)
  242. continue;
  243. for(ini = tp->inis; *ini; ini++){
  244. if(fswalk(fs, *ini, &f) > 0){
  245. mp->inifs = fs;
  246. mp->part = *partp;
  247. mp->ini = f.path;
  248. mp->flag |= Fini;
  249. goto Break2;
  250. }
  251. }
  252. }
  253. }
  254. Break2:
  255. if((flag & mp->flag) && (dev == Dany || dev == i))
  256. return mp;
  257. }
  258. }
  259. return 0;
  260. }
  261. void
  262. main(void)
  263. {
  264. Medium *mp;
  265. int flag, i, mode, tried;
  266. char def[2*NAMELEN], line[80], *p, *file;
  267. Type *tp;
  268. i8042a20();
  269. memset(m, 0, sizeof(Mach));
  270. trapinit();
  271. clockinit();
  272. alarminit();
  273. meminit(0);
  274. spllo();
  275. /*
  276. * the soekris machines have no video but each has a serial port.
  277. * they must see serial output, if any, before cga output because
  278. * otherwise the soekris bios will translate cga output to serial
  279. * output, which will garble serial console output.
  280. */
  281. pcimatch(nil, 0, 0); /* force scan of pci table */
  282. if (!vga) {
  283. consinit("0", "9600"); /* e.g., for soekris debugging */
  284. print("no vga; serial console only\n");
  285. }
  286. kbdinit();
  287. if((ulong)&end > (KZERO|(640*1024)))
  288. panic("i'm too big");
  289. if (!pxe)
  290. /* TODO turning off debug and debugload makes loading fail */
  291. debug = 1;
  292. /*
  293. * find and read plan9.ini, setting configuration variables.
  294. */
  295. if (debug)
  296. print("plan9.ini probe...");
  297. for(tp = types; tp->type != Tnil; tp++){
  298. /*
  299. * we don't know which ether interface to use nor
  300. * whether bios loading is disabled until we have read
  301. * plan9.ini. make an exception for 9pxeload: probe
  302. * ethers anyway. see if we can live with always
  303. * probing the bios.
  304. */
  305. if(!pxe && tp->type == Tether /*|| !vga && tp->type == Tbios */)
  306. continue;
  307. if (debug)
  308. print("probing %s...", typename(tp->type));
  309. if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){
  310. if (debug)
  311. print("using %s!%s!%s\n",
  312. mp->name, mp->part, mp->ini);
  313. iniread = !dotini(mp->inifs);
  314. break;
  315. }
  316. }
  317. if (debug)
  318. print("\n");
  319. /*
  320. * we should now have read plan9.ini, if any.
  321. */
  322. if (!iniread)
  323. print("no plan9.ini\n");
  324. persist = getconf("*bootppersist");
  325. if (!pxe)
  326. debug = 0; /* stop the flood of output */
  327. debugload = getconf("*debugload") != nil;
  328. /*
  329. * !vga is a hack for soekris-like machines.
  330. * 9pxeload can't use bios int 13 calls; they wedge the machine.
  331. */
  332. if(!vga || pxe || getconf("*nobiosload") != nil)
  333. biosload = 0;
  334. if((p = getconf("console")) != nil)
  335. consinit(p, getconf("baud"));
  336. prcpuid();
  337. readlsconf();
  338. apminit();
  339. print("bios (usb) loading %s\n", biosload? "enabled": "disabled");
  340. devpccardlink();
  341. devi82365link();
  342. /*
  343. * Even after we find the ini file, we keep probing disks,
  344. * because we have to collect the partition tables and
  345. * have boot devices for parse.
  346. */
  347. probe(Tany, Fnone, Dany);
  348. if (debugload)
  349. print("end disk probe\n");
  350. tried = 0;
  351. mode = Mauto;
  352. p = getconf("bootfile");
  353. if(p != 0) {
  354. mode = Manual;
  355. for(i = 0; i < NMode; i++){
  356. if(strcmp(p, modes[i].name) == 0){
  357. mode = modes[i].mode;
  358. goto done;
  359. }
  360. }
  361. if((mp = parse(p, &file)) == nil) {
  362. print("Unknown boot device: %s\n", p);
  363. goto done;
  364. }
  365. tried = boot(mp, file);
  366. }
  367. done:
  368. if(tried == 0 && mode != Manual){
  369. flag = Fany;
  370. if(mode == Mlocal)
  371. flag &= ~Fbootp;
  372. if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy)
  373. boot(mp, "");
  374. if (debugload)
  375. print("end auto-boot probe\n");
  376. }
  377. def[0] = 0;
  378. probe(Tany, Fnone, Dany);
  379. if (debugload)
  380. print("end final probe\n");
  381. if(p = getconf("bootdef"))
  382. strncpy(def, p, sizeof def);
  383. /* print possible boot methods */
  384. flag = 0;
  385. for(tp = types; tp->type != Tnil; tp++){
  386. for(mp = tp->media; mp; mp = mp->next){
  387. if(flag == 0){
  388. flag = 1;
  389. print("Boot devices:");
  390. }
  391. (*tp->printdevs)(mp->dev);
  392. }
  393. }
  394. if(flag)
  395. print("\n");
  396. /*
  397. * e.g., *bootppersist=ether0
  398. *
  399. * previously, we looped in bootpopen if we were pxeload or if
  400. * *bootppersist was set. that doesn't work well for pxeload
  401. * in configurations where bootp will never succeed on the first
  402. * interface but only on another interface.
  403. */
  404. if (mode == Mauto && persist != nil &&
  405. (mp = parse(persist, &file)) != nil) {
  406. boot(mp, file);
  407. print("pausing before retry...");
  408. delay(30*1000);
  409. print("\n");
  410. }
  411. for(;;){
  412. if(getstr("boot from", line, sizeof(line), def, (mode != Manual)*15) >= 0)
  413. if(mp = parse(line, &file))
  414. boot(mp, file);
  415. def[0] = 0;
  416. }
  417. }
  418. int
  419. getfields(char *lp, char **fields, int n, char sep)
  420. {
  421. int i;
  422. for(i = 0; lp && *lp && i < n; i++){
  423. while(*lp == sep)
  424. *lp++ = 0;
  425. if(*lp == 0)
  426. break;
  427. fields[i] = lp;
  428. while(*lp && *lp != sep){
  429. if(*lp == '\\' && *(lp+1) == '\n')
  430. *lp++ = ' ';
  431. lp++;
  432. }
  433. }
  434. return i;
  435. }
  436. int
  437. cistrcmp(char *a, char *b)
  438. {
  439. int ac, bc;
  440. for(;;){
  441. ac = *a++;
  442. bc = *b++;
  443. if(ac >= 'A' && ac <= 'Z')
  444. ac = 'a' + (ac - 'A');
  445. if(bc >= 'A' && bc <= 'Z')
  446. bc = 'a' + (bc - 'A');
  447. ac -= bc;
  448. if(ac)
  449. return ac;
  450. if(bc == 0)
  451. break;
  452. }
  453. return 0;
  454. }
  455. int
  456. cistrncmp(char *a, char *b, int n)
  457. {
  458. unsigned ac, bc;
  459. while(n > 0){
  460. ac = *a++;
  461. bc = *b++;
  462. n--;
  463. if(ac >= 'A' && ac <= 'Z')
  464. ac = 'a' + (ac - 'A');
  465. if(bc >= 'A' && bc <= 'Z')
  466. bc = 'a' + (bc - 'A');
  467. ac -= bc;
  468. if(ac)
  469. return ac;
  470. if(bc == 0)
  471. break;
  472. }
  473. return 0;
  474. }
  475. #define PSTART ( 8*1024*1024)
  476. #define PEND (16*1024*1024)
  477. ulong palloc = PSTART;
  478. void*
  479. ialloc(ulong n, int align)
  480. {
  481. ulong p;
  482. int a;
  483. p = palloc;
  484. if(align <= 0)
  485. align = 4;
  486. if(a = n % align)
  487. n += align - a;
  488. if(a = p % align)
  489. p += align - a;
  490. palloc = p+n;
  491. if(palloc > PEND)
  492. panic("ialloc(%lud, %d) called from %#p",
  493. n, align, getcallerpc(&n));
  494. return memset((void*)(p|KZERO), 0, n);
  495. }
  496. void*
  497. xspanalloc(ulong size, int align, ulong span)
  498. {
  499. ulong a, v;
  500. if((palloc + (size+align+span)) > PEND)
  501. panic("xspanalloc(%lud, %d, 0x%lux) called from %#p",
  502. size, align, span, getcallerpc(&size));
  503. a = (ulong)ialloc(size+align+span, 0);
  504. if(span > 2)
  505. v = (a + span) & ~(span-1);
  506. else
  507. v = a;
  508. if(align > 1)
  509. v = (v + align) & ~(align-1);
  510. return (void*)v;
  511. }
  512. static Block *allocbp;
  513. Block*
  514. allocb(int size)
  515. {
  516. Block *bp, **lbp;
  517. ulong addr;
  518. lbp = &allocbp;
  519. for(bp = *lbp; bp; bp = bp->next){
  520. if((bp->lim - bp->base) >= size){
  521. *lbp = bp->next;
  522. break;
  523. }
  524. lbp = &bp->next;
  525. }
  526. if(bp == 0){
  527. if((palloc + (sizeof(Block)+size+64)) > PEND)
  528. panic("allocb(%d) called from %#p",
  529. size, getcallerpc(&size));
  530. bp = ialloc(sizeof(Block)+size+64, 0);
  531. addr = (ulong)bp;
  532. addr = ROUNDUP(addr + sizeof(Block), 8);
  533. bp->base = (uchar*)addr;
  534. bp->lim = ((uchar*)bp) + sizeof(Block)+size+64;
  535. }
  536. if(bp->flag)
  537. panic("allocb reuse");
  538. bp->rp = bp->base;
  539. bp->wp = bp->rp;
  540. bp->next = 0;
  541. bp->flag = 1;
  542. return bp;
  543. }
  544. void
  545. freeb(Block* bp)
  546. {
  547. bp->next = allocbp;
  548. allocbp = bp;
  549. bp->flag = 0;
  550. }
  551. enum {
  552. Paddr= 0x70, /* address port */
  553. Pdata= 0x71, /* data port */
  554. };
  555. uchar
  556. nvramread(int offset)
  557. {
  558. outb(Paddr, offset);
  559. return inb(Pdata);
  560. }
  561. void (*etherdetach)(void);
  562. void (*floppydetach)(void);
  563. void (*sddetach)(void);
  564. void
  565. warp9(ulong entry)
  566. {
  567. if(etherdetach)
  568. etherdetach();
  569. if(floppydetach)
  570. floppydetach();
  571. if(sddetach)
  572. sddetach();
  573. consdrain();
  574. splhi();
  575. trapdisable();
  576. /*
  577. * This is where to push things on the stack to
  578. * boot *BSD systems, e.g.
  579. (*(void(*)(void*, void*, void*, void*, ulong, ulong))(PADDR(entry)))(0, 0, 0, 0, 8196, 640);
  580. * will enable NetBSD boot (the real memory size needs to
  581. * go in the 5th argument).
  582. */
  583. (*(void(*)(void))(PADDR(entry)))();
  584. }