devbios.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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. mask = lastbit = 0;
  117. if (beenhere)
  118. return mask;
  119. beenhere = 1;
  120. /* 9pxeload can't use bios int 13 calls; they wedge the machine */
  121. if (pxe || getconf("*nobiosload") != nil || onlybios0 || !biosinited)
  122. return mask;
  123. for (devid = 0; devid < (1 << 8) && bdrive.ndevs < Maxdevs; devid++) {
  124. lba = islba(devid);
  125. if(!lba /* || devid != Baseid && dreset(devid) < 0 */ )
  126. continue;
  127. type = Typedisk; /* HACK */
  128. if (getsize(devid, &type) == 0) { /* no device, end of range */
  129. devid &= ~0xf;
  130. devid += 0x10;
  131. devid--;
  132. continue;
  133. }
  134. lastbit = 1 << bdrive.ndevs;
  135. mask |= lastbit;
  136. bdp = &bdev[bdrive.ndevs];
  137. bdp->id = devid;
  138. bdp->type = type;
  139. size = extgetsize(bdp);
  140. bdp->size = size;
  141. print("bios%d: drive 0x%ux: %llud bytes, type %d\n",
  142. bdrive.ndevs, devid, size, type);
  143. bdrive.ndevs++;
  144. }
  145. /*
  146. * bioses seem to only be able to read from drive number 0x80
  147. * and certainly can't read from the highest drive number when we
  148. * call them, even if there is only one. attempting to read from
  149. * the last drive number yields a hung machine or a two-minute pause.
  150. */
  151. if (bdrive.ndevs > 0) {
  152. if (bdrive.ndevs == 1) {
  153. print("biosinit: sorry, only one bios drive; "
  154. "can't read last one\n");
  155. onlybios0 = 1;
  156. } else
  157. biosinited = 1;
  158. bdrive.ndevs--; /* omit last drive number; it can't be read */
  159. mask &= ~lastbit;
  160. }
  161. return mask;
  162. }
  163. void
  164. biosinitdev(int i, char *name)
  165. {
  166. if(i >= bdrive.ndevs)
  167. panic("biosinitdev");
  168. sprint(name, "bios%d", i);
  169. }
  170. void
  171. biosprintdevs(int i)
  172. {
  173. if(i >= bdrive.ndevs){
  174. print("got a print for %d, only got %d\n", i, bdrive.ndevs);
  175. panic("biosprintdevs");
  176. }
  177. print(" bios%d", i);
  178. }
  179. int
  180. biosboot(int dev, char *file, Boot *b)
  181. {
  182. Fs *fs;
  183. if(strncmp(file, "dos!", 4) == 0)
  184. file += 4;
  185. if(strchr(file, '!') != nil || strcmp(file, "") == 0) {
  186. print("syntax is bios0!file\n");
  187. return -1;
  188. }
  189. fs = biosgetfspart(dev, "9fat", 1);
  190. if(fs == nil)
  191. return -1;
  192. return fsboot(fs, file, b);
  193. }
  194. /* read n bytes at sector offset into a from drive id */
  195. long
  196. sectread(Biosdev *bdp, void *a, long n, Devsects offset)
  197. {
  198. uchar *biosparam, *cp;
  199. Extread *erp;
  200. if(n < 0 || n > bdp->sectsz)
  201. return -1;
  202. if(Debug)
  203. memset((uchar *)BIOSXCHG, 'r', bdp->sectsz); /* preclean the buffer. */
  204. biosdiskcall(&regs, Biosdrvrdy, 0, bdp->id, 0);
  205. /* space for a BIG sector, just in case... */
  206. biosparam = (uchar *)BIOSXCHG + 2*1024;
  207. /* read into BIOSXCHG */
  208. erp = (Extread *)biosparam;
  209. memset(erp, 0, sizeof *erp);
  210. erp->size = sizeof *erp;
  211. erp->nsects = 1;
  212. erp->addr = PADDR(BIOSXCHG);
  213. erp->stsect = offset;
  214. if (biosdiskcall(&regs, Biosrdsect, 0, bdp->id, PADDR(erp)) < 0) {
  215. print("sectread: bios failed to read %ld @ sector %lld of 0x%ux\n",
  216. n, offset, bdp->id);
  217. return -1;
  218. }
  219. /* copy into caller's buffer */
  220. memmove(a, (char *)BIOSXCHG, n);
  221. if(Debug){
  222. cp = (uchar *)BIOSXCHG;
  223. print("-%ux %ux %ux %ux--%16.16s-\n",
  224. cp[0], cp[1], cp[2], cp[3], (char *)cp + 480);
  225. }
  226. return n;
  227. }
  228. /* not tested yet. */
  229. static int
  230. dreset(uchar drive)
  231. {
  232. if (0) {
  233. print("devbios: resetting disk controllers...");
  234. biosdiskcall(&regs, Biosinit, 0, drive, 0);
  235. print("\n");
  236. }
  237. return regs.ax? -1: 0; /* ax!=0 on error */
  238. }
  239. static int
  240. islba(uchar drive)
  241. {
  242. if (biosdiskcall(&regs, Biosckext, 0x55aa, drive, 0) < 0)
  243. return 0;
  244. if(regs.bx != 0xaa55){
  245. print("islba: buggy bios\n");
  246. return 0;
  247. }
  248. if (Debug)
  249. print("islba: drive 0x%ux extensions version %d.%d cx 0x%lux\n",
  250. drive, (uchar)(regs.ax >> 8),
  251. (uchar)regs.ax, regs.cx); /* cx: 4=edd, 1=use dap */
  252. return regs.cx & 1; /* dap bit */
  253. }
  254. /*
  255. * works so so... some floppies are 0x80+x when they shouldn't be,
  256. * and report lba even if they cannot...
  257. */
  258. static Devsects
  259. getsize(uchar id, char *typep)
  260. {
  261. int dtype;
  262. if (biosdiskcall(&regs, Biosdrvtype, 0x55aa, id, 0) < 0)
  263. return 0;
  264. dtype = (ushort)regs.ax >> 8;
  265. if(dtype == Typenone){
  266. print("no such device 0x%ux of type %d\n", id, dtype);
  267. return 0;
  268. }
  269. if(dtype != Typedisk){
  270. print("non-disk device 0x%ux of type %d\n", id, dtype);
  271. return 0;
  272. }
  273. *typep = dtype;
  274. return (ushort)regs.cx | regs.dx << 16;
  275. }
  276. /* extended get size */
  277. static Devbytes
  278. extgetsize(Biosdev *bdp)
  279. {
  280. Edrvparam *edp;
  281. edp = (Edrvparam *)BIOSXCHG;
  282. memset(edp, 0, sizeof *edp);
  283. edp->size = sizeof *edp;
  284. edp->dpilen = 36;
  285. if (biosdiskcall(&regs, Biosedrvparam, 0, bdp->id, PADDR(edp)) < 0)
  286. return 0;
  287. if(Debug) {
  288. print("extgetsize: drive 0x%ux info flags 0x%ux",
  289. bdp->id, edp->flags);
  290. if (edp->key == 0xbedd)
  291. print(" %s %s", edp->bustype, edp->ifctype);
  292. print("\n");
  293. }
  294. if (edp->sectsz <= 0) {
  295. print("extgetsize: drive 0x%ux: non-positive sector size\n",
  296. bdp->id);
  297. edp->sectsz = 1; /* don't divide by zero */
  298. }
  299. bdp->sectsz = edp->sectsz;
  300. return edp->physsects * edp->sectsz;
  301. }
  302. long
  303. biosread(Fs *fs, void *a, long n)
  304. {
  305. int want, got, part;
  306. long totnr, stuck;
  307. Devbytes offset;
  308. Biosdev *bdp;
  309. if(fs->dev > bdrive.ndevs)
  310. return -1;
  311. if (n <= 0)
  312. return n;
  313. bdp = &bdev[fs->dev];
  314. offset = bdp->offset;
  315. stuck = 0;
  316. for (totnr = 0; totnr < n && stuck < 4; totnr += got) {
  317. want = bdp->sectsz;
  318. if (totnr + want > n)
  319. want = n - totnr;
  320. if(Debug)
  321. print("bios%d, read: %ld @ off %lld, want: %d, id: 0x%ux\n",
  322. fs->dev, n, offset, want, bdp->id);
  323. part = offset % bdp->sectsz;
  324. if (part != 0) { /* back up to start of sector */
  325. offset -= part;
  326. totnr -= part;
  327. if (totnr < 0) {
  328. print("biosread: negative count %ld\n", totnr);
  329. return -1;
  330. }
  331. }
  332. if ((vlong)offset < 0) {
  333. print("biosread: negative offset %lld\n", offset);
  334. return -1;
  335. }
  336. got = sectread(bdp, (char *)a + totnr, want, offset/bdp->sectsz);
  337. if(got <= 0){
  338. // print("biosread: failed to read %ld @ off %lld of 0x%ux, "
  339. // "want %d got %d\n",
  340. // n, offset, bdp->id, want, got);
  341. return -1;
  342. }
  343. offset += got;
  344. bdp->offset = offset;
  345. if (got < bdp->sectsz)
  346. stuck++; /* we'll have to re-read this sector */
  347. else
  348. stuck = 0;
  349. }
  350. return totnr;
  351. }
  352. vlong
  353. biosseek(Fs *fs, vlong off)
  354. {
  355. if (off < 0) {
  356. print("biosseek(fs, %lld) is illegal\n", off);
  357. return -1;
  358. }
  359. if(fs->dev > bdrive.ndevs) {
  360. print("biosseek: fs->dev %d > bdrive.ndevs %d\n",
  361. fs->dev, bdrive.ndevs);
  362. return -1;
  363. }
  364. bdev[fs->dev].offset = off; /* do not know size... (yet) */
  365. return off;
  366. }
  367. void *
  368. biosgetfspart(int i, char *name, int chatty)
  369. {
  370. static Fs fs;
  371. if(strcmp(name, "9fat") != 0){
  372. if(chatty)
  373. print("unknown partition bios%d!%s (use bios%d!9fat)\n",
  374. i, name, i);
  375. return nil;
  376. }
  377. fs.dev = i;
  378. fs.diskread = biosread;
  379. fs.diskseek = biosseek;
  380. if(dosinit(&fs) < 0){
  381. if(chatty)
  382. print("bios%d!%s does not contain a FAT file system\n",
  383. i, name);
  384. return nil;
  385. }
  386. return &fs;
  387. }