2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM 32-bit Disk BIOS
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 /* INCLUDES *******************************************************************/
15 // #include "../../memory.h"
16 // #include "cpu/bop.h"
17 #include "cpu/cpu.h" // for EMULATOR_FLAG_ZF
20 #include "dskbios32.h"
21 // #include <bios/dskbios.h>
24 #include "hardware/disk.h"
27 /* DEFINES ********************************************************************/
29 // Disks which are currently supported by the BIOS Disk module.
30 // NOTE: For the current implementation those are arrays of pointers to
31 // DISK_IMAGEs maintained by the Generic Disk Controller. In the future
32 // they will be arrays of objects containing disk information needed by
34 static PDISK_IMAGE FloppyDrive
[2] = {NULL
};
35 static PDISK_IMAGE HardDrive
[1] = {NULL
};
39 // See: http://www.ctyme.com/intr/rb-2445.htm
40 typedef struct _FLOPPY_PARAM_TABLE
53 } FLOPPY_PARAM_TABLE
, *PFLOPPY_PARAM_TABLE
;
55 typedef struct _FLOPPY_PARAM_TABLE_EX
57 FLOPPY_PARAM_TABLE FloppyParamTable
;
61 BYTE DataTransferRate
;
63 } FLOPPY_PARAM_TABLE_EX
, *PFLOPPY_PARAM_TABLE_EX
;
67 // Parameters for 1.44 MB Floppy, taken from SeaBIOS
69 #define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors
70 #define FLOPPY_DATALEN 0xFF // Not used - because size code is 0x02
71 #define FLOPPY_MOTOR_TICKS 37 // ~2 seconds
72 #define FLOPPY_FILLBYTE 0xF6
73 #define FLOPPY_GAPLEN 0x1B
74 #define FLOPPY_FORMAT_GAPLEN 0x6C
76 static const FLOPPY_PARAM_TABLE_EX FloppyParamTable
=
78 // PC-AT compatible table
80 0xAF, // step rate 12ms, head unload 240ms
81 0x02, // head load time 4ms, DMA used
82 FLOPPY_MOTOR_TICKS
, // ~2 seconds
95 0, // data transfer rate
96 4, // drive type in CMOS
100 #pragma pack(push, 1)
102 // See: http://www.ctyme.com/intr/rb-6135.htm
103 typedef struct _HARDDISK_PARAM_TABLE
111 BYTE StandardTimeout
;
113 BYTE CheckingTimeout
;
114 WORD LandZoneCylinder
;
115 BYTE SectorsPerTrack
;
117 } HARDDISK_PARAM_TABLE
, *PHARDDISK_PARAM_TABLE
;
121 // static const HARDDISK_PARAM_TABLE HardDiskParamTable =
125 /* PRIVATE FUNCTIONS **********************************************************/
128 GetDisk(IN BYTE DiskNumber
)
130 if (DiskNumber
& 0x80)
134 if (DiskNumber
>= ARRAYSIZE(HardDrive
))
136 DPRINT1("GetDisk: HDD number 0x%02X invalid\n", DiskNumber
| 0x80);
140 return HardDrive
[DiskNumber
];
144 if (DiskNumber
>= ARRAYSIZE(FloppyDrive
))
146 DPRINT1("GetDisk: Floppy number 0x%02X invalid\n", DiskNumber
);
150 return FloppyDrive
[DiskNumber
];
157 Bda
->LastDisketteOperation
= 0;
158 Bda
->LastDiskOperation
= 0;
162 VOID WINAPI
BiosDiskService(LPWORD Stack
)
165 PDISK_IMAGE DiskImage
;
169 /* Disk -- Reset Disk System */
180 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
186 if (Drive
>= ARRAYSIZE(FloppyDrive
))
188 DPRINT1("BiosDiskService(0x00): Drive number 0x%02X invalid\n", Drive
);
192 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
200 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
204 /* Disk -- Get Status of Last Operation */
207 BYTE LastOperationStatus
= 0x00;
210 DiskImage
= GetDisk(Drive
);
211 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
213 DPRINT1("BiosDiskService(0x01): Disk number 0x%02X invalid\n", Drive
);
217 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
221 LastOperationStatus
= DiskImage
->LastOperationStatus
;
224 Bda
->LastDiskOperation
= LastOperationStatus
;
226 Bda
->LastDisketteOperation
= LastOperationStatus
;
228 /* Return last error */
229 setAH(LastOperationStatus
);
230 if (LastOperationStatus
== 0x00)
231 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
233 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
238 /* Disk -- Read Sectors into Memory */
243 BYTE NumSectors
= getAL();
245 // CH: Low eight bits of cylinder number
246 // CL: High two bits of cylinder (bits 6-7, hard disk only)
247 WORD Cylinder
= MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
249 // CL: Sector number 1-63 (bits 0-5)
250 BYTE Sector
= (getCL() & 0x3F); // 1-based
253 DiskImage
= GetDisk(Drive
);
254 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
256 DPRINT1("BiosDiskService(0x02): Disk number 0x%02X invalid\n", Drive
);
260 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
264 /* Read the sectors */
265 Status
= ReadDisk(DiskImage
, Cylinder
, Head
, Sector
, NumSectors
);
270 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
274 DPRINT1("BiosDiskService(0x02): Error when reading from disk number 0x%02X (0x%02X)\n", Drive
, Status
);
278 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
284 /* Disk -- Write Disk Sectors */
289 BYTE NumSectors
= getAL();
291 // CH: Low eight bits of cylinder number
292 // CL: High two bits of cylinder (bits 6-7, hard disk only)
293 WORD Cylinder
= MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
295 // CL: Sector number 1-63 (bits 0-5)
296 BYTE Sector
= (getCL() & 0x3F); // 1-based
299 DiskImage
= GetDisk(Drive
);
300 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
302 DPRINT1("BiosDiskService(0x03): Disk number 0x%02X invalid\n", Drive
);
306 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
310 /* Write the sectors */
311 Status
= WriteDisk(DiskImage
, Cylinder
, Head
, Sector
, NumSectors
);
316 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
320 DPRINT1("BiosDiskService(0x03): Error when writing to disk number 0x%02X (0x%02X)\n", Drive
, Status
);
324 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
330 /* Disk -- Verify Disk Sectors */
333 /* Floppy/Fixed Disk -- Format Track */
336 /* Fixed Disk -- Format Track and Set Bad Sector Flags */
339 /* Fixed Disk -- Format Drive starting at Given Track */
343 /* Disk -- Get Drive Parameters */
348 BYTE PresentDrives
= 0;
352 DiskImage
= GetDisk(Drive
);
353 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
355 DPRINT1("BiosDiskService(0x08): Disk number 0x%02X invalid\n", Drive
);
359 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
363 // Minus 2 because it's the maximum cylinder number (not count),
364 // and the last cylinder is reserved (for compatibility with BIOSes
365 // which reserve it for testing purposes).
366 MaxCylinders
= DiskImage
->DiskInfo
.Cylinders
- 2;
367 // Minus 1 because it's the maximum head number (not count).
368 MaxHeads
= DiskImage
->DiskInfo
.Heads
- 1;
370 // CL: Sector number 1-63 (bits 0-5)
371 // High two bits of cylinder (bits 6-7, hard disk only)
372 setCL((DiskImage
->DiskInfo
.Sectors
& 0x3F) |
373 ((HIBYTE(MaxCylinders
) & 0x02) << 6));
374 // CH: Low eight bits of cylinder number
375 setCH(LOBYTE(MaxCylinders
));
381 /* Count the number of active HDDs */
382 for (i
= 0; i
< ARRAYSIZE(HardDrive
); ++i
)
384 if (IsDiskPresent(HardDrive
[i
]))
388 /* Reset ES:DI to NULL */
389 // FIXME: NONONO!! Apps expect (for example, MS-DOS kernel)
390 // that this function does not modify ES:DI if it was called
397 /* Count the number of active floppies */
398 for (i
= 0; i
< ARRAYSIZE(FloppyDrive
); ++i
)
400 if (IsDiskPresent(FloppyDrive
[i
]))
404 /* ES:DI points to the floppy parameter table */
405 setES(HIWORD(((PULONG
)BaseAddress
)[0x1E]));
406 setDI(LOWORD(((PULONG
)BaseAddress
)[0x1E]));
408 setDL(PresentDrives
);
410 setBL(DiskImage
->DiskType
); // DiskGeometryList[DiskImage->DiskType].biosval
415 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
419 /* Hard Disk -- Initialize Controller with Drive Parameters */
422 /* Hard Disk -- Read Long Sectors */
425 /* Hard Disk -- Write Long Sectors */
429 /* Hard Disk -- Seek to Cylinder */
435 // CH: Low eight bits of cylinder number
436 // CL: High two bits of cylinder (bits 6-7, hard disk only)
437 WORD Cylinder
= MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
439 // CL: Sector number 1-63 (bits 0-5)
440 BYTE Sector
= (getCL() & 0x3F); // 1-based
445 DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X is not a HDD\n", Drive
);
449 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
453 DiskImage
= GetDisk(Drive
);
454 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
456 DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X invalid\n", Drive
);
460 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
465 Status
= SeekDisk(DiskImage
, Cylinder
, Head
, Sector
);
470 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
474 DPRINT1("BiosDiskService(0x0C): Error when seeking in disk number 0x%02X (0x%02X)\n", Drive
, Status
);
478 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
484 /* Hard Disk -- Reset Hard Disks */
487 // FIXME: Should do what 0x11 does.
491 /* Hard Disk -- Read Sector Buffer (XT only) */
494 /* Hard Disk -- Write Sector Buffer (XT only) */
498 /* Hard Disk -- Check if Drive is ready */
504 DPRINT1("BiosDiskService(0x10): Disk number 0x%02X is not a HDD\n", Drive
);
508 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
512 DiskImage
= GetDisk(Drive
);
513 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
515 DPRINT1("BiosDiskService(0x10): Disk number 0x%02X invalid\n", Drive
);
519 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
525 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
529 /* Hard Disk -- Recalibrate Drive */
537 DPRINT1("BiosDiskService(0x11): Disk number 0x%02X is not a HDD\n", Drive
);
541 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
545 DiskImage
= GetDisk(Drive
);
546 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
548 DPRINT1("BiosDiskService(0x11): Disk number 0x%02X invalid\n", Drive
);
552 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
556 /* Set position to zero */
557 Status
= SeekDisk(DiskImage
, /*Cylinder*/ 0, /*Head*/ 0, /*Sector*/ 1);
562 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
566 DPRINT1("BiosDiskService(0x11): Error when recalibrating disk number 0x%02X (0x%02X)\n", Drive
, Status
);
570 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
576 /* Hard Disk -- Controller RAM Diagnostic */
579 /* Hard Disk -- Drive Diagnostic */
582 /* Hard Disk -- Controller Internal Diagnostic */
586 /* Disk -- Get Disk Type */
590 DiskImage
= GetDisk(Drive
);
591 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
593 DPRINT1("BiosDiskService(0x15): Disk number 0x%02X invalid\n", Drive
);
597 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
608 /* Number of 512-byte sectors in CX:DX */
609 NumSectors
= DiskImage
->DiskInfo
.Cylinders
* DiskImage
->DiskInfo
.Heads
610 * DiskImage
->DiskInfo
.Sectors
;
611 setCX(HIWORD(NumSectors
));
612 setDX(LOWORD(NumSectors
));
621 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
625 /* Floppy Disk -- Detect Disk Change */
628 /* Floppy Disk -- Set Disk Type for Format */
631 /* Disk -- Set Media Type for Format */
637 DPRINT1("BIOS Function INT 13h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X NOT IMPLEMENTED\n",
638 getAH(), getAL(), getBH());
643 /* PUBLIC FUNCTIONS ***********************************************************/
645 VOID
DiskBios32Post(VOID
)
648 * Initialize BIOS Disk RAM dynamic data
651 /* Some vectors are in fact addresses to tables */
652 // Diskette Parameters
653 ((PULONG
)BaseAddress
)[0x1E] = MAKELONG(0xEFC7, BIOS_SEGMENT
);
654 // Hard Disk 0 Parameter Table Address
655 ((PULONG
)BaseAddress
)[0x41] = (ULONG
)NULL
;
656 // Hard Disk 1 Drive Parameter Table Address
657 ((PULONG
)BaseAddress
)[0x46] = (ULONG
)NULL
;
659 /* Relocated services by the BIOS (when needed) */
660 ((PULONG
)BaseAddress
)[0x40] = (ULONG
)NULL
; // ROM BIOS Diskette Handler relocated by Hard Disk BIOS
661 // RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk BIOS
663 /* Register the BIOS 32-bit Interrupts */
664 RegisterBiosInt32(BIOS_DISK_INTERRUPT
, BiosDiskService
);
666 /* Initialize the BDA */
667 // Bda->LastDisketteOperation = 0;
668 // Bda->LastDiskOperation = 0;
672 BOOLEAN
DiskBios32Initialize(VOID
)
675 * Initialize BIOS Disk ROM static data
678 /* Floppy Parameter Table */
679 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT
, 0xEFC7),
680 &FloppyParamTable
.FloppyParamTable
,
681 sizeof(FloppyParamTable
.FloppyParamTable
));
684 // FIXME: Must be done by HW floppy controller!
687 /* Detect and initialize the supported disks */
688 // TODO: the "Detect" part is missing.
689 FloppyDrive
[0] = &XDCFloppyDrive
[0];
690 FloppyDrive
[1] = &XDCFloppyDrive
[1];
691 HardDrive
[0] = &XDCHardDrive
[0];
696 VOID
DiskBios32Cleanup(VOID
)