load.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. */
  16. static char *diskparts[] = {
  17. "dos", "9fat", "fs", "data", "cdboot", "cache", 0
  18. };
  19. static char *etherparts[] = { "*", 0 };
  20. static char *diskinis[] = {
  21. "plan9/plan9.ini",
  22. "plan9.ini",
  23. 0
  24. };
  25. static char *etherinis[] = {
  26. "/cfg/pxe/%E",
  27. 0
  28. };
  29. /* ordering: devbios must be called before devsd calls sdbios */
  30. Type types[] = {
  31. { Tfloppy,
  32. Fini|Ffs,
  33. floppyinit, floppyinitdev,
  34. floppygetfspart, 0, floppyboot,
  35. floppyprintdevs,
  36. diskparts,
  37. diskinis,
  38. },
  39. { Tether,
  40. Fini|Fbootp,
  41. etherinit, etherinitdev,
  42. pxegetfspart, 0, bootpboot,
  43. etherprintdevs,
  44. etherparts,
  45. etherinis,
  46. },
  47. { Tbios,
  48. Fini|Ffs,
  49. biosinit, biosinitdev,
  50. biosgetfspart, nil, biosboot,
  51. biosprintdevs,
  52. diskparts,
  53. diskinis,
  54. },
  55. { Tcd,
  56. Fini|Ffs,
  57. cdinit, sdinitdev,
  58. sdgetfspart, sdaddconf, sdboot,
  59. sdprintdevs,
  60. diskparts,
  61. diskinis,
  62. },
  63. { Tsd,
  64. Fini|Ffs,
  65. sdinit, sdinitdev,
  66. sdgetfspart, sdaddconf, sdboot,
  67. sdprintdevs,
  68. diskparts,
  69. diskinis,
  70. },
  71. { Tnil,
  72. 0,
  73. nil, nil, nil, nil, nil, nil,
  74. nil,
  75. nil,
  76. 0,
  77. nil,
  78. },
  79. };
  80. extern SDifc sdataifc;
  81. extern SDifc sdiahciifc;
  82. extern SDifc sdaoeifc;
  83. extern SDifc sdbiosifc;
  84. #ifdef NOSCSI
  85. SDifc* sdifc[] = {
  86. &sdataifc,
  87. &sdiahciifc,
  88. &sdbiosifc,
  89. &sdaoeifc,
  90. nil,
  91. };
  92. #else
  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. #endif NOSCSI
  105. typedef struct Mode Mode;
  106. enum {
  107. Maxdev = 7,
  108. Dany = -1,
  109. Nmedia = 16,
  110. Nini = 10,
  111. };
  112. enum { /* mode */
  113. Mauto = 0x00,
  114. Mlocal = 0x01,
  115. Manual = 0x02,
  116. NMode = 0x03,
  117. };
  118. typedef struct Medium Medium;
  119. struct Medium {
  120. Type* type;
  121. int flag;
  122. int dev;
  123. char name[NAMELEN];
  124. Fs *inifs;
  125. char *part;
  126. char *ini;
  127. Medium* next;
  128. };
  129. typedef struct Mode {
  130. char* name;
  131. int mode;
  132. } Mode;
  133. static Medium media[Nmedia];
  134. static Medium *curmedium = media;
  135. static Mode modes[NMode+1] = {
  136. [Mauto] { "auto", Mauto, },
  137. [Mlocal] { "local", Mlocal, },
  138. [Manual] { "manual", Manual, },
  139. };
  140. char **ini;
  141. int scsi0port;
  142. char *defaultpartition;
  143. int iniread;
  144. static Medium*
  145. parse(char *line, char **file)
  146. {
  147. char *p;
  148. Type *tp;
  149. Medium *mp;
  150. if(p = strchr(line, '!')) {
  151. *p++ = 0;
  152. *file = p;
  153. } else
  154. *file = "";
  155. for(tp = types; tp->type != Tnil; tp++)
  156. for(mp = tp->media; mp; mp = mp->next)
  157. if(strcmp(mp->name, line) == 0)
  158. return mp;
  159. if(p)
  160. *--p = '!';
  161. return nil;
  162. }
  163. static int
  164. boot(Medium *mp, char *file)
  165. {
  166. Type *tp;
  167. Medium *xmp;
  168. static int didaddconf;
  169. Boot b;
  170. memset(&b, 0, sizeof b);
  171. b.state = INITKERNEL;
  172. if(didaddconf == 0) {
  173. didaddconf = 1;
  174. for(tp = types; tp->type != Tnil; tp++)
  175. if(tp->addconf)
  176. for(xmp = tp->media; xmp; xmp = xmp->next)
  177. (*tp->addconf)(xmp->dev);
  178. }
  179. sprint(BOOTLINE, "%s!%s", mp->name, file);
  180. return (*mp->type->boot)(mp->dev, file, &b);
  181. }
  182. static Medium*
  183. allocm(Type *tp)
  184. {
  185. Medium **l;
  186. if(curmedium >= &media[Nmedia])
  187. return 0;
  188. for(l = &tp->media; *l; l = &(*l)->next)
  189. ;
  190. *l = curmedium++;
  191. return *l;
  192. }
  193. Medium*
  194. probe(int type, int flag, int dev)
  195. {
  196. Type *tp;
  197. int i;
  198. Medium *mp;
  199. File f;
  200. Fs *fs;
  201. char **partp;
  202. for(tp = types; tp->type != Tnil; tp++){
  203. if(type != Tany && type != tp->type)
  204. continue;
  205. if(flag != Fnone){
  206. for(mp = tp->media; mp; mp = mp->next){
  207. if((flag & mp->flag) && (dev == Dany || dev == mp->dev))
  208. return mp;
  209. }
  210. }
  211. if((tp->flag & Fprobe) == 0){
  212. tp->flag |= Fprobe;
  213. tp->mask = (*tp->init)();
  214. }
  215. for(i = 0; tp->mask; i++){
  216. if((tp->mask & (1<<i)) == 0)
  217. continue;
  218. tp->mask &= ~(1<<i);
  219. if((mp = allocm(tp)) == 0)
  220. continue;
  221. mp->dev = i;
  222. mp->flag = tp->flag;
  223. mp->type = tp;
  224. (*tp->initdev)(i, mp->name);
  225. if(mp->flag & Fini){
  226. mp->flag &= ~Fini;
  227. for(partp = tp->parts; *partp; partp++){
  228. if((fs = (*tp->getfspart)(i, *partp, 0)) == nil)
  229. continue;
  230. for(ini = tp->inis; *ini; ini++){
  231. if(fswalk(fs, *ini, &f) > 0){
  232. mp->inifs = fs;
  233. mp->part = *partp;
  234. mp->ini = f.path;
  235. mp->flag |= Fini;
  236. goto Break2;
  237. }
  238. }
  239. }
  240. }
  241. Break2:
  242. if((flag & mp->flag) && (dev == Dany || dev == i))
  243. return mp;
  244. }
  245. }
  246. return 0;
  247. }
  248. static char *typenm[] = {
  249. [Tnil] "nil",
  250. [Tfloppy] "Tfloppy",
  251. [Tsd] "Tsd",
  252. [Tether] "Tether",
  253. [Tcd] "Tcd",
  254. [Tbios] "Tbios",
  255. };
  256. void
  257. main(void)
  258. {
  259. Medium *mp;
  260. int flag, i, mode, tried;
  261. char def[2*NAMELEN], line[80], *p, *file;
  262. Type *tp;
  263. i8042a20();
  264. memset(m, 0, sizeof(Mach));
  265. trapinit();
  266. clockinit();
  267. alarminit();
  268. meminit(0);
  269. spllo();
  270. kbdinit();
  271. if((ulong)&end > (KZERO|(640*1024)))
  272. panic("i'm too big\n");
  273. readlsconf();
  274. for(tp = types; tp->type != Tnil; tp++){
  275. if(!pxe && tp->type == Tether)
  276. continue;
  277. if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){
  278. print("using %s!%s!%s\n", mp->name, mp->part, mp->ini);
  279. iniread = !dotini(mp->inifs);
  280. break;
  281. }
  282. }
  283. apminit();
  284. if((p = getconf("console")) != nil)
  285. consinit(p, getconf("baud"));
  286. devpccardlink();
  287. devi82365link();
  288. /*
  289. * Even after we find the ini file, we keep probing disks,
  290. * because we have to collect the partition tables and
  291. * have boot devices for parse.
  292. */
  293. probe(Tany, Fnone, Dany);
  294. tried = 0;
  295. mode = Mauto;
  296. p = getconf("bootfile");
  297. if(p != 0) {
  298. mode = Manual;
  299. for(i = 0; i < NMode; i++){
  300. if(strcmp(p, modes[i].name) == 0){
  301. mode = modes[i].mode;
  302. goto done;
  303. }
  304. }
  305. if((mp = parse(p, &file)) == nil) {
  306. print("Unknown boot device: %s\n", p);
  307. goto done;
  308. }
  309. tried = boot(mp, file);
  310. }
  311. done:
  312. if(tried == 0 && mode != Manual){
  313. flag = Fany;
  314. if(mode == Mlocal)
  315. flag &= ~Fbootp;
  316. if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy)
  317. boot(mp, "");
  318. }
  319. def[0] = 0;
  320. probe(Tany, Fnone, Dany);
  321. if(p = getconf("bootdef"))
  322. strcpy(def, p);
  323. flag = 0;
  324. for(tp = types; tp->type != Tnil; tp++){
  325. for(mp = tp->media; mp; mp = mp->next){
  326. if(flag == 0){
  327. flag = 1;
  328. print("Boot devices:");
  329. }
  330. (*tp->printdevs)(mp->dev);
  331. }
  332. }
  333. if(flag)
  334. print("\n");
  335. for(;;){
  336. if(getstr("boot from", line, sizeof(line), def, (mode != Manual)*15) >= 0)
  337. if(mp = parse(line, &file))
  338. boot(mp, file);
  339. def[0] = 0;
  340. }
  341. }
  342. int
  343. getfields(char *lp, char **fields, int n, char sep)
  344. {
  345. int i;
  346. for(i = 0; lp && *lp && i < n; i++){
  347. while(*lp == sep)
  348. *lp++ = 0;
  349. if(*lp == 0)
  350. break;
  351. fields[i] = lp;
  352. while(*lp && *lp != sep){
  353. if(*lp == '\\' && *(lp+1) == '\n')
  354. *lp++ = ' ';
  355. lp++;
  356. }
  357. }
  358. return i;
  359. }
  360. int
  361. cistrcmp(char *a, char *b)
  362. {
  363. int ac, bc;
  364. for(;;){
  365. ac = *a++;
  366. bc = *b++;
  367. if(ac >= 'A' && ac <= 'Z')
  368. ac = 'a' + (ac - 'A');
  369. if(bc >= 'A' && bc <= 'Z')
  370. bc = 'a' + (bc - 'A');
  371. ac -= bc;
  372. if(ac)
  373. return ac;
  374. if(bc == 0)
  375. break;
  376. }
  377. return 0;
  378. }
  379. int
  380. cistrncmp(char *a, char *b, int n)
  381. {
  382. unsigned ac, bc;
  383. while(n > 0){
  384. ac = *a++;
  385. bc = *b++;
  386. n--;
  387. if(ac >= 'A' && ac <= 'Z')
  388. ac = 'a' + (ac - 'A');
  389. if(bc >= 'A' && bc <= 'Z')
  390. bc = 'a' + (bc - 'A');
  391. ac -= bc;
  392. if(ac)
  393. return ac;
  394. if(bc == 0)
  395. break;
  396. }
  397. return 0;
  398. }
  399. #define PSTART ( 8*1024*1024)
  400. #define PEND (16*1024*1024)
  401. ulong palloc = PSTART;
  402. void*
  403. ialloc(ulong n, int align)
  404. {
  405. ulong p;
  406. int a;
  407. p = palloc;
  408. if(align <= 0)
  409. align = 4;
  410. if(a = n % align)
  411. n += align - a;
  412. if(a = p % align)
  413. p += align - a;
  414. palloc = p+n;
  415. if(palloc > PEND)
  416. panic("ialloc(%lud, %d) called from %#p\n",
  417. n, align, getcallerpc(&n));
  418. return memset((void*)(p|KZERO), 0, n);
  419. }
  420. void*
  421. xspanalloc(ulong size, int align, ulong span)
  422. {
  423. ulong a, v;
  424. if((palloc + (size+align+span)) > PEND)
  425. panic("xspanalloc(%lud, %d, 0x%lux) called from %#p\n",
  426. size, align, span, getcallerpc(&size));
  427. a = (ulong)ialloc(size+align+span, 0);
  428. if(span > 2)
  429. v = (a + span) & ~(span-1);
  430. else
  431. v = a;
  432. if(align > 1)
  433. v = (v + align) & ~(align-1);
  434. return (void*)v;
  435. }
  436. static Block *allocbp;
  437. Block*
  438. allocb(int size)
  439. {
  440. Block *bp, **lbp;
  441. ulong addr;
  442. lbp = &allocbp;
  443. for(bp = *lbp; bp; bp = bp->next){
  444. if((bp->lim - bp->base) >= size){
  445. *lbp = bp->next;
  446. break;
  447. }
  448. lbp = &bp->next;
  449. }
  450. if(bp == 0){
  451. if((palloc + (sizeof(Block)+size+64)) > PEND)
  452. panic("allocb(%d) called from %#p\n",
  453. size, getcallerpc(&size));
  454. bp = ialloc(sizeof(Block)+size+64, 0);
  455. addr = (ulong)bp;
  456. addr = ROUNDUP(addr + sizeof(Block), 8);
  457. bp->base = (uchar*)addr;
  458. bp->lim = ((uchar*)bp) + sizeof(Block)+size+64;
  459. }
  460. if(bp->flag)
  461. panic("allocb reuse\n");
  462. bp->rp = bp->base;
  463. bp->wp = bp->rp;
  464. bp->next = 0;
  465. bp->flag = 1;
  466. return bp;
  467. }
  468. void
  469. freeb(Block* bp)
  470. {
  471. bp->next = allocbp;
  472. allocbp = bp;
  473. bp->flag = 0;
  474. }
  475. enum {
  476. Paddr= 0x70, /* address port */
  477. Pdata= 0x71, /* data port */
  478. };
  479. uchar
  480. nvramread(int offset)
  481. {
  482. outb(Paddr, offset);
  483. return inb(Pdata);
  484. }
  485. void (*etherdetach)(void);
  486. void (*floppydetach)(void);
  487. void (*sddetach)(void);
  488. void
  489. warp9(ulong entry)
  490. {
  491. if(etherdetach)
  492. etherdetach();
  493. if(floppydetach)
  494. floppydetach();
  495. if(sddetach)
  496. sddetach();
  497. consdrain();
  498. splhi();
  499. trapdisable();
  500. /*
  501. * This is where to push things on the stack to
  502. * boot *BSD systems, e.g.
  503. (*(void(*)(void*, void*, void*, void*, ulong, ulong))(PADDR(entry)))(0, 0, 0, 0, 8196, 640);
  504. * will enable NetBSD boot (the real memory size needs to
  505. * go in the 5th argument).
  506. */
  507. (*(void(*)(void))(PADDR(entry)))();
  508. }