devbios.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * boot driver for BIOS LBA devices
  3. * heavily dependent upon correct BIOS implementation
  4. */
  5. #include <u.h>
  6. #include "lib.h"
  7. #include "mem.h"
  8. #include "dat.h"
  9. #include "fns.h"
  10. #include "io.h"
  11. #include "ureg.h"
  12. #include "fs.h"
  13. typedef uvlong Devbytes, Devsects;
  14. typedef struct Biosdrive Biosdrive; /* 1 drive -> ndevs */
  15. typedef struct Biosdev Biosdev;
  16. enum {
  17. Debug = 0,
  18. Maxdevs = 8,
  19. CF = 1, /* carry flag: indicates an error */
  20. Flopid = 0, /* first floppy */
  21. Baseid = 0x80, /* first disk */
  22. Dap = 1<<0,
  23. Edd = 1<<2,
  24. /* bios calls: int 0x13 disk services */
  25. Biosinit = 0, /* initialise disk & floppy ctlrs */
  26. Biosdrvsts,
  27. Bioschsrdsects,
  28. Biosdrvparam = 8,
  29. Biosctlrinit,
  30. Biosreset = 0xd, /* reset disk */
  31. Biosdrvrdy = 0x10,
  32. Biosdrvtype = 0x15,
  33. Biosckext = 0x41,
  34. Biosrdsect,
  35. Biosedrvparam = 0x48,
  36. /* disk types */
  37. Typenone = 0,
  38. Typedisk = 3,
  39. };
  40. struct Biosdrive {
  41. int ndevs;
  42. };
  43. struct Biosdev {
  44. Devbytes size;
  45. Devbytes offset;
  46. uchar id; /* drive number; e.g., 0x80 */
  47. char type;
  48. ushort sectsz;
  49. };
  50. typedef struct Extread { /* a device address packet */
  51. uchar size;
  52. uchar unused1;
  53. uchar nsects;
  54. uchar unused2;
  55. ulong addr; /* segment:offset; ea = (segment<<4)+offset */
  56. uvlong stsect; /* starting sector */
  57. } Extread;
  58. typedef struct Edrvparam {
  59. /* from edd 1.1 spec */
  60. ushort size; /* max. buffer size */
  61. ushort flags;
  62. ulong physcyls;
  63. ulong physheads;
  64. ulong phystracksects;
  65. uvlong physsects;
  66. ushort sectsz;
  67. void *dpte; /* ~0ull: invalid */
  68. /* remainder from edd 3.0 spec */
  69. ushort key; /* 0xbedd if present */
  70. uchar dpilen;
  71. uchar unused1;
  72. ushort unused2;
  73. char bustype[4]; /* "PCI" or "ISA" */
  74. char ifctype[8]; /* "ATA", "ATAPI", "SCSI", "USB", "1394", "FIBRE" */
  75. uvlong ifcpath;
  76. uvlong devpath;
  77. uchar unused3;
  78. uchar dpicksum;
  79. } Edrvparam;
  80. void realmode(int intr, Ureg *ureg); /* from trap.c */
  81. int onlybios0;
  82. int biosinited;
  83. static Biosdev bdev[Maxdevs];
  84. static Biosdrive bdrive;
  85. static Ureg regs;
  86. static int dreset(uchar drive);
  87. static Devbytes extgetsize(Biosdev *);
  88. static Devsects getsize(uchar drive, char *type);
  89. static int islba(uchar drive);
  90. /*
  91. * caller must zero or otherwise initialise *rp,
  92. * other than ax, bx, dx, si & ds.
  93. */
  94. static int
  95. biosdiskcall(Ureg *rp, uchar op, ulong bx, ulong dx, ulong si)
  96. {
  97. rp->ax = op << 8;
  98. rp->bx = bx;
  99. rp->dx = dx; /* often drive id */
  100. /*
  101. * ensure that addr fits in a short,
  102. * then jigger it and DS to avoid segment 0.
  103. */
  104. if((si & 0xffff0000) != 0)
  105. print("biosdiskcall: address %#lux not a short\n", si);
  106. rp->ds = si >> 4;
  107. si &= 0xf;
  108. if((si & 0xffff0000) != ((si + 512 - 1) & 0xffff0000))
  109. print("biosdiskcall: address %#lux too near segment boundary\n",
  110. si);
  111. rp->si = si; /* ds:si forms data access packet addr */
  112. /*
  113. * *rp is copied into low memory (realmoderegs) and thence into
  114. * the machine registers before the BIOS call, and the registers are
  115. * copied into realmoderegs and thence into *rp after.
  116. */
  117. realmode(0x13, rp);
  118. if (rp->flags & CF) {
  119. if (Debug && dx == Baseid)
  120. print("\nbiosdiskcall: int 0x13 op 0x%ux drive 0x%lux "
  121. "failed, ah error code 0x%ux\n",
  122. op, dx, (uchar)(rp->ax >> 8));
  123. biosload = 0; /* stop trying before we wedge */
  124. return -1;
  125. }
  126. return 0;
  127. }
  128. /*
  129. * Find out what the bios knows about devices.
  130. * our boot device could be usb; ghod only knows where it will appear.
  131. */
  132. int
  133. biosinit(void)
  134. {
  135. int devid, lba, mask, lastbit, ndrive;
  136. Devbytes size;
  137. char type;
  138. Biosdev *bdp;
  139. static int beenhere;
  140. /* 9pxeload can't use bios int 13 calls; they wedge the machine */
  141. if (pxe || !biosload || onlybios0 || biosinited || beenhere)
  142. return 0;
  143. beenhere = 1;
  144. ndrive = *(uchar *)KADDR(0x475);
  145. if (Debug)
  146. print("bios claims %d drive(s)\n", ndrive);
  147. mask = lastbit = 0;
  148. for (devid = Baseid; devid < (1 << 8) && bdrive.ndevs < Maxdevs;
  149. devid++) {
  150. lba = islba(devid);
  151. if (lba < 0)
  152. break;
  153. /* don't reset; it seems to hang the bios */
  154. if(!lba /* || devid != Baseid && dreset(devid) < 0 */ )
  155. continue;
  156. type = Typenone;
  157. if (getsize(devid, &type) == 0) { /* no device, end of range */
  158. // devid &= ~0xf;
  159. // devid += 0x10;
  160. // devid--;
  161. // break;
  162. continue;
  163. }
  164. lastbit = 1 << bdrive.ndevs;
  165. mask |= lastbit;
  166. bdp = &bdev[bdrive.ndevs];
  167. bdp->id = devid;
  168. bdp->type = type;
  169. size = extgetsize(bdp);
  170. bdp->size = size;
  171. print("bios%d: drive 0x%ux: %,llud bytes, type %d\n",
  172. bdrive.ndevs, devid, size, type);
  173. bdrive.ndevs++;
  174. }
  175. USED(lastbit);
  176. // islba(Baseid); /* do a successful operation to make bios happy again */
  177. if (Debug && ndrive != bdrive.ndevs)
  178. print("bios: ndrive %d != bdrive.ndevs %d\n",
  179. ndrive, bdrive.ndevs);
  180. if (ndrive < bdrive.ndevs)
  181. bdrive.ndevs = ndrive; /* use smaller estimate */
  182. /*
  183. * some bioses seem to only be able to read from drive number 0x80
  184. * and certainly can't read from the highest drive number when we
  185. * call them, even if there is only one. attempting to read from the
  186. * last drive number may yield a hung machine or a two-minute pause.
  187. */
  188. if (bdrive.ndevs > 0) {
  189. #ifdef NOT_LAST_DRIVE
  190. if (bdrive.ndevs == 1) {
  191. print("biosinit: sorry, only one bios drive; "
  192. "can't read last one\n");
  193. onlybios0 = 1;
  194. } else
  195. biosinited = 1;
  196. bdrive.ndevs--; /* omit last drive number; it can't be read */
  197. mask &= ~lastbit;
  198. #else
  199. biosinited = 1;
  200. #endif
  201. }
  202. return mask;
  203. }
  204. void
  205. biosinitdev(int i, char *name)
  206. {
  207. if(i >= bdrive.ndevs)
  208. panic("biosinitdev");
  209. sprint(name, "bios%d", i);
  210. }
  211. void
  212. biosprintdevs(int i)
  213. {
  214. if(i >= bdrive.ndevs){
  215. print("got a print for %d, only got %d\n", i, bdrive.ndevs);
  216. panic("biosprintdevs");
  217. }
  218. print(" bios%d", i);
  219. }
  220. int
  221. biosboot(int dev, char *file, Boot *b)
  222. {
  223. Fs *fs;
  224. if(strncmp(file, "dos!", 4) == 0)
  225. file += 4;
  226. if(strchr(file, '!') != nil || strcmp(file, "") == 0) {
  227. print("syntax is bios0!file\n");
  228. return -1;
  229. }
  230. fs = biosgetfspart(dev, "9fat", 1);
  231. if(fs == nil)
  232. return -1;
  233. return fsboot(fs, file, b);
  234. }
  235. static void
  236. dump(void *addr, int wds)
  237. {
  238. unsigned i;
  239. ulong *p = addr;
  240. for (i = 0; i < wds; i++)
  241. print("%lux ", p[i]);
  242. if (i % 8 == 7)
  243. print("\n");
  244. print("\n");
  245. }
  246. /* read n bytes at sector offset into a from drive id */
  247. long
  248. sectread(Biosdev *bdp, void *a, long n, Devsects offset)
  249. {
  250. uchar *biosparam, *cp;
  251. Extread *erp;
  252. if(n < 0 || n > bdp->sectsz)
  253. return -1;
  254. if(Debug)
  255. /* scribble on the buffer to provoke trouble */
  256. memset((uchar *)BIOSXCHG, 'r', bdp->sectsz);
  257. if(Debug)
  258. print("drive ready %#ux...", bdp->id);
  259. memset(&regs, 0, sizeof regs);
  260. if (biosdiskcall(&regs, Biosdrvrdy, 0, bdp->id, 0) < 0) {
  261. print("not ready\n");
  262. return -1;
  263. }
  264. /* space for a big, optical-size sector, just in case... */
  265. biosparam = (uchar *)BIOSXCHG + 2*1024;
  266. /* read into BIOSXCHG */
  267. erp = (Extread *)biosparam;
  268. memset(erp, 0, sizeof *erp);
  269. erp->size = sizeof *erp;
  270. erp->nsects = 1;
  271. erp->addr = PADDR(BIOSXCHG);
  272. erp->stsect = offset;
  273. /*
  274. * ensure that addr fits in a short,
  275. * then jigger it to avoid segment 0.
  276. */
  277. if((erp->addr & 0xffff0000) != 0)
  278. print("sectread: address %#lux not a short\n", erp->addr);
  279. erp->addr = ((erp->addr & 0xffff) >> 4) << 16 | (erp->addr & 0xf);
  280. if((erp->addr & 0xffff0000) != ((erp->addr + 512 - 1) & 0xffff0000))
  281. print("sectread: address %#lux too near segment boundary\n",
  282. erp->addr);
  283. if (0 && Debug)
  284. print("reading drive %#ux offset %lld into seg:off %lux:%ux...",
  285. bdp->id, offset, erp->addr>>16, (ushort)erp->addr);
  286. if (Debug)
  287. dump(erp, sizeof *erp / 4);
  288. memset(&regs, 0, sizeof regs);
  289. regs.es = erp->addr >> 16;
  290. if (biosdiskcall(&regs, Biosrdsect, (ushort)erp->addr, bdp->id,
  291. PADDR(erp)) < 0) {
  292. print("sectread: bios failed to read %ld @ sector %lld of 0x%ux\n",
  293. n, offset, bdp->id);
  294. return -1;
  295. }
  296. /* copy into caller's buffer */
  297. memmove(a, (char *)BIOSXCHG, n);
  298. if(0 && Debug){
  299. cp = (uchar *)BIOSXCHG;
  300. print("-%ux %ux %ux %ux--%16.16s-\n",
  301. cp[0], cp[1], cp[2], cp[3], (char *)cp + 480);
  302. }
  303. return n;
  304. }
  305. /* not tested yet. */
  306. static int
  307. dreset(uchar drive)
  308. {
  309. print("devbios: resetting %#ux...", drive);
  310. memset(&regs, 0, sizeof regs);
  311. if (biosdiskcall(&regs, Biosinit, 0, drive, 0) < 0)
  312. print("failed");
  313. print("\n");
  314. return regs.ax? -1: 0; /* ax!=0 on error */
  315. }
  316. static int
  317. islba(uchar drive)
  318. {
  319. memset(&regs, 0, sizeof regs);
  320. if (biosdiskcall(&regs, Biosckext, 0x55aa, drive, 0) < 0) {
  321. /*
  322. * we have an old bios without extensions, in theory.
  323. * in practice, there may just be no drive for this number.
  324. */
  325. // print("islba: drive %ux: Biosckext failed\n", drive);
  326. return -1;
  327. }
  328. if(regs.bx != 0xaa55){
  329. print("islba: buggy bios: drive %#ux extension check returned "
  330. "%lux in bx\n", drive, regs.bx);
  331. return -1;
  332. }
  333. if (Debug)
  334. print("islba: drive 0x%ux extensions version %d.%d cx 0x%lux\n",
  335. drive, (uchar)(regs.ax >> 8),
  336. (uchar)regs.ax, regs.cx); /* cx has Edd, Dap bits */
  337. return regs.cx & Dap;
  338. }
  339. /*
  340. * works so so... some floppies are 0x80+x when they shouldn't be,
  341. * and report lba even if they cannot...
  342. */
  343. static Devsects
  344. getsize(uchar id, char *typep)
  345. {
  346. int dtype;
  347. memset(&regs, 0, sizeof regs);
  348. if (biosdiskcall(&regs, Biosdrvtype, 0x55aa, id, 0) < 0)
  349. return 0;
  350. dtype = (ushort)regs.ax >> 8;
  351. *typep = dtype;
  352. if(dtype == Typenone){
  353. print("no such device 0x%ux of type %d\n", id, dtype);
  354. return 0;
  355. }
  356. if(dtype != Typedisk){
  357. print("non-disk device 0x%ux of type %d\n", id, dtype);
  358. return 0;
  359. }
  360. return (ushort)regs.cx | regs.dx << 16;
  361. }
  362. /* extended get size */
  363. static Devbytes
  364. extgetsize(Biosdev *bdp)
  365. {
  366. Edrvparam *edp;
  367. edp = (Edrvparam *)BIOSXCHG;
  368. memset(edp, 0, sizeof *edp);
  369. edp->size = sizeof *edp;
  370. edp->dpilen = 36;
  371. memset(&regs, 0, sizeof regs);
  372. if (biosdiskcall(&regs, Biosedrvparam, 0, bdp->id, PADDR(edp)) < 0)
  373. return 0; /* old bios without extensions */
  374. if(Debug) {
  375. print("extgetsize: drive 0x%ux info flags 0x%ux",
  376. bdp->id, edp->flags);
  377. if (edp->key == 0xbedd)
  378. print(" %.4s %.8s", edp->bustype, edp->ifctype);
  379. print("\n");
  380. }
  381. if (edp->sectsz <= 0) {
  382. print("extgetsize: drive 0x%ux: non-positive sector size\n",
  383. bdp->id);
  384. edp->sectsz = 1; /* don't divide by zero */
  385. }
  386. bdp->sectsz = edp->sectsz;
  387. return edp->physsects * edp->sectsz;
  388. }
  389. long
  390. biosread(Fs *fs, void *a, long n)
  391. {
  392. int want, got, part;
  393. long totnr, stuck;
  394. Devbytes offset;
  395. Biosdev *bdp;
  396. if(!biosload || fs->dev > bdrive.ndevs)
  397. return -1;
  398. if (n <= 0)
  399. return n;
  400. bdp = &bdev[fs->dev];
  401. offset = bdp->offset;
  402. stuck = 0;
  403. for (totnr = 0; totnr < n && stuck < 4; totnr += got) {
  404. if (bdp->sectsz == 0) {
  405. print("devbios: zero sector size\n");
  406. return -1;
  407. }
  408. want = bdp->sectsz;
  409. if (totnr + want > n)
  410. want = n - totnr;
  411. if(0 && Debug && debugload)
  412. print("bios%d, read: %ld @ off %lld, want: %d, id: 0x%ux\n",
  413. fs->dev, n, offset, want, bdp->id);
  414. part = offset % bdp->sectsz;
  415. if (part != 0) { /* back up to start of sector */
  416. offset -= part;
  417. totnr -= part;
  418. if (totnr < 0) {
  419. print("biosread: negative count %ld\n", totnr);
  420. return -1;
  421. }
  422. }
  423. if ((vlong)offset < 0) {
  424. print("biosread: negative offset %lld\n", offset);
  425. return -1;
  426. }
  427. got = sectread(bdp, (char *)a + totnr, want, offset/bdp->sectsz);
  428. if(got <= 0){
  429. // print("biosread: failed to read %ld @ off %lld of 0x%ux, "
  430. // "want %d got %d\n",
  431. // n, offset, bdp->id, want, got);
  432. return -1;
  433. }
  434. offset += got;
  435. bdp->offset = offset;
  436. if (got < bdp->sectsz)
  437. stuck++; /* we'll have to re-read this sector */
  438. else
  439. stuck = 0;
  440. }
  441. return totnr;
  442. }
  443. vlong
  444. biosseek(Fs *fs, vlong off)
  445. {
  446. if (off < 0) {
  447. print("biosseek(fs, %lld) is illegal\n", off);
  448. return -1;
  449. }
  450. if(fs->dev > bdrive.ndevs) {
  451. print("biosseek: fs->dev %d > bdrive.ndevs %d\n",
  452. fs->dev, bdrive.ndevs);
  453. return -1;
  454. }
  455. bdev[fs->dev].offset = off; /* do not know size... (yet) */
  456. return off;
  457. }
  458. void *
  459. biosgetfspart(int i, char *name, int chatty)
  460. {
  461. static Fs fs;
  462. if(strcmp(name, "9fat") != 0){
  463. if(chatty)
  464. print("unknown partition bios%d!%s (use bios%d!9fat)\n",
  465. i, name, i);
  466. return nil;
  467. }
  468. fs.dev = i;
  469. fs.diskread = biosread;
  470. fs.diskseek = biosseek;
  471. if(dosinit(&fs) < 0){
  472. if(chatty)
  473. print("bios%d!%s does not contain a FAT file system\n",
  474. i, name);
  475. return nil;
  476. }
  477. return &fs;
  478. }