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