From 4be928e80c9aa2bd1259ad64055a116835cd655f Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Wed, 29 Apr 2026 11:32:19 +0200 Subject: [PATCH] idedrv Full asynchronous reading/writing, process suspension --- kernel/device/storage/idedrv.c | 102 ++++++++++++++++++++++----------- kernel/device/storage/idedrv.h | 1 + 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/kernel/device/storage/idedrv.c b/kernel/device/storage/idedrv.c index c7667fe..f063f13 100644 --- a/kernel/device/storage/idedrv.c +++ b/kernel/device/storage/idedrv.c @@ -106,6 +106,19 @@ static void ide_delay(uint16_t ctrl) { } #pragma clang optimize on +static int ide_flush(struct idedrv* idedrv) { + uint8_t ctrl = inb(idedrv->ctrl); + ctrl |= 0x02; + outb(idedrv->ctrl, ctrl); + + if (idedrv->lba48) + outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH48); + else + outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH28); + + return ST_OK; +} + static void ide_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rctx) { (void)user, (void)regs, (void)rctx; @@ -123,6 +136,18 @@ static void ide_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rct if ((status & (IDE_ERR | IDE_DF))) { atomic_store(&req->done, 1); idedrv->current_req = NULL; + + struct list_node_link* node = idedrv->sq.proc_list; + + if (node != NULL) { + struct proc_sq_entry* sq_entry = list_entry(node, struct proc_sq_entry, sq_link); + struct proc* proc = sq_entry->proc; + + free(req); + + int status = req->type == IDE_READ ? -ST_XDRV_READ_ERROR : -ST_XDRV_WRITE_ERROR; + proc_sq_resume(proc, sq_entry, rctx, (uintptr_t)status); + } return; } @@ -140,6 +165,20 @@ static void ide_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rct if ((req->sector_done_count >= req->sector_count)) { atomic_store(&req->done, 1); idedrv->current_req = NULL; + + if (req->type == IDE_WRITE) + ide_flush(idedrv); + + struct list_node_link* node = idedrv->sq.proc_list; + + if (node != NULL) { + struct proc_sq_entry* sq_entry = list_entry(node, struct proc_sq_entry, sq_link); + struct proc* proc = sq_entry->proc; + + free(req); + + proc_sq_resume(proc, sq_entry, rctx, (uintptr_t)ST_OK); + } } } @@ -319,7 +358,8 @@ DEFINE_DEVICE_FINI(idedrv_fini) { free(idedrv); } -static int idedrv_do_read_irqs(struct idedrv* idedrv, size_t sector, size_t sector_count, +static int idedrv_do_read_irqs(struct idedrv* idedrv, struct proc* proc, + struct reschedule_ctx* rctx, size_t sector, size_t sector_count, void* buffer) { struct idedrv_request* req = malloc(sizeof(*req)); @@ -339,14 +379,18 @@ static int idedrv_do_read_irqs(struct idedrv* idedrv, size_t sector, size_t sect uint8_t cmd = idedrv->lba48 ? IDE_CMD_READ48 : IDE_CMD_READ28; outb(idedrv->io + IDE_REG_CMD, cmd); - biglock_unlock(); + if ((proc->flags & PROC_KPROC)) { + biglock_unlock(); - while (!atomic_load(&req->done)) - spin_lock_relax(); + while (!atomic_load(&req->done)) + spin_lock_relax(); - biglock_lock(); + biglock_lock(); - free(req); + free(req); + } else { + proc_sq_suspend(proc, &idedrv->sq, rctx, NULL, NULL); + } return ST_OK; } @@ -448,12 +492,13 @@ DEFINE_DEVICE_OP(idedrv_read) { return -ST_XDRV_READ_ERROR; if (idedrv->irqs_support) - return idedrv_do_read_irqs(idedrv, sector, sector_count, buffer); + return idedrv_do_read_irqs(idedrv, proc, rctx, sector, sector_count, buffer); else return idedrv_do_read_no_irqs(idedrv, sector, sector_count, buffer); } -static int idedrv_do_write_irqs(struct idedrv* idedrv, size_t sector, size_t sector_count, +static int idedrv_do_write_irqs(struct idedrv* idedrv, struct proc* proc, + struct reschedule_ctx* rctx, size_t sector, size_t sector_count, void* buffer) { struct idedrv_request* req = malloc(sizeof(*req)); @@ -479,18 +524,24 @@ static int idedrv_do_write_irqs(struct idedrv* idedrv, size_t sector, size_t sec return -ST_XDRV_WRITE_ERROR; } - outsw(idedrv->io + IDE_REG_DATA, buffer, idedrv->sector_size / 2); - req->sector_done_count = 1; - biglock_unlock(); + if (!(proc->flags & PROC_KPROC)) { + proc_sq_suspend(proc, &idedrv->sq, rctx, NULL, NULL); + } - while (!atomic_load(&req->done)) - spin_lock_relax(); + outsw(idedrv->io + IDE_REG_DATA, buffer, idedrv->sector_size / 2); - biglock_lock(); + if ((proc->flags & PROC_KPROC)) { + biglock_unlock(); - free(req); + while (!atomic_load(&req->done)) + spin_lock_relax(); + + biglock_lock(); + + free(req); + } return ST_OK; } @@ -561,6 +612,8 @@ static int idedrv_do_write_no_irqs(struct idedrv* idedrv, size_t sector, size_t } } + ide_flush(idedrv); + return ST_OK; } @@ -589,30 +642,13 @@ DEFINE_DEVICE_OP(idedrv_write) { return -ST_XDRV_WRITE_ERROR; if (idedrv->irqs_support) - ret = idedrv_do_write_irqs(idedrv, sector, sector_count, buffer); + ret = idedrv_do_write_irqs(idedrv, proc, rctx, sector, sector_count, buffer); else ret = idedrv_do_write_no_irqs(idedrv, sector, sector_count, buffer); if (ret < 0) return ret; - uint8_t ctrl = inb(idedrv->ctrl); - ctrl |= 0x02; - outb(idedrv->ctrl, ctrl); - - if (idedrv->lba48) - outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH48); - else - outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH28); - - uint8_t status; - do { - status = inb(idedrv->io + IDE_REG_STATUS); - } while (status & IDE_BSY); - - if (status & (IDE_ERR | IDE_DF)) - return -ST_XDRV_WRITE_ERROR; - return ST_OK; } diff --git a/kernel/device/storage/idedrv.h b/kernel/device/storage/idedrv.h index 9e62a77..f0ac7d5 100644 --- a/kernel/device/storage/idedrv.h +++ b/kernel/device/storage/idedrv.h @@ -56,6 +56,7 @@ struct idedrv { size_t prdt_entry_count; uintptr_t bounce_buffer_phys; void* bounce_buffer; + struct proc_suspension_q sq; }; struct ide_probe {