devbios.c 9.3 KB

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