diff options
author | Alec Murphy <alec@checksum.fail> | 2019-09-22 16:14:31 -0400 |
---|---|---|
committer | Alec Murphy <alec@checksum.fail> | 2019-09-22 16:14:31 -0400 |
commit | 03e697708087ef71dce9b905572614cd9bf86f66 (patch) | |
tree | 985adc0a266dbc12070a3300452a5b7081e9dadf | |
parent | dc1e4b13932cc09d133bd4691ba9428c506d55e7 (diff) |
Add files to repository
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | DefsVIO.HC | 7 | ||||
-rw-r--r-- | DskBlk2.HC | 88 | ||||
-rw-r--r-- | DskBlkDev2.HC | 14 | ||||
-rw-r--r-- | DskDrv2.HC | 56 | ||||
-rw-r--r-- | DskVIO.HC | 87 | ||||
-rw-r--r-- | MakeVirtioBlk.HC | 10 | ||||
-rw-r--r-- | README.md | 13 | ||||
-rw-r--r-- | Virtio-blk.HC | 56 | ||||
-rw-r--r-- | Virtio.HC | 82 | ||||
-rw-r--r-- | preview.png | bin | 0 -> 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 @@ -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 Binary files differnew file mode 100644 index 0000000..23bd92c --- /dev/null +++ b/preview.png |