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/source/vdev/sdcard.c b/source/vdev/sdcard.c index fb0e6f4..64c331f 100644 --- a/source/vdev/sdcard.c +++ b/source/vdev/sdcard.c @@ -3,7 +3,13 @@ #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; @@ -37,8 +43,8 @@ typedef struct { } PACKED blk_config; typedef struct { - u32 resv; u32 type; + u32 resv; u64 sector_offset; } PACKED vblk_t; @@ -50,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) { @@ -59,39 +67,64 @@ static u8 sdmc_cfg_read(vdev_s *vdev, uint offset) { return 0xFF; } +static void sdmc_txrx(vqueue_s *vq, const vblk_t *blk, vjob_s *vj) { + int err = 0; + u32 type = blk->type, offset = blk->sector_offset; + + while(vqueue_fetch_job_next(vq, vj) >= 0) { + vdesc_s desc; + vqueue_get_job_desc(vq, vj, &desc); + + u8 *data = desc.data; + 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 { + __builtin_trap(); + __builtin_unreachable(); + } + + data += len; + offset += nsect; + } else if ((len % 512) == 1) { + // assume single status byte + *data = err; + } else { + __builtin_trap(); + __builtin_unreachable(); + } + } +} + 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); - } - } - } while(vqueue_fetch_job_next(vq, &vjob) >= 0); + vblk_t vblk; + vdesc_s desc; + vqueue_get_job_desc(vq, &vjob, &desc); + + vblk = *(volatile vblk_t*)(desc.data); + + sdmc_txrx(vq, &vblk, &vjob); + 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_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