VirtualBox

source: kStuff/hacks/xtide/writeatatest.c@ 72

Last change on this file since 72 was 72, checked in by bird, 9 years ago

some ata and int13h read+write testing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 27.6 KB
Line 
1/* $Id: writeatatest.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/*********************************************************************************************************************************
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
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39typedef 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
132
133
134/*********************************************************************************************************************************
135* Global Variables *
136*********************************************************************************************************************************/
137uint16_t g_uBasePort = 0x300;
138uint16_t g_uPortShift = 1;
139uint8_t g_fUseLbaMode = 1;
140uint8_t g_f8BitData = 1;
141uint8_t g_bDevice = ATA_DEV_MASTER;
142uint8_t g_bDrv = 0x80;
143
144
145uint16_t g_cHeads;
146uint8_t g_cSectorsPerTrack;
147uint16_t g_cCylinders;
148uint16_t g_cSectorsPerCylinder;
149
150/** The result of the identify command. */
151uint16_t g_awIdentify[256];
152
153
154size_t AtaPrintStatus(FILE *pOut, uint8_t bSts)
155{
156 size_t cch = fprintf(pOut, "%#x", bSts);
157 if (bSts & ATA_STS_BUSY) cch += fprintf(pOut, " busy");
158 if (bSts & ATA_STS_DRDY) cch += fprintf(pOut, " drdy");
159 if (bSts & ATA_STS_DF ) cch += fprintf(pOut, " df");
160 if (bSts & ATA_STS_DSC ) cch += fprintf(pOut, " dsc");
161 if (bSts & ATA_STS_DRQ ) cch += fprintf(pOut, " drq");
162 if (bSts & ATA_STS_CORR) cch += fprintf(pOut, " corr");
163 if (bSts & ATA_STS_IDX ) cch += fprintf(pOut, " idx");
164 if (bSts & ATA_STS_ERR ) cch += fprintf(pOut, " err");
165 return cch;
166}
167
168size_t AtaPrintError(FILE *pOut, uint8_t bErr)
169{
170 size_t cch = fprintf(pOut, "%#x", bErr);
171 if (bErr & ATA_ERR_RSVR ) cch += fprintf(pOut, " rsrv");
172 if (bErr & ATA_ERR_UNC ) cch += fprintf(pOut, " unc");
173 if (bErr & ATA_ERR_MC ) cch += fprintf(pOut, " mc");
174 if (bErr & ATA_ERR_IDNF ) cch += fprintf(pOut, " idnf");
175 if (bErr & ATA_ERR_MCR ) cch += fprintf(pOut, " mcr");
176 if (bErr & ATA_ERR_ABRT ) cch += fprintf(pOut, " abrt");
177 if (bErr & ATA_ERR_TKNONF) cch += fprintf(pOut, " tknonf");
178 if (bErr & ATA_ERR_AMNF ) cch += fprintf(pOut, " amnf");
179 return cch;
180}
181
182static int AtaError(uint8_t bSts, const char *pszFormat, ...)
183{
184 va_list va;
185
186 fprintf(stderr, "error: ");
187 va_start(va, pszFormat);
188 vfprintf(stderr, pszFormat, va);
189 va_end(va);
190
191 fprintf(stderr, "\n status=");
192 AtaPrintStatus(stderr, bSts);
193 fprintf(stderr, "\n error= ");
194 AtaPrintError(stderr, inp(ATA_REG_ERROR(g_uBasePort)));
195 fprintf(stderr, "\n");
196
197 return -1;
198}
199
200uint8_t AtaWaitBusy(void)
201{
202 uint32_t cLoops = 0;
203 uint8_t bStatus;
204 do
205 {
206 if ((++cLoops & 0xfffff) == 0)
207 fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
208 bStatus = inp(ATA_REG_STATUS(g_uBasePort));
209 } while ((bStatus & (ATA_STS_BUSY | ATA_STS_ERR)) == ATA_STS_BUSY);
210 return bStatus;
211}
212
213uint8_t AtaWaitBusyDeviceReady(void)
214{
215 uint32_t cLoops = 0;
216 uint8_t bStatus;
217 do
218 {
219 if ((++cLoops & 0xfffff) == 0)
220 fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
221 bStatus = inp(ATA_REG_STATUS(g_uBasePort));
222 } while ( (bStatus & (ATA_STS_BUSY | ATA_STS_DRDY)) != ATA_STS_DRDY
223 && !(bStatus & ATA_STS_ERR) );
224 return bStatus;
225}
226
227uint8_t AtaWaitBusyForData(void)
228{
229 uint32_t cLoops = 0;
230 uint8_t bStatus;
231 do
232 {
233 if ((++cLoops & 0xfffff) == 0)
234 fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
235 bStatus = inp(ATA_REG_STATUS(g_uBasePort));
236 } while ( (bStatus & (ATA_STS_BUSY | ATA_STS_DRQ)) != ATA_STS_DRQ
237 && !(bStatus & ATA_STS_ERR) );
238 return bStatus;
239}
240
241uint8_t AtaSubmitCommandAndWait(uint8_t bCommand)
242{
243
244 outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
245 ATA_DELAY_400NS();
246 return AtaWaitBusy();
247}
248
249uint8_t AtaSubmitCommandAndWaitForData(uint8_t bCommand)
250{
251
252 outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
253 ATA_DELAY_400NS();
254 return AtaWaitBusyForData();
255}
256
257uint8_t AtaSelectDevice(uint8_t bDevice)
258{
259 outp(ATA_REG_DEVICE_SELECT(g_uBasePort), g_bDevice);
260 ATA_DELAY_400NS();
261 return AtaWaitBusyDeviceReady();
262}
263
264void AtaSetSectorAddress(uint32_t iSector, uint8_t bDevice)
265{
266 if (g_fUseLbaMode)
267 {
268 outp(ATA_REG_LBA_0_7(g_uBasePort), iSector & 0xff);
269 outp(ATA_REG_LBA_8_15(g_uBasePort), (iSector >> 8) & 0xff);
270 outp(ATA_REG_LBA_16_23(g_uBasePort), (iSector >> 16) & 0xff);
271 outp(ATA_REG_LBA_24_27_MODE(g_uBasePort), ((iSector >> 24) & 0x0f) | ATA_LBA_MODE | bDevice);
272 }
273 else
274 {
275 uint16_t iCyl = iSector / g_cSectorsPerCylinder;
276 uint16_t iRem = iSector % g_cSectorsPerCylinder;
277 uint8_t iHd = iRem / g_cSectorsPerTrack;
278 uint8_t iSec = iRem % g_cSectorsPerTrack;
279
280 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), iSec);
281 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), iCyl & 0xff);
282 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), iCyl >> 8);
283 outp(ATA_REG_HEAD(g_uBasePort), iHd | bDevice);
284 }
285}
286
287void AtaReadData(void *pvBuf, size_t cb, uint8_t f8BitData)
288{
289 uint16_t uDataPort = ATA_REG_DATA(g_uBasePort);
290 uint16_t *pu16 = (uint16_t *)pvBuf;
291 cb >>= 1;
292
293 if (f8BitData)
294 {
295 while (cb-- > 0)
296 {
297 uint8_t b1 = inp(uDataPort);
298 uint8_t b2 = inp(uDataPort);
299 *pu16++ = b1 | ((uint16_t)b2 << 8);
300 }
301 }
302 else
303 {
304 while (cb-- > 0)
305 *pu16++ = inpw(uDataPort);
306 }
307}
308
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
332void 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
341void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
342{
343// uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
344 uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
345
346 if (f8BitData)
347 {
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;
355inp(0x21);
356xchg(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 }
378inp(0x21);
379#else
380 uint16_t const *pu16 = (uint16_t const *)pvBuf;
381 cb >>= 1;
382 while (cb-- > 0)
383 {
384 uint16_t register u16 = *pu16++;
385 outp(uDataPort, (uint8_t)u16);
386 outp(uDataPort, (uint8_t)(u16 >> 8));
387 }
388#endif
389 }
390 else
391 {
392 uint16_t const *pu16 = (uint16_t const *)pvBuf;
393 cb >>= 1;
394 while (cb-- > 0)
395 outp(uDataPort, *pu16++);
396 }
397}
398
399int AtaReadSector(uint32_t iSector, void *pvBuf)
400{
401 uint8_t bSts = AtaWaitBusy();
402 if (bSts & ATA_STS_ERR)
403 return AtaError(bSts, "Prepping for reading sector %lu", iSector);
404
405printf("AtaReadSector #2\n");
406 bSts = AtaSelectDevice(g_bDevice);
407 if (bSts & ATA_STS_ERR)
408 return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
409
410//printf("AtaReadSector #3\n");
411 outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
412 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
413 AtaSetSectorAddress(iSector, g_bDevice);
414
415//printf("AtaReadSector #4\n");
416 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
417 if (bSts & ATA_STS_ERR)
418 return AtaError(bSts, "Reading sector %lu", iSector);
419
420 if (!(bSts & ATA_STS_DRQ))
421 return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
422
423
424//printf("AtaReadSector #5\n");
425 AtaReadData(pvBuf, 512, g_f8BitData);
426//printf("AtaReadSector #6: bSts=%#x\n", inp(ATA_REG_ALT_STATUS(g_uBasePort)));
427 bSts = inp(ATA_REG_STATUS(g_uBasePort));
428 if ((bSts & ATA_STS_DRQ))
429 return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
430 if ((bSts & ATA_STS_ERR))
431 return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
432 return 0;
433}
434
435int AtaWriteSector(uint32_t iSector, void const *pvBuf)
436{
437//int x = printf("AtaWriteSector #1\n");
438 uint8_t bSts = AtaWaitBusy();
439 if (bSts & ATA_STS_ERR)
440 return AtaError(bSts, "Prepping for writing sector %lu", iSector);
441printf("AtaWriteSector #2\n");
442
443 bSts = AtaSelectDevice(g_bDevice);
444 if (bSts & ATA_STS_ERR)
445 return AtaError(bSts, "Selecting device for writing sector %lu", iSector);
446
447 outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
448 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
449 AtaSetSectorAddress(iSector, g_bDevice);
450
451//printf("AtaWriteSector #3\n");
452 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
453 if (bSts & ATA_STS_ERR)
454 return AtaError(bSts, "writing sector (#1) %lu", iSector);
455 if (!(bSts & ATA_STS_DRQ))
456 return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
457
458//printf("AtaWriteSector #4\n");
459 AtaWriteData(pvBuf, 512, g_f8BitData);
460//printf("AtaWriteSector #5\n");
461 ATA_DELAY_400NS();
462 bSts = AtaWaitBusy();
463//printf("AtaWriteSector #6\n");
464 if (bSts & ATA_STS_ERR)
465 return AtaError(bSts, "writing sector (#2) %lu", iSector);
466 if (bSts & ATA_STS_DRQ)
467 return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
468
469 return 0;
470}
471
472int AtaIdentifyDevice(uint8_t bDevice, void *pvBuf)
473{
474 uint8_t bSts = AtaWaitBusy();
475 if (bSts & ATA_STS_ERR)
476 return AtaError(bSts, "Prepping for device %#x identification", bDevice);
477
478 bSts = AtaSelectDevice(g_bDevice);
479 if (bSts & ATA_STS_ERR)
480 return AtaError(bSts, "Selecting device %#x for identification", bDevice);
481
482 outp(ATA_REG_FEATURES(g_uBasePort), 0);
483 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 0);
484 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0);
485 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
486 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
487 //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
488
489 bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_IDENTIFY_DEVICE);
490 if (bSts & ATA_STS_ERR)
491 return AtaError(bSts, "Device %#x identification", bDevice);
492 if (!(bSts & ATA_STS_DRQ))
493 return AtaError(bSts, "DRQ not set after device %#x identification", bDevice);
494
495 AtaReadData(pvBuf, 512, g_f8BitData);
496 return 0;
497}
498
499int AtaSetFeature(uint8_t bDevice, uint8_t bFeature, uint8_t bValue)
500{
501 uint8_t bSts = AtaWaitBusy();
502 if (bSts & ATA_STS_ERR)
503 return AtaError(bSts, "Prepping for setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
504
505 bSts = AtaSelectDevice(g_bDevice);
506 if (bSts & ATA_STS_ERR)
507 return AtaError(bSts, "Selecting device %#x for setting feature %#x (%#x)", bDevice, bFeature, bValue);
508
509 outp(ATA_REG_FEATURES(g_uBasePort), bFeature);
510 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 0);
511 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), bValue);
512 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
513 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
514 //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
515
516 bSts = AtaSubmitCommandAndWait(ATA_CMD_SET_FEATURES);
517 if (bSts & ATA_STS_ERR)
518 return AtaError(bSts, "Setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
519 if (bSts & ATA_STS_DRQ)
520 return AtaError(bSts, "DRQ is set after setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
521 return 0;
522}
523
524int AtaInitDeviceParams(uint8_t bDevice, uint8_t cSectorsPerTrack, uint8_t cHeads)
525{
526 uint8_t bSts = AtaWaitBusy();
527 if (bSts & ATA_STS_ERR)
528 return AtaError(bSts, "Prepping for device %#x parameter initialization", bDevice);
529
530 bSts = AtaSelectDevice(g_bDevice);
531 if (bSts & ATA_STS_ERR)
532 return AtaError(bSts, "Selecting device for device %#x parameter initialization", bDevice);
533
534 outp(ATA_REG_FEATURES(g_uBasePort), 0);
535 outp(ATA_REG_SECTOR_COUNT(g_uBasePort), cSectorsPerTrack);
536 outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), 0);
537 outp(ATA_REG_CYLINDER_LOW(g_uBasePort), 0);
538 outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), 0);
539 outp(ATA_REG_HEAD(g_uBasePort), g_bDevice | cHeads);
540
541 bSts = AtaSubmitCommandAndWait(ATA_CMD_INIT_DEVICE_PARAMS);
542 if (bSts & ATA_STS_ERR)
543 return AtaError(bSts, "Device %#x parameter initialization", bDevice);
544 if (bSts & ATA_STS_DRQ)
545 return AtaError(bSts, "DRQ is set after device %#x parameter initialization", bDevice);
546 return 0;
547}
548
549int AtaReset(void)
550{
551 uint8_t bSts;
552
553 /* Set the reset flat. */
554 outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_SRST);
555
556 /* Wait for the busy flag response. */
557 ATA_DELAY_400NS();
558 ATA_DELAY_400NS();
559 while (!(bSts = inp(ATA_REG_STATUS(g_uBasePort))) & ATA_STS_BUSY)
560 ATA_DELAY_400NS();
561
562 /* Clear the reset flag. */
563 outp(ATA_REG_CONTROL(g_uBasePort), 0);
564 ATA_DELAY_400NS();
565
566 /* Wait for the controller to become non-busy. */
567 bSts = AtaWaitBusy();
568 if (bSts & ATA_STS_ERR)
569 return AtaError(bSts, "Software reset failed");
570 return 0;
571}
572
573
574int AtaInit(void)
575{
576 uint8_t bSts = inp(ATA_REG_ALT_STATUS(g_uBasePort));
577 printf("alt status=");
578 AtaPrintStatus(stdout, bSts);
579 printf("\n");
580
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
622void 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
680int 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
701void 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
712int 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
729int 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
748int GetDriveParams(void)
749{
750#ifdef USE_INT13H
751 return Int13hInit();
752#else
753 return AtaInit();
754#endif
755}
756
757int 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
766int 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
778static int usage(void)
779{
780 printf("usage: writetst [sector] [drv]\n");
781 return 1;
782}
783
784
785int 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++)
842 {
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 }
877 }
878
879 /* restore */
880 WriteSector(iSector, s_abSaved);
881 }
882 }
883
884
885 return rc;
886}
887
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette