ReactOS  0.4.15-dev-1068-g467feb9
pc98disk.c
Go to the documentation of this file.
1 /*
2  * PROJECT: FreeLoader
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: Drive access routines for NEC PC-98 series
5  * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include <freeldr.h>
11 #include <hwide.h>
12 
13 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 /* Maximum number of disks, indexed from 0x00 to 0xFF */
19 #define MAX_DRIVES 0x100
20 
21 /* Cache of all possible PC disk drives */
23 
24 /* DISK IO ERROR SUPPORT ******************************************************/
25 
26 static LONG lReportError = 0; /* >= 0: display errors; < 0: hide errors */
27 
28 LONG
30 {
31  /* Set the reference count */
32  if (bShowError)
33  ++lReportError;
34  else
35  --lReportError;
36  return lReportError;
37 }
38 
39 static PCSTR
41 {
42  switch (ErrorCode & 0xF0)
43  {
44  case 0x00: return "No error";
45  case 0x10: return "Drive write protection error";
46  case 0x20: return "DMA access across 64 kB boundary";
47  case 0x30: return "End of cylinder";
48  case 0x40: return "The drive name is invalid or the device have low health";
49  case 0x50: return "Time out, data not written";
50  case 0x60: return "Time out, drive not ready";
51  case 0x70:
52  if (ErrorCode == 0x78)
53  return "Illegal disk address";
54  else
55  return "Drive write protection error";
56  case 0x80: return "Undefined error";
57  case 0x90: return "Time out error";
58  case 0xA0: return "CRC error in the ID section";
59  case 0xB0: return "CRC error in the DATA section";
60  case 0xC0:
61  if (ErrorCode == 0xC8)
62  return "Seek failure";
63  else
64  return "No data (Sector not found)";
65  case 0xD0: return "Bad cylinder";
66  case 0xE0: return "No ID address mark was found";
67  case 0xF0: return "No DATA address mark was found";
68 
69  default: return "Unknown error code";
70  }
71 }
72 
73 static VOID
75 {
76  CHAR ErrorCodeString[200];
77 
78  if (lReportError < 0)
79  return;
80 
81  RtlStringCbPrintfA(ErrorCodeString, sizeof(ErrorCodeString), "%s\n\nError Code: 0x%lx\nError: %s",
83 
84  ERR("%s\n", ErrorCodeString);
85 
86  UiMessageBox(ErrorCodeString);
87 }
88 
89 /* FUNCTIONS ******************************************************************/
90 
92 {
93  REGS Regs;
94 
95  if (DiskDrive->Type & DRIVE_FDD)
96  {
97  /* Int 1Bh AH=07h
98  * DISK BIOS - Recalibrate
99  *
100  * Call with:
101  * AL - drive number
102  *
103  * Return:
104  * CF - set on error, clear if successful
105  * AH - status
106  */
107  Regs.b.ah = 0x07;
108  }
109  else if (DiskDrive->Type != (DRIVE_IDE | DRIVE_CDROM))
110  {
111  /* Int 1Bh AH=03h
112  * DISK BIOS - Initialize
113  *
114  * Call with:
115  * AL - drive number
116  *
117  * Return:
118  * CF - set on error, clear if successful
119  * AH - status
120  */
121  Regs.b.ah = 0x03;
122  }
123  else
124  {
125  return FALSE;
126  }
127 
128  WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DiskDrive->DaUa);
129 
130  Regs.b.al = DiskDrive->DaUa;
131  Int386(0x1B, &Regs, &Regs);
132  return INT386_SUCCESS(Regs);
133 }
134 
136 {
137  AtaFree();
138 }
139 
142 {
143  PPC98_DISK_DRIVE DiskDrive;
144 
145  ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(Pc98DiskDrive)));
146 
147  /* Retrieve a slot */
148  DiskDrive = &Pc98DiskDrive[DriveNumber];
149 
150  /* The pre-initialization of the BIOS disks was already done in Pc98InitializeBootDevices() */
151  if (DiskDrive->Initialized)
152  return DiskDrive;
153  else
154  return NULL;
155 }
156 
157 static inline
158 UCHAR
160 {
161  switch (BytesPerSector)
162  {
163  case 128:
164  return 0;
165  case 256:
166  return 1;
167  case 512:
168  return 2;
169  case 1024:
170  return 3;
171  case 2048:
172  return 4;
173  default:
174  return 0;
175  }
176 }
177 
178 static BOOLEAN
180  IN PPC98_DISK_DRIVE DiskDrive,
181  IN ULONGLONG SectorNumber,
183  OUT PVOID Buffer)
184 {
185  REGS RegsIn, RegsOut;
186  ULONG RetryCount;
187 
188  if (DiskDrive->Type & DRIVE_IDE && DiskDrive->Type & DRIVE_CDROM)
189  {
190  return AtaAtapiReadLogicalSectorsLBA(AtaGetDevice(DiskDrive->IdeUnitNumber), SectorNumber, SectorCount, Buffer);
191  }
192  else
193  {
194  /* Int 1Bh AH=06h
195  * DISK BIOS - Read data
196  *
197  * Call with:
198  * AL - drive number
199  * BX - bytes to read
200  * CX - cylinder number
201  * DH - head number
202  * DL - sector number
203  * ES:BP -> buffer to read data into
204  *
205  * Return:
206  * CF - set on error, clear if successful
207  * AH - status
208  */
209  RegsIn.b.al = DiskDrive->DaUa;
210  RegsIn.b.ah = 0x06;
211  RegsIn.w.bx = DiskDrive->Geometry.BytesPerSector * SectorCount;
212  RegsIn.w.cx = SectorNumber & 0xFFFF;
213  RegsIn.w.dx = (SectorNumber >> 16) & 0xFFFF;
214  RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
215  RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
216 
217  /* Retry 3 times */
218  for (RetryCount = 0; RetryCount < 3; RetryCount++)
219  {
220  Int386(0x1B, &RegsIn, &RegsOut);
221 
222  /* If it worked return TRUE */
223  if (INT386_SUCCESS(RegsOut))
224  {
225  return TRUE;
226  }
227  /* If it was a corrected ECC error then the data is still good */
228  else if (RegsOut.b.ah == 0x08)
229  {
230  return TRUE;
231  }
232  /* If it failed the do the next retry */
233  else
234  {
235  DiskResetController(DiskDrive);
236  continue;
237  }
238  }
239  }
240 
241  /* If we get here then the read failed */
242  DiskError("Disk Read Failed in LBA mode", RegsOut.b.ah);
243  ERR("Disk Read Failed in LBA mode: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n",
244  RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
245  DiskDrive->DaUa, SectorNumber, SectorCount);
246 
247  return FALSE;
248 }
249 
250 static BOOLEAN
252  IN PPC98_DISK_DRIVE DiskDrive,
253  IN ULONGLONG SectorNumber,
255  OUT PVOID Buffer)
256 {
257  UCHAR PhysicalSector;
258  UCHAR PhysicalHead;
259  ULONG PhysicalTrack;
260  GEOMETRY DriveGeometry;
261  ULONG NumberOfSectorsToRead;
262  REGS RegsIn, RegsOut;
263  ULONG RetryCount;
264 
265  DriveGeometry = DiskDrive->Geometry;
266 
267  while (SectorCount > 0)
268  {
269  /*
270  * Calculate the physical disk offsets.
271  * Note: DriveGeometry.Sectors < 64
272  */
273  PhysicalSector = (UCHAR)(SectorNumber % DriveGeometry.Sectors);
274  PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
275  PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
276 
277  /* Floppy sectors value always start at 1 */
278  if (DiskDrive->Type & DRIVE_FDD)
279  ++PhysicalSector;
280 
281  /* Calculate how many sectors we need to read this round */
282  if (PhysicalSector > 1)
283  {
284  if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1)))
285  NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1));
286  else
287  NumberOfSectorsToRead = SectorCount;
288  }
289  else
290  {
291  if (SectorCount >= DriveGeometry.Sectors)
292  NumberOfSectorsToRead = DriveGeometry.Sectors;
293  else
294  NumberOfSectorsToRead = SectorCount;
295  }
296 
297  /* Make sure the read is within the geometry boundaries */
298  if ((PhysicalHead >= DriveGeometry.Heads) ||
299  (PhysicalTrack >= DriveGeometry.Cylinders) ||
300  ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
301  (PhysicalSector > DriveGeometry.Sectors))
302  {
303  DiskError("Disk read exceeds drive geometry limits.", 0);
304  return FALSE;
305  }
306 
307  if (DiskDrive->Type & DRIVE_FDD)
308  {
309  /* Int 1Bh AH=x6h
310  * DISK BIOS - Read data
311  *
312  * Call with:
313  * AL - drive number
314  * BX - bytes to read
315  * CH - sector length code
316  * CL - cylinder number
317  * DH - head number
318  * DL - sector number
319  * ES:BP -> buffer to read data into
320  *
321  * Return:
322  * CF - set on error, clear if successful
323  * AH - status
324  */
325  RegsIn.b.al = DiskDrive->DaUa;
326  RegsIn.b.ah = 0x56; /* With SEEK, and use double-density format (MFM) */
327  RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
328  RegsIn.b.cl = PhysicalTrack & 0xFFFF;
329  RegsIn.b.ch = BytesPerSectorToSectorLengthCode(DriveGeometry.BytesPerSector);
330  RegsIn.b.dl = PhysicalSector;
331  RegsIn.b.dh = PhysicalHead;
332  RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
333  RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
334  }
335  else
336  {
337  /* Int 1Bh AH=06h
338  * DISK BIOS - Read data
339  *
340  * Call with:
341  * AL - drive number
342  * BX - bytes to read
343  * CX - cylinder number
344  * DH - head number
345  * DL - sector number
346  * ES:BP -> buffer to read data into
347  *
348  * Return:
349  * CF - set on error, clear if successful
350  * AH - status
351  */
352  RegsIn.b.al = DiskDrive->DaUa;
353  RegsIn.b.ah = 0x06;
354  RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
355  RegsIn.w.cx = PhysicalTrack & 0xFFFF;
356  RegsIn.b.dl = PhysicalSector;
357  RegsIn.b.dh = PhysicalHead;
358  RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
359  RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
360  }
361 
362  /* Perform the read. Retry 3 times. */
363  for (RetryCount = 0; RetryCount < 3; RetryCount++)
364  {
365  Int386(0x1B, &RegsIn, &RegsOut);
366 
367  /* If it worked break out */
368  if (INT386_SUCCESS(RegsOut))
369  {
370  break;
371  }
372  /* If it was a corrected ECC error then the data is still good */
373  else if (RegsOut.b.ah == 0x08)
374  {
375  break;
376  }
377  /* If it failed then do the next retry */
378  else
379  {
380  DiskResetController(DiskDrive);
381  continue;
382  }
383  }
384 
385  /* If we retried 3 times then fail */
386  if (RetryCount >= 3)
387  {
388  DiskError("Disk Read Failed in CHS mode, after retrying 3 times", RegsOut.b.ah);
389  ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n",
390  RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
391  DiskDrive->DaUa, SectorNumber, SectorCount);
392  return FALSE;
393  }
394 
395  Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
396  SectorCount -= NumberOfSectorsToRead;
397  SectorNumber += NumberOfSectorsToRead;
398  }
399 
400  return TRUE;
401 }
402 
403 static BOOLEAN
405  IN UCHAR DaUa,
406  IN OUT PPC98_DISK_DRIVE DiskDrive)
407 {
408  REGS RegsIn, RegsOut;
409  UCHAR UnitAddress = DaUa & 0x0F;
410  USHORT DiskEquipment = *(PUCHAR)MEM_DISK_EQUIPS;
411  ULONG ScsiParameters = *(PULONG)(MEM_SCSI_TABLE + UnitAddress * sizeof(ULONG));
413 
414  /* Hard drives */
415  if (DiskEquipment & (1 << UnitAddress))
416  {
417  /* Int 1Bh AH=84h
418  * DISK BIOS - Sense
419  *
420  * Call with:
421  * AL - drive number
422  *
423  * Return:
424  * BX - bytes per sector
425  * CX - cylinders number
426  * DH - heads number
427  * DL - sectors number
428  * CF - set on error, clear if successful
429  * AH - status
430  */
431  RegsIn.b.al = DaUa;
432  RegsIn.b.ah = 0x84;
433  Int386(0x1B, &RegsIn, &RegsOut);
434  if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
435  {
436  DiskDrive->Initialized = FALSE;
437  return FALSE;
438  }
439 
440  DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
441  DiskDrive->Geometry.Heads = RegsOut.b.dh;
442  DiskDrive->Geometry.Sectors = RegsOut.b.dl;
443  DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
444  DiskDrive->LBASupported = FALSE;
445  DiskDrive->IsRemovable = FALSE;
446  }
447  /* Other devices */
448  else if (ScsiParameters)
449  {
450  DeviceType = ScsiParameters & 0x1F;
451  switch (DeviceType)
452  {
453  case 0x05:
454  /* CD-ROM */
455  DiskDrive->Geometry.Cylinders = 0xFFFF;
456  DiskDrive->Geometry.Heads = 0xFFFF;
457  DiskDrive->Geometry.Sectors = 0xFFFF;
458  DiskDrive->Geometry.BytesPerSector = 2048;
459  DiskDrive->Type = DRIVE_CDROM;
460  DiskDrive->LBASupported = TRUE;
461  DiskDrive->IsRemovable = TRUE;
462  break;
463 
464  case 0x07:
465  /* Magneto-optical drive */
466  DiskDrive->Geometry.Cylinders = 0xFFFF;
467  DiskDrive->Geometry.Heads = 8;
468  DiskDrive->Geometry.Sectors = 32;
469  DiskDrive->Geometry.BytesPerSector = 512;
470  DiskDrive->Type = DRIVE_MO;
471  DiskDrive->LBASupported = TRUE;
472  DiskDrive->IsRemovable = TRUE;
473  break;
474 
475  default:
476  DiskDrive->Initialized = FALSE;
477  return FALSE;
478  }
479  }
480  else
481  {
482  DiskDrive->Initialized = FALSE;
483  return FALSE;
484  }
485 
486  DiskDrive->DaUa = DaUa;
487  DiskDrive->Type |= DRIVE_SCSI;
488  DiskDrive->Initialized = TRUE;
489 
490  TRACE("InitScsiDrive(0x%x) returned:\n"
491  "Cylinders : 0x%x\n"
492  "Heads : 0x%x\n"
493  "Sects/Track: 0x%x\n"
494  "Bytes/Sect : 0x%x\n",
495  DaUa,
496  DiskDrive->Geometry.Cylinders,
497  DiskDrive->Geometry.Heads,
498  DiskDrive->Geometry.Sectors,
499  DiskDrive->Geometry.BytesPerSector);
500 
501  return TRUE;
502 }
503 
504 static BOOLEAN
506  IN UCHAR UnitNumber,
507  IN OUT PPC98_DISK_DRIVE DiskDrive)
508 {
509  PDEVICE_UNIT DeviceUnit = AtaGetDevice(UnitNumber);
510 
511  /* We work directly only with ATAPI drives because BIOS has ATA support */
512  if (DeviceUnit && DeviceUnit->Flags & ATA_DEVICE_ATAPI)
513  {
514  DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
515  DiskDrive->Geometry.Heads = DeviceUnit->Heads;
516  DiskDrive->Geometry.Sectors = DeviceUnit->Sectors;
517  DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
518  DiskDrive->DaUa = 0xFF;
519  DiskDrive->IdeUnitNumber = UnitNumber;
520  DiskDrive->Type = DRIVE_IDE | DRIVE_CDROM;
521  DiskDrive->LBASupported = TRUE;
522  DiskDrive->IsRemovable = TRUE;
523  DiskDrive->Initialized = TRUE;
524 
525  TRACE("InitIdeDrive(0x%x) returned:\n"
526  "Cylinders : 0x%x\n"
527  "Heads : 0x%x\n"
528  "Sects/Track: 0x%x\n"
529  "Bytes/Sect : 0x%x\n",
530  UnitNumber,
531  DiskDrive->Geometry.Cylinders,
532  DiskDrive->Geometry.Heads,
533  DiskDrive->Geometry.Sectors,
534  DiskDrive->Geometry.BytesPerSector);
535 
536  return TRUE;
537  }
538 
539  DiskDrive->Initialized = FALSE;
540  return FALSE;
541 }
542 
543 static BOOLEAN
545  IN UCHAR DaUa,
546  IN OUT PPC98_DISK_DRIVE DiskDrive)
547 {
548  REGS RegsIn, RegsOut;
549 
550  /* Int 1Bh AH=8Eh
551  * DISK BIOS - Set half-height operation mode
552  *
553  * Call with:
554  * AL - drive number
555  */
556  RegsIn.b.al = DaUa;
557  RegsIn.b.ah = 0x8E;
558  Int386(0x1B, &RegsIn, &RegsOut);
559 
560  /* Int 1Bh AH=84h
561  * DISK BIOS - Sense
562  *
563  * Call with:
564  * AL - drive number
565  *
566  * Return:
567  * BX - bytes per sector
568  * CX - cylinders number
569  * DH - heads number
570  * DL - sectors number
571  * CF - set on error, clear if successful
572  * AH - status
573  */
574  RegsIn.b.al = DaUa;
575  RegsIn.b.ah = 0x84;
576  Int386(0x1B, &RegsIn, &RegsOut);
577  if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
578  {
579  DiskDrive->Initialized = FALSE;
580  return FALSE;
581  }
582 
583  DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
584  DiskDrive->Geometry.Heads = RegsOut.b.dh;
585  DiskDrive->Geometry.Sectors = RegsOut.b.dl;
586  DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
587  DiskDrive->DaUa = DaUa;
588  DiskDrive->Type = DRIVE_IDE;
589  DiskDrive->LBASupported = FALSE;
590  DiskDrive->IsRemovable = FALSE;
591  DiskDrive->Initialized = TRUE;
592 
593  TRACE("InitHardDrive(0x%x) returned:\n"
594  "Cylinders : 0x%x\n"
595  "Heads : 0x%x\n"
596  "Sects/Track: 0x%x\n"
597  "Bytes/Sect : 0x%x\n",
598  DaUa,
599  DiskDrive->Geometry.Cylinders,
600  DiskDrive->Geometry.Heads,
601  DiskDrive->Geometry.Sectors,
602  DiskDrive->Geometry.BytesPerSector);
603 
604  return TRUE;
605 }
606 
607 static BOOLEAN
609  IN UCHAR DaUa,
610  IN OUT PPC98_DISK_DRIVE DiskDrive)
611 {
612  REGS RegsIn, RegsOut;
613  USHORT BytesPerSector;
614  UCHAR DeviceAddress = DaUa & 0xF0;
615 
616  /* There's no way to obtain floppy disk geometry in BIOS */
617 
618  /* Int 1Bh AH=4Ah
619  * DISK BIOS - Read ID
620  *
621  * Call with:
622  * AL - drive number
623  *
624  * Return:
625  * CH - sector size
626  * CL - cylinder
627  * DH - head
628  * DL - sector
629  * CF - set on error, clear if successful
630  * AH - status
631  */
632  RegsIn.b.ah = 0x4A;
633  RegsIn.b.al = DaUa;
634  Int386(0x1B, &RegsIn, &RegsOut);
635  if (!INT386_SUCCESS(RegsOut))
636  {
637  DiskDrive->Initialized = FALSE;
638  return FALSE;
639  }
640 
641  BytesPerSector = 128 << RegsOut.b.ch;
642  switch (BytesPerSector)
643  {
644  case 256:
645  if (DeviceAddress == 0x50)
646  {
647  /* 320 kB 2DD */
648  DiskDrive->Geometry.Cylinders = 80;
649  DiskDrive->Geometry.Heads = 2;
650  DiskDrive->Geometry.Sectors = 16;
651  }
652  else
653  {
654  /* 1 MB 2HD */
655  DiskDrive->Geometry.Cylinders = 77;
656  DiskDrive->Geometry.Heads = 2;
657  DiskDrive->Geometry.Sectors = 26;
658  }
659  break;
660 
661  case 512:
662  if (DeviceAddress == 0x30 || DeviceAddress == 0xB0)
663  {
664  /* 1.44 MB 2HD */
665  DiskDrive->Geometry.Cylinders = 80;
666  DiskDrive->Geometry.Heads = 2;
667  DiskDrive->Geometry.Sectors = 18;
668  }
669  else if (DeviceAddress == 0x70 || DeviceAddress == 0xF0)
670  {
671  /* 720/640 kB 2DD */
672  DiskDrive->Geometry.Cylinders = 80;
673  DiskDrive->Geometry.Heads = 2;
674  DiskDrive->Geometry.Sectors = 8;
675  }
676  else
677  {
678  /* 1.2 MB 2HC */
679  DiskDrive->Geometry.Cylinders = 80;
680  DiskDrive->Geometry.Heads = 2;
681  DiskDrive->Geometry.Sectors = 15;
682  }
683  break;
684 
685  case 1024:
686  /* 1.25 MB 2HD */
687  DiskDrive->Geometry.Cylinders = 77;
688  DiskDrive->Geometry.Heads = 2;
689  DiskDrive->Geometry.Sectors = 8;
690  break;
691 
692  default:
693  DiskDrive->Initialized = FALSE;
694  return FALSE;
695  }
696 
697  DiskDrive->Geometry.BytesPerSector = BytesPerSector;
698  DiskDrive->DaUa = DaUa;
699  DiskDrive->Type = DRIVE_FDD;
700  DiskDrive->LBASupported = FALSE;
701  DiskDrive->IsRemovable = TRUE;
702  DiskDrive->Initialized = TRUE;
703 
704  TRACE("InitFloppyDrive(0x%x) returned:\n"
705  "Cylinders : 0x%x\n"
706  "Heads : 0x%x\n"
707  "Sects/Track: 0x%x\n"
708  "Bytes/Sect : 0x%x\n",
709  DaUa,
710  DiskDrive->Geometry.Cylinders,
711  DiskDrive->Geometry.Heads,
712  DiskDrive->Geometry.Sectors,
713  DiskDrive->Geometry.BytesPerSector);
714 
715  return TRUE;
716 }
717 
718 /* We emulate PC BIOS drive numbers here */
719 BOOLEAN
721 {
722  PPC98_DISK_DRIVE DiskDrive;
723  UCHAR FakeFloppyDriveNumber = 0x30;
724  UCHAR FakeHardDriveDriveNumber = 0x80;
725  UCHAR FakeCdRomDriveNumber = 0xE0;
726  USHORT DiskEquipment = *(PUSHORT)MEM_DISK_EQUIP & ~(*(PUCHAR)MEM_RDISK_EQUIP);
727  UCHAR IdeDetectedCount;
728  UCHAR i;
729 
730  TRACE("Pc98InitializeBootDevices()\n");
731 
733 
734  /*
735  * Map DA/UA to drive number, i.e.
736  * 0x90 -> 0x30
737  * 0x80 -> 0x80
738  * 0xA0 -> 0x81, etc.
739  */
740 
741  /* Map floppies */
742 
743  for (i = 0; i < 4; i++)
744  {
745  DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
746  if (FIRSTBYTE(DiskEquipment) & (1 << i))
747  {
748  if (InitFloppyDrive(0x30 + i, DiskDrive) || InitFloppyDrive(0xB0 + i, DiskDrive) ||
749  InitFloppyDrive(0x90 + i, DiskDrive) || InitFloppyDrive(0x10 + i, DiskDrive))
750  ++FakeFloppyDriveNumber;
751  }
752  }
753 
754  for (i = 0; i < 4; i++)
755  {
756  DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
757  if (FIRSTBYTE(DiskEquipment) & (16 << i))
758  {
759  if (InitFloppyDrive(0x50 + i, DiskDrive))
760  ++FakeFloppyDriveNumber;
761  }
762  }
763 
764  for (i = 0; i < 4; i++)
765  {
766  DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
767  if (SECONDBYTE(DiskEquipment) & (16 << i))
768  {
769  if (InitFloppyDrive(0x70 + i, DiskDrive) || InitFloppyDrive(0xF0 + i, DiskDrive))
770  ++FakeFloppyDriveNumber;
771  }
772  }
773 
774  /* Map IDE/SASI drives */
775 
776  for (i = 0; i < 4; i++)
777  {
778  DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
779  if (InitHardDrive(0x80 + i, DiskDrive) || InitHardDrive(0x00 + i, DiskDrive))
780  ++FakeHardDriveDriveNumber;
781  }
782 
783  AtaInit(&IdeDetectedCount);
784  for (i = 0; i <= IdeDetectedCount; i++)
785  {
786  DiskDrive = &Pc98DiskDrive[FakeCdRomDriveNumber];
787  if (InitIdeDrive(i, DiskDrive))
788  ++FakeCdRomDriveNumber;
789  }
790 
791  /* Map SCSI drives */
792 
793  for (i = 0; i < 7; i++)
794  {
795  DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
796  if (InitScsiDrive(0xA0 + i, DiskDrive) || InitScsiDrive(0x20 + i, DiskDrive))
797  {
798  if (DiskDrive->Type & DRIVE_CDROM || DiskDrive->Type & DRIVE_MO)
799  {
800  /* Move to CD-ROM area */
801  Pc98DiskDrive[FakeCdRomDriveNumber] = *DiskDrive;
802  RtlZeroMemory(DiskDrive, sizeof(PC98_DISK_DRIVE));
803  ++FakeCdRomDriveNumber;
804  }
805  else
806  {
807  ++FakeHardDriveDriveNumber;
808  }
809  }
810  }
811 
812 #if 1
813  // Ugly HACK: Force ISO boot
814  // FIXME: Fill ARC disk blocks completely
815  // to allow usage of CD-ROM root path (See floppy_pc98.ini).
816  FrldrBootDrive = 0xE0;
817  FrldrBootPartition = 0xFF;
818 #else
819  /* Reassign boot drive */
820  for (i = 0; i < MAX_DRIVES - 1; i++)
821  {
822  DiskDrive = &Pc98DiskDrive[i];
823  if (DiskDrive->Initialized && DiskDrive->DaUa == FrldrBootDrive)
824  {
825  TRACE("Boot drive: old 0x%x, new 0x%x\n", FrldrBootDrive, i);
826  FrldrBootDrive = i;
827  break;
828  }
829  }
830 #endif
831 
832  /* Call PC version */
833  return PcInitializeBootDevices();
834 }
835 
836 BOOLEAN
838  IN UCHAR DriveNumber,
839  IN ULONGLONG SectorNumber,
841  OUT PVOID Buffer)
842 {
843  PPC98_DISK_DRIVE DiskDrive;
844 
845  TRACE("Pc98DiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n",
846  DriveNumber, SectorNumber, SectorCount, Buffer);
847 
848  /* 16-bit BIOS addressing limitation */
849  ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
850 
851  DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
852  if (!DiskDrive)
853  return FALSE;
854 
855  if (DiskDrive->LBASupported)
856  {
857  /* LBA is easy, nothing to calculate. Just do the read. */
858  TRACE("--> Using LBA\n");
859  return Pc98DiskReadLogicalSectorsLBA(DiskDrive, SectorNumber, SectorCount, Buffer);
860  }
861  else
862  {
863  /* LBA is not supported, default to CHS */
864  TRACE("--> Using CHS\n");
865  return Pc98DiskReadLogicalSectorsCHS(DiskDrive, SectorNumber, SectorCount, Buffer);
866  }
867 }
868 
869 BOOLEAN
871 {
872  PPC98_DISK_DRIVE DiskDrive;
873 
874  TRACE("Pc98DiskGetDriveGeometry(0x%x)\n", DriveNumber);
875 
876  DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
877  if (!DiskDrive)
878  return FALSE;
879 
880  *Geometry = DiskDrive->Geometry;
881 
882  return TRUE;
883 }
884 
885 ULONG
887 {
888  PPC98_DISK_DRIVE DiskDrive;
889 
890  DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
891  if (!DiskDrive)
892  return 1; // Unknown count.
893 
894  /*
895  * If LBA is supported then the block size will be 64 sectors (32k).
896  * If not then the block size is the size of one track.
897  */
898  if (DiskDrive->LBASupported)
899  return 64;
900  else
901  return DiskDrive->Geometry.Sectors;
902 }
ULONG Cylinders
Definition: hwide.h:294
#define IN
Definition: typedefs.h:39
unsigned short dx
Definition: pcbios.h:108
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
VOID Pc98DiskPrepareForReactOS(VOID)
Definition: pc98disk.c:135
#define TRUE
Definition: types.h:120
VOID AtaFree(VOID)
Definition: hwide.c:166
ULONG Cylinders
Definition: disk.h:26
static BOOLEAN InitScsiDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:404
BOOLEAN LBASupported
Definition: machpc98.h:121
DeviceType
Definition: mmdrv.h:41
#define MAX_DRIVES
Definition: pc98disk.c:19
unsigned char * PUCHAR
Definition: retypes.h:3
static BOOLEAN Pc98DiskReadLogicalSectorsLBA(IN PPC98_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:179
char CHAR
Definition: xmlstorage.h:175
#define WARN(fmt,...)
Definition: debug.h:112
#define FIRSTBYTE(VALUE)
Definition: rtlfuncs.h:795
unsigned short cx
Definition: pcbios.h:107
unsigned short es
Definition: pcbios.h:115
unsigned char ah
Definition: pcbios.h:126
#define MEM_RDISK_EQUIP
Definition: machpc98.h:33
BOOLEAN AtaInit(OUT PUCHAR DetectedCount)
Definition: hwide.c:139
ULONG SectorSize
Definition: hwide.h:297
ULONG Heads
Definition: hwide.h:295
unsigned char dh
Definition: pcbios.h:135
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define MEM_DISK_EQUIP
Definition: machpc98.h:41
int __cdecl Int386(int ivec, REGS *in, REGS *out)
static UCHAR BytesPerSectorToSectorLengthCode(IN ULONG BytesPerSector)
Definition: pc98disk.c:159
BOOLEAN Initialized
Definition: machpc98.h:133
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
ULONG Sectors
Definition: hwide.h:296
unsigned char dl
Definition: pcbios.h:134
#define DRIVE_CDROM
Definition: machpc98.h:115
#define FALSE
Definition: types.h:117
_In_ PUSB_DEVICE_HANDLE _Out_ PUSHORT DeviceAddress
Definition: hubbusif.h:359
BOOLEAN PcInitializeBootDevices(VOID)
Definition: hwdisk.c:470
ULONG FrldrBootPartition
long LONG
Definition: pedump.c:60
#define INT386_SUCCESS(regs)
Definition: pcbios.h:173
static BOOLEAN InitFloppyDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:608
static PCSTR DiskGetErrorCodeString(ULONG ErrorCode)
Definition: pc98disk.c:40
VOID UiMessageBox(PCSTR Format,...)
Definition: ui.c:320
#define DRIVE_MO
Definition: machpc98.h:117
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
BOOLEAN AtaAtapiReadLogicalSectorsLBA(IN OUT PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: hwide.c:187
Definition: bufpool.h:45
void * PVOID
Definition: retypes.h:9
NTSTRSAFEVAPI RtlStringCbPrintfA(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,...)
Definition: ntstrsafe.h:1148
LONG DiskReportError(BOOLEAN bShowError)
Definition: pc98disk.c:29
BOOLEAN Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
Definition: pc98disk.c:870
ULONG Sectors
Definition: disk.h:28
#define TRACE(s)
Definition: solgame.cpp:4
DBG_DEFAULT_CHANNEL(DISK)
PC98_DISK_DRIVE Pc98DiskDrive[MAX_DRIVES]
Definition: pc98disk.c:22
#define DRIVE_FDD
Definition: machpc98.h:116
uint64_t ULONGLONG
Definition: typedefs.h:67
BOOLEAN Pc98DiskReadLogicalSectors(IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:837
#define DRIVE_SCSI
Definition: machpc98.h:114
unsigned char ch
Definition: pcbios.h:132
USHORT Flags
Definition: hwide.h:299
static BOOLEAN InitIdeDrive(IN UCHAR UnitNumber, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:505
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
unsigned char UCHAR
Definition: xmlstorage.h:181
unsigned char cl
Definition: pcbios.h:131
#define DRIVE_IDE
Definition: machpc98.h:113
BYTEREGS b
Definition: pcbios.h:157
#define MEM_SCSI_TABLE
Definition: machpc98.h:24
UCHAR FrldrBootDrive
unsigned char al
Definition: pcbios.h:125
ULONG SectorCount
Definition: part_xbox.c:31
#define MEM_DISK_EQUIPS
Definition: machpc98.h:30
PPC98_DISK_DRIVE Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber)
Definition: pc98disk.c:141
static BOOLEAN InitHardDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:544
#define ERR(fmt,...)
Definition: debug.h:110
ULONG Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber)
Definition: pc98disk.c:886
#define ATA_DEVICE_ATAPI
Definition: hwide.h:303
ULONG BytesPerSector
Definition: disk.h:29
BOOLEAN Pc98InitializeBootDevices(VOID)
Definition: pc98disk.c:720
unsigned short bp
Definition: pcbios.h:112
unsigned short USHORT
Definition: pedump.c:61
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
Definition: disk.h:24
unsigned short bx
Definition: pcbios.h:106
static BOOLEAN Pc98DiskReadLogicalSectorsCHS(IN PPC98_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:251
static LONG lReportError
Definition: pc98disk.c:26
unsigned int * PULONG
Definition: retypes.h:1
PDEVICE_UNIT AtaGetDevice(IN UCHAR UnitNumber)
Definition: hwide.c:178
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
Definition: pcbios.h:152
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define ULONG_PTR
Definition: config.h:101
const char * PCSTR
Definition: typedefs.h:52
GEOMETRY Geometry
Definition: machpc98.h:102
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
static VOID DiskError(PCSTR ErrorString, ULONG ErrorCode)
Definition: pc98disk.c:74
unsigned short * PUSHORT
Definition: retypes.h:2
WORDREGS w
Definition: pcbios.h:156
#define SECONDBYTE(VALUE)
Definition: rtlfuncs.h:796
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:91
ULONG Heads
Definition: disk.h:27