From c14469d16d5a6a6eebc347525df2bce9ac9ec86b Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Sat, 24 Jul 2021 12:38:24 -0300 Subject: [PATCH 1/4] initial version with SD card write support (not working yet) needs more research into how linux manages the vqs --- source/vdev/sdcard.c | 134 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 20 deletions(-) diff --git a/source/vdev/sdcard.c b/source/vdev/sdcard.c index fb0e6f4..b0bad57 100644 --- a/source/vdev/sdcard.c +++ b/source/vdev/sdcard.c @@ -4,6 +4,7 @@ #include "virt/manager.h" #define VIRTIO_BLK_F_RO BIT(5) +#define VIRTIO_BLK_F_BLK_SIZE BIT(6) typedef struct { u64 capacity; @@ -59,39 +60,132 @@ static u8 sdmc_cfg_read(vdev_s *vdev, uint offset) { return 0xFF; } +static void sdmc_rx(vdev_s *vdev, vqueue_s *vq, const vblk_t *blk, vjob_s *vj, vdesc_s *vd) { + // send data from SD to linux + + // first descriptor is a simple vblk (RO), then + // a 512*n byte buffer (RW) descriptor, and finally the status byte + + u32 offset = blk->sector_offset; + + // all data needs to be handled in separate descriptors + while(vqueue_fetch_job_next(vq, vj) >= 0) { + u8 *data; + vdesc_s desc; + + vqueue_get_job_desc(vq, vj, &desc); + + data = desc.data; + + if (desc.length % 512) { + // assume status byte + *data = 0; + } else { + u32 count = desc.length / 512; + sdmmc_sdcard_readsectors(offset, count, data); + + offset += count * 512; + vjob_add_written(vj, count * 512); + } + } +} + +static void sdmc_tx(vdev_s *vdev, vqueue_s *vq, const vblk_t *blk, vjob_s *vj, vdesc_s *vd) { + // single continuous descriptor that contains everything? + + u32 offset, count; + u8 *data = vd->data + sizeof(*blk); + + offset = blk->sector_offset; + count = vd->length - sizeof(*blk) - 1; + + DBG_ASSERT(!(count % 512)); + + count /= 512; + + sdmmc_sdcard_writesectors(offset, count, data); + data[count * 512] = 0; // status byte +} + static void sdmc_process_vqueue(vdev_s *vdev, vqueue_s *vq) { vjob_s vjob; while(vqueue_fetch_job_new(vq, &vjob) >= 0) { - do { - u32 *data; - vdesc_s desc; - vqueue_get_job_desc(vq, &vjob, &desc); - - if (desc.dir == HOST_TO_VDEV) { - const vblk_t *blk = (const vblk_t*)desc.data; - OBJ_SETPRIV(vq, (u32)blk->sector_offset); - } else { - u8 *data = desc.data; - if (desc.length < 512) { - *data = 0; - } else { - u32 sectors = desc.length >> 9; - sdmmc_sdcard_readsectors(OBJ_GETPRIV(vq, u32), sectors, data); - OBJ_SETPRIV(vq, OBJ_GETPRIV(vq, u32) + sectors); - vjob_add_written(&vjob, desc.length); + vblk_t vblk; + vdesc_s desc; + vqueue_get_job_desc(vq, &vjob, &desc); + + vblk = *(volatile vblk_t*)(desc.data); + + switch(vblk.type) { + case 0: // VIRTIO_BLK_T_IN + sdmc_rx(vdev, vq, &vblk, &vjob, &desc); + break; + + case 1: // VIRTIO_BLK_T_OUT + sdmc_tx(vdev, vq, &vblk, &vjob, &desc); + break; + } + + vqueue_push_job(vq, &vjob); + vman_notify_host(vdev, VIRQ_VQUEUE); + } + +/* + // categorize data by request size first + switch(desc.length) { + case 1: // status byte + { + // blindly assume there's no error + *(u8*)(desc.data) = 0; + break; + } + + case sizeof(vblk_t): // block request header + { + *vdev_vblk = *(volatile vblk_t*)(desc.data); + OBJ_SETPRIV(vq, (u32)vdev_vblk->sector_offset); + break; + } + + default: // probably data + { + u8 *data; + u32 count, offset; + + data = desc.data; + count = desc.length; + offset = OBJ_GETPRIV(vq, u32); + + if (count % 512) // wtf? + break; + + count /= 512; + // given in multiples of 512 + + if (vdev_vblk->type == 0) { + // VIRTIO_BLK_T_IN + sdmmc_sdcard_readsectors(offset, count, data); + vjob_add_written(&vjob, count << 9); + } else if (vdev_vblk->type == 1) { + // VIRTIO_BLK_T_OUT + sdmmc_sdcard_writesectors(offset, count, data); } + + OBJ_SETPRIV(vq, offset + count); + break; + } } } while(vqueue_fetch_job_next(vq, &vjob) >= 0); vqueue_push_job(vq, &vjob); - } + }*/ - vman_notify_host(vdev, VIRQ_VQUEUE); + //vman_notify_host(vdev, VIRQ_VQUEUE); } DECLARE_VIRTDEV( vdev_sdcard, NULL, - VDEV_T_BLOCK, VIRTIO_BLK_F_RO, 1, + VDEV_T_BLOCK, VIRTIO_BLK_F_BLK_SIZE, 1, sdmc_hard_reset, sdmc_cfg_read, vdev_cfg_write_stub, sdmc_process_vqueue From d57e177bdf57637e4f4732c3be0094b65ef2e1f2 Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Sun, 29 Dec 2024 19:36:01 +0100 Subject: [PATCH 2/4] sd write works --- .gitignore | 2 ++ Makefile | 2 +- source/vdev/sdcard.c | 35 +++++++++++++++++++++++++---------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 4d41277..fb92f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ build/ *.bin *.elf + +.vscode/ diff --git a/Makefile b/Makefile index 5f01756..7ad2c80 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ DBG_FLAG := INCLUDE := -I$(SOURCE) -I$(INCDIR) ASFLAGS := $(SUBARCH) $(INCLUDE) -x assembler-with-cpp -CFLAGS := $(SUBARCH) $(INCLUDE) -MMD -MP -std=c11 -Os -pipe -Wall -Wextra \ +CFLAGS := $(SUBARCH) $(INCLUDE) -MMD -MP -std=c11 -Og -pipe -Wall -Wextra \ -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function \ -ffunction-sections -fomit-frame-pointer -ffast-math $(DBG_FLAG) diff --git a/source/vdev/sdcard.c b/source/vdev/sdcard.c index b0bad57..4151b1f 100644 --- a/source/vdev/sdcard.c +++ b/source/vdev/sdcard.c @@ -38,8 +38,8 @@ typedef struct { } PACKED blk_config; typedef struct { - u32 resv; u32 type; + u32 resv; u64 sector_offset; } PACKED vblk_t; @@ -91,20 +91,35 @@ static void sdmc_rx(vdev_s *vdev, vqueue_s *vq, const vblk_t *blk, vjob_s *vj, v } static void sdmc_tx(vdev_s *vdev, vqueue_s *vq, const vblk_t *blk, vjob_s *vj, vdesc_s *vd) { - // single continuous descriptor that contains everything? + int err = 0; + u32 offset = blk->sector_offset; - u32 offset, count; - u8 *data = vd->data + sizeof(*blk); + // all data needs to be handled in separate descriptors + while(vqueue_fetch_job_next(vq, vj) >= 0) { + vdesc_s desc; - offset = blk->sector_offset; - count = vd->length - sizeof(*blk) - 1; + vqueue_get_job_desc(vq, vj, &desc); + + uint32_t len = desc.length; + u8 *data = desc.data; - DBG_ASSERT(!(count % 512)); + while(len > 0) { + uint32_t blklen = len >= 512 ? 512 : len; - count /= 512; + if (blklen == 512) { + err |= sdmmc_sdcard_writesectors(offset, 1, data) ? 1 : 0; + } else if (blklen == 1) { + *data = 0; + vjob_add_written(vj, 1); + } else { + __asm__ volatile("bkpt\n\t" ::: "memory"); + } - sdmmc_sdcard_writesectors(offset, count, data); - data[count * 512] = 0; // status byte + offset += blklen; + data += blklen; + len -= blklen; + } + } } static void sdmc_process_vqueue(vdev_s *vdev, vqueue_s *vq) { From 6d56907382e469e1f9bb5c6eeb89b4978dccefc8 Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Wed, 1 Jan 2025 14:28:24 +0100 Subject: [PATCH 3/4] refactor r/w functions into one processing fn --- source/vdev/sdcard.c | 146 +++++++++++-------------------------------- 1 file changed, 35 insertions(+), 111 deletions(-) diff --git a/source/vdev/sdcard.c b/source/vdev/sdcard.c index 4151b1f..64c331f 100644 --- a/source/vdev/sdcard.c +++ b/source/vdev/sdcard.c @@ -3,9 +3,14 @@ #include "hw/sdmmc.h" #include "virt/manager.h" -#define VIRTIO_BLK_F_RO BIT(5) +#define VIRTIO_BLK_F_SIZE_MAX BIT(1) +#define VIRTIO_BLK_F_SEG_MAX BIT(2) +#define VIRTIO_BLK_F_READONLY BIT(5) #define VIRTIO_BLK_F_BLK_SIZE BIT(6) +#define VIRTIO_BLK_TYPE_IN 0 +#define VIRTIO_BLK_TYPE_OUT 1 + typedef struct { u64 capacity; u32 size_max; @@ -51,7 +56,9 @@ static void sdmc_hard_reset(vdev_s *vdev) { data[i] = 0; sdmmc_sdcard_init(); sdmc_blk_config.capacity = sdmmc_sdcard_size(); - sdmc_blk_config.blk_size = 512; + sdmc_blk_config.blk_size = 512u; + sdmc_blk_config.size_max = 512u * ((1u << 16) - 1); // limited by hardware + sdmc_blk_config.seg_max = 16u; // picked by a fair dice roll } static u8 sdmc_cfg_read(vdev_s *vdev, uint offset) { @@ -60,64 +67,40 @@ static u8 sdmc_cfg_read(vdev_s *vdev, uint offset) { return 0xFF; } -static void sdmc_rx(vdev_s *vdev, vqueue_s *vq, const vblk_t *blk, vjob_s *vj, vdesc_s *vd) { - // send data from SD to linux - - // first descriptor is a simple vblk (RO), then - // a 512*n byte buffer (RW) descriptor, and finally the status byte - - u32 offset = blk->sector_offset; - - // all data needs to be handled in separate descriptors - while(vqueue_fetch_job_next(vq, vj) >= 0) { - u8 *data; - vdesc_s desc; - - vqueue_get_job_desc(vq, vj, &desc); - - data = desc.data; - - if (desc.length % 512) { - // assume status byte - *data = 0; - } else { - u32 count = desc.length / 512; - sdmmc_sdcard_readsectors(offset, count, data); - - offset += count * 512; - vjob_add_written(vj, count * 512); - } - } -} - -static void sdmc_tx(vdev_s *vdev, vqueue_s *vq, const vblk_t *blk, vjob_s *vj, vdesc_s *vd) { +static void sdmc_txrx(vqueue_s *vq, const vblk_t *blk, vjob_s *vj) { int err = 0; - u32 offset = blk->sector_offset; + u32 type = blk->type, offset = blk->sector_offset; - // all data needs to be handled in separate descriptors while(vqueue_fetch_job_next(vq, vj) >= 0) { vdesc_s desc; - vqueue_get_job_desc(vq, vj, &desc); - uint32_t len = desc.length; u8 *data = desc.data; - - while(len > 0) { - uint32_t blklen = len >= 512 ? 512 : len; - - if (blklen == 512) { - err |= sdmmc_sdcard_writesectors(offset, 1, data) ? 1 : 0; - } else if (blklen == 1) { - *data = 0; - vjob_add_written(vj, 1); + u32 len = desc.length; + + if ((len % 512) == 0) { + u32 nsect = len / 512; + + if (type == VIRTIO_BLK_TYPE_IN) { + // SD -> memory + err |= sdmmc_sdcard_readsectors(offset, nsect, data) ? 1 : 0; + vjob_add_written(vj, len); + } else if (type == VIRTIO_BLK_TYPE_OUT) { + // memory -> SD + err |= sdmmc_sdcard_writesectors(offset, nsect, data) ? 1 : 0; } else { - __asm__ volatile("bkpt\n\t" ::: "memory"); + __builtin_trap(); + __builtin_unreachable(); } - offset += blklen; - data += blklen; - len -= blklen; + data += len; + offset += nsect; + } else if ((len % 512) == 1) { + // assume single status byte + *data = err; + } else { + __builtin_trap(); + __builtin_unreachable(); } } } @@ -132,75 +115,16 @@ static void sdmc_process_vqueue(vdev_s *vdev, vqueue_s *vq) { vblk = *(volatile vblk_t*)(desc.data); - switch(vblk.type) { - case 0: // VIRTIO_BLK_T_IN - sdmc_rx(vdev, vq, &vblk, &vjob, &desc); - break; - - case 1: // VIRTIO_BLK_T_OUT - sdmc_tx(vdev, vq, &vblk, &vjob, &desc); - break; - } + sdmc_txrx(vq, &vblk, &vjob); vqueue_push_job(vq, &vjob); vman_notify_host(vdev, VIRQ_VQUEUE); } - -/* - // categorize data by request size first - switch(desc.length) { - case 1: // status byte - { - // blindly assume there's no error - *(u8*)(desc.data) = 0; - break; - } - - case sizeof(vblk_t): // block request header - { - *vdev_vblk = *(volatile vblk_t*)(desc.data); - OBJ_SETPRIV(vq, (u32)vdev_vblk->sector_offset); - break; - } - - default: // probably data - { - u8 *data; - u32 count, offset; - - data = desc.data; - count = desc.length; - offset = OBJ_GETPRIV(vq, u32); - - if (count % 512) // wtf? - break; - - count /= 512; - // given in multiples of 512 - - if (vdev_vblk->type == 0) { - // VIRTIO_BLK_T_IN - sdmmc_sdcard_readsectors(offset, count, data); - vjob_add_written(&vjob, count << 9); - } else if (vdev_vblk->type == 1) { - // VIRTIO_BLK_T_OUT - sdmmc_sdcard_writesectors(offset, count, data); - } - - OBJ_SETPRIV(vq, offset + count); - break; - } - } - } while(vqueue_fetch_job_next(vq, &vjob) >= 0); - vqueue_push_job(vq, &vjob); - }*/ - - //vman_notify_host(vdev, VIRQ_VQUEUE); } DECLARE_VIRTDEV( vdev_sdcard, NULL, - VDEV_T_BLOCK, VIRTIO_BLK_F_BLK_SIZE, 1, + VDEV_T_BLOCK, VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_BLK_SIZE, 1, sdmc_hard_reset, sdmc_cfg_read, vdev_cfg_write_stub, sdmc_process_vqueue From 9c54808f4b0c1024bd29b4eb3187400d7c28ef05 Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Wed, 1 Jan 2025 14:32:33 +0100 Subject: [PATCH 4/4] undo Makefile change --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7ad2c80..5f01756 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ DBG_FLAG := INCLUDE := -I$(SOURCE) -I$(INCDIR) ASFLAGS := $(SUBARCH) $(INCLUDE) -x assembler-with-cpp -CFLAGS := $(SUBARCH) $(INCLUDE) -MMD -MP -std=c11 -Og -pipe -Wall -Wextra \ +CFLAGS := $(SUBARCH) $(INCLUDE) -MMD -MP -std=c11 -Os -pipe -Wall -Wextra \ -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function \ -ffunction-sections -fomit-frame-pointer -ffast-math $(DBG_FLAG)