ReactOS 0.4.15-dev-5669-g09dde2c
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
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
157static inline
158UCHAR
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
178static BOOLEAN
180 IN PPC98_DISK_DRIVE DiskDrive,
181 IN ULONGLONG SectorNumber,
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
250static BOOLEAN
252 IN PPC98_DISK_DRIVE DiskDrive,
253 IN ULONGLONG SectorNumber,
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
403static 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
504static 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
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.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
607static 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 */
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);
827 break;
828 }
829 }
830#endif
831
832 /* Call PC version */
834}
835
838 IN UCHAR DriveNumber,
839 IN ULONGLONG SectorNumber,
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
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
885ULONG
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}
unsigned char BOOLEAN
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
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:470
PDEVICE_UNIT AtaGetDevice(IN UCHAR UnitNumber)
Definition: hwide.c:178
BOOLEAN AtaAtapiReadLogicalSectorsLBA(IN OUT PDEVICE_UNIT DeviceUnit, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: hwide.c:187
BOOLEAN AtaInit(OUT PUCHAR DetectedCount)
Definition: hwide.c:139
VOID AtaFree()
#define ATA_DEVICE_ATAPI
Definition: hwide.h:303
#define DRIVE_SCSI
Definition: machpc98.h:114
#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:117
#define DRIVE_IDE
Definition: machpc98.h:113
#define MEM_DISK_EQUIPS
Definition: machpc98.h:30
#define DRIVE_CDROM
Definition: machpc98.h:115
#define DRIVE_FDD
Definition: machpc98.h:116
UCHAR FrldrBootDrive
ULONG FrldrBootPartition
DeviceType
Definition: mmdrv.h:42
#define ASSERT(a)
Definition: mode.c:44
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
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:886
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:141
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:179
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:91
LONG DiskReportError(BOOLEAN bShowError)
Definition: pc98disk.c:29
VOID Pc98DiskPrepareForReactOS(VOID)
Definition: pc98disk.c:135
BOOLEAN Pc98InitializeBootDevices(VOID)
Definition: pc98disk.c:720
static BOOLEAN InitFloppyDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:608
BOOLEAN Pc98DiskReadLogicalSectors(IN UCHAR DriveNumber, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:837
static BOOLEAN Pc98DiskReadLogicalSectorsCHS(IN PPC98_DISK_DRIVE DiskDrive, IN ULONGLONG SectorNumber, IN ULONG SectorCount, OUT PVOID Buffer)
Definition: pc98disk.c:251
#define MAX_DRIVES
Definition: pc98disk.c:19
static BOOLEAN InitIdeDrive(IN UCHAR UnitNumber, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:505
static BOOLEAN InitScsiDrive(IN UCHAR DaUa, IN OUT PPC98_DISK_DRIVE DiskDrive)
Definition: pc98disk.c:404
static UCHAR BytesPerSectorToSectorLengthCode(IN ULONG BytesPerSector)
Definition: pc98disk.c:159
BOOLEAN Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
Definition: pc98disk.c:870
static VOID DiskError(PCSTR ErrorString, ULONG ErrorCode)
Definition: pc98disk.c:74
#define INT386_SUCCESS(regs)
Definition: pcbios.h:179
int __cdecl Int386(int ivec, REGS *in, REGS *out)
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define TRACE(s)
Definition: solgame.cpp:4
unsigned char ch
Definition: pcbios.h:138
unsigned char dl
Definition: pcbios.h:140
unsigned char cl
Definition: pcbios.h:137
unsigned char al
Definition: pcbios.h:131
unsigned char ah
Definition: pcbios.h:132
unsigned char dh
Definition: pcbios.h:141
unsigned short bp
Definition: pcbios.h:118
unsigned short es
Definition: pcbios.h:121
unsigned short cx
Definition: pcbios.h:113
unsigned short dx
Definition: pcbios.h:114
unsigned short bx
Definition: pcbios.h:112
USHORT Flags
Definition: hwide.h:299
ULONG Cylinders
Definition: hwide.h:294
ULONG SectorSize
Definition: hwide.h:297
ULONG Sectors
Definition: hwide.h:296
ULONG Heads
Definition: hwide.h:295
Definition: disk.h:25
ULONG BytesPerSector
Definition: disk.h:29
ULONG Sectors
Definition: disk.h:28
ULONG Cylinders
Definition: disk.h:26
ULONG Heads
Definition: disk.h:27
BOOLEAN LBASupported
Definition: machpc98.h:121
GEOMETRY Geometry
Definition: machpc98.h:102
BOOLEAN Initialized
Definition: machpc98.h:133
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
VOID UiMessageBox(PCSTR Format,...)
Definition: ui.c:363
Definition: pcbios.h:159
BYTEREGS b
Definition: pcbios.h:163
WORDREGS w
Definition: pcbios.h:162
#define SECONDBYTE(VALUE)
Definition: rtlfuncs.h:796
#define FIRSTBYTE(VALUE)
Definition: rtlfuncs.h:795
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175