ReactOS 0.4.16-dev-1946-g52006dd
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
26static LONG lReportError = 0; /* >= 0: display errors; < 0: hide errors */
27
28LONG
30{
31 /* Set the reference count */
32 if (bShowError)
34 else
36 return lReportError;
37}
38
39static 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
73static 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
137{
138 PPC98_DISK_DRIVE DiskDrive;
139
140 ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(Pc98DiskDrive)));
141
142 /* Retrieve a slot */
143 DiskDrive = &Pc98DiskDrive[DriveNumber];
144
145 /* The pre-initialization of the BIOS disks was already done in Pc98InitializeBootDevices() */
146 if (DiskDrive->Initialized)
147 return DiskDrive;
148 else
149 return NULL;
150}
151
154 _In_ UCHAR DriveNumber)
155{
156 PPC98_DISK_DRIVE DiskDrive;
157
158 DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
159 if (!DiskDrive)
160 return -1; // MaximumType;
161
162 if (DiskDrive->Type & DRIVE_CDROM || DiskDrive->Type & DRIVE_MO)
163 return CdromController;
164 else if (DiskDrive->Type & DRIVE_FDD)
166 else
167 return DiskPeripheral;
168}
169
170static inline
171UCHAR
173{
174 switch (BytesPerSector)
175 {
176 case 128:
177 return 0;
178 case 256:
179 return 1;
180 case 512:
181 return 2;
182 case 1024:
183 return 3;
184 case 2048:
185 return 4;
186 default:
187 return 0;
188 }
189}
190
191static BOOLEAN
193 IN PPC98_DISK_DRIVE DiskDrive,
194 IN ULONGLONG SectorNumber,
197{
198 REGS RegsIn, RegsOut;
199 ULONG RetryCount;
200
201 if (DiskDrive->Type & DRIVE_IDE && DiskDrive->Type & DRIVE_CDROM)
202 {
203 return AtaReadLogicalSectors(AtaGetDevice(DiskDrive->IdeUnitNumber), SectorNumber, SectorCount, Buffer);
204 }
205 else
206 {
207 /* Int 1Bh AH=06h
208 * DISK BIOS - Read data
209 *
210 * Call with:
211 * AL - drive number
212 * BX - bytes to read
213 * CX - cylinder number
214 * DH - head number
215 * DL - sector number
216 * ES:BP -> buffer to read data into
217 *
218 * Return:
219 * CF - set on error, clear if successful
220 * AH - status
221 */
222 RegsIn.b.al = DiskDrive->DaUa;
223 RegsIn.b.ah = 0x06;
224 RegsIn.w.bx = DiskDrive->Geometry.BytesPerSector * SectorCount;
225 RegsIn.w.cx = SectorNumber & 0xFFFF;
226 RegsIn.w.dx = (SectorNumber >> 16) & 0xFFFF;
227 RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
228 RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
229
230 /* Retry 3 times */
231 for (RetryCount = 0; RetryCount < 3; ++RetryCount)
232 {
233 Int386(0x1B, &RegsIn, &RegsOut);
234
235 /* If it worked, or if it was a corrected ECC error
236 * and the data is still good, return success */
237 if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x08))
238 return TRUE;
239
240 /* It failed, do the next retry */
241 DiskResetController(DiskDrive);
242 }
243 }
244
245 /* If we get here then the read failed */
246 DiskError("Disk Read Failed in LBA mode", RegsOut.b.ah);
247 ERR("Disk Read Failed in LBA mode: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u)\n",
248 RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
249 DiskDrive->DaUa, SectorNumber, SectorCount);
250
251 return FALSE;
252}
253
254static BOOLEAN
256 IN PPC98_DISK_DRIVE DiskDrive,
257 IN ULONGLONG SectorNumber,
260{
261 UCHAR PhysicalSector;
262 UCHAR PhysicalHead;
263 ULONG PhysicalTrack;
264 GEOMETRY DriveGeometry;
265 ULONG NumberOfSectorsToRead;
266 REGS RegsIn, RegsOut;
267 ULONG RetryCount;
268
269 DriveGeometry = DiskDrive->Geometry;
270
271 while (SectorCount > 0)
272 {
273 /*
274 * Calculate the physical disk offsets.
275 * Note: DriveGeometry.SectorsPerTrack < 64
276 */
277 PhysicalSector = (UCHAR)(SectorNumber % DriveGeometry.SectorsPerTrack);
278 PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.SectorsPerTrack) % DriveGeometry.Heads);
279 PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.SectorsPerTrack) / DriveGeometry.Heads);
280
281 /* Floppy sectors value always start at 1 */
282 if (DiskDrive->Type & DRIVE_FDD)
283 ++PhysicalSector;
284
285 /* Calculate how many sectors we need to read this round */
286 if (PhysicalSector > 1)
287 {
288 NumberOfSectorsToRead = min(SectorCount,
289 (DriveGeometry.SectorsPerTrack - (PhysicalSector - 1)));
290 }
291 else
292 {
293 NumberOfSectorsToRead = min(SectorCount, DriveGeometry.SectorsPerTrack);
294 }
295
296 /* Make sure the read is within the geometry boundaries */
297 if ((PhysicalHead >= DriveGeometry.Heads) ||
298 (PhysicalTrack >= DriveGeometry.Cylinders) ||
299 ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.SectorsPerTrack + 1)) ||
300 (PhysicalSector > DriveGeometry.SectorsPerTrack))
301 {
302 DiskError("Disk read exceeds drive geometry limits.", 0);
303 return FALSE;
304 }
305
306 if (DiskDrive->Type & DRIVE_FDD)
307 {
308 /* Int 1Bh AH=x6h
309 * DISK BIOS - Read data
310 *
311 * Call with:
312 * AL - drive number
313 * BX - bytes to read
314 * CH - sector length code
315 * CL - cylinder number
316 * DH - head number
317 * DL - sector number
318 * ES:BP -> buffer to read data into
319 *
320 * Return:
321 * CF - set on error, clear if successful
322 * AH - status
323 */
324 RegsIn.b.al = DiskDrive->DaUa;
325 RegsIn.b.ah = 0x56; /* With SEEK, and use double-density format (MFM) */
326 RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
327 RegsIn.b.cl = PhysicalTrack & 0xFFFF;
328 RegsIn.b.ch = BytesPerSectorToSectorLengthCode(DriveGeometry.BytesPerSector);
329 RegsIn.b.dl = PhysicalSector;
330 RegsIn.b.dh = PhysicalHead;
331 RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
332 RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
333 }
334 else
335 {
336 /* Int 1Bh AH=06h
337 * DISK BIOS - Read data
338 *
339 * Call with:
340 * AL - drive number
341 * BX - bytes to read
342 * CX - cylinder number
343 * DH - head number
344 * DL - sector number
345 * ES:BP -> buffer to read data into
346 *
347 * Return:
348 * CF - set on error, clear if successful
349 * AH - status
350 */
351 RegsIn.b.al = DiskDrive->DaUa;
352 RegsIn.b.ah = 0x06;
353 RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
354 RegsIn.w.cx = PhysicalTrack & 0xFFFF;
355 RegsIn.b.dl = PhysicalSector;
356 RegsIn.b.dh = PhysicalHead;
357 RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
358 RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
359 }
360
361 /* Perform the read. Retry 3 times. */
362 for (RetryCount = 0; RetryCount < 3; ++RetryCount)
363 {
364 Int386(0x1B, &RegsIn, &RegsOut);
365
366 /* If it worked, or if it was a corrected ECC error
367 * and the data is still good, return success */
368 if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x08))
369 break;
370
371 /* It failed, do the next retry */
372 DiskResetController(DiskDrive);
373 }
374
375 /* If we retried 3 times then fail */
376 if (RetryCount >= 3)
377 {
378 DiskError("Disk Read Failed in CHS mode, after retrying 3 times", RegsOut.b.ah);
379 ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u)\n",
380 RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
381 DiskDrive->DaUa, SectorNumber, SectorCount);
382 return FALSE;
383 }
384
385 Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
386 SectorCount -= NumberOfSectorsToRead;
387 SectorNumber += NumberOfSectorsToRead;
388 }
389
390 return TRUE;
391}
392
393static BOOLEAN
395 IN UCHAR DaUa,
396 IN OUT PPC98_DISK_DRIVE DiskDrive)
397{
398 REGS RegsIn, RegsOut;
399 UCHAR UnitAddress = DaUa & 0x0F;
400 USHORT DiskEquipment = *(PUCHAR)MEM_DISK_EQUIPS;
401 ULONG ScsiParameters = *(PULONG)(MEM_SCSI_TABLE + UnitAddress * sizeof(ULONG));
403
404 /* Hard drives */
405 if (DiskEquipment & (1 << UnitAddress))
406 {
407 /* Int 1Bh AH=84h
408 * DISK BIOS - Sense
409 *
410 * Call with:
411 * AL - drive number
412 *
413 * Return:
414 * BX - bytes per sector
415 * CX - cylinders number
416 * DH - heads number
417 * DL - sectors number
418 * CF - set on error, clear if successful
419 * AH - status
420 */
421 RegsIn.b.al = DaUa;
422 RegsIn.b.ah = 0x84;
423 Int386(0x1B, &RegsIn, &RegsOut);
424 if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
425 {
426 DiskDrive->Initialized = FALSE;
427 return FALSE;
428 }
429
430 DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
431 DiskDrive->Geometry.Heads = RegsOut.b.dh;
432 DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.dl;
433 DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
434 DiskDrive->LBASupported = FALSE;
435 DiskDrive->IsRemovable = FALSE;
436 }
437 /* Other devices */
438 else if (ScsiParameters)
439 {
440 DeviceType = ScsiParameters & 0x1F;
441 switch (DeviceType)
442 {
443 case 0x05:
444 /* CD-ROM */
445 DiskDrive->Geometry.Cylinders = 0xFFFF;
446 DiskDrive->Geometry.Heads = 0xFFFF;
447 DiskDrive->Geometry.SectorsPerTrack = 0xFFFF;
448 DiskDrive->Geometry.BytesPerSector = 2048;
449 DiskDrive->Type = DRIVE_CDROM;
450 DiskDrive->LBASupported = TRUE;
451 DiskDrive->IsRemovable = TRUE;
452 break;
453
454 case 0x07:
455 /* Magneto-optical drive */
456 DiskDrive->Geometry.Cylinders = 0xFFFF;
457 DiskDrive->Geometry.Heads = 8;
458 DiskDrive->Geometry.SectorsPerTrack = 32;
459 DiskDrive->Geometry.BytesPerSector = 512;
460 DiskDrive->Type = DRIVE_MO;
461 DiskDrive->LBASupported = TRUE;
462 DiskDrive->IsRemovable = TRUE;
463 break;
464
465 default:
466 DiskDrive->Initialized = FALSE;
467 return FALSE;
468 }
469 }
470 else
471 {
472 DiskDrive->Initialized = FALSE;
473 return FALSE;
474 }
475
476 DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
477 DiskDrive->Geometry.Heads *
478 DiskDrive->Geometry.SectorsPerTrack;
479
480 DiskDrive->DaUa = DaUa;
481 DiskDrive->Type |= DRIVE_SCSI;
482 DiskDrive->Initialized = TRUE;
483
484 TRACE("InitScsiDrive(0x%x) returned:\n"
485 "Cylinders : 0x%x\n"
486 "Heads : 0x%x\n"
487 "Sects/Track: 0x%x\n"
488 "Total Sects: 0x%llx\n"
489 "Bytes/Sect : 0x%x\n",
490 DaUa,
491 DiskDrive->Geometry.Cylinders,
492 DiskDrive->Geometry.Heads,
493 DiskDrive->Geometry.SectorsPerTrack,
494 DiskDrive->Geometry.Sectors,
495 DiskDrive->Geometry.BytesPerSector);
496
497 return TRUE;
498}
499
500static BOOLEAN
502 IN UCHAR UnitNumber,
503 IN OUT PPC98_DISK_DRIVE DiskDrive)
504{
505 PDEVICE_UNIT DeviceUnit = AtaGetDevice(UnitNumber);
506
507 /* We work directly only with ATAPI drives because BIOS has ATA support */
508 if (DeviceUnit && DeviceUnit->Flags & ATA_DEVICE_ATAPI)
509 {
510 DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
511 DiskDrive->Geometry.Heads = DeviceUnit->Heads;
512 DiskDrive->Geometry.SectorsPerTrack = DeviceUnit->SectorsPerTrack;
513 DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
514 DiskDrive->Geometry.Sectors = DeviceUnit->TotalSectors;
515
516 DiskDrive->DaUa = 0xFF;
517 DiskDrive->IdeUnitNumber = UnitNumber;
518 DiskDrive->Type = DRIVE_IDE | DRIVE_CDROM;
519 DiskDrive->LBASupported = TRUE;
520 DiskDrive->IsRemovable = TRUE;
521 DiskDrive->Initialized = TRUE;
522
523 TRACE("InitIdeDrive(0x%x) returned:\n"
524 "Cylinders : 0x%x\n"
525 "Heads : 0x%x\n"
526 "Sects/Track: 0x%x\n"
527 "Total Sects: 0x%llx\n"
528 "Bytes/Sect : 0x%x\n",
529 UnitNumber,
530 DiskDrive->Geometry.Cylinders,
531 DiskDrive->Geometry.Heads,
532 DiskDrive->Geometry.SectorsPerTrack,
533 DiskDrive->Geometry.Sectors,
534 DiskDrive->Geometry.BytesPerSector);
535
536 return TRUE;
537 }
538
539 DiskDrive->Initialized = FALSE;
540 return FALSE;
541}
542
543static 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.SectorsPerTrack = RegsOut.b.dl;
586 DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
587
588 DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
589 DiskDrive->Geometry.Heads *
590 DiskDrive->Geometry.SectorsPerTrack;
591
592 DiskDrive->DaUa = DaUa;
593 DiskDrive->Type = DRIVE_IDE;
594 DiskDrive->LBASupported = FALSE;
595 DiskDrive->IsRemovable = FALSE;
596 DiskDrive->Initialized = TRUE;
597
598 TRACE("InitHardDrive(0x%x) returned:\n"
599 "Cylinders : 0x%x\n"
600 "Heads : 0x%x\n"
601 "Sects/Track: 0x%x\n"
602 "Total Sects: 0x%llx\n"
603 "Bytes/Sect : 0x%x\n",
604 DaUa,
605 DiskDrive->Geometry.Cylinders,
606 DiskDrive->Geometry.Heads,
607 DiskDrive->Geometry.SectorsPerTrack,
608 DiskDrive->Geometry.Sectors,
609 DiskDrive->Geometry.BytesPerSector);
610
611 return TRUE;
612}
613
614static BOOLEAN
616 IN UCHAR DaUa,
617 IN OUT PPC98_DISK_DRIVE DiskDrive)
618{
619 REGS RegsIn, RegsOut;
620 USHORT BytesPerSector;
621 UCHAR DeviceAddress = DaUa & 0xF0;
622
623 /* There's no way to obtain floppy disk geometry in BIOS */
624
625 /* Int 1Bh AH=4Ah
626 * DISK BIOS - Read ID
627 *
628 * Call with:
629 * AL - drive number
630 *
631 * Return:
632 * CH - sector size
633 * CL - cylinder
634 * DH - head
635 * DL - sector
636 * CF - set on error, clear if successful
637 * AH - status
638 */
639 RegsIn.b.ah = 0x4A;
640 RegsIn.b.al = DaUa;
641 Int386(0x1B, &RegsIn, &RegsOut);
642 if (!INT386_SUCCESS(RegsOut))
643 {
644 DiskDrive->Initialized = FALSE;
645 return FALSE;
646 }
647
648 BytesPerSector = 128 << RegsOut.b.ch;
649 switch (BytesPerSector)
650 {
651 case 256:
652 if (DeviceAddress == 0x50)
653 {
654 /* 320 kB 2DD */
655 DiskDrive->Geometry.Cylinders = 80;
656 DiskDrive->Geometry.Heads = 2;
657 DiskDrive->Geometry.SectorsPerTrack = 16;
658 }
659 else
660 {
661 /* 1 MB 2HD */
662 DiskDrive->Geometry.Cylinders = 77;
663 DiskDrive->Geometry.Heads = 2;
664 DiskDrive->Geometry.SectorsPerTrack = 26;
665 }
666 break;
667
668 case 512:
669 if (DeviceAddress == 0x30 || DeviceAddress == 0xB0)
670 {
671 /* 1.44 MB 2HD */
672 DiskDrive->Geometry.Cylinders = 80;
673 DiskDrive->Geometry.Heads = 2;
674 DiskDrive->Geometry.SectorsPerTrack = 18;
675 }
676 else if (DeviceAddress == 0x70 || DeviceAddress == 0xF0)
677 {
678 /* 720/640 kB 2DD */
679 DiskDrive->Geometry.Cylinders = 80;
680 DiskDrive->Geometry.Heads = 2;
681 DiskDrive->Geometry.SectorsPerTrack = 8;
682 }
683 else
684 {
685 /* 1.2 MB 2HC */
686 DiskDrive->Geometry.Cylinders = 80;
687 DiskDrive->Geometry.Heads = 2;
688 DiskDrive->Geometry.SectorsPerTrack = 15;
689 }
690 break;
691
692 case 1024:
693 /* 1.25 MB 2HD */
694 DiskDrive->Geometry.Cylinders = 77;
695 DiskDrive->Geometry.Heads = 2;
696 DiskDrive->Geometry.SectorsPerTrack = 8;
697 break;
698
699 default:
700 DiskDrive->Initialized = FALSE;
701 return FALSE;
702 }
703
704 DiskDrive->Geometry.BytesPerSector = BytesPerSector;
705 DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
706 DiskDrive->Geometry.Heads *
707 DiskDrive->Geometry.SectorsPerTrack;
708
709 DiskDrive->DaUa = DaUa;
710 DiskDrive->Type = DRIVE_FDD;
711 DiskDrive->LBASupported = FALSE;
712 DiskDrive->IsRemovable = TRUE;
713 DiskDrive->Initialized = TRUE;
714
715 TRACE("InitFloppyDrive(0x%x) returned:\n"
716 "Cylinders : 0x%x\n"
717 "Heads : 0x%x\n"
718 "Sects/Track: 0x%x\n"
719 "Total Sects: 0x%llx\n"
720 "Bytes/Sect : 0x%x\n",
721 DaUa,
722 DiskDrive->Geometry.Cylinders,
723 DiskDrive->Geometry.Heads,
724 DiskDrive->Geometry.SectorsPerTrack,
725 DiskDrive->Geometry.Sectors,
726 DiskDrive->Geometry.BytesPerSector);
727
728 return TRUE;
729}
730
731/* We emulate PC BIOS drive numbers here */
734{
735 PPC98_DISK_DRIVE DiskDrive;
736 UCHAR FakeFloppyDriveNumber = 0x30;
737 UCHAR FakeHardDriveDriveNumber = 0x80;
738 UCHAR FakeCdRomDriveNumber = 0xE0;
739 USHORT DiskEquipment = *(PUSHORT)MEM_DISK_EQUIP & ~(*(PUCHAR)MEM_RDISK_EQUIP);
740 UCHAR IdeDetectedCount;
741 UCHAR i;
742
743 TRACE("Pc98InitializeBootDevices()\n");
744
746
747 /*
748 * Map DA/UA to drive number, i.e.
749 * 0x90 -> 0x30
750 * 0x80 -> 0x80
751 * 0xA0 -> 0x81, etc.
752 */
753
754 /* Map floppies */
755
756 for (i = 0; i < 4; i++)
757 {
758 DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
759 if (FIRSTBYTE(DiskEquipment) & (1 << i))
760 {
761 if (InitFloppyDrive(0x30 + i, DiskDrive) || InitFloppyDrive(0xB0 + i, DiskDrive) ||
762 InitFloppyDrive(0x90 + i, DiskDrive) || InitFloppyDrive(0x10 + i, DiskDrive))
763 ++FakeFloppyDriveNumber;
764 }
765 }
766
767 for (i = 0; i < 4; i++)
768 {
769 DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
770 if (FIRSTBYTE(DiskEquipment) & (16 << i))
771 {
772 if (InitFloppyDrive(0x50 + i, DiskDrive))
773 ++FakeFloppyDriveNumber;
774 }
775 }
776
777 for (i = 0; i < 4; i++)
778 {
779 DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
780 if (SECONDBYTE(DiskEquipment) & (16 << i))
781 {
782 if (InitFloppyDrive(0x70 + i, DiskDrive) || InitFloppyDrive(0xF0 + i, DiskDrive))
783 ++FakeFloppyDriveNumber;
784 }
785 }
786
787 /* Map IDE/SASI drives */
788
789 for (i = 0; i < 4; i++)
790 {
791 DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
792 if (InitHardDrive(0x80 + i, DiskDrive) || InitHardDrive(0x00 + i, DiskDrive))
793 ++FakeHardDriveDriveNumber;
794 }
795
796 AtaInit(&IdeDetectedCount);
797 for (i = 0; i <= IdeDetectedCount; i++)
798 {
799 DiskDrive = &Pc98DiskDrive[FakeCdRomDriveNumber];
800 if (InitIdeDrive(i, DiskDrive))
801 ++FakeCdRomDriveNumber;
802 }
803
804 /* Map SCSI drives */
805
806 for (i = 0; i < 7; i++)
807 {
808 DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
809 if (InitScsiDrive(0xA0 + i, DiskDrive) || InitScsiDrive(0x20 + i, DiskDrive))
810 {
811 if (DiskDrive->Type & DRIVE_CDROM || DiskDrive->Type & DRIVE_MO)
812 {
813 /* Move to CD-ROM area */
814 Pc98DiskDrive[FakeCdRomDriveNumber] = *DiskDrive;
815 RtlZeroMemory(DiskDrive, sizeof(PC98_DISK_DRIVE));
816 ++FakeCdRomDriveNumber;
817 }
818 else
819 {
820 ++FakeHardDriveDriveNumber;
821 }
822 }
823 }
824
825#if 1
826 // Ugly HACK: Force ISO boot
827 // FIXME: Fill ARC disk blocks completely
828 // to allow usage of CD-ROM root path (See floppy_pc98.ini).
829 FrldrBootDrive = 0xE0;
830 FrldrBootPartition = 0xFF;
831#else
832 /* Reassign boot drive */
833 for (i = 0; i < MAX_DRIVES - 1; i++)
834 {
835 DiskDrive = &Pc98DiskDrive[i];
836 if (DiskDrive->Initialized && DiskDrive->DaUa == FrldrBootDrive)
837 {
838 TRACE("Boot drive: old 0x%x, new 0x%x\n", FrldrBootDrive, i);
840 break;
841 }
842 }
843#endif
844
845 /* Call PC version */
847}
848
851 IN UCHAR DriveNumber,
852 IN ULONGLONG SectorNumber,
855{
856 PPC98_DISK_DRIVE DiskDrive;
857
858 TRACE("Pc98DiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64u SectorCount: %u Buffer: 0x%x\n",
859 DriveNumber, SectorNumber, SectorCount, Buffer);
860
861 /* 16-bit BIOS addressing limitation */
862 ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
863
864 DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
865 if (!DiskDrive)
866 return FALSE;
867
868 if (DiskDrive->LBASupported)
869 {
870 /* LBA is easy, nothing to calculate. Just do the read. */
871 TRACE("--> Using LBA\n");
872 return Pc98DiskReadLogicalSectorsLBA(DiskDrive, SectorNumber, SectorCount, Buffer);
873 }
874 else
875 {
876 /* LBA is not supported, default to CHS */
877 TRACE("--> Using CHS\n");
878 return Pc98DiskReadLogicalSectorsCHS(DiskDrive, SectorNumber, SectorCount, Buffer);
879 }
880}
881
884{
885 PPC98_DISK_DRIVE DiskDrive;
886
887 TRACE("Pc98DiskGetDriveGeometry(0x%x)\n", DriveNumber);
888
889 DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
890 if (!DiskDrive)
891 return FALSE;
892
893 *Geometry = DiskDrive->Geometry;
894
895 return TRUE;
896}
897
898ULONG
900{
901 PPC98_DISK_DRIVE DiskDrive;
902
903 DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
904 if (!DiskDrive)
905 return 1; // Unknown count.
906
907 /*
908 * If LBA is supported then the block size will be 64 sectors (32k).
909 * If not then the block size is the size of one track.
910 */
911 if (DiskDrive->LBASupported)
912 return 64;
913 else
914 return DiskDrive->Geometry.SectorsPerTrack;
915}
unsigned char BOOLEAN
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
VOID UiMessageBox(_In_ PCSTR Format,...)
Definition: ui.c:359
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ULONG_PTR
Definition: config.h:101
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
_In_ PUSB_DEVICE_HANDLE _Out_ PUSHORT DeviceAddress
Definition: hubbusif.h:360
BOOLEAN PcInitializeBootDevices(VOID)
Definition: hwdisk.c:458
PDEVICE_UNIT AtaGetDevice(_In_ UCHAR UnitNumber)
Definition: hwide.c:1254
BOOLEAN AtaInit(_Out_ PUCHAR DetectedCount)
Definition: hwide.c:1264
BOOLEAN AtaReadLogicalSectors(_In_ PDEVICE_UNIT DeviceUnit, _In_ ULONG64 SectorNumber, _In_ ULONG SectorCount, _Out_writes_bytes_all_(SectorCount *DeviceUnit->SectorSize) PVOID Buffer)
Definition: hwide.c:1215
#define ATA_DEVICE_ATAPI
Definition: hwide.h:30
#define DRIVE_SCSI
Definition: machpc98.h:118
#define MEM_RDISK_EQUIP
Definition: machpc98.h:33
#define MEM_DISK_EQUIP
Definition: machpc98.h:41
#define MEM_SCSI_TABLE
Definition: machpc98.h:24
#define DRIVE_MO
Definition: machpc98.h:121
#define DRIVE_IDE
Definition: machpc98.h:117
#define MEM_DISK_EQUIPS
Definition: machpc98.h:30
#define DRIVE_CDROM
Definition: machpc98.h:119
#define DRIVE_FDD
Definition: machpc98.h:120
DeviceType
Definition: mmdrv.h:42
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
#define _In_
Definition: no_sal2.h:158
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
ULONG SectorCount
Definition: part_xbox.c:31
ULONG Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber)
Definition: pc98disk.c:899
static LONG lReportError
Definition: pc98disk.c:26
static BOOLEAN InitHardDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:544
static PCSTR DiskGetErrorCodeString(ULONG ErrorCode)
Definition: pc98disk.c:40
PPC98_DISK_DRIVE Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber)
Definition: pc98disk.c:136
PC98_DISK_DRIVE Pc98DiskDrive[MAX_DRIVES]
Definition: pc98disk.c:22
static BOOLEAN Pc98DiskReadLogicalSectorsLBA(IN PPC98_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:192
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:91
LONG DiskReportError(BOOLEAN bShowError)
Definition: pc98disk.c:29
BOOLEAN Pc98InitializeBootDevices(VOID)
Definition: pc98disk.c:733
static BOOLEAN InitFloppyDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:615
BOOLEAN Pc98DiskReadLogicalSectors(IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:850
CONFIGURATION_TYPE DiskGetConfigType(_In_ UCHAR DriveNumber)
Definition: pc98disk.c:153
static BOOLEAN Pc98DiskReadLogicalSectorsCHS(IN PPC98_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:255
#define MAX_DRIVES
Definition: pc98disk.c:19
static BOOLEAN InitIdeDrive(IN UCHAR UnitNumber, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:501
static BOOLEAN InitScsiDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:394
static UCHAR BytesPerSectorToSectorLengthCode(IN ULONG BytesPerSector)
Definition: pc98disk.c:172
BOOLEAN Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
Definition: pc98disk.c:883
static VOID DiskError(PCSTR ErrorString, ULONG ErrorCode)
Definition: pc98disk.c:74
#define INT386_SUCCESS(regs)
Definition: pcbios.h:181
int __cdecl Int386(int ivec, REGS *in, REGS *out)
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
@ DiskPeripheral
Definition: arc.h:138
@ FloppyDiskPeripheral
Definition: arc.h:139
@ CdromController
Definition: arc.h:128
enum _CONFIGURATION_TYPE CONFIGURATION_TYPE
#define TRACE(s)
Definition: solgame.cpp:4
unsigned char ch
Definition: pcbios.h:140
unsigned char dl
Definition: pcbios.h:142
unsigned char cl
Definition: pcbios.h:139
unsigned char al
Definition: pcbios.h:133
unsigned char ah
Definition: pcbios.h:134
unsigned char dh
Definition: pcbios.h:143
unsigned short bp
Definition: pcbios.h:120
unsigned short es
Definition: pcbios.h:123
unsigned short cx
Definition: pcbios.h:115
unsigned short dx
Definition: pcbios.h:116
unsigned short bx
Definition: pcbios.h:114
Data structure for the ATA device.
Definition: hwide.h:12
ULONG Cylinders
Definition: hwide.h:14
ULONG SectorSize
Definition: hwide.h:23
ULONG SectorsPerTrack
Definition: hwide.h:20
ULONG64 TotalSectors
Definition: hwide.h:26
ULONG Flags
Definition: hwide.h:29
ULONG Heads
Definition: hwide.h:17
Definition: disk.h:26
ULONG BytesPerSector
Number of bytes per sector.
Definition: disk.h:30
ULONG Cylinders
Number of cylinders on the disk.
Definition: disk.h:27
ULONG SectorsPerTrack
Number of sectors per track.
Definition: disk.h:29
ULONG Heads
Number of heads on the disk.
Definition: disk.h:28
BOOLEAN LBASupported
Definition: machpc98.h:125
GEOMETRY Geometry
Definition: machpc98.h:106
BOOLEAN Initialized
Definition: machpc98.h:137
uint32_t * PULONG
Definition: typedefs.h:59
void * PVOID
Definition: typedefs.h:50
uint16_t * PUSHORT
Definition: typedefs.h:56
const char * PCSTR
Definition: typedefs.h:52
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
UCHAR FrldrBootDrive
Definition: uefidisk.c:47
ULONG FrldrBootPartition
Definition: uefidisk.c:48
Definition: pcbios.h:161
BYTEREGS b
Definition: pcbios.h:165
WORDREGS w
Definition: pcbios.h:164
#define SECONDBYTE(VALUE)
Definition: rtlfuncs.h:807
#define FIRSTBYTE(VALUE)
Definition: rtlfuncs.h:806
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175