]> 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 4c19a9586d8c01778d640f1683f30dbf38a8e333..82833b3cd284bd43892f579b4a09f735d3365f7b 100644 (file)
@@ -29,4 +29,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 5acb97a0786e77416f9478c58549e53112a61361..8ef5e855ff1f64231fb721a5763b73968360030e 100644 (file)
@@ -321,3 +321,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;
+}