Author: hbelusca
Date: Sat Sep 26 17:35:31 2015
New Revision: 69365
URL:
http://svn.reactos.org/svn/reactos?rev=69365&view=rev
Log:
[NTVDM]
Add basic disk support with mounting/unmounting images in NTVDM:
- basic disk controller (at the moment this is just a collection of helper functions. A
real HW emulation will come later on).
- INT 13h services for the BIOS.
At the moment, the images to be mounted are hardcoded in disk.c. Please see disk.c for
examples of how to use the function. This will be reworked to allow user choice without
having to recompile NTVDM.
CORE-10262 #resolve
Added:
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.h (with props)
trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.h (with props)
Modified:
trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios.h
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c
trunk/reactos/subsystems/mvdm/ntvdm/emulator.c
trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c
trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/CMak…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt [iso-8859-1] Sat Sep 26 17:35:31
2015
@@ -20,10 +20,11 @@
list(APPEND SOURCE
bios/bios32/bios32.c
+ bios/bios32/dskbios32.c
bios/bios32/kbdbios32.c
+ bios/bios32/moubios32.c
bios/bios32/vbe.c
bios/bios32/vidbios32.c
- bios/bios32/moubios32.c
bios/bios.c
bios/kbdbios.c
bios/rom.c
@@ -34,6 +35,7 @@
cpu/cpu.c
cpu/registers.c
hardware/cmos.c
+ hardware/disk.c
hardware/dma.c
hardware/keyboard.c
hardware/mouse.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios.h [iso-8859-1] Sat Sep 26 17:35:31 2015
@@ -27,8 +27,6 @@
#define BDA_SEGMENT 0x40
#define BIOS_SEGMENT 0xF000
-
-#define BIOS_EQUIPMENT_LIST 0x2E // Bit1: FPU, Bit 2: Mouse
#pragma pack(push, 1)
@@ -78,7 +76,7 @@
DWORD TickCounter; // 0x6c
BYTE MidnightPassed; // 0x70
- BYTE BreakFlag; // 0x71
+ BYTE CtrlBreakFlag; // 0x71
WORD SoftReset; // 0x72
BYTE LastDiskOperation; // 0x74
BYTE NumDisks; // 0x75
@@ -96,7 +94,7 @@
BYTE VGADccIDActive; // 0x8a
DWORD Reserved3; // 0x8b
BYTE Reserved4; // 0x8f
- BYTE Reserved5[2]; // 0x90
+ BYTE FloppyDriveState[2]; // 0x90
BYTE Reserved6[2]; // 0x92
BYTE Reserved7[2]; // 0x94
BYTE KeybdStatusFlags; // 0x96
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c [iso-8859-1] Sat Sep 26
17:35:31 2015
@@ -25,6 +25,7 @@
#include <bios/rom.h>
#include "bios32.h"
#include "bios32p.h"
+#include "dskbios32.h"
#include "kbdbios32.h"
#include "vidbios32.h"
#include "moubios32.h"
@@ -512,7 +513,8 @@
}
-VOID DosBootsectorInitialize(VOID);
+extern VOID DosBootsectorInitialize(VOID);
+extern VOID WINAPI BiosDiskService(LPWORD Stack);
static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
{
@@ -525,9 +527,68 @@
DPRINT("BiosBootstrapLoader -->\n");
- /* Load DOS */
+ {
+ USHORT i;
+
+ USHORT AX, BX, CX, DX, ES;
+ AX = getAX();
+ BX = getBX();
+ CX = getCX();
+ DX = getDX();
+ ES = getES();
+
+ // i = 0;
+ i = 1;
+ do
+ {
+ if (i == 0)
+ {
+ /* Boot from 1st floppy drive */
+
+ setAH(0x02); // Read sectors
+ setAL(0x01); // Number of sectors
+ setDH(0x00); // First head
+ setCH(0x00); // First cylinder
+ setCL(0x01); // First sector
+ setDL(0x00); // First diskette drive (used by loader code, so should not
be cleared)
+ setES(0x0000); // Place data in 0000:7C00
+ setBX(0x7C00);
+ BiosDiskService(Stack);
+ if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
+ DPRINT1("An error happened while loading the bootsector from floppy
0, error = %d\n", getAH());
+ }
+ else if (i == 1)
+ {
+ /* Boot from 1st HDD drive */
+
+ setAH(0x02); // Read sectors
+ setAL(0x01); // Number of sectors
+ setDH(0x00); // First head
+ setCH(0x00); // First cylinder
+ setCL(0x01); // First sector
+ setDL(0x80); // First HDD drive (used by loader code, so should not be
cleared)
+ setES(0x0000); // Place data in 0000:7C00
+ setBX(0x7C00);
+ BiosDiskService(Stack);
+ if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
+ DPRINT1("An error happened while loading the bootsector from HDD 0,
error = %d\n", getAH());
+ }
+ // } while (i++ < 1);
+ } while (i-- > 0);
+
+ /* Clear everything, we are going to load DOS32 */
+ setAX(AX);
+ setBX(BX);
+ setCX(CX);
+ setDX(DX);
+ setES(ES);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+
+ /* Load our DOS */
DosBootsectorInitialize();
+Quit:
/*
* Position CPU to 0000:7C00 to boot the OS.
*
@@ -848,7 +909,7 @@
// BIOS_VIDEO_INTERRUPT : 0x10 (vidbios32.c)
RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
- // BIOS_DISK_INTERRUPT : 0x13 -- UNIMPLEMENTED
+ // BIOS_DISK_INTERRUPT : 0x13 (dskbios32.c)
// BIOS_SERIAL_INTERRUPT : 0x14 -- UNIMPLEMENTED
RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
// BIOS_KBD_INTERRUPT : 0x16 (kbdbios32.c)
@@ -860,7 +921,6 @@
RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
/* Vectors that should be implemented (see above) */
- RegisterBiosInt32(0x13, NULL);
RegisterBiosInt32(0x14, NULL);
RegisterBiosInt32(0x17, NULL);
RegisterBiosInt32(0x1B, NULL);
@@ -896,11 +956,18 @@
/* Initialize the BDA contents */
RtlZeroMemory(Bda, sizeof(*Bda));
- Bda->EquipmentList = BIOS_EQUIPMENT_LIST;
+
+ /*
+ * Retrieve the basic equipment list from the CMOS
+ */
+ IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_EQUIPMENT_LIST | CMOS_DISABLE_NMI);
+ Bda->EquipmentList = IOReadB(CMOS_DATA_PORT);
+ // TODO: Update it if required.
+ Bda->EquipmentList &= 0x00FF; // High byte cleared for now...
/*
* Retrieve the conventional memory size
- * in kB from CMOS, typically 640 kB.
+ * in kB from the CMOS, typically 640 kB.
*/
IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW | CMOS_DISABLE_NMI);
Low = IOReadB(CMOS_DATA_PORT);
@@ -1069,6 +1136,7 @@
KbdBios32Post();
VidBiosPost();
MouseBios32Post();
+ DiskBios32Post();
// WriteProtectRom(...);
@@ -1118,7 +1186,7 @@
*(PBYTE)(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFFE)) = BIOS_MODEL;
/* Initialize the Keyboard and Video BIOS */
- if (!KbdBiosInitialize() || !VidBiosInitialize() || !MouseBiosInitialize())
+ if (!KbdBiosInitialize() || !VidBiosInitialize() || !MouseBiosInitialize() ||
!DiskBios32Initialize())
{
/* Stop the VDM */
EmulatorTerminate();
@@ -1137,6 +1205,7 @@
VOID Bios32Cleanup(VOID)
{
+ DiskBios32Cleanup();
MouseBios32Cleanup();
VidBios32Cleanup();
KbdBiosCleanup();
Added: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.c (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.c [iso-8859-1] Sat Sep 26
17:35:31 2015
@@ -0,0 +1,700 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dskbios32.c
+ * PURPOSE: VDM 32-bit Disk BIOS
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "ntvdm.h"
+#include "emulator.h"
+// #include "../../memory.h"
+// #include "cpu/bop.h"
+#include "cpu/cpu.h" // for EMULATOR_FLAG_ZF
+#include "int32.h"
+
+#include "dskbios32.h"
+// #include <bios/dskbios.h>
+#include "bios32p.h"
+
+#include "hardware/disk.h"
+
+
+/* DEFINES ********************************************************************/
+
+// Disks which are currently supported by the BIOS Disk module.
+// NOTE: For the current implementation those are arrays of pointers to
+// DISK_IMAGEs maintained by the Generic Disk Controller. In the future
+// they will be arrays of objects containing disk information needed by
+// the BIOS only.
+static PDISK_IMAGE FloppyDrive[2] = {NULL};
+static PDISK_IMAGE HardDrive[1] = {NULL};
+
+#pragma pack(push, 1)
+
+// See:
http://www.ctyme.com/intr/rb-2445.htm
+typedef struct _FLOPPY_PARAM_TABLE
+{
+ BYTE Unused0;
+ BYTE Unused1;
+ BYTE MotorOffDelay;
+ BYTE SectorSize;
+ BYTE SectorsPerTrack;
+ BYTE SectorGapLength;
+ BYTE DataLength;
+ BYTE FormatGapLength;
+ BYTE FormatFillByte;
+ BYTE HeadSettleTime;
+ BYTE MotorStartTime;
+} FLOPPY_PARAM_TABLE, *PFLOPPY_PARAM_TABLE;
+
+typedef struct _FLOPPY_PARAM_TABLE_EX
+{
+ FLOPPY_PARAM_TABLE FloppyParamTable;
+
+ // IBM Additions
+ BYTE MaxTrackNumber;
+ BYTE DataTransferRate;
+ BYTE CmosDriveType;
+} FLOPPY_PARAM_TABLE_EX, *PFLOPPY_PARAM_TABLE_EX;
+
+#pragma pack(pop)
+
+// Parameters for 1.44 MB Floppy, taken from SeaBIOS
+
+#define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors
+#define FLOPPY_DATALEN 0xFF // Not used - because size code is 0x02
+#define FLOPPY_MOTOR_TICKS 37 // ~2 seconds
+#define FLOPPY_FILLBYTE 0xF6
+#define FLOPPY_GAPLEN 0x1B
+#define FLOPPY_FORMAT_GAPLEN 0x6C
+
+static const FLOPPY_PARAM_TABLE_EX FloppyParamTable =
+{
+ // PC-AT compatible table
+ {
+ 0xAF, // step rate 12ms, head unload 240ms
+ 0x02, // head load time 4ms, DMA used
+ FLOPPY_MOTOR_TICKS, // ~2 seconds
+ FLOPPY_SIZE_CODE,
+ 18,
+ FLOPPY_GAPLEN,
+ FLOPPY_DATALEN,
+ FLOPPY_FORMAT_GAPLEN,
+ FLOPPY_FILLBYTE,
+ 0x0F, // 15ms
+ 0x08, // 1 second
+ },
+
+ // IBM Additions
+ 79, // maximum track
+ 0, // data transfer rate
+ 4, // drive type in CMOS
+};
+
+
+#pragma pack(push, 1)
+
+// See:
http://www.ctyme.com/intr/rb-6135.htm
+typedef struct _HARDDISK_PARAM_TABLE
+{
+ WORD Cylinders;
+ BYTE Heads;
+ WORD Unused0;
+ WORD Unused1;
+ BYTE Unused2;
+ BYTE Control;
+ BYTE StandardTimeout;
+ BYTE FormatTimeout;
+ BYTE CheckingTimeout;
+ WORD LandZoneCylinder;
+ BYTE SectorsPerTrack;
+ BYTE Reserved;
+} HARDDISK_PARAM_TABLE, *PHARDDISK_PARAM_TABLE;
+
+#pragma pack(pop)
+
+// static const HARDDISK_PARAM_TABLE HardDiskParamTable =
+// {0};
+
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static PDISK_IMAGE
+GetDisk(IN BYTE DiskNumber)
+{
+ if (DiskNumber & 0x80)
+ {
+ DiskNumber &= ~0x80;
+
+ if (DiskNumber >= ARRAYSIZE(HardDrive))
+ {
+ DPRINT1("GetDisk: HDD number 0x%02X invalid\n", DiskNumber |
0x80);
+ return NULL;
+ }
+
+ return HardDrive[DiskNumber];
+ }
+ else
+ {
+ if (DiskNumber >= ARRAYSIZE(FloppyDrive))
+ {
+ DPRINT1("GetDisk: Floppy number 0x%02X invalid\n", DiskNumber);
+ return NULL;
+ }
+
+ return FloppyDrive[DiskNumber];
+ }
+}
+
+static VOID
+AllDisksReset(VOID)
+{
+ Bda->LastDisketteOperation = 0;
+ Bda->LastDiskOperation = 0;
+}
+
+/*static*/
+VOID WINAPI BiosDiskService(LPWORD Stack)
+{
+ BYTE Drive;
+ PDISK_IMAGE DiskImage;
+
+ switch (getAH())
+ {
+ /* Disk -- Reset Disk System */
+ case 0x00:
+ {
+ Drive = getDL();
+
+ if (Drive & 0x80)
+ {
+ AllDisksReset();
+
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ break;
+ }
+
+ Drive &= ~0x80;
+
+ if (Drive >= ARRAYSIZE(FloppyDrive))
+ {
+ DPRINT1("BiosDiskService(0x00): Drive number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ // TODO: Reset drive
+
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Disk -- Get Status of Last Operation */
+ case 0x01:
+ {
+ BYTE LastOperationStatus = 0x00;
+
+ Drive = getDL();
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x01): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ LastOperationStatus = DiskImage->LastOperationStatus;
+
+ if (Drive & 0x80)
+ Bda->LastDiskOperation = LastOperationStatus;
+ else
+ Bda->LastDisketteOperation = LastOperationStatus;
+
+ /* Return last error */
+ setAH(LastOperationStatus);
+ if (LastOperationStatus == 0x00)
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ else
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+
+ break;
+ }
+
+ /* Disk -- Read Sectors into Memory */
+ case 0x02:
+ {
+ BYTE Status;
+ BYTE Head = getDH();
+ BYTE NumSectors = getAL();
+
+ // CH: Low eight bits of cylinder number
+ // CL: High two bits of cylinder (bits 6-7, hard disk only)
+ WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
+
+ // CL: Sector number 1-63 (bits 0-5)
+ BYTE Sector = (getCL() & 0x3F); // 1-based
+
+ Drive = getDL();
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x02): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Read the sectors */
+ Status = ReadDisk(DiskImage, Cylinder, Head, Sector, NumSectors);
+ if (Status == 0x00)
+ {
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ DPRINT1("BiosDiskService(0x02): Error when reading from disk number
0x%02X (0x%02X)\n", Drive, Status);
+
+ /* Return error */
+ setAH(Status);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ }
+
+ break;
+ }
+
+ /* Disk -- Write Disk Sectors */
+ case 0x03:
+ {
+ BYTE Status;
+ BYTE Head = getDH();
+ BYTE NumSectors = getAL();
+
+ // CH: Low eight bits of cylinder number
+ // CL: High two bits of cylinder (bits 6-7, hard disk only)
+ WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
+
+ // CL: Sector number 1-63 (bits 0-5)
+ BYTE Sector = (getCL() & 0x3F); // 1-based
+
+ Drive = getDL();
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x03): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Write the sectors */
+ Status = WriteDisk(DiskImage, Cylinder, Head, Sector, NumSectors);
+ if (Status == 0x00)
+ {
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ DPRINT1("BiosDiskService(0x03): Error when writing to disk number
0x%02X (0x%02X)\n", Drive, Status);
+
+ /* Return error */
+ setAH(Status);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ }
+
+ break;
+ }
+
+ /* Disk -- Verify Disk Sectors */
+ case 0x04:
+
+ /* Floppy/Fixed Disk -- Format Track */
+ case 0x05:
+
+ /* Fixed Disk -- Format Track and Set Bad Sector Flags */
+ case 0x06:
+
+ /* Fixed Disk -- Format Drive starting at Given Track */
+ case 0x07:
+ goto Default;
+
+ /* Disk -- Get Drive Parameters */
+ case 0x08:
+ {
+ WORD MaxCylinders;
+ BYTE MaxHeads;
+ BYTE PresentDrives = 0;
+ BYTE i;
+
+ Drive = getDL();
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x08): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ // Minus 2 because it's the maximum cylinder number (not count),
+ // and the last cylinder is reserved (for compatibility with BIOSes
+ // which reserve it for testing purposes).
+ MaxCylinders = DiskImage->DiskInfo.Cylinders - 2;
+ // Minus 1 because it's the maximum head number (not count).
+ MaxHeads = DiskImage->DiskInfo.Heads - 1;
+
+ // CL: Sector number 1-63 (bits 0-5)
+ // High two bits of cylinder (bits 6-7, hard disk only)
+ setCL((DiskImage->DiskInfo.Sectors & 0x3F) |
+ ((HIBYTE(MaxCylinders) & 0x02) << 6));
+ // CH: Low eight bits of cylinder number
+ setCH(LOBYTE(MaxCylinders));
+
+ setDH(MaxHeads);
+
+ if (Drive & 0x80)
+ {
+ /* Count the number of active HDDs */
+ for (i = 0; i < ARRAYSIZE(HardDrive); ++i)
+ {
+ if (IsDiskPresent(HardDrive[i]))
+ ++PresentDrives;
+ }
+
+ /* Reset ES:DI to NULL */
+ // FIXME: NONONO!! Apps expect (for example, MS-DOS kernel)
+ // that this function does not modify ES:DI if it was called
+ // for a HDD.
+ // setES(0x0000);
+ // setDI(0x0000);
+ }
+ else
+ {
+ /* Count the number of active floppies */
+ for (i = 0; i < ARRAYSIZE(FloppyDrive); ++i)
+ {
+ if (IsDiskPresent(FloppyDrive[i]))
+ ++PresentDrives;
+ }
+
+ /* ES:DI points to the floppy parameter table */
+ setES(HIWORD(((PULONG)BaseAddress)[0x1E]));
+ setDI(LOWORD(((PULONG)BaseAddress)[0x1E]));
+ }
+ setDL(PresentDrives);
+
+ setBL(DiskImage->DiskType); //
DiskGeometryList[DiskImage->DiskType].biosval
+ setAL(0x00);
+
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Hard Disk -- Initialize Controller with Drive Parameters */
+ case 0x09:
+
+ /* Hard Disk -- Read Long Sectors */
+ case 0x0A:
+
+ /* Hard Disk -- Write Long Sectors */
+ case 0x0B:
+ goto Default;
+
+ /* Hard Disk -- Seek to Cylinder */
+ case 0x0C:
+ {
+ BYTE Status;
+ BYTE Head = getDH();
+
+ // CH: Low eight bits of cylinder number
+ // CL: High two bits of cylinder (bits 6-7, hard disk only)
+ WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02);
+
+ // CL: Sector number 1-63 (bits 0-5)
+ BYTE Sector = (getCL() & 0x3F); // 1-based
+
+ Drive = getDL();
+ if (!(Drive & 0x80))
+ {
+ DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X is not a
HDD\n", Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Set position */
+ Status = SeekDisk(DiskImage, Cylinder, Head, Sector);
+ if (Status == 0x00)
+ {
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ DPRINT1("BiosDiskService(0x0C): Error when seeking in disk number
0x%02X (0x%02X)\n", Drive, Status);
+
+ /* Return error */
+ setAH(Status);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ }
+
+ break;
+ }
+
+ /* Hard Disk -- Reset Hard Disks */
+ case 0x0D:
+ {
+ // FIXME: Should do what 0x11 does.
+ UNIMPLEMENTED;
+ }
+
+ /* Hard Disk -- Read Sector Buffer (XT only) */
+ case 0x0E:
+
+ /* Hard Disk -- Write Sector Buffer (XT only) */
+ case 0x0F:
+ goto Default;
+
+ /* Hard Disk -- Check if Drive is ready */
+ case 0x10:
+ {
+ Drive = getDL();
+ if (!(Drive & 0x80))
+ {
+ DPRINT1("BiosDiskService(0x10): Disk number 0x%02X is not a
HDD\n", Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x10): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Hard Disk -- Recalibrate Drive */
+ case 0x11:
+ {
+ BYTE Status;
+
+ Drive = getDL();
+ if (!(Drive & 0x80))
+ {
+ DPRINT1("BiosDiskService(0x11): Disk number 0x%02X is not a
HDD\n", Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x11): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Set position to zero */
+ Status = SeekDisk(DiskImage, /*Cylinder*/ 0, /*Head*/ 0, /*Sector*/ 1);
+ if (Status == 0x00)
+ {
+ /* Return success */
+ setAH(0x00);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ DPRINT1("BiosDiskService(0x11): Error when recalibrating disk number
0x%02X (0x%02X)\n", Drive, Status);
+
+ /* Return error */
+ setAH(Status);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ }
+
+ break;
+ }
+
+ /* Hard Disk -- Controller RAM Diagnostic */
+ case 0x12:
+
+ /* Hard Disk -- Drive Diagnostic */
+ case 0x13:
+
+ /* Hard Disk -- Controller Internal Diagnostic */
+ case 0x14:
+ goto Default;
+
+ /* Disk -- Get Disk Type */
+ case 0x15:
+ {
+ Drive = getDL();
+ DiskImage = GetDisk(Drive);
+ if (!DiskImage || !IsDiskPresent(DiskImage))
+ {
+ DPRINT1("BiosDiskService(0x15): Disk number 0x%02X invalid\n",
Drive);
+
+ /* Return error */
+ setAH(0x01);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ break;
+ }
+
+ if (Drive & 0x80)
+ {
+ ULONG NumSectors;
+
+ /* Hard disk */
+ setAH(0x03);
+
+ /* Number of 512-byte sectors in CX:DX */
+ NumSectors = DiskImage->DiskInfo.Cylinders *
DiskImage->DiskInfo.Heads
+ *
DiskImage->DiskInfo.Sectors;
+ setCX(HIWORD(NumSectors));
+ setDX(LOWORD(NumSectors));
+ }
+ else
+ {
+ /* Floppy */
+ setAH(0x01);
+ }
+
+ /* Return success */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ break;
+ }
+
+ /* Floppy Disk -- Detect Disk Change */
+ case 0x16:
+
+ /* Floppy Disk -- Set Disk Type for Format */
+ case 0x17:
+
+ /* Disk -- Set Media Type for Format */
+ case 0x18:
+ goto Default;
+
+ default: Default:
+ {
+ DPRINT1("BIOS Function INT 13h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X
NOT IMPLEMENTED\n",
+ getAH(), getAL(), getBH());
+ }
+ }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID DiskBios32Post(VOID)
+{
+ /*
+ * Initialize BIOS Disk RAM dynamic data
+ */
+
+ /* Some vectors are in fact addresses to tables */
+ // Diskette Parameters
+ ((PULONG)BaseAddress)[0x1E] = MAKELONG(0xEFC7, BIOS_SEGMENT);
+ // Hard Disk 0 Parameter Table Address
+ ((PULONG)BaseAddress)[0x41] = (ULONG)NULL;
+ // Hard Disk 1 Drive Parameter Table Address
+ ((PULONG)BaseAddress)[0x46] = (ULONG)NULL;
+
+ /* Relocated services by the BIOS (when needed) */
+ ((PULONG)BaseAddress)[0x40] = (ULONG)NULL; // ROM BIOS Diskette Handler relocated by
Hard Disk BIOS
+ // RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk
BIOS
+
+ /* Register the BIOS 32-bit Interrupts */
+ RegisterBiosInt32(BIOS_DISK_INTERRUPT, BiosDiskService);
+
+ /* Initialize the BDA */
+ // Bda->LastDisketteOperation = 0;
+ // Bda->LastDiskOperation = 0;
+ AllDisksReset();
+}
+
+BOOLEAN DiskBios32Initialize(VOID)
+{
+ /*
+ * Initialize BIOS Disk ROM static data
+ */
+
+ /* Floppy Parameter Table */
+ RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xEFC7),
+ &FloppyParamTable.FloppyParamTable,
+ sizeof(FloppyParamTable.FloppyParamTable));
+
+ //
+ // FIXME: Must be done by HW floppy controller!
+ //
+
+ /* Detect and initialize the supported disks */
+ // TODO: the "Detect" part is missing.
+ FloppyDrive[0] = &XDCFloppyDrive[0];
+ FloppyDrive[1] = &XDCFloppyDrive[1];
+ HardDrive[0] = &XDCHardDrive[0];
+
+ return TRUE;
+}
+
+VOID DiskBios32Cleanup(VOID)
+{
+}
+
+/* EOF */
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.h (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.h [iso-8859-1] Sat Sep 26
17:35:31 2015
@@ -0,0 +1,25 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dskbios32.h
+ * PURPOSE: VDM 32-bit Disk BIOS
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+#ifndef _DSKBIOS32_H_
+#define _DSKBIOS32_H_
+
+/* DEFINES ********************************************************************/
+
+#define BIOS_DISK_INTERRUPT 0x13
+
+/* FUNCTIONS ******************************************************************/
+
+VOID DiskBios32Post(VOID);
+
+BOOLEAN DiskBios32Initialize(VOID);
+VOID DiskBios32Cleanup(VOID);
+
+#endif /* _DSKBIOS32_H_ */
+
+/* EOF */
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/dskbios32.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/subsystems/mvdm/ntvdm/emulator.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/emul…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/emulator.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/emulator.c [iso-8859-1] Sat Sep 26 17:35:31 2015
@@ -24,6 +24,7 @@
#include "clock.h"
#include "bios/rom.h"
#include "hardware/cmos.h"
+#include "hardware/disk.h"
#include "hardware/dma.h"
#include "hardware/keyboard.h"
#include "hardware/mouse.h"
@@ -497,6 +498,14 @@
return FALSE;
}
+ /* Initialize the disk controller */
+ if (!DiskCtrlInitialize())
+ {
+ wprintf(L"FATAL: Failed to completely initialize the disk
controller.\n");
+ EmulatorCleanup();
+ return FALSE;
+ }
+
/* Initialize the software callback system and register the emulator BOPs */
InitializeInt32();
RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
@@ -510,6 +519,8 @@
VOID EmulatorCleanup(VOID)
{
+ DiskCtrlCleanup();
+
VgaCleanup();
/* Close the input thread handle */
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c [iso-8859-1] Sat Sep 26 17:35:31
2015
@@ -235,12 +235,9 @@
case CMOS_REG_STATUS_C:
{
- /* Return the old value */
+ /* Return the old status register value, then clear it */
Value = CmosMemory.StatusRegC;
-
- /* Clear status register C */
CmosMemory.StatusRegC = 0x00;
-
break;
}
@@ -370,8 +367,7 @@
ChangeTime = TRUE;
/* Clear everything except the century */
- CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
-
+ CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
@@ -405,8 +401,8 @@
case CMOS_REG_ACTUAL_EXT_MEMORY_LOW:
{
/* Sync EMS and UMS */
- CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] =
- CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = Data;
+ CmosMemory.ExtMemoryLow =
+ CmosMemory.ActualExtMemoryLow = Data;
break;
}
@@ -415,8 +411,8 @@
case CMOS_REG_ACTUAL_EXT_MEMORY_HIGH:
{
/* Sync EMS and UMS */
- CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] =
- CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = Data;
+ CmosMemory.ExtMemoryHigh =
+ CmosMemory.ActualExtMemoryHigh = Data;
break;
}
@@ -470,7 +466,7 @@
Success = ReadFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
if (CmosSize != sizeof(CmosMemory))
{
- /* Bad CMOS Ram file. Reinitialize the CMOS memory. */
+ /* Bad CMOS RAM file. Reinitialize the CMOS memory. */
DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n",
CmosSize, sizeof(CmosMemory));
RtlZeroMemory(&CmosMemory, sizeof(CmosMemory));
}
@@ -485,6 +481,7 @@
CmosMemory.StatusRegD = CMOS_BATTERY_OK; // Our CMOS battery works perfectly
forever.
CmosMemory.Diagnostics = 0x00; // Diagnostics must not find any
errors.
CmosMemory.ShutdownStatus = 0x00;
+ CmosMemory.EquipmentList = CMOS_EQUIPMENT_LIST;
/* Memory settings */
@@ -494,14 +491,13 @@
* and see Ralf Brown:
http://www.ctyme.com/intr/rb-0598.htm
* for more information.
*/
- CmosMemory.Regs[CMOS_REG_BASE_MEMORY_LOW ] = LOBYTE(0x0280);
- CmosMemory.Regs[CMOS_REG_BASE_MEMORY_HIGH] = HIBYTE(0x0280);
-
- CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] =
- CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = LOBYTE((MAX_ADDRESS - 0x100000) /
1024);
-
- CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] =
- CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = HIBYTE((MAX_ADDRESS - 0x100000) /
1024);
+ CmosMemory.BaseMemoryLow = LOBYTE(0x0280);
+ CmosMemory.BaseMemoryHigh = HIBYTE(0x0280);
+
+ CmosMemory.ExtMemoryLow =
+ CmosMemory.ActualExtMemoryLow = LOBYTE((MAX_ADDRESS - 0x100000) / 1024);
+ CmosMemory.ExtMemoryHigh =
+ CmosMemory.ActualExtMemoryHigh = HIBYTE((MAX_ADDRESS - 0x100000) / 1024);
/* Register the I/O Ports */
RegisterIoPort(CMOS_ADDRESS_PORT, NULL, CmosWriteAddress);
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h [iso-8859-1] Sat Sep 26 17:35:31
2015
@@ -37,6 +37,10 @@
#define CMOS_DEFAULT_STA 0x26
#define CMOS_DEFAULT_STB CMOS_STB_24HOUR
+// Bit 0: Floppy, Bit 1: FPU, Bit 2: Mouse, Bits 4-5: 80x25 Color Video, Bits 6-7: 2
floppy drives
+#define CMOS_EQUIPMENT_LIST 0x6F
+
+
#define WRITE_CMOS_DATA(Cmos, Value) \
((Cmos).StatusRegB & CMOS_STB_BINARY) ? (Value) : BCD_TO_BINARY(Value)
@@ -61,6 +65,7 @@
CMOS_REG_STATUS_D,
CMOS_REG_DIAGNOSTICS,
CMOS_REG_SHUTDOWN_STATUS,
+ CMOS_REG_EQUIPMENT_LIST = 0x14,
CMOS_REG_BASE_MEMORY_LOW = 0x15,
CMOS_REG_BASE_MEMORY_HIGH = 0x16,
CMOS_REG_EXT_MEMORY_LOW = 0x17,
@@ -105,16 +110,28 @@
{
struct
{
- CMOS_CLOCK; // 0x00 - 0x0b
- BYTE StatusRegC; // 0x0c
- BYTE StatusRegD; // 0x0d
- BYTE Diagnostics; // 0x0e
- BYTE ShutdownStatus; // 0x0f
- BYTE Padding[0x22]; // 0x10
- BYTE Century; // 0x32
+ CMOS_CLOCK; // 0x00 - 0x0b
+ BYTE StatusRegC; // 0x0c
+ BYTE StatusRegD; // 0x0d
+ BYTE Diagnostics; // 0x0e
+ BYTE ShutdownStatus; // 0x0f
+ BYTE FloppyDrivesType; // 0x10
+ BYTE Reserved0; // 0x11
+ BYTE HardDrivesType; // 0x12
+ BYTE Reserved1; // 0x13
+ BYTE EquipmentList; // 0x14
+ BYTE BaseMemoryLow; // 0x15
+ BYTE BaseMemoryHigh; // 0x16
+ BYTE ExtMemoryLow; // 0x17
+ BYTE ExtMemoryHigh; // 0x18
+ BYTE ExtHardDrivesType[2]; // 0x19 - 0x1a
+ BYTE Reserved2[0x15]; // 0x1b
+ BYTE ActualExtMemoryLow; // 0x30
+ BYTE ActualExtMemoryHigh; // 0x31
+ BYTE Century; // 0x32
};
- BYTE Regs1[0x10]; // 0x00 - 0x0f
- BYTE Regs [0x40]; // 0x00 - 0x3f
+ BYTE Regs1[0x10]; // 0x00 - 0x0f
+ BYTE Regs [0x40]; // 0x00 - 0x3f
};
/*
Added: trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c [iso-8859-1] Sat Sep 26 17:35:31
2015
@@ -0,0 +1,600 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: subsystems/mvdm/ntvdm/hardware/disk.c
+ * PURPOSE: Generic Disk Controller (Floppy, Hard Disk, ...)
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ *
+ * NOTE 1: This file is meant to be splitted into FDC and HDC
+ * when its code will grow out of control!
+ *
+ * NOTE 2: This is poor-man implementation, i.e. at the moment this file
+ * contains an API for manipulating the disks for the rest of NTVDM,
+ * but does not implement real hardware emulation (IO ports, etc...).
+ * One will have to progressively transform it into a real HW emulation
+ * and, in case the disk APIs are needed, move them elsewhere.
+ *
+ * FIXME: The big endian support (which is hardcoded here for machines
+ * in little endian) *MUST* be fixed!
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "ntvdm.h"
+#include "emulator.h"
+#include "disk.h"
+
+// #include "io.h"
+#include "memory.h"
+
+#include "utils.h"
+
+
+/**************** HARD DRIVES -- VHD FIXED DISK FORMAT SUPPORT ****************/
+
+//
http://citrixblogger.org/2008/12/01/dynamic-vhd-walkthrough/
+//
http://www.microsoft.com/en-us/download/details.aspx?id=23850
+//
https://projects.honeynet.org/svn/sebek/virtualization/qebek/trunk/block/vp…
+//
https://git.virtualopensystems.com/trescca/qemu/raw/40645c7bfd7c4d45381927e…
+//
https://gitweb.gentoo.org/proj/qemu-kvm.git/tree/block/vpc.c?h=qemu-kvm-0.1…
+
+#pragma pack(push, 1)
+
+enum VHD_TYPE
+{
+ VHD_FIXED = 2,
+ VHD_DYNAMIC = 3,
+ VHD_DIFFERENCING = 4,
+};
+
+// Seconds since Jan 1, 2000 0:00:00 (UTC)
+#define VHD_TIMESTAMP_BASE 946684800
+
+// Always in BIG-endian format!
+typedef struct _VHD_FOOTER
+{
+ CHAR creator[8]; // "conectix"
+ ULONG features;
+ ULONG version;
+
+ // Offset of next header structure, 0xFFFFFFFF if none
+ ULONG64 data_offset;
+
+ // Seconds since Jan 1, 2000 0:00:00 (UTC)
+ ULONG timestamp;
+
+ CHAR creator_app[4]; // "vpc "; "win"
+ USHORT major;
+ USHORT minor;
+ CHAR creator_os[4]; // "Wi2k"
+
+ ULONG64 orig_size;
+ ULONG64 size;
+
+ USHORT cyls;
+ BYTE heads;
+ BYTE secs_per_cyl;
+
+ ULONG type; // VHD_TYPE
+
+ // Checksum of the Hard Disk Footer ("one's complement of the sum of all
+ // the bytes in the footer without the checksum field")
+ ULONG checksum;
+
+ // UUID used to identify a parent hard disk (backing file)
+ BYTE uuid[16];
+
+ BYTE in_saved_state;
+
+ BYTE Padding[0x200-0x55];
+
+} VHD_FOOTER, *PVHD_FOOTER;
+C_ASSERT(sizeof(VHD_FOOTER) == 0x200);
+
+#pragma pack(pop)
+
+#if 0
+/*
+ * Calculates the number of cylinders, heads and sectors per cylinder
+ * based on a given number of sectors. This is the algorithm described
+ * in the VHD specification.
+ *
+ * Note that the geometry doesn't always exactly match total_sectors but
+ * may round it down.
+ *
+ * Returns TRUE on success, FALSE if the size is larger than 127 GB
+ */
+static BOOLEAN
+calculate_geometry(ULONG64 total_sectors, PUSHORT cyls,
+ PBYTE heads, PBYTE secs_per_cyl)
+{
+ ULONG cyls_times_heads;
+
+ if (total_sectors > 65535 * 16 * 255)
+ return FALSE;
+
+ if (total_sectors > 65535 * 16 * 63)
+ {
+ *secs_per_cyl = 255;
+ *heads = 16;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ }
+ else
+ {
+ *secs_per_cyl = 17;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ *heads = (cyls_times_heads + 1023) / 1024;
+
+ if (*heads < 4)
+ *heads = 4;
+
+ if (cyls_times_heads >= (*heads * 1024) || *heads > 16)
+ {
+ *secs_per_cyl = 31;
+ *heads = 16;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ }
+
+ if (cyls_times_heads >= (*heads * 1024))
+ {
+ *secs_per_cyl = 63;
+ *heads = 16;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ }
+ }
+
+ *cyls = cyls_times_heads / *heads;
+
+ return TRUE;
+}
+#endif
+
+
+
+/*************************** FLOPPY DISK CONTROLLER ***************************/
+
+// A Floppy Controller can support up to 4 floppy drives.
+/*static*/
+DISK_IMAGE XDCFloppyDrive[4];
+
+// Taken from DOSBox
+typedef struct _DISK_GEO
+{
+ DWORD ksize; /* Size in kilobytes */
+ WORD secttrack; /* Sectors per track */
+ WORD headscyl; /* Heads per cylinder */
+ WORD cylcount; /* Cylinders per side */
+ WORD biosval; /* Type to return from BIOS & CMOS */
+} DISK_GEO, *PDISK_GEO;
+
+// FIXME: At the moment, all of our diskettes have 512 bytes per sector...
+static WORD HackSectorSize = 512;
+static DISK_GEO DiskGeometryList[] =
+{
+ { 160, 8, 1, 40, 0},
+ { 180, 9, 1, 40, 0},
+ { 200, 10, 1, 40, 0},
+ { 320, 8, 2, 40, 1},
+ { 360, 9, 2, 40, 1},
+ { 400, 10, 2, 40, 1},
+ { 720, 9, 2, 80, 3},
+ {1200, 15, 2, 80, 2},
+ {1440, 18, 2, 80, 4},
+ {2880, 36, 2, 80, 6},
+};
+
+BOOLEAN
+MountFDI(IN PDISK_IMAGE DiskImage,
+ IN HANDLE hFile)
+{
+ ULONG FileSize;
+ USHORT i;
+
+ /*
+ * Retrieve the size of the file. In NTVDM we will handle files
+ * of maximum 1Mb so we can largely use GetFileSize only.
+ */
+ FileSize = GetFileSize(hFile, NULL);
+ if (FileSize == INVALID_FILE_SIZE && GetLastError() != ERROR_SUCCESS)
+ {
+ /* We failed, bail out */
+ DisplayMessage(L"Error when retrieving file size, or size too large
(%d).", FileSize);
+ return FALSE;
+ }
+
+ /* Convert the size in kB */
+ FileSize /= 1024;
+
+ /* Find the floppy format in the list, and mount it if found */
+ for (i = 0; i < ARRAYSIZE(DiskGeometryList); ++i)
+ {
+ if (DiskGeometryList[i].ksize == FileSize ||
+ DiskGeometryList[i].ksize + 1 == FileSize)
+ {
+ /* Found, mount it */
+ DiskImage->DiskType = DiskGeometryList[i].biosval;
+ DiskImage->DiskInfo.Cylinders = DiskGeometryList[i].cylcount;
+ DiskImage->DiskInfo.Heads = DiskGeometryList[i].headscyl;
+ DiskImage->DiskInfo.Sectors = DiskGeometryList[i].secttrack;
+ DiskImage->DiskInfo.SectorSize = HackSectorSize;
+
+ /* Set the file pointer to the beginning */
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+
+ DiskImage->hDisk = hFile;
+ return TRUE;
+ }
+ }
+
+ /* If we are here, we failed to find a suitable format. Bail out. */
+ DisplayMessage(L"MountFDI: Floppy image of invalid size %d.", FileSize);
+ return FALSE;
+}
+
+
+/************************** IDE HARD DISK CONTROLLER **************************/
+
+// An IDE Hard Disk Controller can support up to 4 drives:
+// Primary Master Drive, Primary Slave Drive,
+// Secondary Master Drive, Secondary Slave Drive.
+/*static*/
+DISK_IMAGE XDCHardDrive[4];
+
+BOOLEAN
+MountHDD(IN PDISK_IMAGE DiskImage,
+ IN HANDLE hFile)
+{
+ /**** Support for VHD fixed disks ****/
+ DWORD FilePointer, BytesToRead;
+ VHD_FOOTER vhd_footer;
+
+ /* Go to the end of the file and retrieve the footer */
+ FilePointer = SetFilePointer(hFile, -(LONG)sizeof(VHD_FOOTER), NULL, FILE_END);
+ if (FilePointer == INVALID_SET_FILE_POINTER)
+ {
+ DPRINT1("MountHDD: Error when seeking HDD footer, last error = %d\n",
GetLastError());
+ return FALSE;
+ }
+
+ /* Read footer */
+ // FIXME: We may consider just mapping section to the file...
+ BytesToRead = sizeof(VHD_FOOTER);
+ if (!ReadFile(hFile, &vhd_footer, BytesToRead, &BytesToRead, NULL))
+ {
+ DPRINT1("MountHDD: Error when reading HDD footer, last error = %d\n",
GetLastError());
+ return FALSE;
+ }
+
+ /* Perform validity checks */
+ if (RtlCompareMemory(vhd_footer.creator, "conectix",
+ sizeof(vhd_footer.creator)) != sizeof(vhd_footer.creator))
+ {
+ DisplayMessage(L"MountHDD: Invalid HDD image (expected VHD).");
+ return FALSE;
+ }
+ if (vhd_footer.version != 0x00000100 &&
+ vhd_footer.version != 0x00000500) // FIXME: Big endian!
+ {
+ DisplayMessage(L"MountHDD: VHD HDD image of unexpected version %d.",
vhd_footer.version);
+ return FALSE;
+ }
+ if (RtlUlongByteSwap(vhd_footer.type) != VHD_FIXED) // FIXME: Big endian!
+ {
+ DisplayMessage(L"MountHDD: Only VHD HDD fixed images are supported.");
+ return FALSE;
+ }
+ if (vhd_footer.data_offset != 0xFFFFFFFFFFFFFFFF)
+ {
+ DisplayMessage(L"MountHDD: Unexpected data offset for VHD HDD fixed
image.");
+ return FALSE;
+ }
+ if (vhd_footer.orig_size != vhd_footer.size)
+ {
+ DisplayMessage(L"MountHDD: VHD HDD fixed image size should be the same as
its original size.");
+ return FALSE;
+ }
+ // FIXME: Checksum!
+
+ /* Found, mount it */
+ DiskImage->DiskType = 0;
+ DiskImage->DiskInfo.Cylinders = RtlUshortByteSwap(vhd_footer.cyls); // FIXME: Big
endian!
+ DiskImage->DiskInfo.Heads = vhd_footer.heads;
+ DiskImage->DiskInfo.Sectors = vhd_footer.secs_per_cyl;
+ DiskImage->DiskInfo.SectorSize = RtlUlonglongByteSwap(vhd_footer.size) / // FIXME:
Big endian!
+ DiskImage->DiskInfo.Cylinders /
+ DiskImage->DiskInfo.Heads /
DiskImage->DiskInfo.Sectors;
+
+ /* Set the file pointer to the beginning */
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+
+ DiskImage->hDisk = hFile;
+ return TRUE;
+}
+
+
+
+/************************ GENERIC DISK CONTROLLER API *************************/
+
+BOOLEAN
+IsDiskPresent(IN PDISK_IMAGE DiskImage)
+{
+ ASSERT(DiskImage);
+ return (DiskImage->hDisk != INVALID_HANDLE_VALUE && DiskImage->hDisk !=
NULL);
+}
+
+BYTE
+SeekDisk(IN PDISK_IMAGE DiskImage,
+ IN WORD Cylinder,
+ IN BYTE Head,
+ IN BYTE Sector)
+{
+ DWORD FilePointer;
+
+ /* Check that the sector number is 1-based */
+ // FIXME: Or do it in the caller?
+ if (Sector == 0)
+ {
+ /* Return error */
+ return 0x01;
+ }
+
+ /* Set position */
+ // Compute the offset
+ FilePointer = ((Cylinder * DiskImage->DiskInfo.Heads + Head)
+ * DiskImage->DiskInfo.Sectors + (Sector - 1))
+ * DiskImage->DiskInfo.SectorSize;
+ FilePointer = SetFilePointer(DiskImage->hDisk, FilePointer, NULL, FILE_BEGIN);
+ if (FilePointer == INVALID_SET_FILE_POINTER)
+ {
+ /* Return error */
+ return 0x40;
+ }
+
+ return 0x00;
+}
+
+BYTE
+ReadDisk(IN PDISK_IMAGE DiskImage,
+ IN WORD Cylinder,
+ IN BYTE Head,
+ IN BYTE Sector,
+ IN BYTE NumSectors)
+{
+ BYTE Result;
+ DWORD BytesToRead;
+
+ PVOID LocalBuffer;
+ BYTE StaticBuffer[1024];
+
+ /* Read the sectors */
+ Result = SeekDisk(DiskImage, Cylinder, Head, Sector);
+ if (Result != 0x00)
+ return Result;
+
+ BytesToRead = NumSectors * DiskImage->DiskInfo.SectorSize;
+
+ // FIXME: Consider just looping around filling each time the buffer...
+
+ if (BytesToRead <= sizeof(StaticBuffer))
+ {
+ LocalBuffer = StaticBuffer;
+ }
+ else
+ {
+ LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BytesToRead);
+ ASSERT(LocalBuffer != NULL);
+ }
+
+ if (ReadFile(DiskImage->hDisk, LocalBuffer, BytesToRead, &BytesToRead, NULL))
+ {
+ /* Write to the memory */
+ EmulatorWriteMemory(&EmulatorContext,
+ TO_LINEAR(getES(), getBX()),
+ LocalBuffer,
+ BytesToRead);
+
+ Result = 0x00;
+ }
+ else
+ {
+ Result = 0x04;
+ }
+
+ if (LocalBuffer != StaticBuffer)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
+
+ /* Return success or error */
+ return Result;
+}
+
+BYTE
+WriteDisk(IN PDISK_IMAGE DiskImage,
+ IN WORD Cylinder,
+ IN BYTE Head,
+ IN BYTE Sector,
+ IN BYTE NumSectors)
+{
+ BYTE Result;
+ DWORD BytesToWrite;
+
+ PVOID LocalBuffer;
+ BYTE StaticBuffer[1024];
+
+ /* Check for write protection */
+ if (DiskImage->ReadOnly)
+ {
+ /* Return error */
+ return 0x03;
+ }
+
+ /* Write the sectors */
+ Result = SeekDisk(DiskImage, Cylinder, Head, Sector);
+ if (Result != 0x00)
+ return Result;
+
+ BytesToWrite = NumSectors * DiskImage->DiskInfo.SectorSize;
+
+ // FIXME: Consider just looping around filling each time the buffer...
+
+ if (BytesToWrite <= sizeof(StaticBuffer))
+ {
+ LocalBuffer = StaticBuffer;
+ }
+ else
+ {
+ LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BytesToWrite);
+ ASSERT(LocalBuffer != NULL);
+ }
+
+ /* Read from the memory */
+ EmulatorReadMemory(&EmulatorContext,
+ TO_LINEAR(getES(), getBX()),
+ LocalBuffer,
+ BytesToWrite);
+
+ if (WriteFile(DiskImage->hDisk, LocalBuffer, BytesToWrite, &BytesToWrite,
NULL))
+ Result = 0x00;
+ else
+ Result = 0x04;
+
+ if (LocalBuffer != StaticBuffer)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
+
+ /* Return success or error */
+ return Result;
+}
+
+typedef BOOLEAN (*MOUNT_DISK_HANDLER)(IN PDISK_IMAGE DiskImage, IN HANDLE hFile);
+
+BOOLEAN
+MountDisk(IN PDISK_IMAGE DiskImage,
+ MOUNT_DISK_HANDLER MountDiskHelper,
+ IN PCSTR FileName,
+ IN BOOLEAN ReadOnly)
+{
+ BOOLEAN Success = FALSE;
+ HANDLE hFile;
+
+ BY_HANDLE_FILE_INFORMATION FileInformation;
+
+ if (IsDiskPresent(DiskImage))
+ {
+ DisplayMessage(L"MountDisk: Disk 0x%p already in use.", DiskImage);
+ return FALSE;
+ }
+
+ /* Try to open the file */
+ SetLastError(0); // For debugging purposes
+ if (ReadOnly)
+ {
+ hFile = CreateFileA(FileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ }
+ else
+ {
+ hFile = CreateFileA(FileName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0, // No sharing access
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ }
+ DPRINT1("File '%s' opening %s ; GetLastError() = %u\n",
+ FileName, hFile != INVALID_HANDLE_VALUE ? "succeeded" :
"failed", GetLastError());
+
+ /* If we failed, bail out */
+ if (hFile == INVALID_HANDLE_VALUE) return FALSE;
+
+ /* OK, we have a handle to the file */
+
+ /*
+ * Check that it is really a file, and not a physical drive.
+ * For obvious security reasons, we do not want to be able to
+ * write directly to physical drives.
+ *
+ * Redundant checks
+ */
+ SetLastError(0);
+ if (!GetFileInformationByHandle(hFile, &FileInformation) &&
+ GetLastError() == ERROR_INVALID_FUNCTION)
+ {
+ /* Objects other than real files are not supported */
+ DisplayMessage(L"'%S' is not a valid disk file.", FileName);
+ goto Quit;
+ }
+ SetLastError(0);
+ if (GetFileSize(hFile, NULL) == INVALID_FILE_SIZE &&
+ GetLastError() == ERROR_INVALID_FUNCTION)
+ {
+ /* Objects other than real files are not supported */
+ DisplayMessage(L"'%S' is not a valid disk file.", FileName);
+ goto Quit;
+ }
+
+ /* Success, mount the image */
+ if (!MountDiskHelper(DiskImage, hFile))
+ {
+ DisplayMessage(L"MountDisk: Failed to mount disk file '%S' in
0x%p.", FileName, DiskImage);
+ goto Quit;
+ }
+ Success = TRUE;
+
+Quit:
+ if (!Success) FileClose(hFile);
+ return Success;
+}
+
+BOOLEAN
+UnmountDisk(IN PDISK_IMAGE DiskImage)
+{
+ if (!IsDiskPresent(DiskImage))
+ {
+ DisplayMessage(L"UnmountDisk: Disk 0x%p is already unmounted.",
DiskImage);
+ return FALSE;
+ }
+
+ /* Flush the image and unmount it */
+ FlushFileBuffers(DiskImage->hDisk);
+ FileClose(DiskImage->hDisk);
+ DiskImage->hDisk = NULL;
+ return TRUE;
+}
+
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+BOOLEAN DiskCtrlInitialize(VOID)
+{
+#if 0
+ // The following commands are examples of MountDisk usage.
+ // NOTE: Those values are hardcoded paths on my local test machines!!
+
+ // MountDisk(&XDCFloppyDrive[0], MountFDI,
"H:\\trunk\\ntvdm_studies\\diskette_high.vfd", TRUE);
+ // MountDisk(&XDCFloppyDrive[0], MountFDI, "H:\\DOS_tests\\Dos5.0.img",
TRUE);
+ // MountDisk(&XDCHardDrive[0] , MountHDD,
"H:\\trunk\\ntvdm_studies\\hdd_10Mo_fixed.vhd", TRUE);
+
+ MountDisk(&XDCFloppyDrive[0], MountFDI,
"H:\\DOS_tests\\diskette_test.vfd", FALSE);
+ MountDisk(&XDCHardDrive[0] , MountHDD, "H:\\DOS_tests\\MS-DOS
6_fixed_size.vhd", FALSE);
+#endif
+
+ return TRUE;
+}
+
+VOID DiskCtrlCleanup(VOID)
+{
+#if 0
+ // The following commands are examples of UnmountDisk usage.
+ UnmountDisk(&XDCHardDrive[0]);
+ UnmountDisk(&XDCFloppyDrive[0]);
+#endif
+}
+
+/* EOF */
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.h (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.h [iso-8859-1] Sat Sep 26 17:35:31
2015
@@ -0,0 +1,76 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: subsystems/mvdm/ntvdm/hardware/disk.h
+ * PURPOSE: Generic Disk Controller (Floppy, Hard Disk, ...)
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+#ifndef _DISK_H_
+#define _DISK_H_
+
+/* DEFINES ********************************************************************/
+
+//
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363972(v=vs.85).…
+//
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363976(v=vs.85).…
+//
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363969(v=vs.85).…
+//
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365231(v=vs.85).…
+
+typedef struct _DISK_INFO
+{
+ WORD Cylinders; // DWORD
+ BYTE Heads; // DWORD
+ BYTE Sectors; // QWORD
+ // SectorPerTrack; ??? // DWORD
+ WORD SectorSize;
+} DISK_INFO, *PDISK_INFO;
+
+typedef struct _DISK_IMAGE
+{
+ DISK_INFO DiskInfo;
+ BYTE DiskType; // Type to return from BIOS & CMOS
+
+ BYTE LastOperationStatus;
+ // CurrentPos;
+
+ HANDLE hDisk;
+ BOOLEAN ReadOnly;
+ // WCHAR ImageFile[MAX_PATH];
+
+} DISK_IMAGE, *PDISK_IMAGE;
+
+// HACKHACK! For dskbios32.c
+extern DISK_IMAGE XDCFloppyDrive[];
+extern DISK_IMAGE XDCHardDrive[];
+
+/* FUNCTIONS ******************************************************************/
+
+BOOLEAN
+IsDiskPresent(IN PDISK_IMAGE DiskImage);
+
+BYTE
+SeekDisk(IN PDISK_IMAGE DiskImage,
+ IN WORD Cylinder,
+ IN BYTE Head,
+ IN BYTE Sector);
+
+BYTE
+ReadDisk(IN PDISK_IMAGE DiskImage,
+ IN WORD Cylinder,
+ IN BYTE Head,
+ IN BYTE Sector,
+ IN BYTE NumSectors);
+
+BYTE
+WriteDisk(IN PDISK_IMAGE DiskImage,
+ IN WORD Cylinder,
+ IN BYTE Head,
+ IN BYTE Sector,
+ IN BYTE NumSectors);
+
+BOOLEAN DiskCtrlInitialize(VOID);
+VOID DiskCtrlCleanup(VOID);
+
+#endif // _DISK_H_
+
+/* EOF */
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.h
------------------------------------------------------------------------------
svn:eol-style = native