]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: zero-copy DMA I/O — ata_dma_read_direct/ata_dma_write_direct bypass bounce...
authorTulio A M Mendes <[email protected]>
Thu, 12 Feb 2026 04:36:43 +0000 (01:36 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:20:50 +0000 (23:20 -0300)
include/ata_dma.h
src/hal/x86/ata_dma.c

index 5f4b384c4d8e0f3e8e83818ef5f752ac4e95ae57..fef3b4792ebf1f2a7cf86fac60f2d5aaa663cef9 100644 (file)
@@ -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
index 6d87fa6ddc7c0bbd9ed4c1bc46c41f8152e1d261..aeb8ce0aaef6fd2a52b85c46a536526b7a5e3b54 100644 (file)
@@ -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;
+}