/* $Id: writetest.c 72 2015-12-20 18:29:17Z bird $ */ /** @file * Does a little write test. */ /* * Copyright (c) 2015 knut st. osmundsen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with This program. If not, see * */ #include #include #include #include #include #include /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef struct REGS16 { uint16_t ax; /**< 0 */ uint16_t cx; /**< 2 */ uint16_t dx; /**< 4 */ uint16_t si; /**< 6 */ uint16_t di; /**< 8 */ uint16_t es; /**< 10 */ uint16_t efl; /**< 12 */ uint16_t ds; /**< 14 */ uint16_t bx; /**< 16 */ } REGS16; #define X86_EFL_CF 1 /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ uint8_t g_bDrv; uint16_t g_cHeads; uint8_t g_cSectorsPerTrack; uint16_t g_cCylinders; uint16_t g_cSectorsPerCylinder; void BiosCall13(REGS16 *pRegs); #pragma aux BiosCall13 = \ "push ax" \ "push cx" \ "push dx" \ "push bp" \ "push si" \ "push di" \ "push es" \ "push bx" \ "push ds" \ \ "mov ax, [bx]" \ "mov cx, [bx + 2]" \ "mov dx, [bx + 4]" \ "mov si, [bx + 6]" \ "mov di, [bx + 8]" \ "mov es, [bx + 10]" \ "push word ptr [bx + 12]" \ "popf" \ "push word ptr [bx + 14]" \ "push word ptr [bx + 16]" \ "pop bx" \ "pop ds" \ \ "int 13h"\ \ "push ds" \ "push bx" \ "mov bp, sp" \ "mov ds, [bp + 4]" \ "mov bx, [bp + 6]" \ "mov [bx], ax" \ "mov [bx + 2], cx" \ "mov [bx + 4], dx" \ "mov [bx + 6], si" \ "mov [bx + 8], di" \ "mov [bx + 10], es" \ "pushf" \ "pop ax" \ "mov [bx + 12], ax" \ "pop ax" \ "mov [bx + 14], ax" \ "pop ax" \ "mov [bx + 16], ax" \ \ "pop ds" \ "pop bx" \ "pop es" \ "pop di" \ "pop si" \ "pop bp" \ "pop dx" \ "pop cx" \ "pop ax" \ parm [bx]; int GetDriveParams(void) { REGS16 Regs; memset(&Regs, 0, sizeof(Regs)); Regs.ax = 0x0800; Regs.dx = g_bDrv; BiosCall13(&Regs); /** @todo check for errors. */ g_cHeads = (Regs.dx >> 8) + 1; g_cSectorsPerTrack = Regs.cx & 0x3f; g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2); g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack; printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n", g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack); if (!(Regs.efl & X86_EFL_CF)) return 0; fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax); return -1; } void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs) { uint16_t iRem = iSector % g_cSectorsPerCylinder; uint16_t iCyl = iSector / g_cSectorsPerCylinder; pRegs->cx = iCyl << 8; pRegs->cx |= (iCyl >> 2) & 0xc0; pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f; pRegs->dx &= UINT16_C(0x00ff); pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8; } int ReadSector(uint32_t iSector, void *pvBuf) { REGS16 Regs; memset(&Regs, 0, sizeof(Regs)); Regs.ax = 0x0201; Regs.dx = g_bDrv; Regs.bx = (unsigned)(void __near *)pvBuf; Regs.es = (__segment)pvBuf; SectorNoToInt13(iSector, &Regs); printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx); BiosCall13(&Regs); if (!(Regs.efl & X86_EFL_CF)) return 0; fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax); return -1; } int WriteSector(uint32_t iSector, void const *pvBuf) { REGS16 Regs; memset(&Regs, 0, sizeof(Regs)); Regs.ax = 0x0301; Regs.dx = g_bDrv; Regs.bx = (unsigned)(void const __near *)pvBuf; Regs.es = (__segment)pvBuf; SectorNoToInt13(iSector, &Regs); printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx); BiosCall13(&Regs); if (!(Regs.efl & X86_EFL_CF)) return 0; fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax); return -1; } static int usage(void) { printf("usage: writetst [sector] [drv]\n"); return 1; } int main(int argc, char **argv) { int rc = 1; /* * Parse parameters. */ uint32_t iSector = 3; g_bDrv = 0x80; if (argc > 3) { fprintf(stderr, "too many parameters!\n"); return usage(); } if (argc > 1) { iSector = strtoul(argv[1], NULL, 0); if ( iSector == 0 || (iSector >= 32 && iSector < 65535) || iSector > 0x800000 /*4G*/) { fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector); return usage(); } } if (argc > 2) { unsigned long uTmp = strtoul(argv[2], NULL, 0); if (uTmp < 0x80 || uTmp > 0x8f) { fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp); return usage(); } g_bDrv = (uint8_t)uTmp; } /* * Detect drive parameters. */ if (GetDriveParams() == 0) { static uint8_t s_abSaved[512]; if (ReadSector(iSector, s_abSaved) == 0) { static uint8_t s_abWrite[512]; unsigned i; unsigned cTries; for (i = 0; i < 512; i++) s_abWrite[i] = (uint8_t)i; for (cTries = 0; cTries < 20 && rc != 0; cTries++) { if (WriteSector(iSector, s_abWrite) == 0) { static uint8_t s_abReadBack[512]; if (ReadSector(iSector, s_abReadBack) == 0) { for (i = 0; i < 512; i++) s_abWrite[i] = (uint8_t)i; if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0) { rc = 0; printf("wrote sector and successfully read it back\n"); } else if (cTries >= 19) { unsigned cErrors = 0; fprintf(stderr, "read back doesn't match what was written:\n"); for (i = 0; i < 512; i++) if (s_abReadBack[i] != (uint8_t)i) { fprintf(stderr, " %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]); if ((cErrors % 5) == 4) fprintf(stderr, "\n"); cErrors++; } if ((cErrors % 5) != 0) fprintf(stderr, "\n"); } } } } /* restore */ WriteSector(iSector, s_abSaved); } } return rc; }