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 *******************************************************************/
17 // #include "../../memory.h"
18 // #include "cpu/bop.h"
19 #include "cpu/cpu.h" // for EMULATOR_FLAG_ZF
22 #include "dskbios32.h"
23 // #include <bios/dskbios.h>
26 #include "hardware/disk.h"
29 /* DEFINES ********************************************************************/
31 // Disks which are currently supported by the BIOS Disk module.
32 // NOTE: For the current implementation those are arrays of pointers to
33 // DISK_IMAGEs maintained by the Generic Disk Controller. In the future
34 // they will be arrays of objects containing disk information needed by
36 static PDISK_IMAGE FloppyDrive
[2] = {NULL
};
37 static PDISK_IMAGE HardDrive
[4] = {NULL
};
41 // See: http://www.ctyme.com/intr/rb-2445.htm
42 typedef struct _FLOPPY_PARAM_TABLE
55 } FLOPPY_PARAM_TABLE
, *PFLOPPY_PARAM_TABLE
;
57 typedef struct _FLOPPY_PARAM_TABLE_EX
59 FLOPPY_PARAM_TABLE FloppyParamTable
;
63 BYTE DataTransferRate
;
65 } FLOPPY_PARAM_TABLE_EX
, *PFLOPPY_PARAM_TABLE_EX
;
69 // Parameters for 1.44 MB Floppy, taken from SeaBIOS
71 #define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors
72 #define FLOPPY_DATALEN 0xFF // Not used - because size code is 0x02
73 #define FLOPPY_MOTOR_TICKS 37 // ~2 seconds
74 #define FLOPPY_FILLBYTE 0xF6
75 #define FLOPPY_GAPLEN 0x1B
76 #define FLOPPY_FORMAT_GAPLEN 0x6C
78 static const FLOPPY_PARAM_TABLE_EX FloppyParamTable
=
80 // PC-AT compatible table
82 0xAF, // step rate 12ms, head unload 240ms
83 0x02, // head load time 4ms, DMA used
84 FLOPPY_MOTOR_TICKS
, // ~2 seconds
97 0, // data transfer rate
98 4, // drive type in CMOS
102 #pragma pack(push, 1)
104 // See: http://www.ctyme.com/intr/rb-6135.htm
105 typedef struct _HARDDISK_PARAM_TABLE
113 BYTE StandardTimeout
;
115 BYTE CheckingTimeout
;
116 WORD LandZoneCylinder
;
117 BYTE SectorsPerTrack
;
119 } HARDDISK_PARAM_TABLE
, *PHARDDISK_PARAM_TABLE
;
123 // static const HARDDISK_PARAM_TABLE HardDiskParamTable =
127 /* PRIVATE FUNCTIONS **********************************************************/
130 GetDisk(IN BYTE DiskNumber
)
132 if (DiskNumber
& 0x80)
136 if (DiskNumber
>= ARRAYSIZE(HardDrive
))
138 DPRINT1("GetDisk: HDD number 0x%02X invalid\n", DiskNumber
| 0x80);
142 return HardDrive
[DiskNumber
];
146 if (DiskNumber
>= ARRAYSIZE(FloppyDrive
))
148 DPRINT1("GetDisk: Floppy number 0x%02X invalid\n", DiskNumber
);
152 return FloppyDrive
[DiskNumber
];
159 Bda
->LastDisketteOperation
= 0;
160 Bda
->LastDiskOperation
= 0;
164 VOID WINAPI
BiosDiskService(LPWORD Stack
)
167 PDISK_IMAGE DiskImage
;
171 /* Disk -- Reset Disk System */
182 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
188 if (Drive
>= ARRAYSIZE(FloppyDrive
))
190 DPRINT1("BiosDiskService(0x00): Drive number 0x%02X invalid\n", Drive
);
194 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
202 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
206 /* Disk -- Get Status of Last Operation */
209 BYTE LastOperationStatus
= 0x00;
212 DiskImage
= GetDisk(Drive
);
213 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
215 DPRINT1("BiosDiskService(0x01): Disk number 0x%02X invalid\n", Drive
);
219 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
223 LastOperationStatus
= DiskImage
->LastOperationStatus
;
226 Bda
->LastDiskOperation
= LastOperationStatus
;
228 Bda
->LastDisketteOperation
= LastOperationStatus
;
230 /* Return last error */
231 setAH(LastOperationStatus
);
232 if (LastOperationStatus
== 0x00)
233 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
235 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
240 /* Disk -- Read Sectors into Memory */
245 BYTE NumSectors
= getAL();
247 // CH: Low eight bits of cylinder number
248 // CL: High two bits of cylinder (bits 6-7, hard disk only)
249 WORD Cylinder
= MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
251 // CL: Sector number 1-63 (bits 0-5)
252 BYTE Sector
= (getCL() & 0x3F); // 1-based
255 DiskImage
= GetDisk(Drive
);
256 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
258 DPRINT1("BiosDiskService(0x02): Disk number 0x%02X invalid\n", Drive
);
262 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
266 /* Read the sectors */
267 Status
= ReadDisk(DiskImage
, Cylinder
, Head
, Sector
, NumSectors
);
272 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
276 DPRINT1("BiosDiskService(0x02): Error when reading from disk number 0x%02X (0x%02X)\n", Drive
, Status
);
280 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
286 /* Disk -- Write Disk Sectors */
291 BYTE NumSectors
= getAL();
293 // CH: Low eight bits of cylinder number
294 // CL: High two bits of cylinder (bits 6-7, hard disk only)
295 WORD Cylinder
= MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
297 // CL: Sector number 1-63 (bits 0-5)
298 BYTE Sector
= (getCL() & 0x3F); // 1-based
301 DiskImage
= GetDisk(Drive
);
302 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
304 DPRINT1("BiosDiskService(0x03): Disk number 0x%02X invalid\n", Drive
);
308 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
312 /* Write the sectors */
313 Status
= WriteDisk(DiskImage
, Cylinder
, Head
, Sector
, NumSectors
);
318 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
322 DPRINT1("BiosDiskService(0x03): Error when writing to disk number 0x%02X (0x%02X)\n", Drive
, Status
);
326 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
332 /* Disk -- Verify Disk Sectors */
335 /* Floppy/Fixed Disk -- Format Track */
338 /* Fixed Disk -- Format Track and Set Bad Sector Flags */
341 /* Fixed Disk -- Format Drive starting at Given Track */
345 /* Disk -- Get Drive Parameters */
350 BYTE PresentDrives
= 0;
354 DiskImage
= GetDisk(Drive
);
355 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
357 DPRINT1("BiosDiskService(0x08): Disk number 0x%02X invalid\n", Drive
);
361 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
365 // Minus 2 because it's the maximum cylinder number (not count),
366 // and the last cylinder is reserved (for compatibility with BIOSes
367 // which reserve it for testing purposes).
368 MaxCylinders
= DiskImage
->DiskInfo
.Cylinders
- 2;
369 // Minus 1 because it's the maximum head number (not count).
370 MaxHeads
= DiskImage
->DiskInfo
.Heads
- 1;
372 // CL: Sector number 1-63 (bits 0-5)
373 // High two bits of cylinder (bits 6-7, hard disk only)
374 setCL((DiskImage
->DiskInfo
.Sectors
& 0x3F) |
375 ((HIBYTE(MaxCylinders
) & 0x02) << 6));
376 // CH: Low eight bits of cylinder number
377 setCH(LOBYTE(MaxCylinders
));
383 /* Count the number of active HDDs */
384 for (i
= 0; i
< ARRAYSIZE(HardDrive
); ++i
)
386 if (IsDiskPresent(HardDrive
[i
]))
390 /* Reset ES:DI to NULL */
391 // FIXME: NONONO!! Apps expect (for example, MS-DOS kernel)
392 // that this function does not modify ES:DI if it was called
399 /* Count the number of active floppies */
400 for (i
= 0; i
< ARRAYSIZE(FloppyDrive
); ++i
)
402 if (IsDiskPresent(FloppyDrive
[i
]))
406 /* ES:DI points to the floppy parameter table */
407 setES(HIWORD(((PULONG
)BaseAddress
)[0x1E]));
408 setDI(LOWORD(((PULONG
)BaseAddress
)[0x1E]));
410 setDL(PresentDrives
);
412 setBL(DiskImage
->DiskType
); // DiskGeometryList[DiskImage->DiskType].biosval
417 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
421 /* Hard Disk -- Initialize Controller with Drive Parameters */
424 /* Hard Disk -- Read Long Sectors */
427 /* Hard Disk -- Write Long Sectors */
431 /* Hard Disk -- Seek to Cylinder */
437 // CH: Low eight bits of cylinder number
438 // CL: High two bits of cylinder (bits 6-7, hard disk only)
439 WORD Cylinder
= MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
441 // CL: Sector number 1-63 (bits 0-5)
442 BYTE Sector
= (getCL() & 0x3F); // 1-based
447 DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X is not a HDD\n", Drive
);
451 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
455 DiskImage
= GetDisk(Drive
);
456 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
458 DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X invalid\n", Drive
);
462 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
467 Status
= SeekDisk(DiskImage
, Cylinder
, Head
, Sector
);
472 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
476 DPRINT1("BiosDiskService(0x0C): Error when seeking in disk number 0x%02X (0x%02X)\n", Drive
, Status
);
480 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
486 /* Hard Disk -- Reset Hard Disks */
489 // FIXME: Should do what 0x11 does.
493 /* Hard Disk -- Read Sector Buffer (XT only) */
496 /* Hard Disk -- Write Sector Buffer (XT only) */
500 /* Hard Disk -- Check if Drive is ready */
506 DPRINT1("BiosDiskService(0x10): Disk number 0x%02X is not a HDD\n", Drive
);
510 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
514 DiskImage
= GetDisk(Drive
);
515 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
517 DPRINT1("BiosDiskService(0x10): Disk number 0x%02X invalid\n", Drive
);
521 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
527 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
531 /* Hard Disk -- Recalibrate Drive */
539 DPRINT1("BiosDiskService(0x11): Disk number 0x%02X is not a HDD\n", Drive
);
543 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
547 DiskImage
= GetDisk(Drive
);
548 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
550 DPRINT1("BiosDiskService(0x11): Disk number 0x%02X invalid\n", Drive
);
554 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
558 /* Set position to zero */
559 Status
= SeekDisk(DiskImage
, /*Cylinder*/ 0, /*Head*/ 0, /*Sector*/ 1);
564 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
568 DPRINT1("BiosDiskService(0x11): Error when recalibrating disk number 0x%02X (0x%02X)\n", Drive
, Status
);
572 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
578 /* Hard Disk -- Controller RAM Diagnostic */
581 /* Hard Disk -- Drive Diagnostic */
584 /* Hard Disk -- Controller Internal Diagnostic */
588 /* Disk -- Get Disk Type */
592 DiskImage
= GetDisk(Drive
);
593 if (!DiskImage
|| !IsDiskPresent(DiskImage
))
595 DPRINT1("BiosDiskService(0x15): Disk number 0x%02X invalid\n", Drive
);
599 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
610 /* Number of 512-byte sectors in CX:DX */
611 NumSectors
= (ULONG
)((ULONG
)DiskImage
->DiskInfo
.Cylinders
* DiskImage
->DiskInfo
.Heads
)
612 * DiskImage
->DiskInfo
.Sectors
;
613 setCX(HIWORD(NumSectors
));
614 setDX(LOWORD(NumSectors
));
623 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
627 /* Floppy Disk -- Detect Disk Change */
630 /* Floppy Disk -- Set Disk Type for Format */
633 /* Disk -- Set Media Type for Format */
639 DPRINT1("BIOS Function INT 13h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X NOT IMPLEMENTED\n",
640 getAH(), getAL(), getBH());
645 /* PUBLIC FUNCTIONS ***********************************************************/
647 VOID
DiskBios32Post(VOID
)
650 * Initialize BIOS Disk RAM dynamic data
653 /* Some vectors are in fact addresses to tables */
654 // Diskette Parameters
655 ((PULONG
)BaseAddress
)[0x1E] = MAKELONG(0xEFC7, BIOS_SEGMENT
);
656 // Hard Disk 0 Parameter Table Address
657 ((PULONG
)BaseAddress
)[0x41] = NULL32
;
658 // Hard Disk 1 Drive Parameter Table Address
659 ((PULONG
)BaseAddress
)[0x46] = NULL32
;
661 /* Relocated services by the BIOS (when needed) */
662 ((PULONG
)BaseAddress
)[0x40] = NULL32
; // ROM BIOS Diskette Handler relocated by Hard Disk BIOS
663 // RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk BIOS
665 /* Register the BIOS 32-bit Interrupts */
666 RegisterBiosInt32(BIOS_DISK_INTERRUPT
, BiosDiskService
);
668 /* Initialize the BDA */
669 // Bda->LastDisketteOperation = 0;
670 // Bda->LastDiskOperation = 0;
674 BOOLEAN
DiskBios32Initialize(VOID
)
677 * Initialize BIOS Disk ROM static data
680 /* Floppy Parameter Table */
681 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT
, 0xEFC7),
682 &FloppyParamTable
.FloppyParamTable
,
683 sizeof(FloppyParamTable
.FloppyParamTable
));
686 // FIXME: Must be done by HW floppy controller!
689 /* Detect and initialize the supported disks */
690 // TODO: the "Detect" part is missing.
691 FloppyDrive
[0] = RetrieveDisk(FLOPPY_DISK
, 0);
692 FloppyDrive
[1] = RetrieveDisk(FLOPPY_DISK
, 1);
693 HardDrive
[0] = RetrieveDisk(HARD_DISK
, 0);
694 HardDrive
[1] = RetrieveDisk(HARD_DISK
, 1);
695 HardDrive
[2] = RetrieveDisk(HARD_DISK
, 2);
696 HardDrive
[3] = RetrieveDisk(HARD_DISK
, 3);
701 VOID
DiskBios32Cleanup(VOID
)