| 1 | /* $Id: writeatatest.c 73 2015-12-20 21:17:34Z bird $ */
 | 
|---|
| 2 | /** @file
 | 
|---|
| 3 |  * Does a little write test.
 | 
|---|
| 4 |  */
 | 
|---|
| 5 | 
 | 
|---|
| 6 | /*
 | 
|---|
| 7 |  * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * This program is free software; you can redistribute it and/or modify
 | 
|---|
| 10 |  * it under the terms of the GNU General Public License as published by
 | 
|---|
| 11 |  * the Free Software Foundation; either version 3 of the License, or
 | 
|---|
| 12 |  * (at your option) any later version.
 | 
|---|
| 13 |  *
 | 
|---|
| 14 |  * This program is distributed in the hope that it will be useful,
 | 
|---|
| 15 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 16 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 17 |  * GNU General Public License for more details.
 | 
|---|
| 18 |  *
 | 
|---|
| 19 |  * You should have received a copy of the GNU General Public License
 | 
|---|
| 20 |  * along with This program.  If not, see <http://www.gnu.org/licenses/>
 | 
|---|
| 21 |  *
 | 
|---|
| 22 |  */
 | 
|---|
| 23 | 
 | 
|---|
| 24 | 
 | 
|---|
| 25 | /*********************************************************************************************************************************
 | 
|---|
| 26 | *   Header Files                                                                                                                 *
 | 
|---|
| 27 | *********************************************************************************************************************************/
 | 
|---|
| 28 | #include <stdarg.h>
 | 
|---|
| 29 | #include <stdio.h>
 | 
|---|
| 30 | #include <stdlib.h>
 | 
|---|
| 31 | #include <string.h>
 | 
|---|
| 32 | #include <stdint.h>
 | 
|---|
| 33 | #include <io.h>
 | 
|---|
| 34 | #include <conio.h>
 | 
|---|
| 35 | #include "atalib.h"
 | 
|---|
| 36 | 
 | 
|---|
| 37 | 
 | 
|---|
| 38 | /*********************************************************************************************************************************
 | 
|---|
| 39 | *   Structures and Typedefs                                                                                                      *
 | 
|---|
| 40 | *********************************************************************************************************************************/
 | 
|---|
| 41 | typedef struct REGS16
 | 
|---|
| 42 | {
 | 
|---|
| 43 |     uint16_t    ax;     /**<  0 */
 | 
|---|
| 44 |     uint16_t    cx;     /**<  2 */
 | 
|---|
| 45 |     uint16_t    dx;     /**<  4 */
 | 
|---|
| 46 |     uint16_t    si;     /**<  6 */
 | 
|---|
| 47 |     uint16_t    di;     /**<  8 */
 | 
|---|
| 48 |     uint16_t    es;     /**< 10 */
 | 
|---|
| 49 |     uint16_t    efl;    /**< 12 */
 | 
|---|
| 50 |     uint16_t    ds;     /**< 14 */
 | 
|---|
| 51 |     uint16_t    bx;     /**< 16 */
 | 
|---|
| 52 | } REGS16;
 | 
|---|
| 53 | 
 | 
|---|
| 54 | #define X86_EFL_CF 1
 | 
|---|
| 55 | 
 | 
|---|
| 56 | 
 | 
|---|
| 57 | /*********************************************************************************************************************************
 | 
|---|
| 58 | *   Global Variables                                                                                                             *
 | 
|---|
| 59 | *********************************************************************************************************************************/
 | 
|---|
| 60 | uint8_t  g_bDrv        = 0x80;
 | 
|---|
| 61 | 
 | 
|---|
| 62 | 
 | 
|---|
| 63 | /*
 | 
|---|
| 64 |  * INT13h access methods
 | 
|---|
| 65 |  * INT13h access methods
 | 
|---|
| 66 |  * INT13h access methods
 | 
|---|
| 67 |  */
 | 
|---|
| 68 | 
 | 
|---|
| 69 | void BiosCall13(REGS16 *pRegs);
 | 
|---|
| 70 | #pragma aux BiosCall13 = \
 | 
|---|
| 71 |     "push   ax" \
 | 
|---|
| 72 |     "push   cx" \
 | 
|---|
| 73 |     "push   dx" \
 | 
|---|
| 74 |     "push   bp" \
 | 
|---|
| 75 |     "push   si" \
 | 
|---|
| 76 |     "push   di" \
 | 
|---|
| 77 |     "push   es" \
 | 
|---|
| 78 |     "push   bx" \
 | 
|---|
| 79 |     "push   ds" \
 | 
|---|
| 80 |     \
 | 
|---|
| 81 |     "mov    ax,  [bx]" \
 | 
|---|
| 82 |     "mov    cx,  [bx +  2]" \
 | 
|---|
| 83 |     "mov    dx,  [bx +  4]" \
 | 
|---|
| 84 |     "mov    si,  [bx +  6]" \
 | 
|---|
| 85 |     "mov    di,  [bx +  8]" \
 | 
|---|
| 86 |     "mov    es,  [bx + 10]" \
 | 
|---|
| 87 |     "push   word ptr [bx + 12]" \
 | 
|---|
| 88 |     "popf" \
 | 
|---|
| 89 |     "push   word ptr [bx + 14]" \
 | 
|---|
| 90 |     "push   word ptr [bx + 16]" \
 | 
|---|
| 91 |     "pop    bx" \
 | 
|---|
| 92 |     "pop    ds" \
 | 
|---|
| 93 |     \
 | 
|---|
| 94 |     "int    13h"\
 | 
|---|
| 95 |     \
 | 
|---|
| 96 |     "push   ds" \
 | 
|---|
| 97 |     "push   bx" \
 | 
|---|
| 98 |     "mov    bp, sp" \
 | 
|---|
| 99 |     "mov    ds, [bp + 4]" \
 | 
|---|
| 100 |     "mov    bx, [bp + 6]" \
 | 
|---|
| 101 |     "mov    [bx], ax" \
 | 
|---|
| 102 |     "mov    [bx +  2], cx" \
 | 
|---|
| 103 |     "mov    [bx +  4], dx" \
 | 
|---|
| 104 |     "mov    [bx +  6], si" \
 | 
|---|
| 105 |     "mov    [bx +  8], di" \
 | 
|---|
| 106 |     "mov    [bx + 10], es" \
 | 
|---|
| 107 |     "pushf" \
 | 
|---|
| 108 |     "pop    ax" \
 | 
|---|
| 109 |     "mov    [bx + 12], ax" \
 | 
|---|
| 110 |     "pop    ax" \
 | 
|---|
| 111 |     "mov    [bx + 14], ax" \
 | 
|---|
| 112 |     "pop    ax" \
 | 
|---|
| 113 |     "mov    [bx + 16], ax" \
 | 
|---|
| 114 |     \
 | 
|---|
| 115 |     "pop    ds" \
 | 
|---|
| 116 |     "pop    bx" \
 | 
|---|
| 117 |     "pop    es" \
 | 
|---|
| 118 |     "pop    di" \
 | 
|---|
| 119 |     "pop    si" \
 | 
|---|
| 120 |     "pop    bp" \
 | 
|---|
| 121 |     "pop    dx" \
 | 
|---|
| 122 |     "pop    cx" \
 | 
|---|
| 123 |     "pop    ax" \
 | 
|---|
| 124 |     parm [bx];
 | 
|---|
| 125 | 
 | 
|---|
| 126 | 
 | 
|---|
| 127 | int Int13hInit(void)
 | 
|---|
| 128 | {
 | 
|---|
| 129 |     REGS16 Regs;
 | 
|---|
| 130 |     memset(&Regs, 0, sizeof(Regs));
 | 
|---|
| 131 |     Regs.ax = 0x0800;
 | 
|---|
| 132 |     Regs.dx = g_bDrv;
 | 
|---|
| 133 |     BiosCall13(&Regs);
 | 
|---|
| 134 |     /** @todo check for errors.   */
 | 
|---|
| 135 |     g_cHeads = (Regs.dx >> 8) + 1;
 | 
|---|
| 136 |     g_cSectorsPerTrack = Regs.cx & 0x3f;
 | 
|---|
| 137 |     g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2);
 | 
|---|
| 138 |     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
 | 
|---|
| 139 | 
 | 
|---|
| 140 |     printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n",
 | 
|---|
| 141 |            g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
 | 
|---|
| 142 |     if (!(Regs.efl & X86_EFL_CF))
 | 
|---|
| 143 |         return 0;
 | 
|---|
| 144 |     fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax);
 | 
|---|
| 145 |     return -1;
 | 
|---|
| 146 | }
 | 
|---|
| 147 | 
 | 
|---|
| 148 | void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs)
 | 
|---|
| 149 | {
 | 
|---|
| 150 |     uint16_t iRem = iSector % g_cSectorsPerCylinder;
 | 
|---|
| 151 |     uint16_t iCyl = iSector / g_cSectorsPerCylinder;
 | 
|---|
| 152 |     pRegs->cx  = iCyl << 8;
 | 
|---|
| 153 |     pRegs->cx |= (iCyl >> 2) & 0xc0;
 | 
|---|
| 154 |     pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f;
 | 
|---|
| 155 |     pRegs->dx &= UINT16_C(0x00ff);
 | 
|---|
| 156 |     pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8;
 | 
|---|
| 157 | }
 | 
|---|
| 158 | 
 | 
|---|
| 159 | int Int13hReadSector(uint32_t iSector, void *pvBuf)
 | 
|---|
| 160 | {
 | 
|---|
| 161 |     REGS16   Regs;
 | 
|---|
| 162 |     memset(&Regs, 0, sizeof(Regs));
 | 
|---|
| 163 |     Regs.ax = 0x0201;
 | 
|---|
| 164 |     Regs.dx = g_bDrv;
 | 
|---|
| 165 |     Regs.bx = (unsigned)(void __near *)pvBuf;
 | 
|---|
| 166 |     Regs.es = (__segment)pvBuf;
 | 
|---|
| 167 |     SectorNoToInt13(iSector, &Regs);
 | 
|---|
| 168 |     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
 | 
|---|
| 169 |     BiosCall13(&Regs);
 | 
|---|
| 170 |     if (!(Regs.efl & X86_EFL_CF))
 | 
|---|
| 171 |         return 0;
 | 
|---|
| 172 |     fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
 | 
|---|
| 173 |     return -1;
 | 
|---|
| 174 | }
 | 
|---|
| 175 | 
 | 
|---|
| 176 | int Int13hWriteSector(uint32_t iSector, void const *pvBuf)
 | 
|---|
| 177 | {
 | 
|---|
| 178 |     REGS16   Regs;
 | 
|---|
| 179 |     memset(&Regs, 0, sizeof(Regs));
 | 
|---|
| 180 |     Regs.ax = 0x0301;
 | 
|---|
| 181 |     Regs.dx = g_bDrv;
 | 
|---|
| 182 |     Regs.bx = (unsigned)(void const __near *)pvBuf;
 | 
|---|
| 183 |     Regs.es = (__segment)pvBuf;
 | 
|---|
| 184 |     SectorNoToInt13(iSector, &Regs);
 | 
|---|
| 185 |     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
 | 
|---|
| 186 |     BiosCall13(&Regs);
 | 
|---|
| 187 |     if (!(Regs.efl & X86_EFL_CF))
 | 
|---|
| 188 |         return 0;
 | 
|---|
| 189 |     fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
 | 
|---|
| 190 |     return -1;
 | 
|---|
| 191 | }
 | 
|---|
| 192 | 
 | 
|---|
| 193 | 
 | 
|---|
| 194 | 
 | 
|---|
| 195 | int GetDriveParams(uint8_t bDevice)
 | 
|---|
| 196 | {
 | 
|---|
| 197 | #ifdef USE_INT13H
 | 
|---|
| 198 |     return Int13hInit();
 | 
|---|
| 199 | #else
 | 
|---|
| 200 |     return 0;
 | 
|---|
| 201 | #endif
 | 
|---|
| 202 | }
 | 
|---|
| 203 | 
 | 
|---|
| 204 | int ReadSector(uint32_t iSector, void *pvBuf)
 | 
|---|
| 205 | {
 | 
|---|
| 206 | #ifdef USE_INT13H
 | 
|---|
| 207 |     return Int13hReadSector(iSector, pvBuf);
 | 
|---|
| 208 | #else
 | 
|---|
| 209 |     return AtaReadSector(iSector, pvBuf);
 | 
|---|
| 210 | #endif
 | 
|---|
| 211 | }
 | 
|---|
| 212 | 
 | 
|---|
| 213 | int WriteSector(uint32_t iSector, void const *pvBuf)
 | 
|---|
| 214 | {
 | 
|---|
| 215 | #ifdef USE_INT13H
 | 
|---|
| 216 |     return Int13hWriteSector(iSector, pvBuf);
 | 
|---|
| 217 | #else
 | 
|---|
| 218 |     return AtaWriteSector(iSector, pvBuf);
 | 
|---|
| 219 | #endif
 | 
|---|
| 220 | }
 | 
|---|
| 221 | 
 | 
|---|
| 222 | 
 | 
|---|
| 223 | 
 | 
|---|
| 224 | 
 | 
|---|
| 225 | static int usage(void)
 | 
|---|
| 226 | {
 | 
|---|
| 227 |     printf("usage: writetst [sector] [drv]\n");
 | 
|---|
| 228 |     return 1;
 | 
|---|
| 229 | }
 | 
|---|
| 230 | 
 | 
|---|
| 231 | 
 | 
|---|
| 232 | int main(int argc, char **argv)
 | 
|---|
| 233 | {
 | 
|---|
| 234 |     int rc = 1;
 | 
|---|
| 235 | 
 | 
|---|
| 236 |     /*
 | 
|---|
| 237 |      * Parse parameters.
 | 
|---|
| 238 |      */
 | 
|---|
| 239 |     uint32_t iSector = 3;
 | 
|---|
| 240 |     uint8_t  bDevice = ATA_DEV_MASTER;
 | 
|---|
| 241 |     g_bDrv = 0x80;
 | 
|---|
| 242 | 
 | 
|---|
| 243 |     if (argc > 3)
 | 
|---|
| 244 |     {
 | 
|---|
| 245 |         fprintf(stderr, "too many parameters!\n");
 | 
|---|
| 246 |         return usage();
 | 
|---|
| 247 |     }
 | 
|---|
| 248 |     if (argc > 1)
 | 
|---|
| 249 |     {
 | 
|---|
| 250 |         iSector = strtoul(argv[1], NULL, 0);
 | 
|---|
| 251 |         if (   iSector == 0
 | 
|---|
| 252 |             || (iSector >= 32 && iSector < 65535)
 | 
|---|
| 253 |             || iSector > 0x800000 /*4G*/)
 | 
|---|
| 254 |         {
 | 
|---|
| 255 |             fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector);
 | 
|---|
| 256 |             return usage();
 | 
|---|
| 257 |         }
 | 
|---|
| 258 |     }
 | 
|---|
| 259 |     if (argc > 2)
 | 
|---|
| 260 |     {
 | 
|---|
| 261 |         if (AtaInitFromArgv(2, argc, argv) != 0)
 | 
|---|
| 262 |             return usage();
 | 
|---|
| 263 |     }
 | 
|---|
| 264 | 
 | 
|---|
| 265 |     /*
 | 
|---|
| 266 |      * Detect drive parameters.
 | 
|---|
| 267 |      */
 | 
|---|
| 268 |     if (GetDriveParams(bDevice) == 0)
 | 
|---|
| 269 |     {
 | 
|---|
| 270 |         static uint8_t s_abSaved[512];
 | 
|---|
| 271 |         if (ReadSector(iSector, s_abSaved) == 0)
 | 
|---|
| 272 |         {
 | 
|---|
| 273 |             static uint8_t s_abWrite[512];
 | 
|---|
| 274 |             unsigned i;
 | 
|---|
| 275 |             unsigned cTries;
 | 
|---|
| 276 |             //unsigned cMaxTries = 20;
 | 
|---|
| 277 |             unsigned cMaxTries = 1;
 | 
|---|
| 278 | 
 | 
|---|
| 279 |             for (i = 0; i < 512; i++)
 | 
|---|
| 280 |                 s_abWrite[i] = (uint8_t)i;
 | 
|---|
| 281 | 
 | 
|---|
| 282 |             for (cTries = 0; cTries < cMaxTries && rc != 0; cTries++)
 | 
|---|
| 283 |             {
 | 
|---|
| 284 |                 if (WriteSector(iSector, s_abWrite) == 0)
 | 
|---|
| 285 |                 {
 | 
|---|
| 286 |                     static uint8_t s_abReadBack[512];
 | 
|---|
| 287 | 
 | 
|---|
| 288 |                     if (ReadSector(iSector, s_abReadBack) == 0)
 | 
|---|
| 289 |                     {
 | 
|---|
| 290 |                         for (i = 0; i < 512; i++)
 | 
|---|
| 291 |                             s_abWrite[i] = (uint8_t)i;
 | 
|---|
| 292 | 
 | 
|---|
| 293 |                         if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0)
 | 
|---|
| 294 |                         {
 | 
|---|
| 295 |                             rc = 0;
 | 
|---|
| 296 |                             printf("wrote sector and successfully read it back\n");
 | 
|---|
| 297 |                         }
 | 
|---|
| 298 |                         else if (cTries >= cMaxTries - 1)
 | 
|---|
| 299 |                         {
 | 
|---|
| 300 |                             unsigned cErrors = 0;
 | 
|---|
| 301 |                             fprintf(stderr, "read back doesn't match what was written:\n");
 | 
|---|
| 302 |                             for (i = 0; i < 512; i++)
 | 
|---|
| 303 |                                 if (s_abReadBack[i] != (uint8_t)i)
 | 
|---|
| 304 |                                 {
 | 
|---|
| 305 |                                     fprintf(stderr,  "  %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]);
 | 
|---|
| 306 |                                     if ((cErrors % 5) == 4)
 | 
|---|
| 307 |                                         fprintf(stderr, "\n");
 | 
|---|
| 308 |                                     cErrors++;
 | 
|---|
| 309 |                                     if (cErrors > 5 * 10)
 | 
|---|
| 310 |                                         break;
 | 
|---|
| 311 |                                 }
 | 
|---|
| 312 |                             if ((cErrors % 5) != 0)
 | 
|---|
| 313 |                                 fprintf(stderr, "\n");
 | 
|---|
| 314 |                         }
 | 
|---|
| 315 |                     }
 | 
|---|
| 316 | 
 | 
|---|
| 317 |                 }
 | 
|---|
| 318 |             }
 | 
|---|
| 319 | 
 | 
|---|
| 320 |             /* restore */
 | 
|---|
| 321 |             WriteSector(iSector, s_abSaved);
 | 
|---|
| 322 |         }
 | 
|---|
| 323 |     }
 | 
|---|
| 324 | 
 | 
|---|
| 325 | 
 | 
|---|
| 326 |     return rc;
 | 
|---|
| 327 | }
 | 
|---|
| 328 | 
 | 
|---|