devbios.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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. return -1;
  124. }
  125. return 0;
  126. }
  127. /*
  128. * Find out what the bios knows about devices.
  129. * our boot device could be usb; ghod only knows where it will appear.
  130. */
  131. int
  132. biosinit(void)
  133. {
  134. int devid, lba, mask, lastbit;
  135. Devbytes size;
  136. char type;
  137. Biosdev *bdp;
  138. static int beenhere;
  139. /* 9pxeload can't use bios int 13 calls; they wedge the machine */
  140. if (pxe || !biosload || onlybios0 || biosinited || beenhere)
  141. return 0;
  142. beenhere = 1;
  143. mask = lastbit = 0;
  144. for (devid = Baseid; devid < (1 << 8) && bdrive.ndevs < Maxdevs;
  145. devid++) {
  146. lba = islba(devid);
  147. if (lba < 0)
  148. break;
  149. /* don't reset; it seems to hang the bios */
  150. if(!lba /* || devid != Baseid && dreset(devid) < 0 */ )
  151. continue;
  152. type = Typenone;
  153. if (getsize(devid, &type) == 0) { /* no device, end of range */
  154. // devid &= ~0xf;
  155. // devid += 0x10;
  156. // devid--;
  157. // break;
  158. continue;
  159. }
  160. lastbit = 1 << bdrive.ndevs;
  161. mask |= lastbit;
  162. bdp = &bdev[bdrive.ndevs];
  163. bdp->id = devid;
  164. bdp->type = type;
  165. size = extgetsize(bdp);
  166. bdp->size = size;
  167. print("bios%d: drive 0x%ux: %,llud bytes, type %d\n",
  168. bdrive.ndevs, devid, size, type);
  169. bdrive.ndevs++;
  170. }
  171. USED(lastbit);
  172. // islba(Baseid); /* do a successful operation to make bios happy again */
  173. /*
  174. * some bioses seem to only be able to read from drive number 0x80
  175. * and certainly can't read from the highest drive number when we
  176. * call them, even if there is only one. attempting to read from the
  177. * last drive number may yield a hung machine or a two-minute pause.
  178. */
  179. if (bdrive.ndevs > 0) {
  180. #ifdef NOT_LAST_DRIVE
  181. if (bdrive.ndevs == 1) {
  182. print("biosinit: sorry, only one bios drive; "
  183. "can't read last one\n");
  184. onlybios0 = 1;
  185. } else
  186. biosinited = 1;
  187. bdrive.ndevs--; /* omit last drive number; it can't be read */
  188. mask &= ~lastbit;
  189. #else
  190. biosinited = 1;
  191. #endif
  192. }
  193. return mask;
  194. }
  195. void
  196. biosinitdev(int i, char *name)
  197. {
  198. if(i >= bdrive.ndevs)
  199. panic("biosinitdev");
  200. sprint(name, "bios%d", i);
  201. }
  202. void
  203. biosprintdevs(int i)
  204. {
  205. if(i >= bdrive.ndevs){
  206. print("got a print for %d, only got %d\n", i, bdrive.ndevs);
  207. panic("biosprintdevs");
  208. }
  209. print(" bios%d", i);
  210. }
  211. int
  212. biosboot(int dev, char *file, Boot *b)
  213. {
  214. Fs *fs;
  215. if(strncmp(file, "dos!", 4) == 0)
  216. file += 4;
  217. if(strchr(file, '!') != nil || strcmp(file, "") == 0) {
  218. print("syntax is bios0!file\n");
  219. return -1;
  220. }
  221. fs = biosgetfspart(dev, "9fat", 1);
  222. if(fs == nil)
  223. return -1;
  224. return fsboot(fs, file, b);
  225. }
  226. static void
  227. dump(void *addr, int wds)
  228. {
  229. unsigned i;
  230. ulong *p = addr;
  231. for (i = 0; i < wds; i++)
  232. print("%lux ", p[i]);
  233. if (i % 8 == 7)
  234. print("\n");
  235. print("\n");
  236. }
  237. /* read n bytes at sector offset into a from drive id */
  238. long
  239. sectread(Biosdev *bdp, void *a, long n, Devsects offset)
  240. {
  241. uchar *biosparam, *cp;
  242. Extread *erp;
  243. if(n < 0 || n > bdp->sectsz)
  244. return -1;
  245. if(Debug)
  246. /* scribble on the buffer to provoke trouble */
  247. memset((uchar *)BIOSXCHG, 'r', bdp->sectsz);
  248. // if(Debug)
  249. // print("drive ready %#ux...", bdp->id);
  250. // memset(&regs, 0, sizeof regs);
  251. // if (biosdiskcall(&regs, Biosdrvrdy, 0, bdp->id, 0) < 0)
  252. // print("not ready\n");
  253. /* space for a big, optical-size sector, just in case... */
  254. biosparam = (uchar *)BIOSXCHG + 2*1024;
  255. /* read into BIOSXCHG */
  256. erp = (Extread *)biosparam;
  257. memset(erp, 0, sizeof *erp);
  258. erp->size = sizeof *erp;
  259. erp->nsects = 1;
  260. erp->addr = PADDR(BIOSXCHG);
  261. erp->stsect = offset;
  262. /*
  263. * ensure that addr fits in a short,
  264. * then jigger it to avoid segment 0.
  265. */
  266. if((erp->addr & 0xffff0000) != 0)
  267. print("sectread: address %#lux not a short\n", erp->addr);
  268. erp->addr = ((erp->addr & 0xffff) >> 4) << 16 | (erp->addr & 0xf);
  269. if((erp->addr & 0xffff0000) != ((erp->addr + 512 - 1) & 0xffff0000))
  270. print("sectread: address %#lux too near segment boundary\n",
  271. erp->addr);
  272. if (0 && Debug)
  273. print("reading drive %#ux offset %lld into seg:off %lux:%ux...",
  274. bdp->id, offset, erp->addr>>16, (ushort)erp->addr);
  275. if (Debug)
  276. dump(erp, sizeof *erp / 4);
  277. memset(&regs, 0, sizeof regs);
  278. regs.es = erp->addr >> 16;
  279. if (biosdiskcall(&regs, Biosrdsect, (ushort)erp->addr, bdp->id,
  280. PADDR(erp)) < 0) {
  281. print("sectread: bios failed to read %ld @ sector %lld of 0x%ux\n",
  282. n, offset, bdp->id);
  283. return -1;
  284. }
  285. /* copy into caller's buffer */
  286. memmove(a, (char *)BIOSXCHG, n);
  287. if(0 && Debug){
  288. cp = (uchar *)BIOSXCHG;
  289. print("-%ux %ux %ux %ux--%16.16s-\n",
  290. cp[0], cp[1], cp[2], cp[3], (char *)cp + 480);
  291. }
  292. return n;
  293. }
  294. /* not tested yet. */
  295. static int
  296. dreset(uchar drive)
  297. {
  298. print("devbios: resetting %#ux...", drive);
  299. memset(&regs, 0, sizeof regs);
  300. if (biosdiskcall(&regs, Biosinit, 0, drive, 0) < 0)
  301. print("failed");
  302. print("\n");
  303. return regs.ax? -1: 0; /* ax!=0 on error */
  304. }
  305. static int
  306. islba(uchar drive)
  307. {
  308. memset(&regs, 0, sizeof regs);
  309. if (biosdiskcall(&regs, Biosckext, 0x55aa, drive, 0) < 0) {
  310. /*
  311. * we have an old bios without extensions, in theory.
  312. * in practice, there may just be no drive for this number.
  313. */
  314. // print("islba: drive %ux: Biosckext failed\n", drive);
  315. return -1;
  316. }
  317. if(regs.bx != 0xaa55){
  318. print("islba: buggy bios: drive %#ux extension check returned "
  319. "%lux in bx\n", drive, regs.bx);
  320. return -1;
  321. }
  322. if (Debug)
  323. print("islba: drive 0x%ux extensions version %d.%d cx 0x%lux\n",
  324. drive, (uchar)(regs.ax >> 8),
  325. (uchar)regs.ax, regs.cx); /* cx has Edd, Dap bits */
  326. return regs.cx & Dap;
  327. }
  328. /*
  329. * works so so... some floppies are 0x80+x when they shouldn't be,
  330. * and report lba even if they cannot...
  331. */
  332. static Devsects
  333. getsize(uchar id, char *typep)
  334. {
  335. int dtype;
  336. memset(&regs, 0, sizeof regs);
  337. if (biosdiskcall(&regs, Biosdrvtype, 0x55aa, id, 0) < 0)
  338. return 0;
  339. dtype = (ushort)regs.ax >> 8;
  340. *typep = dtype;
  341. if(dtype == Typenone){
  342. print("no such device 0x%ux of type %d\n", id, dtype);
  343. return 0;
  344. }
  345. if(dtype != Typedisk){
  346. print("non-disk device 0x%ux of type %d\n", id, dtype);
  347. return 0;
  348. }
  349. return (ushort)regs.cx | regs.dx << 16;
  350. }
  351. /* extended get size */
  352. static Devbytes
  353. extgetsize(Biosdev *bdp)
  354. {
  355. Edrvparam *edp;
  356. edp = (Edrvparam *)BIOSXCHG;
  357. memset(edp, 0, sizeof *edp);
  358. edp->size = sizeof *edp;
  359. edp->dpilen = 36;
  360. memset(&regs, 0, sizeof regs);
  361. if (biosdiskcall(&regs, Biosedrvparam, 0, bdp->id, PADDR(edp)) < 0)
  362. return 0; /* old bios without extensions */
  363. if(Debug) {
  364. print("extgetsize: drive 0x%ux info flags 0x%ux",
  365. bdp->id, edp->flags);
  366. if (edp->key == 0xbedd)
  367. print(" %.4s %.8s", edp->bustype, edp->ifctype);
  368. print("\n");
  369. }
  370. if (edp->sectsz <= 0) {
  371. print("extgetsize: drive 0x%ux: non-positive sector size\n",
  372. bdp->id);
  373. edp->sectsz = 1; /* don't divide by zero */
  374. }
  375. bdp->sectsz = edp->sectsz;
  376. return edp->physsects * edp->sectsz;
  377. }
  378. long
  379. biosread(Fs *fs, void *a, long n)
  380. {
  381. int want, got, part;
  382. long totnr, stuck;
  383. Devbytes offset;
  384. Biosdev *bdp;
  385. if(fs->dev > bdrive.ndevs)
  386. return -1;
  387. if (n <= 0)
  388. return n;
  389. bdp = &bdev[fs->dev];
  390. offset = bdp->offset;
  391. stuck = 0;
  392. for (totnr = 0; totnr < n && stuck < 4; totnr += got) {
  393. if (bdp->sectsz == 0) {
  394. print("devbios: zero sector size\n");
  395. return -1;
  396. }
  397. want = bdp->sectsz;
  398. if (totnr + want > n)
  399. want = n - totnr;
  400. if(0 && Debug && debugload)
  401. print("bios%d, read: %ld @ off %lld, want: %d, id: 0x%ux\n",
  402. fs->dev, n, offset, want, bdp->id);
  403. part = offset % bdp->sectsz;
  404. if (part != 0) { /* back up to start of sector */
  405. offset -= part;
  406. totnr -= part;
  407. if (totnr < 0) {
  408. print("biosread: negative count %ld\n", totnr);
  409. return -1;
  410. }
  411. }
  412. if ((vlong)offset < 0) {
  413. print("biosread: negative offset %lld\n", offset);
  414. return -1;
  415. }
  416. got = sectread(bdp, (char *)a + totnr, want, offset/bdp->sectsz);
  417. if(got <= 0){
  418. // print("biosread: failed to read %ld @ off %lld of 0x%ux, "
  419. // "want %d got %d\n",
  420. // n, offset, bdp->id, want, got);
  421. return -1;
  422. }
  423. offset += got;
  424. bdp->offset = offset;
  425. if (got < bdp->sectsz)
  426. stuck++; /* we'll have to re-read this sector */
  427. else
  428. stuck = 0;
  429. }
  430. return totnr;
  431. }
  432. vlong
  433. biosseek(Fs *fs, vlong off)
  434. {
  435. if (off < 0) {
  436. print("biosseek(fs, %lld) is illegal\n", off);
  437. return -1;
  438. }
  439. if(fs->dev > bdrive.ndevs) {
  440. print("biosseek: fs->dev %d > bdrive.ndevs %d\n",
  441. fs->dev, bdrive.ndevs);
  442. return -1;
  443. }
  444. bdev[fs->dev].offset = off; /* do not know size... (yet) */
  445. return off;
  446. }
  447. void *
  448. biosgetfspart(int i, char *name, int chatty)
  449. {
  450. static Fs fs;
  451. if(strcmp(name, "9fat") != 0){
  452. if(chatty)
  453. print("unknown partition bios%d!%s (use bios%d!9fat)\n",
  454. i, name, i);
  455. return nil;
  456. }
  457. fs.dev = i;
  458. fs.diskread = biosread;
  459. fs.diskseek = biosseek;
  460. if(dosinit(&fs) < 0){
  461. if(chatty)
  462. print("bios%d!%s does not contain a FAT file system\n",
  463. i, name);
  464. return nil;
  465. }
  466. return &fs;
  467. }