From: Tulio A M Mendes Date: Thu, 12 Feb 2026 04:36:43 +0000 (-0300) Subject: feat: zero-copy DMA I/O — ata_dma_read_direct/ata_dma_write_direct bypass bounce... X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=d23c85ecd32a6b732ebe3c986bc6fe19d6be7015;p=AdrOS.git feat: zero-copy DMA I/O — ata_dma_read_direct/ata_dma_write_direct bypass bounce buffer with caller-provided physical address --- diff --git a/include/ata_dma.h b/include/ata_dma.h index 5f4b384..fef3b47 100644 --- a/include/ata_dma.h +++ b/include/ata_dma.h @@ -20,4 +20,10 @@ int ata_dma_read28(uint32_t lba, uint8_t* buf512); * Returns 0 on success, negative errno on failure. */ int ata_dma_write28(uint32_t lba, const uint8_t* buf512); +/* Zero-copy DMA: read/write using a caller-provided physical address. + * phys_buf must be 32-bit aligned, below 4GB, and not cross a 64KB boundary. + * Returns 0 on success, negative errno on failure. */ +int ata_dma_read_direct(uint32_t lba, uint32_t phys_buf, uint16_t byte_count); +int ata_dma_write_direct(uint32_t lba, uint32_t phys_buf, uint16_t byte_count); + #endif diff --git a/src/hal/x86/ata_dma.c b/src/hal/x86/ata_dma.c index 6d87fa6..aeb8ce0 100644 --- a/src/hal/x86/ata_dma.c +++ b/src/hal/x86/ata_dma.c @@ -312,3 +312,52 @@ int ata_dma_write28(uint32_t lba, const uint8_t* buf512) { spin_unlock(&dma_lock); return ret; } + +int ata_dma_read_direct(uint32_t lba, uint32_t phys_buf, uint16_t byte_count) { + if (!dma_available) return -ENOSYS; + if (phys_buf == 0 || (phys_buf & 1)) return -EINVAL; + if (byte_count == 0) byte_count = 512; + + spin_lock(&dma_lock); + + /* Save original PRDT and reprogram for zero-copy */ + uint32_t saved_addr = prdt[0].phys_addr; + uint16_t saved_count = prdt[0].byte_count; + prdt[0].phys_addr = phys_buf; + prdt[0].byte_count = byte_count; + + int ret = ata_dma_transfer(lba, 0); + + /* Restore original PRDT for bounce-buffer mode */ + prdt[0].phys_addr = saved_addr; + prdt[0].byte_count = saved_count; + + spin_unlock(&dma_lock); + return ret; +} + +int ata_dma_write_direct(uint32_t lba, uint32_t phys_buf, uint16_t byte_count) { + if (!dma_available) return -ENOSYS; + if (phys_buf == 0 || (phys_buf & 1)) return -EINVAL; + if (byte_count == 0) byte_count = 512; + + spin_lock(&dma_lock); + + uint32_t saved_addr = prdt[0].phys_addr; + uint16_t saved_count = prdt[0].byte_count; + prdt[0].phys_addr = phys_buf; + prdt[0].byte_count = byte_count; + + int ret = ata_dma_transfer(lba, 1); + + if (ret == 0) { + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_CACHE_FLUSH); + (void)ata_wait_not_busy(); + } + + prdt[0].phys_addr = saved_addr; + prdt[0].byte_count = saved_count; + + spin_unlock(&dma_lock); + return ret; +}