| 1 | /* $Id: writetest.c 72 2015-12-20 18:29:17Z 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 | #include <stdio.h>
 | 
|---|
| 26 | #include <stdlib.h>
 | 
|---|
| 27 | #include <string.h>
 | 
|---|
| 28 | #include <stdint.h>
 | 
|---|
| 29 | #include <io.h>
 | 
|---|
| 30 | #include <conio.h>
 | 
|---|
| 31 | 
 | 
|---|
| 32 | /*********************************************************************************************************************************
 | 
|---|
| 33 | *   Structures and Typedefs                                                                                                      *
 | 
|---|
| 34 | *********************************************************************************************************************************/
 | 
|---|
| 35 | typedef struct REGS16
 | 
|---|
| 36 | {
 | 
|---|
| 37 |     uint16_t    ax;     /**<  0 */
 | 
|---|
| 38 |     uint16_t    cx;     /**<  2 */
 | 
|---|
| 39 |     uint16_t    dx;     /**<  4 */
 | 
|---|
| 40 |     uint16_t    si;     /**<  6 */
 | 
|---|
| 41 |     uint16_t    di;     /**<  8 */
 | 
|---|
| 42 |     uint16_t    es;     /**< 10 */
 | 
|---|
| 43 |     uint16_t    efl;    /**< 12 */
 | 
|---|
| 44 |     uint16_t    ds;     /**< 14 */
 | 
|---|
| 45 |     uint16_t    bx;     /**< 16 */
 | 
|---|
| 46 | } REGS16;
 | 
|---|
| 47 | 
 | 
|---|
| 48 | #define X86_EFL_CF 1
 | 
|---|
| 49 | 
 | 
|---|
| 50 | 
 | 
|---|
| 51 | /*********************************************************************************************************************************
 | 
|---|
| 52 | *   Global Variables                                                                                                             *
 | 
|---|
| 53 | *********************************************************************************************************************************/
 | 
|---|
| 54 | uint8_t  g_bDrv;
 | 
|---|
| 55 | uint16_t g_cHeads;
 | 
|---|
| 56 | uint8_t  g_cSectorsPerTrack;
 | 
|---|
| 57 | uint16_t g_cCylinders;
 | 
|---|
| 58 | uint16_t g_cSectorsPerCylinder;
 | 
|---|
| 59 | 
 | 
|---|
| 60 | 
 | 
|---|
| 61 | void BiosCall13(REGS16 *pRegs);
 | 
|---|
| 62 | #pragma aux BiosCall13 = \
 | 
|---|
| 63 |     "push   ax" \
 | 
|---|
| 64 |     "push   cx" \
 | 
|---|
| 65 |     "push   dx" \
 | 
|---|
| 66 |     "push   bp" \
 | 
|---|
| 67 |     "push   si" \
 | 
|---|
| 68 |     "push   di" \
 | 
|---|
| 69 |     "push   es" \
 | 
|---|
| 70 |     "push   bx" \
 | 
|---|
| 71 |     "push   ds" \
 | 
|---|
| 72 |     \
 | 
|---|
| 73 |     "mov    ax,  [bx]" \
 | 
|---|
| 74 |     "mov    cx,  [bx +  2]" \
 | 
|---|
| 75 |     "mov    dx,  [bx +  4]" \
 | 
|---|
| 76 |     "mov    si,  [bx +  6]" \
 | 
|---|
| 77 |     "mov    di,  [bx +  8]" \
 | 
|---|
| 78 |     "mov    es,  [bx + 10]" \
 | 
|---|
| 79 |     "push   word ptr [bx + 12]" \
 | 
|---|
| 80 |     "popf" \
 | 
|---|
| 81 |     "push   word ptr [bx + 14]" \
 | 
|---|
| 82 |     "push   word ptr [bx + 16]" \
 | 
|---|
| 83 |     "pop    bx" \
 | 
|---|
| 84 |     "pop    ds" \
 | 
|---|
| 85 |     \
 | 
|---|
| 86 |     "int    13h"\
 | 
|---|
| 87 |     \
 | 
|---|
| 88 |     "push   ds" \
 | 
|---|
| 89 |     "push   bx" \
 | 
|---|
| 90 |     "mov    bp, sp" \
 | 
|---|
| 91 |     "mov    ds, [bp + 4]" \
 | 
|---|
| 92 |     "mov    bx, [bp + 6]" \
 | 
|---|
| 93 |     "mov    [bx], ax" \
 | 
|---|
| 94 |     "mov    [bx +  2], cx" \
 | 
|---|
| 95 |     "mov    [bx +  4], dx" \
 | 
|---|
| 96 |     "mov    [bx +  6], si" \
 | 
|---|
| 97 |     "mov    [bx +  8], di" \
 | 
|---|
| 98 |     "mov    [bx + 10], es" \
 | 
|---|
| 99 |     "pushf" \
 | 
|---|
| 100 |     "pop    ax" \
 | 
|---|
| 101 |     "mov    [bx + 12], ax" \
 | 
|---|
| 102 |     "pop    ax" \
 | 
|---|
| 103 |     "mov    [bx + 14], ax" \
 | 
|---|
| 104 |     "pop    ax" \
 | 
|---|
| 105 |     "mov    [bx + 16], ax" \
 | 
|---|
| 106 |     \
 | 
|---|
| 107 |     "pop    ds" \
 | 
|---|
| 108 |     "pop    bx" \
 | 
|---|
| 109 |     "pop    es" \
 | 
|---|
| 110 |     "pop    di" \
 | 
|---|
| 111 |     "pop    si" \
 | 
|---|
| 112 |     "pop    bp" \
 | 
|---|
| 113 |     "pop    dx" \
 | 
|---|
| 114 |     "pop    cx" \
 | 
|---|
| 115 |     "pop    ax" \
 | 
|---|
| 116 |     parm [bx];
 | 
|---|
| 117 | 
 | 
|---|
| 118 | 
 | 
|---|
| 119 | int GetDriveParams(void)
 | 
|---|
| 120 | {
 | 
|---|
| 121 |     REGS16 Regs;
 | 
|---|
| 122 |     memset(&Regs, 0, sizeof(Regs));
 | 
|---|
| 123 |     Regs.ax = 0x0800;
 | 
|---|
| 124 |     Regs.dx = g_bDrv;
 | 
|---|
| 125 |     BiosCall13(&Regs);
 | 
|---|
| 126 |     /** @todo check for errors.   */
 | 
|---|
| 127 |     g_cHeads = (Regs.dx >> 8) + 1;
 | 
|---|
| 128 |     g_cSectorsPerTrack = Regs.cx & 0x3f;
 | 
|---|
| 129 |     g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2);
 | 
|---|
| 130 |     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
 | 
|---|
| 131 | 
 | 
|---|
| 132 |     printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n",
 | 
|---|
| 133 |            g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
 | 
|---|
| 134 |     if (!(Regs.efl & X86_EFL_CF))
 | 
|---|
| 135 |         return 0;
 | 
|---|
| 136 |     fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax);
 | 
|---|
| 137 |     return -1;
 | 
|---|
| 138 | }
 | 
|---|
| 139 | 
 | 
|---|
| 140 | void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs)
 | 
|---|
| 141 | {
 | 
|---|
| 142 |     uint16_t iRem = iSector % g_cSectorsPerCylinder;
 | 
|---|
| 143 |     uint16_t iCyl = iSector / g_cSectorsPerCylinder;
 | 
|---|
| 144 |     pRegs->cx  = iCyl << 8;
 | 
|---|
| 145 |     pRegs->cx |= (iCyl >> 2) & 0xc0;
 | 
|---|
| 146 |     pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f;
 | 
|---|
| 147 |     pRegs->dx &= UINT16_C(0x00ff);
 | 
|---|
| 148 |     pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8;
 | 
|---|
| 149 | }
 | 
|---|
| 150 | 
 | 
|---|
| 151 | int ReadSector(uint32_t iSector, void *pvBuf)
 | 
|---|
| 152 | {
 | 
|---|
| 153 |     REGS16   Regs;
 | 
|---|
| 154 |     memset(&Regs, 0, sizeof(Regs));
 | 
|---|
| 155 |     Regs.ax = 0x0201;
 | 
|---|
| 156 |     Regs.dx = g_bDrv;
 | 
|---|
| 157 |     Regs.bx = (unsigned)(void __near *)pvBuf;
 | 
|---|
| 158 |     Regs.es = (__segment)pvBuf;
 | 
|---|
| 159 |     SectorNoToInt13(iSector, &Regs);
 | 
|---|
| 160 |     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
 | 
|---|
| 161 |     BiosCall13(&Regs);
 | 
|---|
| 162 |     if (!(Regs.efl & X86_EFL_CF))
 | 
|---|
| 163 |         return 0;
 | 
|---|
| 164 |     fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
 | 
|---|
| 165 |     return -1;
 | 
|---|
| 166 | }
 | 
|---|
| 167 | 
 | 
|---|
| 168 | int WriteSector(uint32_t iSector, void const *pvBuf)
 | 
|---|
| 169 | {
 | 
|---|
| 170 |     REGS16   Regs;
 | 
|---|
| 171 |     memset(&Regs, 0, sizeof(Regs));
 | 
|---|
| 172 |     Regs.ax = 0x0301;
 | 
|---|
| 173 |     Regs.dx = g_bDrv;
 | 
|---|
| 174 |     Regs.bx = (unsigned)(void const __near *)pvBuf;
 | 
|---|
| 175 |     Regs.es = (__segment)pvBuf;
 | 
|---|
| 176 |     SectorNoToInt13(iSector, &Regs);
 | 
|---|
| 177 |     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
 | 
|---|
| 178 |     BiosCall13(&Regs);
 | 
|---|
| 179 |     if (!(Regs.efl & X86_EFL_CF))
 | 
|---|
| 180 |         return 0;
 | 
|---|
| 181 |     fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
 | 
|---|
| 182 |     return -1;
 | 
|---|
| 183 | }
 | 
|---|
| 184 | 
 | 
|---|
| 185 | 
 | 
|---|
| 186 | static int usage(void)
 | 
|---|
| 187 | {
 | 
|---|
| 188 |     printf("usage: writetst [sector] [drv]\n");
 | 
|---|
| 189 |     return 1;
 | 
|---|
| 190 | }
 | 
|---|
| 191 | 
 | 
|---|
| 192 | 
 | 
|---|
| 193 | int main(int argc, char **argv)
 | 
|---|
| 194 | {
 | 
|---|
| 195 |     int rc = 1;
 | 
|---|
| 196 | 
 | 
|---|
| 197 |     /*
 | 
|---|
| 198 |      * Parse parameters.
 | 
|---|
| 199 |      */
 | 
|---|
| 200 |     uint32_t iSector = 3;
 | 
|---|
| 201 |     g_bDrv = 0x80;
 | 
|---|
| 202 | 
 | 
|---|
| 203 |     if (argc > 3)
 | 
|---|
| 204 |     {
 | 
|---|
| 205 |         fprintf(stderr, "too many parameters!\n");
 | 
|---|
| 206 |         return usage();
 | 
|---|
| 207 |     }
 | 
|---|
| 208 |     if (argc > 1)
 | 
|---|
| 209 |     {
 | 
|---|
| 210 |         iSector = strtoul(argv[1], NULL, 0);
 | 
|---|
| 211 |         if (   iSector == 0
 | 
|---|
| 212 |             || (iSector >= 32 && iSector < 65535)
 | 
|---|
| 213 |             || iSector > 0x800000 /*4G*/)
 | 
|---|
| 214 |         {
 | 
|---|
| 215 |             fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector);
 | 
|---|
| 216 |             return usage();
 | 
|---|
| 217 |         }
 | 
|---|
| 218 |     }
 | 
|---|
| 219 |     if (argc > 2)
 | 
|---|
| 220 |     {
 | 
|---|
| 221 |         unsigned long uTmp = strtoul(argv[2], NULL, 0);
 | 
|---|
| 222 |         if (uTmp < 0x80 || uTmp > 0x8f)
 | 
|---|
| 223 |         {
 | 
|---|
| 224 |             fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp);
 | 
|---|
| 225 |             return usage();
 | 
|---|
| 226 |         }
 | 
|---|
| 227 |         g_bDrv = (uint8_t)uTmp;
 | 
|---|
| 228 |     }
 | 
|---|
| 229 | 
 | 
|---|
| 230 |     /*
 | 
|---|
| 231 |      * Detect drive parameters.
 | 
|---|
| 232 |      */
 | 
|---|
| 233 |     if (GetDriveParams() == 0)
 | 
|---|
| 234 |     {
 | 
|---|
| 235 |         static uint8_t s_abSaved[512];
 | 
|---|
| 236 |         if (ReadSector(iSector, s_abSaved) == 0)
 | 
|---|
| 237 |         {
 | 
|---|
| 238 |             static uint8_t s_abWrite[512];
 | 
|---|
| 239 |             unsigned i;
 | 
|---|
| 240 |             unsigned cTries;
 | 
|---|
| 241 | 
 | 
|---|
| 242 |             for (i = 0; i < 512; i++)
 | 
|---|
| 243 |                 s_abWrite[i] = (uint8_t)i;
 | 
|---|
| 244 | 
 | 
|---|
| 245 |             for (cTries = 0; cTries < 20 && rc != 0; cTries++)
 | 
|---|
| 246 |             {
 | 
|---|
| 247 |                 if (WriteSector(iSector, s_abWrite) == 0)
 | 
|---|
| 248 |                 {
 | 
|---|
| 249 |                     static uint8_t s_abReadBack[512];
 | 
|---|
| 250 | 
 | 
|---|
| 251 |                     if (ReadSector(iSector, s_abReadBack) == 0)
 | 
|---|
| 252 |                     {
 | 
|---|
| 253 |                         for (i = 0; i < 512; i++)
 | 
|---|
| 254 |                             s_abWrite[i] = (uint8_t)i;
 | 
|---|
| 255 | 
 | 
|---|
| 256 |                         if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0)
 | 
|---|
| 257 |                         {
 | 
|---|
| 258 |                             rc = 0;
 | 
|---|
| 259 |                             printf("wrote sector and successfully read it back\n");
 | 
|---|
| 260 |                         }
 | 
|---|
| 261 |                         else if (cTries >= 19)
 | 
|---|
| 262 |                         {
 | 
|---|
| 263 |                             unsigned cErrors = 0;
 | 
|---|
| 264 |                             fprintf(stderr, "read back doesn't match what was written:\n");
 | 
|---|
| 265 |                             for (i = 0; i < 512; i++)
 | 
|---|
| 266 |                                 if (s_abReadBack[i] != (uint8_t)i)
 | 
|---|
| 267 |                                 {
 | 
|---|
| 268 |                                     fprintf(stderr,  "  %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]);
 | 
|---|
| 269 |                                     if ((cErrors % 5) == 4)
 | 
|---|
| 270 |                                         fprintf(stderr, "\n");
 | 
|---|
| 271 |                                     cErrors++;
 | 
|---|
| 272 |                                 }
 | 
|---|
| 273 |                             if ((cErrors % 5) != 0)
 | 
|---|
| 274 |                                 fprintf(stderr, "\n");
 | 
|---|
| 275 |                         }
 | 
|---|
| 276 |                     }
 | 
|---|
| 277 | 
 | 
|---|
| 278 |                 }
 | 
|---|
| 279 |             }
 | 
|---|
| 280 | 
 | 
|---|
| 281 |             /* restore */
 | 
|---|
| 282 |             WriteSector(iSector, s_abSaved);
 | 
|---|
| 283 |         }
 | 
|---|
| 284 |     }
 | 
|---|
| 285 | 
 | 
|---|
| 286 | 
 | 
|---|
| 287 |     return rc;
 | 
|---|
| 288 | }
 | 
|---|
| 289 | 
 | 
|---|