summaryrefslogtreecommitdiff
path: root/os/boot/pc/sdbios.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/boot/pc/sdbios.c')
-rw-r--r--os/boot/pc/sdbios.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/os/boot/pc/sdbios.c b/os/boot/pc/sdbios.c
new file mode 100644
index 00000000..fd4fe681
--- /dev/null
+++ b/os/boot/pc/sdbios.c
@@ -0,0 +1,165 @@
+/*
+ * boot driver for BIOS devices with partitions
+ * devbios must be called first
+ */
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "error.h"
+
+#include "sd.h"
+#include "fs.h"
+
+long biosread(Fs *, void *, long);
+vlong biosseek(Fs *fs, vlong off);
+
+extern SDifc sdbiosifc;
+extern int onlybios0, biosinited;
+
+int
+biosverify(SDunit* )
+{
+ if (onlybios0 || !biosinited)
+ return 0;
+ return 1;
+}
+
+int
+biosonline(SDunit* unit)
+{
+ if (onlybios0 || !biosinited || !unit)
+ return 0;
+ unit->sectors = 1UL << 30; /* a bunch */
+ unit->secsize = 512; /* conventional */
+ return 1;
+}
+
+static int
+biosrio(SDreq* r)
+{
+ int nb;
+ long got;
+ vlong len, off;
+ uchar *p;
+ Fs fs; /* just for fs->dev, which is zero */
+
+ if (onlybios0 || !biosinited)
+ return SDeio;
+ /*
+ * Most SCSI commands can be passed unchanged except for
+ * the padding on the end. The few which require munging
+ * are not used internally. Mode select/sense(6) could be
+ * converted to the 10-byte form but it's not worth the
+ * effort. Read/write(6) are easy.
+ */
+ r->rlen = 0;
+ r->status = SDok;
+ switch(r->cmd[0]){
+ case 0x08: /* read */
+ case 0x28: /* read */
+ if (r->cmd[0] == 0x08)
+ panic("biosrio: 0x08 read op\n");
+ off = r->cmd[2]<<24 | r->cmd[3]<<16 | r->cmd[4]<<8 | r->cmd[5];
+ nb = r->cmd[7]<<8 | r->cmd[8]; /* often 4 */
+ USED(nb); /* is nb*512 == r->dlen? */
+ memset(&fs, 0, sizeof fs);
+ biosseek(&fs, off*512);
+ got = biosread(&fs, r->data, r->dlen);
+ if (got < 0)
+ r->status = SDeio;
+ else
+ r->rlen = got;
+ break;
+ case 0x0A: /* write */
+ case 0x2A: /* write */
+ r->status = SDeio; /* boot programs don't write */
+ break;
+ case 0x25: /* read capacity */
+ /*
+ * Read capacity returns the LBA of the last sector.
+ */
+ len = r->unit->sectors - 1;
+ p = r->data;
+ *p++ = len>>24;
+ *p++ = len>>16;
+ *p++ = len>>8;
+ *p++ = len;
+ len = r->unit->secsize;
+ *p++ = len>>24;
+ *p++ = len>>16;
+ *p++ = len>>8;
+ *p = len;
+ r->data = (char *)r->data + 8;
+ return SDok;
+ case 0x9E: /* long read capacity */
+ /*
+ * Read capacity returns the LBA of the last sector.
+ */
+ len = r->unit->sectors - 1;
+ p = r->data;
+ *p++ = len>>56;
+ *p++ = len>>48;
+ *p++ = len>>40;
+ *p++ = len>>32;
+ *p++ = len>>24;
+ *p++ = len>>16;
+ *p++ = len>>8;
+ *p++ = len;
+ len = r->unit->secsize;
+ *p++ = len>>24;
+ *p++ = len>>16;
+ *p++ = len>>8;
+ *p = len;
+ r->data = (char *)r->data + 8;
+ return SDok;
+ /* ignore others */
+ }
+ return r->status;
+}
+
+SDev*
+biosid(SDev* sdev)
+{
+ for (; sdev; sdev = sdev->next)
+ if (sdev->ifc == &sdbiosifc)
+ sdev->idno = 'B';
+ return sdev;
+}
+
+static SDev*
+biospnp(void)
+{
+ SDev *sdev;
+
+ /* 9pxeload can't use bios int 13 calls; they wedge the machine */
+ if (pxe || getconf("*nobiosload") != nil || onlybios0 || !biosinited)
+ return nil;
+ if((sdev = malloc(sizeof(SDev))) != nil) {
+ sdev->ifc = &sdbiosifc;
+ sdev->index = -1;
+ sdev->nunit = 1;
+ }
+ return sdev;
+}
+
+SDifc sdbiosifc = {
+ "bios", /* name */
+
+ biospnp, /* pnp */
+ nil, /* legacy */
+ biosid, /* id */
+ nil, /* enable */
+ nil, /* disable */
+
+ biosverify, /* verify */
+ biosonline, /* online */
+ biosrio, /* rio */
+ nil, /* rctl */
+ nil, /* wctl */
+
+ scsibio, /* bio */
+};