[SeaBIOS] [PATCH 4/7] ahci: handle unaligned buffers.

Gerd Hoffmann kraxel at redhat.com
Thu Jul 14 16:24:02 CEST 2011


From: Scott Duplichan <scott at notabs.org>

This change allows unaligned buffers to be used for reads or writes
to non-atapi devices. Currently only MS-DOS boot is known to need
unaligned buffer support.

Signed-off-by: Scott Duplichan <scott at notabs.org>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
---
 src/ahci.c |   53 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/src/ahci.c b/src/ahci.c
index ec698ef..e2ec07a 100644
--- a/src/ahci.c
+++ b/src/ahci.c
@@ -22,6 +22,7 @@
 /****************************************************************
  * these bits must run in both 16bit and 32bit modes
  ****************************************************************/
+u8 *ahci_buf_fl VAR16VISIBLE;
 
 // prepare sata command fis
 static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command)
@@ -230,9 +231,9 @@ int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
     return DISK_RET_SUCCESS;
 }
 
-// read/write count blocks from a harddrive.
+// read/write count blocks from a harddrive, op->buf_fl must be word aligned
 static int
-ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
+ahci_disk_readwrite_aligned(struct disk_op_s *op, int iswrite)
 {
     struct ahci_port_s *port = container_of(
         op->drive_g, struct ahci_port_s, drive);
@@ -249,6 +250,47 @@ ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
     return DISK_RET_SUCCESS;
 }
 
+// read/write count blocks from a harddrive.
+static int
+ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
+{
+    // if caller's buffer is word aligned, use it directly
+    if (((u32) op->buf_fl & 1) == 0)
+        return ahci_disk_readwrite_aligned(op, iswrite);
+
+    // Use a word aligned buffer for AHCI I/O
+    int rc;
+    struct disk_op_s localop = *op;
+    u8 *alignedbuf_fl = GET_GLOBAL(ahci_buf_fl);
+    u8 *position = op->buf_fl;
+
+    localop.buf_fl = alignedbuf_fl;
+    localop.count = 1;
+
+    if (iswrite) {
+        u16 block;
+        for (block = 0; block < op->count; block++) {
+            memcpy_fl (alignedbuf_fl, position, DISK_SECTOR_SIZE);
+            rc = ahci_disk_readwrite_aligned (&localop, 1);
+            if (rc)
+                return rc;
+            position += DISK_SECTOR_SIZE;
+            localop.lba++;
+        }
+    } else { // read
+        u16 block;
+        for (block = 0; block < op->count; block++) {
+            rc = ahci_disk_readwrite_aligned (&localop, 0);
+            if (rc)
+                return rc;
+            memcpy_fl (position, alignedbuf_fl, DISK_SECTOR_SIZE);
+            position += DISK_SECTOR_SIZE;
+            localop.lba++;
+        }
+    }
+    return DISK_RET_SUCCESS;
+}
+
 // command demuxer
 int process_ahci_op(struct disk_op_s *op)
 {
@@ -493,6 +535,13 @@ ahci_init_controller(int bdf)
         warn_noalloc();
         return;
     }
+
+    ahci_buf_fl = malloc_low(DISK_SECTOR_SIZE);
+    if (!ahci_buf_fl) {
+        warn_noalloc();
+        return;
+    }
+
     ctrl->pci_bdf = bdf;
     ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5);
     ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
-- 
1.7.1




More information about the SeaBIOS mailing list