Use 32bit absolute pointers for buffers in ATA code.
authorKevin O'Connor <kevin@koconnor.net>
Thu, 13 Mar 2008 00:33:15 +0000 (20:33 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Thu, 13 Mar 2008 00:33:15 +0000 (20:33 -0400)
Using 32bit pointers makes the code a little simpler.  It also allows
the code to be used from 32 bit mode.  It does require all callers to
encode the segment/offset into an absolute address.  The ins/outs
functions also need to know how to convert from 32bit back to
segment/offset addresses.

The change also includes a minor cleanup of the macros in farptr.h.

src/ata.c
src/ata.h
src/cdrom.c
src/disk.c
src/farptr.h

index 3aea3ad..2e44d41 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
@@ -186,10 +186,10 @@ send_cmd(struct ata_pio_command *cmd)
 int
 ata_transfer(struct ata_pio_command *cmd)
 {
-    DEBUGF("ata_transfer id=%d cmd=%d lba=%d count=%d seg=%x off=%x\n"
+    DEBUGF("ata_transfer id=%d cmd=%d lba=%d count=%d buf=%p\n"
            , cmd->biosid, cmd->command
            , (cmd->lba_high << 16) | (cmd->lba_mid << 8) | cmd->lba_low
-           , cmd->sector_count, cmd->segment, cmd->offset);
+           , cmd->sector_count, cmd->far_buffer);
 
     // Reset count of transferred data
     SET_EBDA(ata.trsfsectors,0);
@@ -208,34 +208,28 @@ ata_transfer(struct ata_pio_command *cmd)
 
     irq_enable();
 
-    u16 segment = cmd->segment;
-    u16 offset = cmd->offset;
     u8 current = 0;
     u16 count = cmd->sector_count;
     u8 status;
+    void *far_buffer = cmd->far_buffer;
     for (;;) {
-        if (offset >= 0xf800) {
-            offset -= 0x800;
-            segment += 0x80;
-        }
-
         if (iswrite) {
             // Write data to controller
-            DEBUGF("Write sector id=%d dest=%x:%x\n", biosid, segment, offset);
+            DEBUGF("Write sector id=%d dest=%p\n", biosid, far_buffer);
             if (mode == ATA_MODE_PIO32)
-                outsl_seg(iobase1, segment, offset, 512 / 4);
+                outsl_far(iobase1, far_buffer, 512 / 4);
             else
-                outsw_seg(iobase1, segment, offset, 512 / 2);
+                outsw_far(iobase1, far_buffer, 512 / 2);
         } else {
             // Read data from controller
-            DEBUGF("Read sector id=%d dest=%x:%x\n", biosid, segment, offset);
+            DEBUGF("Read sector id=%d dest=%p\n", biosid, far_buffer);
             if (mode == ATA_MODE_PIO32)
-                insl_seg(iobase1, segment, offset, 512 / 4);
+                insl_far(iobase1, far_buffer, 512 / 4);
             else
-                insw_seg(iobase1, segment, offset, 512 / 2);
+                insw_far(iobase1, far_buffer, 512 / 2);
             await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
         }
-        offset += 512;
+        far_buffer += 512;
 
         current++;
         SET_EBDA(ata.trsfsectors,current);
@@ -280,12 +274,10 @@ ata_transfer(struct ata_pio_command *cmd)
       // 4 : not ready
 int
 ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
-               , u16 header, u32 length, u16 bufseg, u16 bufoff)
+               , u16 header, u32 length, void *far_buffer)
 {
-    DEBUGF("ata_cmd_packet d=%d cmdlen=%d h=%d l=%d"
-           " seg=%x off=%x\n"
-           , biosid, cmdlen, header, length
-           , bufseg, bufoff);
+    DEBUGF("ata_cmd_packet d=%d cmdlen=%d h=%d l=%d buf=%p\n"
+           , biosid, cmdlen, header, length, far_buffer);
 
     u8 channel = biosid / 2;
     u8 slave = biosid % 2;
@@ -321,7 +313,7 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
     irq_enable();
 
     // Send command to device
-    outsw_seg(iobase1, GET_SEG(SS), (u32)cmdbuf, cmdlen / 2);
+    outsw_far(iobase1, MAKE_32_PTR(GET_SEG(SS), (u32)cmdbuf), cmdlen / 2);
 
     u8 status;
     u16 loops = 0;
@@ -346,10 +338,6 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
             return 3;
         }
 
-        // Normalize address
-        bufseg += (bufoff / 16);
-        bufoff %= 16;
-
         // Get the byte count
         u16 lcount =  (((u16)(inb(iobase1 + ATA_CB_CH))<<8)
                        + inb(iobase1 + ATA_CB_CL));
@@ -378,9 +366,8 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
         // Save byte count
         u16 count = lcount;
 
-        DEBUGF("Trying to read %04x bytes (%04x %04x %04x) "
-               , lbefore+lcount+lafter, lbefore, lcount, lafter);
-        DEBUGF("to 0x%04x:0x%04x\n", bufseg, bufoff);
+        DEBUGF("Trying to read %04x bytes (%04x %04x %04x) to %p\n"
+               , lbefore+lcount+lafter, lbefore, lcount, lafter, far_buffer);
 
         // If counts not dividable by 4, use 16bits mode
         u8 lmode = mode;
@@ -410,9 +397,9 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
                 inw(iobase1);
 
         if (lmode == ATA_MODE_PIO32)
-            insl_seg(iobase1, bufseg, bufoff, lcount);
+            insl_far(iobase1, far_buffer, lcount);
         else
-            insw_seg(iobase1, bufseg, bufoff, lcount);
+            insw_far(iobase1, far_buffer, lcount);
 
         for (i=0; i<lafter; i++)
             if (lmode == ATA_MODE_PIO32)
@@ -421,7 +408,7 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
                 inw(iobase1);
 
         // Compute new buffer address
-        bufoff += count;
+        far_buffer += count;
 
         // Save transferred bytes count
         SET_EBDA(ata.trsfsectors, loops);
@@ -442,7 +429,7 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
 }
 
 int
-cdrom_read(u16 biosid, u32 lba, u32 count, u16 segment, u16 offset, u16 skip)
+cdrom_read(u16 biosid, u32 lba, u32 count, void *far_buffer, u16 skip)
 {
     u16 sectors = (count + 2048 - 1) / 2048;
 
@@ -457,7 +444,7 @@ cdrom_read(u16 biosid, u32 lba, u32 count, u16 segment, u16 offset, u16 skip)
     atacmd[5]=(lba & 0x000000ff);
 
     return ata_cmd_packet(biosid, atacmd, sizeof(atacmd)
-                          , skip, count, segment, offset);
+                          , skip, count, far_buffer);
 }
 
 // ---------------------------------------------------------------------------
@@ -568,7 +555,7 @@ ata_detect()
 
             u16 ret = ata_cmd_data_chs(device, ATA_CMD_IDENTIFY_DEVICE
                                        , 0, 0, 1, 1
-                                       , GET_SEG(SS), (u32)buffer);
+                                       , MAKE_32_PTR(GET_SEG(SS), (u32)buffer));
             if (ret)
                 BX_PANIC("ata-detect: Failed to detect ATA device\n");
 
@@ -672,7 +659,7 @@ ata_detect()
 
             u16 ret = ata_cmd_data_chs(device, ATA_CMD_IDENTIFY_DEVICE_PACKET
                                        , 0, 0, 1, 1
-                                       , GET_SEG(SS), (u32)buffer);
+                                       , MAKE_32_PTR(GET_SEG(SS), (u32)buffer));
             if (ret != 0)
                 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
 
index 0ad3590..8d7c508 100644 (file)
--- a/src/ata.h
+++ b/src/ata.h
@@ -12,8 +12,7 @@
 #include "atabits.h"
 
 struct ata_pio_command {
-    u16 segment;
-    u16 offset;
+    void *far_buffer;
     u8 biosid;
 
     u8 feature;
@@ -34,21 +33,19 @@ struct ata_pio_command {
 void ata_reset(u16 device);
 int ata_transfer(struct ata_pio_command *cmd);
 int ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen
-                   , u16 header, u32 length, u16 bufseg, u16 bufoff);
+                   , u16 header, u32 length, void *far_buffer);
 int cdrom_read(u16 device, u32 lba, u32 count
-               , u16 segment, u16 offset, u16 skip);
+               , void *far_buffer, u16 skip);
 void ata_detect();
 
 static inline int
-ata_cmd_data(u16 biosid, u16 command, u32 lba, u16 count
-             , u16 segment, u16 offset)
+ata_cmd_data(u16 biosid, u16 command, u32 lba, u16 count, void *far_buffer)
 {
     u8 slave   = biosid % 2;
 
     struct ata_pio_command cmd;
+    cmd.far_buffer = far_buffer;
     cmd.biosid = biosid;
-    cmd.segment = segment;
-    cmd.offset = offset;
 
     if (count >= (1<<8) || lba + count >= (1<<28)) {
         cmd.sector_count2 = count >> 8;
@@ -73,14 +70,13 @@ ata_cmd_data(u16 biosid, u16 command, u32 lba, u16 count
 
 static inline int
 ata_cmd_data_chs(u16 biosid, u16 command, u16 cyl, u16 head, u16 sect, u16 count
-                 , u16 segment, u16 offset)
+                 , void *far_buffer)
 {
     u8 slave   = biosid % 2;
 
     struct ata_pio_command cmd;
+    cmd.far_buffer = far_buffer;
     cmd.biosid = biosid;
-    cmd.segment = segment;
-    cmd.offset = offset;
 
     cmd.sector_count = count & 0xff;
     cmd.feature = 0;
index 55db9b5..cf77584 100644 (file)
@@ -296,7 +296,8 @@ atapi_get_sense(u16 device, u8 *asc, u8 *ascq)
     atacmd[0] = ATA_CMD_REQUEST_SENSE;
     atacmd[4] = sizeof(buffer);
     u16 ret = ata_cmd_packet(device, atacmd, sizeof(atacmd)
-                             , 0, sizeof(buffer), GET_SEG(SS), (u32)buffer);
+                             , 0, sizeof(buffer)
+                             , MAKE_32_PTR(GET_SEG(SS), (u32)buffer));
     if (ret != 0)
         return 0x0002;
 
@@ -332,7 +333,8 @@ atapi_is_ready(u16 device)
             return -1;
         }
         u16 ret = ata_cmd_packet(device, packet, sizeof(packet)
-                                 , 0, sizeof(buf), GET_SEG(SS), (u32)buf);
+                                 , 0, sizeof(buf)
+                                 , MAKE_32_PTR(GET_SEG(SS), (u32)buf));
         if (ret == 0)
             break;
 
@@ -429,7 +431,8 @@ cdrom_boot()
 
     // Read the Boot Record Volume Descriptor
     u8 buffer[2048];
-    ret = cdrom_read(device, 0x11, 2048, GET_SEG(SS), (u32)buffer, 0);
+    ret = cdrom_read(device, 0x11, 2048
+                     , MAKE_32_PTR(GET_SEG(SS), (u32)buffer), 0);
     if (ret)
         return 3;
 
@@ -443,7 +446,8 @@ cdrom_boot()
     u32 lba = *(u32*)&buffer[0x47];
 
     // And we read the Boot Catalog
-    ret = cdrom_read(device, lba, 2048, GET_SEG(SS), (u32)buffer, 0);
+    ret = cdrom_read(device, lba, 2048
+                     , MAKE_32_PTR(GET_SEG(SS), (u32)buffer), 0);
     if (ret)
         return 7;
 
@@ -489,7 +493,7 @@ cdrom_boot()
 
     // And we read the image in memory
     ret = cdrom_read(device, lba, nbsectors*512
-                     , boot_segment, 0, 0);
+                     , MAKE_32_PTR(boot_segment, 0), 0);
     if (ret)
         return 12;
 
index 1d5fd27..9320c3c 100644 (file)
@@ -81,12 +81,13 @@ basic_access(struct bregs *regs, u8 device, u16 command)
         // translate lchs to lba
         lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
                + (u32)sector - 1);
-        status = ata_cmd_data(device, command, lba, count, segment, offset);
+        status = ata_cmd_data(device, command, lba, count
+                              , MAKE_32_PTR(segment, offset));
     } else {
         // XXX - see if lba access can always be used.
         status = ata_cmd_data_chs(device, command
-                                  , cylinder, head, sector
-                                  , count, segment, offset);
+                                  , cylinder, head, sector, count
+                                  , MAKE_32_PTR(segment, offset));
     }
 
     // Set nb of sector transferred
@@ -145,7 +146,8 @@ emu_access(struct bregs *regs, u8 device, u16 command)
     u16 segment = regs->es;
     u16 offset  = regs->bx;
 
-    u8 status = cdrom_read(device, lba, count*512, segment, offset, before*512);
+    u8 status = cdrom_read(device, lba, count*512
+                           , MAKE_32_PTR(segment, offset), before*512);
     if (status != 0) {
         BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
         regs->al = 0;
@@ -190,9 +192,11 @@ extended_access(struct bregs *regs, u8 device, u16 command)
 
     u8 status;
     if (type == ATA_TYPE_ATA)
-        status = ata_cmd_data(device, command, lba, count, segment, offset);
+        status = ata_cmd_data(device, command, lba, count
+                              , MAKE_32_PTR(segment, offset));
     else
-        status = cdrom_read(device, lba, count*2048, segment, offset, 0);
+        status = cdrom_read(device, lba, count*2048
+                            , MAKE_32_PTR(segment, offset), 0);
 
     SET_INT13EXT(regs, count, GET_EBDA(ata.trsfsectors));
 
index 4759a08..1dea4b6 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "ioport.h" // insb
 
+// Low level macros for reading/writing memory via a segment selector.
 #define READ8_SEG(SEG, var) ({                                          \
     u8 __value;                                                         \
     __asm__ __volatile__("movb %%" #SEG ":%1, %b0"                      \
     __asm__ __volatile__("movl %0, %%" #SEG ":%1"       \
                          : : "r"(value), "m"(var))
 
+// Low level macros for getting/setting a segment register.
+#define __SET_SEG(SEG, value)                                   \
+    __asm__ __volatile__("movw %w0, %%" #SEG : : "r"(value))
+#define __GET_SEG(SEG) ({                                       \
+    u16 __seg;                                                  \
+    __asm__ __volatile__("movw %%" #SEG ", %w0" : "=r"(__seg)); \
+    __seg;})
+
+// Macros for automatically choosing the appropriate memory size
+// access method.
 extern void __force_link_error__unknown_type();
 
 #define __GET_VAR(seg, var) ({                                  \
@@ -58,74 +69,95 @@ extern void __force_link_error__unknown_type();
             __force_link_error__unknown_type();                   \
     } while (0)
 
-#define __SET_SEG(SEG, value)                                   \
-    __asm__ __volatile__("movw %w0, %%" #SEG : : "r"(value))
-#define __GET_SEG(SEG) ({                                       \
-    u16 __seg;                                                  \
-    __asm__ __volatile__("movw %%" #SEG ", %w0" : "=r"(__seg)); \
-    __seg;})
-
-#define GET_FARVAR(seg, var) ({                 \
+// Macros for accessing a variable in another segment.  (They
+// automatically update the %es segment and then make the appropriate
+// access.)
+#define __GET_FARVAR(seg, var) ({               \
     SET_SEG(ES, (seg));                         \
     GET_VAR(ES, (var)); })
-#define SET_FARVAR(seg, var, val) do {          \
+#define __SET_FARVAR(seg, var, val) do {        \
         typeof(var) __sfv_val = (val);          \
         SET_SEG(ES, (seg));                     \
         SET_VAR(ES, (var), __sfv_val);          \
     } while (0)
 
-#define PTR_TO_SEG(p) ((((u32)(p)) >> 4) & 0xf000)
-#define PTR_TO_OFFSET(p) (((u32)(p)) & 0xffff)
-
+// Macros for accesssing a 32bit pointer from 16bit mode.  (They
+// automatically update the %es segment, break the pointer into
+// segment/offset, and then make the access.)
 #define __GET_FARPTR(ptr) ({                                            \
-    typeof (&(ptr)) __ptr;                                              \
+    typeof (&(ptr)) __ptr = (ptr);                                      \
     GET_FARVAR(PTR_TO_SEG(__ptr), *(typeof __ptr)PTR_TO_OFFSET(__ptr)); })
-#define __SET_FARVAR(ptr, val) do {                                     \
-        typeof (&(ptr)) __ptr;                                          \
+#define __SET_FARPTR(ptr, val) do {                                     \
+        typeof (&(ptr)) __ptr = (ptr);                                  \
         SET_FARVAR(PTR_TO_SEG(__ptr), *(typeof __ptr)PTR_TO_OFFSET(__ptr) \
                    , (val));                                            \
     } while (0)
 
+// Macros for converting to/from 32bit style pointers to their
+// equivalent 16bit segment/offset values.
+#define PTR_TO_SEG(p) (((u32)(p)) >> 4)
+#define PTR_TO_OFFSET(p) (((u32)(p)) & 0xf)
+#define MAKE_32_PTR(seg,off) ((void*)(((seg)<<4)+(off)))
+
+
 #ifdef MODE16
+
+// Definitions when in 16 bit mode.
+#define GET_FARVAR(seg, var) __GET_FARVAR((seg), (var))
+#define SET_FARVAR(seg, var, val) __SET_FARVAR((seg), (var), (val))
 #define GET_VAR(seg, var) __GET_VAR(seg, (var))
 #define SET_VAR(seg, var, val) __SET_VAR(seg, (var), (val))
 #define SET_SEG(SEG, value) __SET_SEG(SEG, (value))
 #define GET_SEG(SEG) __GET_SEG(SEG)
 #define GET_FARPTR(ptr) __GET_FARPTR(ptr)
 #define SET_FARPTR(ptr, val) __SET_FARPTR((ptr), (val))
+
+static inline void insb_far(u16 port, void *farptr, u16 count) {
+    SET_SEG(ES, PTR_TO_SEG(farptr));
+    insb(port, (u8*)PTR_TO_OFFSET(farptr), count);
+}
+static inline void insw_far(u16 port, void *farptr, u16 count) {
+    SET_SEG(ES, PTR_TO_SEG(farptr));
+    insw(port, (u16*)PTR_TO_OFFSET(farptr), count);
+}
+static inline void insl_far(u16 port, void *farptr, u16 count) {
+    SET_SEG(ES, PTR_TO_SEG(farptr));
+    insl(port, (u32*)PTR_TO_OFFSET(farptr), count);
+}
+static inline void outsb_far(u16 port, void *farptr, u16 count) {
+    SET_SEG(ES, PTR_TO_SEG(farptr));
+    outsb(port, (u8*)PTR_TO_OFFSET(farptr), count);
+}
+static inline void outsw_far(u16 port, void *farptr, u16 count) {
+    SET_SEG(ES, PTR_TO_SEG(farptr));
+    outsw(port, (u16*)PTR_TO_OFFSET(farptr), count);
+}
+static inline void outsl_far(u16 port, void *farptr, u16 count) {
+    SET_SEG(ES, PTR_TO_SEG(farptr));
+    outsl(port, (u32*)PTR_TO_OFFSET(farptr), count);
+}
+
 #else
+
 // In 32-bit mode there is no need to mess with the segments.
+#define GET_FARVAR(seg, var) \
+    (*((typeof(&(var)))MAKE_32_PTR((seg), (u32)&(var))))
+#define SET_FARVAR(seg, var, val) \
+    do { GET_FARVAR((seg), (var)) = (val); } while (0)
 #define GET_VAR(seg, var) (var)
 #define SET_VAR(seg, var, val) do { (var) = (val); } while (0)
 #define SET_SEG(SEG, value) ((void)(value))
 #define GET_SEG(SEG) 0
 #define GET_FARPTR(ptr) (ptr)
 #define SET_FARPTR(ptr, val) do { (var) = (val); } while (0)
-#endif
 
-static inline void insb_seg(u16 port, u16 segment, u16 offset, u16 count) {
-    SET_SEG(ES, segment);
-    insb(port, (u8*)(offset+0), count);
-}
-static inline void insw_seg(u16 port, u16 segment, u16 offset, u16 count) {
-    SET_SEG(ES, segment);
-    insw(port, (u16*)(offset+0), count);
-}
-static inline void insl_seg(u16 port, u16 segment, u16 offset, u16 count) {
-    SET_SEG(ES, segment);
-    insl(port, (u32*)(offset+0), count);
-}
-static inline void outsb_seg(u16 port, u16 segment, u16 offset, u16 count) {
-    SET_SEG(ES, segment);
-    outsb(port, (u8*)(offset+0), count);
-}
-static inline void outsw_seg(u16 port, u16 segment, u16 offset, u16 count) {
-    SET_SEG(ES, segment);
-    outsw(port, (u16*)(offset+0), count);
-}
-static inline void outsl_seg(u16 port, u16 segment, u16 offset, u16 count) {
-    SET_SEG(ES, segment);
-    outsl(port, (u32*)(offset+0), count);
-}
+#define insb_far(port, farptr, count) insb(port, farptr, count)
+#define insw_far(port, farptr, count) insw(port, farptr, count)
+#define insl_far(port, farptr, count) insl(port, farptr, count)
+#define outsb_far(port, farptr, count) outsb(port, farptr, count)
+#define outsw_far(port, farptr, count) outsw(port, farptr, count)
+#define outsl_far(port, farptr, count) outsl(port, farptr, count)
+
+#endif
 
 #endif // farptr.h