Changeset 73 for hacks/xtide/atalib.c


Ignore:
Timestamp:
Dec 20, 2015, 10:17:34 PM (10 years ago)
Author:
bird
Message:

xtide util hacking.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • hacks/xtide/atalib.c

    r72 r73  
    3333#include <io.h>
    3434#include <conio.h>
    35 
    36 /*********************************************************************************************************************************
    37 *   Structures and Typedefs                                                                                                      *
    38 *********************************************************************************************************************************/
    39 typedef struct REGS16
    40 {
    41     uint16_t    ax;     /**<  0 */
    42     uint16_t    cx;     /**<  2 */
    43     uint16_t    dx;     /**<  4 */
    44     uint16_t    si;     /**<  6 */
    45     uint16_t    di;     /**<  8 */
    46     uint16_t    es;     /**< 10 */
    47     uint16_t    efl;    /**< 12 */
    48     uint16_t    ds;     /**< 14 */
    49     uint16_t    bx;     /**< 16 */
    50 } REGS16;
    51 
    52 #define X86_EFL_CF 1
    53 
    54 /* The necessary I/O ports, indexed by "bus". */
    55 #define ATA_PORT_SHIFT      1 /* For XT-CF trick */
    56 #define ATA_REG_DATA(x)             (x)
    57 #define ATA_REG_FEATURES(x)         ((x) + (1 << ATA_PORT_SHIFT))
    58 #define ATA_REG_SECTOR_COUNT(x)     ((x) + (2 << ATA_PORT_SHIFT))
    59 
    60 #define ATA_REG_SECTOR_NUMBER(x)    ((x) + (3 << ATA_PORT_SHIFT))
    61 #define ATA_REG_CYLINDER_LOW(x)     ((x) + (4 << ATA_PORT_SHIFT))
    62 #define ATA_REG_CYLINDER_HIGH(x)    ((x) + (5 << ATA_PORT_SHIFT))
    63 #define ATA_REG_HEAD(x)             ((x) + (6 << ATA_PORT_SHIFT))
    64 
    65 #define ATA_REG_LBA_0_7(x)          ((x) + (3 << ATA_PORT_SHIFT))
    66 #define ATA_REG_LBA_8_15(x)         ((x) + (4 << ATA_PORT_SHIFT))
    67 #define ATA_REG_LBA_16_23(x)        ((x) + (5 << ATA_PORT_SHIFT))
    68 #define ATA_REG_LBA_24_27_MODE(x)   ((x) + (6 << ATA_PORT_SHIFT))
    69 #define ATA_LBA_MODE                UINT8_C(0x40) /**< Selects LBA mode in ATA_REG_LBA_24_27_MODE. */
    70 
    71 #define ATA_REG_DEVICE_SELECT(x)    ((x) + (6 << ATA_PORT_SHIFT))
    72 #define ATA_REG_COMMAND(x)          ((x) + (7 << ATA_PORT_SHIFT))
    73 
    74 
    75 #define ATA_REG_STATUS(x)           ATA_REG_COMMAND(x)
    76 #define ATA_REG_ALT_STATUS(x)       ATA_REG_CONTROL(x)
    77 #define ATA_STS_BUSY                UINT8_C(0x80)
    78 #define ATA_STS_DRDY                UINT8_C(0x40)
    79 #define ATA_STS_DF                  UINT8_C(0x20)
    80 #define ATA_STS_DSC                 UINT8_C(0x10)
    81 #define ATA_STS_DRQ                 UINT8_C(0x08)
    82 #define ATA_STS_CORR                UINT8_C(0x04)
    83 #define ATA_STS_IDX                 UINT8_C(0x02)
    84 #define ATA_STS_ERR                 UINT8_C(0x01)
    85 
    86 #define ATA_REG_ERROR(x)            ATA_REG_FEATURES(x)
    87 #define ATA_ERR_RSVR                UINT8_C(0x80)
    88 #define ATA_ERR_UNC                 UINT8_C(0x40)
    89 #define ATA_ERR_MC                  UINT8_C(0x20)
    90 #define ATA_ERR_IDNF                UINT8_C(0x10)
    91 #define ATA_ERR_MCR                 UINT8_C(0x08)
    92 #define ATA_ERR_ABRT                UINT8_C(0x04)
    93 #define ATA_ERR_TKNONF              UINT8_C(0x02)
    94 #define ATA_ERR_AMNF                UINT8_C(0x01)
    95 
    96 #define ATA_REG_CONTROL(x)          ((x) + (14 << ATA_PORT_SHIFT))
    97 #define ATA_CTL_IEN                 UINT8_C(0x02) /**< Interrupt enable. */
    98 #define ATA_CTL_SRST                UINT8_C(0x04) /**< software reset */
    99 
    100 #define ATA_CMD_NOP                 UINT8_C(0x00)
    101 #define ATA_CMD_READ_SECTORS        UINT8_C(0x20)
    102 #define ATA_CMD_READ_SECTORS_NR     UINT8_C(0x21)
    103 #define ATA_CMD_READ_LONG           UINT8_C(0x22)
    104 #define ATA_CMD_READ_LONG_NR        UINT8_C(0x23)
    105 #define ATA_CMD_WRITE_SECTORS       UINT8_C(0x30)
    106 #define ATA_CMD_WRITE_SECTORS_NR    UINT8_C(0x31)
    107 #define ATA_CMD_WRITE_LONG          UINT8_C(0x32)
    108 #define ATA_CMD_WRITE_LONG_NR       UINT8_C(0x33)
    109 #define ATA_CMD_INIT_DEVICE_PARAMS  UINT8_C(0x91)
    110 #define ATA_CMD_SET_FEATURES        UINT8_C(0xef)
    111 #define ATA_CMD_IDENTIFY_DEVICE     UINT8_C(0xec)
    112 
    113 
    114 #define ATA_DEV_MASTER              UINT8_C(0x00)  /**< Master device selection bit value. */
    115 #define ATA_DEV_SLAVE               UINT8_C(0x10)  /**< Slave device selection bit value. */
    116 
    117 #define ATA_FEATURE_EN_8BIT_DATA        UINT8_C(0x01)
    118 #define ATA_FEATURE_DI_8BIT_DATA        UINT8_C(0x81)
    119 #define ATA_FEATURE_EN_WRITE_CACHE      UINT8_C(0x02)
    120 #define ATA_FEATURE_DI_WRITE_CACHE      UINT8_C(0x82)
    121 #define ATA_FEATURE_SET_XFERMODE        UINT8_C(0x03)
    122 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT             UINT8_C(0x00)
    123 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY    UINT8_C(0x01)
    124 #define ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG            UINT8_C(0x08)
    125 #define ATA_FV_XFERMODE_SWDMA_MODE_XXX_FLAG          UINT8_C(0x10)
    126 #define ATA_FV_XFERMODE_MWDMA_MODE_XXX_FLAG          UINT8_C(0x20)
    127 
    128 /** Delay a bit by reading PIC mask. Should take 4-5 bus cycles,
    129  * and thus be more than the required 400ns delay on old computers. */
    130 #define ATA_DELAY_400NS()   do { inp(0x21); } while (0)
    131 
     35#include "atalib.h"
     36
     37#define STR_TUPLE(a_szStr) a_szStr, sizeof(a_szStr) - 1
    13238
    13339
     
    13541*   Global Variables                                                                                                             *
    13642*********************************************************************************************************************************/
    137 uint16_t g_uBasePort   = 0x300;
    138 uint16_t g_uPortShift  = 1;
     43uint16_t g_uBasePort;
     44uint16_t g_uCtrlPort;
     45uint16_t g_uPortShift;
     46uint8_t  g_bDevice;
    13947uint8_t  g_fUseLbaMode = 1;
    140 uint8_t  g_f8BitData   = 1;
    141 uint8_t  g_bDevice     = ATA_DEV_MASTER;
    142 uint8_t  g_bDrv        = 0x80;
    143 
     48uint8_t  g_f8BitData;
     49uint8_t  g_fSupportsSetFeature8BitData;
     50uint8_t  g_fSupportsSetFeatureWriteCache;
     51uint8_t  g_fSupportsSetFeatureXferMode;
     52int8_t   g_fSupportsReadBuffer = -1;
     53int8_t   g_fSupportsWriteBuffer = -1;
    14454
    14555uint16_t g_cHeads;
     
    307217}
    308218
    309 ////static uint8_t AtaWaitForDataRequest(size_t cbLeft)
    310 ////{
    311 ////    uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    312 ////    uint8_t  bStsFirst = inp(uAltStsPort);
    313 ////    uint8_t  bSts = bStsFirst;
    314 ////    uint32_t cLoops = 0;
    315 ////    do
    316 ////    {
    317 ////        if (++cLoops & 0xffff)
    318 ////        {
    319 ////static unsigned x = 0;
    320 ////if (x < 16)
    321 ////{
    322 ////    printf("AtaWaitForDataRequest: bFirst=%#x bLast=%#x cbLeft=%#x\n", bStsFirst, bSts, cbLeft);
    323 ////    x++;
    324 ////}
    325 ////            break;
    326 ////        }
    327 ////        bSts = inp(uAltStsPort);
    328 ////    } while (!(bSts & (ATA_STS_DRQ | ATA_STS_ERR)));
    329 ////    return bSts;
    330 ////}
    331 
    332 void xchg(uint8_t volatile *pb);
    333 #pragma aux xchg = \
    334     "xchg [si], cx" \
    335     "xchg [si], cx" \
    336     "xchg [si], cx" \
    337     "xchg [si], cx" \
    338     parm [si] \
    339     modify exact [cx];
    340 
    341219void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
    342220{
    343 //    uint16_t        uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    344221    uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
    345 
     222    uint16_t const   *pu16      = (uint16_t const *)pvBuf;
     223
     224    cb >>= 1;
    346225    if (f8BitData)
    347226    {
    348 #if 0
    349         uint8_t const   * volatile pbSrc = (uint8_t const *)pvBuf;
    350         uint8_t volatile ab[64];
    351         uint8_t volatile *pb = &ab[0];
    352         while (((uintptr_t)pb & 0x1f) != 0x1f)
    353             pb++;
    354         //uint8_t  bSts1, bSts2;
    355 inp(0x21);
    356 xchg(pb);
    357 
    358         while (cb-- > 0)
    359         {
    360             uint8_t b = *pbSrc++;
    361             xchg(pb);
    362             outp(uDataPort, b);
    363             xchg(pb);
    364             b = *pbSrc++;
    365             xchg(pb);
    366 //inp(0x21);
    367             outp(uDataPort, b);
    368             xchg(pb);
    369 //inp(0x21);
    370             //if (cb < 30)
    371             //{
    372             //    if ((cb & 3) == 3)
    373             //        printf("bSts1=%#x bSts2=%#x ", bSts1, bSts2);
    374             //    else
    375             //        printf("bSts1=%#x bSts2=%#x\n", bSts1, bSts2);
    376             //}
    377         }
    378 inp(0x21);
    379 #else
    380         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    381         cb >>= 1;
    382227        while (cb-- > 0)
    383228        {
     
    386231            outp(uDataPort, (uint8_t)(u16 >> 8));
    387232        }
    388 #endif
    389233    }
    390234    else
    391     {
    392         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    393         cb >>= 1;
    394235        while (cb-- > 0)
    395             outp(uDataPort, *pu16++);
    396     }
     236            outpw(uDataPort, *pu16++);
    397237}
    398238
     
    403243        return AtaError(bSts, "Prepping for reading sector %lu", iSector);
    404244
    405 printf("AtaReadSector #2\n");
    406245    bSts = AtaSelectDevice(g_bDevice);
    407246    if (bSts & ATA_STS_ERR)
    408247        return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
    409248
    410 //printf("AtaReadSector #3\n");
    411249    outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
    412250    outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
    413251    AtaSetSectorAddress(iSector, g_bDevice);
    414252
    415 //printf("AtaReadSector #4\n");
    416253    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
    417254    if (bSts & ATA_STS_ERR)
     
    421258        return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
    422259
    423 
    424 //printf("AtaReadSector #5\n");
    425260    AtaReadData(pvBuf, 512, g_f8BitData);
    426 //printf("AtaReadSector #6: bSts=%#x\n", inp(ATA_REG_ALT_STATUS(g_uBasePort)));
    427261    bSts = inp(ATA_REG_STATUS(g_uBasePort));
    428     if ((bSts & ATA_STS_DRQ))
     262    if (bSts & ATA_STS_DRQ)
    429263        return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
    430     if ((bSts & ATA_STS_ERR))
     264    if (bSts & ATA_STS_ERR)
    431265        return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
    432266    return 0;
     
    435269int AtaWriteSector(uint32_t iSector, void const *pvBuf)
    436270{
    437 //int x = printf("AtaWriteSector #1\n");
    438271    uint8_t bSts = AtaWaitBusy();
    439272    if (bSts & ATA_STS_ERR)
    440273        return AtaError(bSts, "Prepping for writing sector %lu", iSector);
    441 printf("AtaWriteSector #2\n");
    442274
    443275    bSts = AtaSelectDevice(g_bDevice);
     
    449281    AtaSetSectorAddress(iSector, g_bDevice);
    450282
    451 //printf("AtaWriteSector #3\n");
    452283    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
    453284    if (bSts & ATA_STS_ERR)
     
    456287        return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
    457288
    458 //printf("AtaWriteSector #4\n");
    459289    AtaWriteData(pvBuf, 512, g_f8BitData);
    460 //printf("AtaWriteSector #5\n");
    461290    ATA_DELAY_400NS();
    462291    bSts = AtaWaitBusy();
    463 //printf("AtaWriteSector #6\n");
    464292    if (bSts & ATA_STS_ERR)
    465293        return AtaError(bSts, "writing sector (#2) %lu", iSector);
    466294    if (bSts & ATA_STS_DRQ)
    467295        return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
     296
     297    return 0;
     298}
     299
     300
     301/**
     302 * @param pvBuf     Pointer to a 512-byte buffer.
     303 */
     304int AtaReadBuffer(void *pvBuf, uint8_t fExtraChecks)
     305{
     306    uint8_t bSts;
     307
     308    if (!g_fSupportsReadBuffer)
     309        return -2;
     310
     311    bSts = AtaWaitBusy();
     312    if (bSts & ATA_STS_ERR)
     313        return AtaError(bSts, "Prepping for reading buffer");
     314
     315    bSts = AtaSelectDevice(g_bDevice);
     316    if (bSts & ATA_STS_ERR)
     317        return AtaError(bSts, "Selecting device for reading buffer");
     318
     319    outp(ATA_REG_FEATURES(g_uBasePort),         0);
     320    outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     1); /* ignored */
     321    outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
     322    outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
     323    outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
     324
     325    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_BUFFER);
     326    if (bSts & ATA_STS_ERR)
     327        return AtaError(bSts, "Reading buffer");
     328
     329    if (!(bSts & ATA_STS_DRQ))
     330        return AtaError(bSts, "DRQ not set after reading buffer");
     331
     332    if (!fExtraChecks)
     333        AtaReadData(pvBuf, 512, g_f8BitData);
     334    else
     335        AtaReadData(pvBuf, 512, g_f8BitData);
     336    bSts = inp(ATA_REG_STATUS(g_uBasePort));
     337    if (bSts & ATA_STS_DRQ)
     338        return AtaError(bSts, "DRQ is still set after reading buffer");
     339    if (bSts & ATA_STS_ERR)
     340        return AtaError(bSts, "ERR is set after reading buffer");
     341    return 0;
     342}
     343
     344int AtaWriteBuffer(void const *pvBuf, uint8_t fExtraChecks)
     345{
     346    uint8_t bSts;
     347
     348    if (!g_fSupportsWriteBuffer)
     349        return -2;
     350
     351    bSts = AtaWaitBusy();
     352    if (bSts & ATA_STS_ERR)
     353        return AtaError(bSts, "Prepping for writing buffer");
     354
     355    bSts = AtaSelectDevice(g_bDevice);
     356    if (bSts & ATA_STS_ERR)
     357        return AtaError(bSts, "Selecting device for writing buffer");
     358
     359    outp(ATA_REG_FEATURES(g_uBasePort),         0);
     360    outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     1); /* ignored */
     361    outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
     362    outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
     363    outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
     364
     365    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
     366    if (bSts & ATA_STS_ERR)
     367        return AtaError(bSts, "writing buffer (#1)");
     368    if (!(bSts & ATA_STS_DRQ))
     369        return AtaError(bSts, "DRQ not set after writing buffer (#1)");
     370
     371    if (!fExtraChecks)
     372        AtaWriteData(pvBuf, 512, g_f8BitData);
     373    else
     374        AtaWriteData(pvBuf, 512, g_f8BitData);
     375    ATA_DELAY_400NS();
     376    bSts = AtaWaitBusy();
     377    if (bSts & ATA_STS_ERR)
     378        return AtaError(bSts, "writing buffer (#2)");
     379    if (bSts & ATA_STS_DRQ)
     380        return AtaError(bSts, "DRQ is set after writing buffer (#2)");
    468381
    469382    return 0;
     
    571484}
    572485
    573 
    574 int AtaInit(void)
    575 {
    576     uint8_t bSts = inp(ATA_REG_ALT_STATUS(g_uBasePort));
    577     printf("alt status=");
     486int AtaReInit(void)
     487{
     488    int rc;
     489
     490    /* Reset the controller + devices. */
     491    if (AtaReset() != 0)
     492        return -1;
     493
     494    if (g_fSupportsSetFeature8BitData)
     495    {
     496        if (g_f8BitData)
     497            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
     498        else
     499            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
     500        if (rc != 0)
     501            return rc;
     502    }
     503
     504    /* Try disable write cache. */
     505    if (g_fSupportsSetFeatureWriteCache)
     506    {
     507        rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
     508        if (rc != 0)
     509            return rc;
     510    }
     511
     512    /* Select PIO mode without IORDY. */
     513    if (g_fSupportsSetFeatureXferMode)
     514    {
     515        rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
     516        if (rc != 0)
     517            return rc;
     518    }
     519
     520    return 0;
     521}
     522
     523int AtaInit(uint16_t uBasePort, uint16_t uCtrlPort, uint8_t uPortShift, uint8_t bDevice, uint8_t f8BitData)
     524{
     525    int rc;
     526    uint8_t bSts, bStsAlt;
     527
     528    g_uBasePort  = uBasePort;
     529    g_uCtrlPort  = uCtrlPort;
     530    g_uPortShift = uPortShift;
     531    g_bDevice    = bDevice;
     532    g_f8BitData  = f8BitData;
     533    g_fSupportsSetFeature8BitData = 1;
     534    g_fSupportsSetFeatureWriteCache = 1;
     535    g_fSupportsSetFeatureXferMode = 1;
     536
     537    /* Check whether the two status registers match up. If they don't we
     538       probably don't have a controller at this address. */
     539    inp(ATA_REG_STATUS(g_uBasePort));
     540    bSts    = inp(ATA_REG_STATUS(g_uBasePort));
     541    bStsAlt = inp(ATA_REG_ALT_STATUS(g_uBasePort));
     542    if (bSts != bStsAlt || bSts == 0xff)
     543    {
     544        fprintf(stderr, "Status register differs or is 0xff\n");
     545        fprintf(stderr, "     status=");
     546        AtaPrintStatus(stdout, bSts);
     547        fprintf(stderr, "\n");
     548        fprintf(stderr, " alt status=");
     549        AtaPrintStatus(stdout, bStsAlt);
     550        fprintf(stderr, "\n");
     551        return -1;
     552    }
     553    printf("Pre init status=");
    578554    AtaPrintStatus(stdout, bSts);
    579555    printf("\n");
    580556
    581     bSts = inp(ATA_REG_STATUS(g_uBasePort));
    582     printf("    status=");
    583     AtaPrintStatus(stdout, bSts);
    584     printf("\n");
    585 
    586     if (AtaReset() != 0)
    587         return -1;
    588 
    589     /* Enable 8-bit data transfers (just to be on the safe side). */
    590     AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
    591 
    592     /* Identify the device. */
    593     memset(g_awIdentify, 0, sizeof(g_awIdentify));
    594     if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
    595         return -1;
    596 
    597     /** @todo this is rather simple... */
    598     g_cCylinders = g_awIdentify[1];
    599     g_cHeads     = g_awIdentify[3];
    600     g_cSectorsPerTrack = g_awIdentify[6];
    601     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    602     printf("Device %#x parameters: %u cylinders, %u heads, %u sectors\n",
    603            g_bDevice, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    604 
    605     /* Disable stuff and try select pio modes. */
    606     AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
    607     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
    608     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG | 0);
    609 
    610     return 0;
    611 }
    612 
    613 
    614 
    615 
    616 /*
    617  * INT13h access methods
    618  * INT13h access methods
    619  * INT13h access methods
    620  */
    621 
    622 void BiosCall13(REGS16 *pRegs);
    623 #pragma aux BiosCall13 = \
    624     "push   ax" \
    625     "push   cx" \
    626     "push   dx" \
    627     "push   bp" \
    628     "push   si" \
    629     "push   di" \
    630     "push   es" \
    631     "push   bx" \
    632     "push   ds" \
    633     \
    634     "mov    ax,  [bx]" \
    635     "mov    cx,  [bx +  2]" \
    636     "mov    dx,  [bx +  4]" \
    637     "mov    si,  [bx +  6]" \
    638     "mov    di,  [bx +  8]" \
    639     "mov    es,  [bx + 10]" \
    640     "push   word ptr [bx + 12]" \
    641     "popf" \
    642     "push   word ptr [bx + 14]" \
    643     "push   word ptr [bx + 16]" \
    644     "pop    bx" \
    645     "pop    ds" \
    646     \
    647     "int    13h"\
    648     \
    649     "push   ds" \
    650     "push   bx" \
    651     "mov    bp, sp" \
    652     "mov    ds, [bp + 4]" \
    653     "mov    bx, [bp + 6]" \
    654     "mov    [bx], ax" \
    655     "mov    [bx +  2], cx" \
    656     "mov    [bx +  4], dx" \
    657     "mov    [bx +  6], si" \
    658     "mov    [bx +  8], di" \
    659     "mov    [bx + 10], es" \
    660     "pushf" \
    661     "pop    ax" \
    662     "mov    [bx + 12], ax" \
    663     "pop    ax" \
    664     "mov    [bx + 14], ax" \
    665     "pop    ax" \
    666     "mov    [bx + 16], ax" \
    667     \
    668     "pop    ds" \
    669     "pop    bx" \
    670     "pop    es" \
    671     "pop    di" \
    672     "pop    si" \
    673     "pop    bp" \
    674     "pop    dx" \
    675     "pop    cx" \
    676     "pop    ax" \
    677     parm [bx];
    678 
    679 
    680 int Int13hInit(void)
    681 {
    682     REGS16 Regs;
    683     memset(&Regs, 0, sizeof(Regs));
    684     Regs.ax = 0x0800;
    685     Regs.dx = g_bDrv;
    686     BiosCall13(&Regs);
    687     /** @todo check for errors.   */
    688     g_cHeads = (Regs.dx >> 8) + 1;
    689     g_cSectorsPerTrack = Regs.cx & 0x3f;
    690     g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2);
    691     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    692 
    693     printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n",
    694            g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    695     if (!(Regs.efl & X86_EFL_CF))
    696         return 0;
    697     fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax);
    698     return -1;
    699 }
    700 
    701 void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs)
    702 {
    703     uint16_t iRem = iSector % g_cSectorsPerCylinder;
    704     uint16_t iCyl = iSector / g_cSectorsPerCylinder;
    705     pRegs->cx  = iCyl << 8;
    706     pRegs->cx |= (iCyl >> 2) & 0xc0;
    707     pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f;
    708     pRegs->dx &= UINT16_C(0x00ff);
    709     pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8;
    710 }
    711 
    712 int Int13hReadSector(uint32_t iSector, void *pvBuf)
    713 {
    714     REGS16   Regs;
    715     memset(&Regs, 0, sizeof(Regs));
    716     Regs.ax = 0x0201;
    717     Regs.dx = g_bDrv;
    718     Regs.bx = (unsigned)(void __near *)pvBuf;
    719     Regs.es = (__segment)pvBuf;
    720     SectorNoToInt13(iSector, &Regs);
    721     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
    722     BiosCall13(&Regs);
    723     if (!(Regs.efl & X86_EFL_CF))
    724         return 0;
    725     fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
    726     return -1;
    727 }
    728 
    729 int Int13hWriteSector(uint32_t iSector, void const *pvBuf)
    730 {
    731     REGS16   Regs;
    732     memset(&Regs, 0, sizeof(Regs));
    733     Regs.ax = 0x0301;
    734     Regs.dx = g_bDrv;
    735     Regs.bx = (unsigned)(void const __near *)pvBuf;
    736     Regs.es = (__segment)pvBuf;
    737     SectorNoToInt13(iSector, &Regs);
    738     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
    739     BiosCall13(&Regs);
    740     if (!(Regs.efl & X86_EFL_CF))
    741         return 0;
    742     fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
    743     return -1;
    744 }
    745 
    746 
    747 
    748 int GetDriveParams(void)
    749 {
    750 #ifdef USE_INT13H
    751     return Int13hInit();
     557    for (;;)
     558    {
     559        /* Reset the controller + devices. */
     560        if (AtaReset() != 0)
     561            return -1;
     562
     563        /* Enable 8-bit data transfers (just to be on the safe side). */
     564        if (g_fSupportsSetFeature8BitData)
     565        {
     566            if (g_f8BitData)
     567                rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
     568            else
     569                rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
     570            if (rc != 0)
     571            {
     572                fprintf(stderr,
     573                        f8BitData
     574                        ? "warning: ATA_FEATURE_EN_8BIT_DATA failed, assuming not supported. Retrying in 16-bit mode."
     575                        : "warning: ATA_FEATURE_DI_8BIT_DATA failed, assuming not supported. Retrying.");
     576                g_fSupportsSetFeature8BitData = 0;
     577                g_f8BitData = 0;
     578                continue;
     579            }
     580        }
     581
     582        /* Try disable write cache. */
     583        if (g_fSupportsSetFeatureWriteCache)
     584        {
     585            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
     586            if (rc != 0)
     587            {
     588                fprintf(stderr, "warning: ATA_FEATURE_DI_WRITE_CACHE failed, assuming not supported. Retrying.");
     589                g_fSupportsSetFeatureWriteCache = 0;
     590                continue;
     591            }
     592        }
     593
     594        /* Select PIO mode without IORDY. */
     595        if (g_fSupportsSetFeatureXferMode)
     596        {
     597            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
     598            if (rc != 0)
     599            {
     600                fprintf(stderr, "warning: ATA_FEATURE_SET_XFERMODE = DEFAULT_NO_IORDY failed, assuming not supported. Retrying.");
     601                g_fSupportsSetFeatureXferMode = 0;
     602                continue;
     603            }
     604        }
     605
     606        /* Identify the device. */
     607        memset(g_awIdentify, 0, sizeof(g_awIdentify));
     608        if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
     609            return -1;
     610
     611        /** @todo this is rather simple... */
     612        g_cCylinders = g_awIdentify[1];
     613        g_cHeads     = g_awIdentify[3];
     614        g_cSectorsPerTrack = g_awIdentify[6];
     615        g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
     616        printf("Device %#x at %#x/%#x: %u cylinders, %u heads, %u sectors, %s data\n",
     617               g_bDevice, g_uBasePort, g_uCtrlPort, g_cCylinders, g_cHeads, g_cSectorsPerTrack,
     618               g_f8BitData ? "8-bit" : "16-bit");
     619
     620        /* Figure 5-9 in SanDisk Manual Rev 12.0: */
     621        if (   (g_awIdentify[83] & UINT16_C(0xc00)) == UINT16_C(0x4000)
     622            && (g_awIdentify[84] & UINT16_C(0xc00)) == UINT16_C(0x4000))
     623        {
     624            g_fSupportsWriteBuffer = (g_awIdentify[82] & UINT16_C(0x1000)) != 0;
     625            g_fSupportsReadBuffer  = (g_awIdentify[82] & UINT16_C(0x2000)) != 0;
     626        }
     627        printf("  %s WRITE_BUFFER, %s READ_BUFFER\n",
     628               g_fSupportsWriteBuffer == 1 ? "have" : g_fSupportsWriteBuffer == 0 ? "no" : "uncertain",
     629               g_fSupportsReadBuffer  == 1 ? "have" : g_fSupportsReadBuffer  == 0 ? "no" : "uncertain");
     630    }
     631
     632    return 0;
     633}
     634
     635int AtaArgMatchWithValue(const char *pszArg, const char *pszMatch, size_t cchMatch,
     636                         int cArgs, char **papszArgs, int *piArg, const char **ppszValue)
     637{
     638    if (strncmp(pszArg, pszMatch, cchMatch) == 0)
     639    {
     640        pszArg += cchMatch;
     641        if (!*pszArg)
     642        {
     643            if (*piArg < cArgs)
     644            {
     645                *ppszValue = papszArgs[*piArg];
     646                *piArg += 1;
     647            }
     648            else
     649            {
     650                fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
     651                *ppszValue = NULL;
     652            }
     653            return 1;
     654        }
     655
     656        if (*pszArg == ':' || *pszArg == '=')
     657        {
     658            if (!*pszArg)
     659                fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
     660            *ppszValue = pszArg;
     661            return 1;
     662        }
     663    }
     664
     665    return 0;
     666}
     667
     668int AtaInitFromArgv(int iArg, int cArgs, char **papszArgs)
     669{
     670    uint8_t  bDevice    = ATA_DEV_MASTER;
     671#if 0
     672    uint16_t uBasePort  = 0x1f0;    /* Primary ATA host controller. */
     673    uint16_t uCtrlPort  = 0x3f0;    /* The control block of the primary ATA host controller. */
     674    uint8_t  cShiftPort = 0;
     675    uint8_t  f8BitData  = 0;
    752676#else
    753     return AtaInit();
     677    uint16_t uBasePort  = 0x300;    /* Lo-tech CF-lite. */
     678    uint16_t uCtrlPort  = 0x310;    /* Lo-tech CF-lite. */
     679    uint8_t  cShiftPort = 1;        /* Special Lo-tech CF-lite hack. */
     680    uint8_t  f8BitData  = 1;
    754681#endif
    755 }
    756 
    757 int ReadSector(uint32_t iSector, void *pvBuf)
    758 {
    759 #ifdef USE_INT13H
    760     return Int13hReadSector(iSector, pvBuf);
    761 #else
    762     return AtaReadSector(iSector, pvBuf);
    763 #endif
    764 }
    765 
    766 int WriteSector(uint32_t iSector, void const *pvBuf)
    767 {
    768 #ifdef USE_INT13H
    769     return Int13hWriteSector(iSector, pvBuf);
    770 #else
    771     return AtaWriteSector(iSector, pvBuf);
    772 #endif
    773 }
    774 
    775 
    776 
    777 
    778 static int usage(void)
    779 {
    780     printf("usage: writetst [sector] [drv]\n");
    781     return 1;
    782 }
    783 
    784 
    785 int main(int argc, char **argv)
    786 {
    787     int rc = 1;
    788 
    789     /*
    790      * Parse parameters.
    791      */
    792     uint32_t iSector = 3;
    793     g_bDrv = 0x80;
    794     g_bDevice = ATA_DEV_MASTER;
    795 
    796     if (argc > 3)
    797     {
    798         fprintf(stderr, "too many parameters!\n");
    799         return usage();
    800     }
    801     if (argc > 1)
    802     {
    803         iSector = strtoul(argv[1], NULL, 0);
    804         if (   iSector == 0
    805             || (iSector >= 32 && iSector < 65535)
    806             || iSector > 0x800000 /*4G*/)
    807         {
    808             fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector);
    809             return usage();
    810         }
    811     }
    812     if (argc > 2)
    813     {
    814         unsigned long uTmp = strtoul(argv[2], NULL, 0);
    815         if (uTmp < 0x80 || uTmp > 0x8f)
    816         {
    817             fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp);
    818             return usage();
    819         }
    820         g_bDrv = (uint8_t)uTmp;
    821         g_bDevice = g_bDrv == 0x80 ? ATA_DEV_MASTER : ATA_DEV_SLAVE; /* simplified */
    822     }
    823 
    824     /*
    825      * Detect drive parameters.
    826      */
    827     if (GetDriveParams() == 0)
    828     {
    829         static uint8_t s_abSaved[512];
    830         if (ReadSector(iSector, s_abSaved) == 0)
    831         {
    832             static uint8_t s_abWrite[512];
    833             unsigned i;
    834             unsigned cTries;
    835             //unsigned cMaxTries = 20;
    836             unsigned cMaxTries = 1;
    837 
    838             for (i = 0; i < 512; i++)
    839                 s_abWrite[i] = (uint8_t)i;
    840 
    841             for (cTries = 0; cTries < cMaxTries && rc != 0; cTries++)
     682
     683    while (iArg < cArgs)
     684    {
     685        const char *pszArg = papszArgs[iArg++];
     686        const char *pszValue;
     687        int         iWhich = 0;
     688        if (   (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--base-port"), cArgs, papszArgs, &iArg, &pszValue))
     689            || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-b"), cArgs, papszArgs, &iArg, &pszValue))
     690            || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--ctrl-port"), cArgs, papszArgs, &iArg, &pszValue) * 2)
     691            || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-c"), cArgs, papszArgs, &iArg, &pszValue)          * 2) )
     692         {
     693            unsigned long uTmp = strtoul(pszValue, NULL, 16);
     694            if (uTmp < 16 || uTmp >= 1024)
    842695            {
    843                 if (WriteSector(iSector, s_abWrite) == 0)
    844                 {
    845                     static uint8_t s_abReadBack[512];
    846 
    847                     if (ReadSector(iSector, s_abReadBack) == 0)
    848                     {
    849                         for (i = 0; i < 512; i++)
    850                             s_abWrite[i] = (uint8_t)i;
    851 
    852                         if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0)
    853                         {
    854                             rc = 0;
    855                             printf("wrote sector and successfully read it back\n");
    856                         }
    857                         else if (cTries >= cMaxTries - 1)
    858                         {
    859                             unsigned cErrors = 0;
    860                             fprintf(stderr, "read back doesn't match what was written:\n");
    861                             for (i = 0; i < 512; i++)
    862                                 if (s_abReadBack[i] != (uint8_t)i)
    863                                 {
    864                                     fprintf(stderr,  "  %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]);
    865                                     if ((cErrors % 5) == 4)
    866                                         fprintf(stderr, "\n");
    867                                     cErrors++;
    868                                     if (cErrors > 5 * 10)
    869                                         break;
    870                                 }
    871                             if ((cErrors % 5) != 0)
    872                                 fprintf(stderr, "\n");
    873                         }
    874                     }
    875 
    876                 }
     696                fprintf(stderr, "error: Invalid port number %#lx for %s (valid range 0x010..0x3ff)\n", uTmp, pszArg);
     697                return -1;
    877698            }
    878 
    879             /* restore */
    880             WriteSector(iSector, s_abSaved);
    881         }
    882     }
    883 
    884 
    885     return rc;
    886 }
    887 
     699            if (iWhich == 1)
     700                uBasePort = (uint16_t)uTmp;
     701            else
     702                uCtrlPort = (uint16_t)uTmp;
     703        }
     704        else if (   AtaArgMatchWithValue(pszArg, STR_TUPLE("--port-shift"), cArgs, papszArgs, &iArg, &pszValue)
     705                 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-s"), cArgs, papszArgs, &iArg, &pszValue) )
     706        {
     707            unsigned long uTmp = strtoul(pszValue, NULL, 0);
     708            if (uTmp >= 4)
     709            {
     710                fprintf(stderr, "error: Invalid port shift number %#lx (valid range 0..3)\n", uTmp);
     711                return -1;
     712            }
     713            cShiftPort = (uint8_t)uTmp;
     714        }
     715        else if (   AtaArgMatchWithValue(pszArg, STR_TUPLE("--device"), cArgs, papszArgs, &iArg, &pszValue)
     716                 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-d"), cArgs, papszArgs, &iArg, &pszValue) )
     717        {
     718            unsigned long uTmp = strtoul(pszValue, NULL, 16);
     719            if (   uTmp != ATA_DEV_MASTER
     720                && uTmp != ATA_DEV_SLAVE)
     721            {
     722                fprintf(stderr, "error: Invalid device number %#lx; only %#x (master) or %#x (slave) are allowed.\n",
     723                        uTmp, ATA_DEV_MASTER, ATA_DEV_SLAVE);
     724                return -1;
     725            }
     726            bDevice = (uint8_t)uTmp;
     727        }
     728        else if (   strcmp(pszArg, "--8-bit-data") == 0
     729                 || strcmp(pszArg, "-8") == 0)
     730            f8BitData = 1;
     731        else if (   strcmp(pszArg, "--16-bit-data") == 0
     732                 || strcmp(pszArg, "-16") == 0)
     733            f8BitData = 0;
     734    }
     735
     736    return AtaInit(uBasePort, uCtrlPort, cShiftPort, bDevice, f8BitData);
     737}
     738
Note: See TracChangeset for help on using the changeset viewer.