aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Murphy <alec@checksum.fail>2019-09-22 16:14:31 -0400
committerAlec Murphy <alec@checksum.fail>2019-09-22 16:14:31 -0400
commit03e697708087ef71dce9b905572614cd9bf86f66 (patch)
tree985adc0a266dbc12070a3300452a5b7081e9dadf
parentdc1e4b13932cc09d133bd4691ba9428c506d55e7 (diff)
Add files to repository
-rw-r--r--.gitignore2
-rw-r--r--DefsVIO.HC7
-rw-r--r--DskBlk2.HC88
-rw-r--r--DskBlkDev2.HC14
-rw-r--r--DskDrv2.HC56
-rw-r--r--DskVIO.HC87
-rw-r--r--MakeVirtioBlk.HC10
-rw-r--r--README.md13
-rw-r--r--Virtio-blk.HC56
-rw-r--r--Virtio.HC82
-rw-r--r--preview.pngbin0 -> 21524 bytes
11 files changed, 415 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e89346a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+uncrustify.cfg
+.vscode/
diff --git a/DefsVIO.HC b/DefsVIO.HC
new file mode 100644
index 0000000..ddec6d7
--- /dev/null
+++ b/DefsVIO.HC
@@ -0,0 +1,7 @@
+#define BDT_VIRTIO_BLK 10
+
+U0 PatchJmpRel32(U32 from, U32 to)
+{
+ *(from(U8*)) = 0xE9;
+ *((from+1)(I32*)) = to-from-5;
+} \ No newline at end of file
diff --git a/DskBlk2.HC b/DskBlk2.HC
new file mode 100644
index 0000000..d08041b
--- /dev/null
+++ b/DskBlk2.HC
@@ -0,0 +1,88 @@
+Bool BlkRead2(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
+{//Read blk cnt from Drv to buf.
+ Bool res=TRUE,unlock;
+ CBlkDev *bd=dv->bd;
+ if (cnt<=0) return TRUE;
+ DrvChk(dv);
+ try {
+ unlock=DrvLock(dv);
+ CallExtStr("BlkDevInit",bd);
+ if (dv->drv_offset && blk<dv->drv_offset ||
+ blk+cnt>dv->drv_offset+dv->size)
+ throw('Drv');
+ if (bd->flags & BDF_READ_CACHE)
+ CallExtStr("RCache",dv,&buf,&blk,&cnt);
+ if (cnt>0) {
+ switch (bd->type) {
+ case BDT_RAM:
+ MemCpy(buf,bd->RAM_dsk+blk<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
+ break;
+ case BDT_ISO_FILE_READ:
+ case BDT_ISO_FILE_WRITE:
+ FBlkRead(bd->file_dsk,buf,blk,cnt);
+ break;
+ case BDT_ATA:
+ case BDT_ATAPI:
+ res=CallExtStr("ATARBlks",dv,buf,blk,cnt);
+ break;
+ case BDT_VIRTIO_BLK:
+ res=VIORBlks(dv,buf,blk,cnt);
+ break;
+ }
+ bd->last_time=tS;
+ if (bd->flags & BDF_READ_CACHE)
+ CallExtStr("DskCacheAdd",dv,buf,blk,cnt);
+ }
+ if (unlock)
+ DrvUnlock(dv);
+ } catch
+ if (unlock)
+ DrvUnlock(dv);
+ return res;
+}
+
+Bool BlkWrite2(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
+{//Write blk cnt from buf to Drv.
+ Bool res=TRUE,unlock;
+ CBlkDev *bd=dv->bd;
+ if (cnt<=0) return TRUE;
+ DrvChk(dv);
+ try {
+ unlock=DrvLock(dv);
+ CallExtStr("BlkDevInit",bd);
+ if (bd->flags&BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
+ throw('BlkDev');
+ if (dv->drv_offset && blk<dv->drv_offset ||
+ blk+cnt>dv->drv_offset+dv->size)
+ throw('Drv');
+ if (cnt>0) {
+ switch (bd->type) {
+ case BDT_RAM:
+ MemCpy(bd->RAM_dsk+blk<<BLK_SIZE_BITS,buf,cnt<<BLK_SIZE_BITS);
+ break;
+ case BDT_ISO_FILE_READ:
+ case BDT_ISO_FILE_WRITE:
+ FBlkWrite(bd->file_dsk,buf,blk,cnt);
+ break;
+ case BDT_ATA:
+ case BDT_ATAPI:
+ res=CallExtStr("ATAWBlks",dv,buf,blk,cnt);
+ break;
+ case BDT_VIRTIO_BLK:
+ res=VIOWBlks(dv,buf,blk,cnt);
+ break;
+ }
+ bd->last_time=tS;
+ if (bd->flags & BDF_READ_CACHE)
+ CallExtStr("DskCacheAdd",dv,buf,blk,cnt);
+ }
+ if (unlock)
+ DrvUnlock(dv);
+ } catch
+ if (unlock)
+ DrvUnlock(dv);
+ return res;
+}
+
+PatchJmpRel32(&BlkRead, &BlkRead2);
+PatchJmpRel32(&BlkWrite, &BlkWrite2);
diff --git a/DskBlkDev2.HC b/DskBlkDev2.HC
new file mode 100644
index 0000000..e875b51
--- /dev/null
+++ b/DskBlkDev2.HC
@@ -0,0 +1,14 @@
+CBlkDev *BlkDevChk2(CBlkDev *bd,Bool except=TRUE)
+{//Check for valid BlkDev. Throw exception.
+ if (bd->type==BDT_VIRTIO_BLK) return bd;
+ if (!bd || bd->bd_signature!=BD_SIGNATURE_VAL ||
+ !(BDT_NULL<bd->type<BDT_TYPES_NUM)) {
+ if (except)
+ throw('BlkDev');
+ else
+ return NULL;
+ } else
+ return bd;
+}
+
+PatchJmpRel32(&BlkDevChk, &BlkDevChk2); \ No newline at end of file
diff --git a/DskDrv2.HC b/DskDrv2.HC
new file mode 100644
index 0000000..471300b
--- /dev/null
+++ b/DskDrv2.HC
@@ -0,0 +1,56 @@
+DefineLstLoad("ST_BLKDEV_TYPES2",
+ "NULL\0RAM\0ATA\0FILE_READ\0FILE_WRITE\0ATAPI\0NULL\0NULL\0NULL\0NULL\0VIRTIO\0");
+
+U8 DrvTextAttrGet2(U8 drv_let=0)
+{//Get color of drive.
+ U8 *blkdev_text_attr2 = blkdev_text_attr;
+ U8 *drv_text_attr2 = drv_text_attr;
+ I64 dta_size = 3;
+ drv_let=Let2Let(drv_let);
+ if (drv_let=='A') return BLACK<<4|WHITE;
+ if ('A'<=drv_let<='Z')
+ return blkdev_text_attr2[Let2BlkDevType(drv_let)]<<4|
+ drv_text_attr2[drv_let%dta_size];
+ else
+ return BLACK<<4|WHITE;
+}
+
+U0 DrvRep2()
+{//Drive report.
+ CDrv *dv;
+ CBlkDev *bd;
+ I64 ch,i,drv_let,attr;
+ U8 *st;
+ "\nDefined Drives:\n";
+ for (i=0,dv=blkdev.drvs;i<DRVS_NUM;i++,dv++) {
+ if (dv->dv_signature==DRV_SIGNATURE_VAL) {
+ bd=dv->bd;
+ drv_let=Drv2Let(dv);
+ if (Bt(&dv->fs_type,FStf_DISABLE))
+ ch='-';
+ else if (drv_let==blkdev.boot_drv_let)
+ ch=':';
+ else
+ ch='+';
+ attr=DrvTextAttrGet(drv_let);
+ "$$FG,%d$$$$BG,%d$$%C %-8Z %-10Z %04X %04X %02X\n",
+ attr&15,attr>>4,drv_let,dv->fs_type&FSG_TYPE_MASK,"ST_DRV_TYPES",
+ bd->type,"ST_BLKDEV_TYPES2",bd->base0,bd->base1,bd->unit;
+ if (st=DrvModelNum(drv_let)) {
+ "Model#:%s\n",st;
+ Free(st);
+ }
+ if (st=DrvSerialNum(drv_let)) {
+ "Serial#:%s\n",st;
+ Free(st);
+ }
+ if (bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
+ "File=\"%s\"\n",bd->file_dsk_name;
+ "%016X-%016X\n$$FG$$$$BG$$",dv->drv_offset,dv->drv_offset+dv->size-1;
+ }
+ }
+ "Home Dir:\"%s\"\n",blkdev.home_dir;
+}
+
+PatchJmpRel32(&DrvTextAttrGet, &DrvTextAttrGet2);
+PatchJmpRel32(&DrvRep, &DrvRep2); \ No newline at end of file
diff --git a/DskVIO.HC b/DskVIO.HC
new file mode 100644
index 0000000..4984494
--- /dev/null
+++ b/DskVIO.HC
@@ -0,0 +1,87 @@
+Bool VIORBlks(CDrv *dv, U8 *buf, I64 blk, I64 cnt)
+{
+ I64 i, j;
+ I64 vq_idx;
+ U64 addr;
+ CVirtioBlkRequest *brq = CAlloc(sizeof(CVirtioBlkRequest));
+ for (i=0; i<cnt; i++)
+ {
+ brq->type = VIRTIO_BLK_T_IN;
+ brq->sector = blk + i;
+ vq_idx = virtio_blk.vq->available.index % 128;
+ addr = buf + (BLK_SIZE*i);
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].address = brq;
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].length = sizeof(CVirtioBlkRequest);
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].flags = VRING_DESC_F_NEXT;
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].next = (virtio_blk.vq_index+1)%128;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].address = addr;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].length = BLK_SIZE;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].next = (virtio_blk.vq_index+2)%128;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].address = &virtio_blk.status;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].length = 1;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].flags = VRING_DESC_F_WRITE;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].next = 0;
+ virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index%128;
+ virtio_blk.vq_index += 3;
+ j = virtio_blk.vq->used.index;
+ virtio_blk.vq->available.index++;
+ OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
+ while (j==virtio_blk.vq->used.index){Yield;}
+ }
+ Free(brq);
+ return TRUE;
+}
+
+Bool VIOWBlks(CDrv *dv, U8 *buf, I64 blk, I64 cnt)
+{
+ I64 i, j;
+ I64 vq_idx;
+ U64 addr;
+ CVirtioBlkRequest *brq = CAlloc(sizeof(CVirtioBlkRequest));
+ for (i=0; i<cnt; i++)
+ {
+ brq->type = VIRTIO_BLK_T_OUT;
+ brq->sector = blk + i;
+ vq_idx = virtio_blk.vq->available.index % 128;
+ addr = buf + (BLK_SIZE*i);
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].address = brq;
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].length = sizeof(CVirtioBlkRequest);
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].flags = VRING_DESC_F_NEXT;
+ virtio_blk.vq->buffers[virtio_blk.vq_index%128].next = (virtio_blk.vq_index+1)%128;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].address = addr;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].length = BLK_SIZE;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].flags = VRING_DESC_F_NEXT;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+1)%128].next = (virtio_blk.vq_index+2)%128;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].address = &virtio_blk.status;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].length = 1;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].flags = VRING_DESC_F_WRITE;
+ virtio_blk.vq->buffers[(virtio_blk.vq_index+2)%128].next = 0;
+ virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index%128;
+ virtio_blk.vq_index += 3;
+ j = virtio_blk.vq->used.index;
+ virtio_blk.vq->available.index++;
+ OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
+ while (j==virtio_blk.vq->used.index){Yield;}
+ }
+ Free(brq);
+ return TRUE;
+}
+
+U8 MountVirtioBlk()
+{//Mount Virtio-blk device
+ CDrv *dv=DrvMakeFreeSlot(DrvNextFreeLet('A'));
+ CBlkDev *bd=BlkDevNextFreeSlot(dv->drv_let,BDT_RAM);
+ CRedSeaBoot *bs=CAlloc(BLK_SIZE);
+ bd->max_blk = 512;
+ BlkDevAdd(bd,,TRUE,TRUE);
+ bd->type = BDT_VIRTIO_BLK;
+ bd->max_blk = virtio_blk.blks;
+ Free(bd->RAM_dsk);
+ dv->size=bd->max_blk+1-bd->drv_offset;
+ VIORBlks(dv,bs,0,1);
+ dv->root_clus = bs->root_clus;
+ dv->data_area = bs->bitmap_sects;
+ Free(bs);
+ return dv->drv_let;
+} \ No newline at end of file
diff --git a/MakeVirtioBlk.HC b/MakeVirtioBlk.HC
new file mode 100644
index 0000000..8734b0d
--- /dev/null
+++ b/MakeVirtioBlk.HC
@@ -0,0 +1,10 @@
+AdamFile("T:/Virtio.HC");
+AdamFile("T:/Virtio-blk.HC");
+
+AdamFile("T:/DefsVIO.HC");
+AdamFile("T:/DskVIO.HC");
+AdamFile("T:/DskBlk2.HC");
+AdamFile("T:/DskBlkDev2.HC");
+AdamFile("T:/DskDrv2.HC");
+
+VirtioBlkInit; \ No newline at end of file
diff --git a/README.md b/README.md
index 4f53ddd..e50c137 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,15 @@
# bdt-virtio-blk
Virtio-blk Loadable Device Driver for TempleOS
+
+![Virtio-blk Loadable Device Driver for TempleOS](https://raw.githubusercontent.com/obecebo/bdt-virtio-blk/master/preview.png?)
+
+# details
+
+Mount a Virtio block device in TempleOS on QEMU, without having to recompile the Kernel. Re-assigns drive letter `A` to `BDT_VIRTIO_BLK` device.
+
+# usage
+
+- Clone the repo, create a RedSea ISO.C disk image using [RedSeaExplorer](https://checksum.fail/files/RedSeaExplorer-0.6.zip) for Windows or [redseafs](https://github.com/obecebo/redseafs) for Linux.
+- Load the driver `#include "MakeVirtioBlk";`
+- Mount the block device `MountVirtioBlk;`
+- Format (if new device) `Fmt('A',,FALSE,FSt_REDSEA);`
diff --git a/Virtio-blk.HC b/Virtio-blk.HC
new file mode 100644
index 0000000..78cccc5
--- /dev/null
+++ b/Virtio-blk.HC
@@ -0,0 +1,56 @@
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+
+class CVirtioBlk
+{
+U16 port;
+U32 blks;
+CVirtioQueue *vq;
+I64 vq_size;
+I64 vq_index;
+U8 status;
+};
+
+class CVirtioBlkRequest
+{
+U32 type;
+U32 priority;
+U64 sector;
+};
+
+CVirtioBlk virtio_blk;
+MemSet(&virtio_blk, 0, sizeof(CVirtioBlk));
+
+I64 VirtioBlkInit()
+{
+ I64 i,j;
+ U8 k;
+
+ //Scan for device
+ j=PCIClassFind(0x010000,0);
+ if (j<0)
+ {
+ "\nVirtio-blk device not found.\n";
+ return -1;
+ }
+ virtio_blk.port=PCIReadU32(j.u8[2],
+ j.u8[1],j.u8[0],0x10) & 0xFFFFFFFC;
+
+ virtio_blk.blks = InU32(virtio_blk.port + VIRTIO_PCI_CONFIG);
+
+ // Reset Device
+ OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, 0);
+
+ // Found Driver
+ OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, InU8(virtio_blk.port + VIRTIO_PCI_STATUS) | VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER);
+
+ // Set up virt queue
+ OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_SEL, 0);
+ virtio_blk.vq_size = InU16(virtio_blk.port + VIRTIO_PCI_QUEUE_SIZE);//256
+ virtio_blk.vq = CAllocAligned(sizeof(CVirtioQueue), 4096, Fs->code_heap);
+ OutU32(virtio_blk.port + VIRTIO_PCI_QUEUE_PFN, virtio_blk.vq / 4096);
+
+ // Init OK
+ OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, InU8(virtio_blk.port + VIRTIO_PCI_STATUS) | VIRTIO_CONFIG_S_DRIVER_OK);
+ virtio_blk.vq_index = 0;
+} \ No newline at end of file
diff --git a/Virtio.HC b/Virtio.HC
new file mode 100644
index 0000000..aede005
--- /dev/null
+++ b/Virtio.HC
@@ -0,0 +1,82 @@
+//
+// PCI virtio I/O registers.
+//
+
+#define VIRTIO_PCI_HOST_FEATURES 0 // Features supported by the host
+#define VIRTIO_PCI_GUEST_FEATURES 4 // Features activated by the guest
+#define VIRTIO_PCI_QUEUE_PFN 8 // PFN for the currently selected queue
+#define VIRTIO_PCI_QUEUE_SIZE 12 // Queue size for the currently selected queue
+#define VIRTIO_PCI_QUEUE_SEL 14 // Queue selector
+#define VIRTIO_PCI_QUEUE_NOTIFY 16 // Queue notifier
+#define VIRTIO_PCI_STATUS 18 // Device status register
+#define VIRTIO_PCI_ISR 19 // Interrupt status register
+#define VIRTIO_PCI_CONFIG 20 // Configuration data block
+
+//
+// PCI virtio status register bits
+//
+
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
+#define VIRTIO_CONFIG_S_DRIVER 2
+#define VIRTIO_CONFIG_S_DRIVER_OK 4
+#define VIRTIO_CONFIG_S_FAILED 0x80
+
+//
+// Ring descriptor flags
+//
+
+#define VRING_DESC_F_NEXT 1 // Buffer continues via the next field
+#define VRING_DESC_F_WRITE 2 // Buffer is write-only (otherwise read-only)
+#define VRING_DESC_F_INDIRECT 4 // Buffer contains a list of buffer descriptors
+
+class CVirtioQueueBuf
+{
+ U64 address;
+ U32 length;
+ U16 flags;
+ U16 next;
+};
+class CVirtioAvail
+{
+ U16 flags;
+ U16 index;
+ U16 ring[128];
+ U16 int_index;
+};
+class CVirtioUsedItem
+{
+ U32 index;
+ U32 length;
+};
+class CVirtioUsed
+{
+ U16 flags;
+ U16 index;
+ CVirtioUsedItem ring[128];
+ U16 int_index;
+};
+class CVirtioQueue
+{
+ CVirtioQueueBuf buffers[128];
+ CVirtioAvail available;
+ U8 padding[1786];
+ CVirtioUsed used;
+};
+
+class CVirtioAvailBuf
+{
+ U32 index;
+ U64 address;
+ U32 length;
+};
+
+class CVirtioBufInfo
+{
+ U8* buffer;
+ U64 size;
+ U8 flags;
+
+ // If the user wants to keep same buffer as passed in this struct, use "true".
+ // otherwise, the supplied buffer will be copied in the queues' buffer
+ Bool copy;
+}; \ No newline at end of file
diff --git a/preview.png b/preview.png
new file mode 100644
index 0000000..23bd92c
--- /dev/null
+++ b/preview.png
Binary files differ