Implement DOS character device support and driver loading support.
Separate the DOS memory manager code from the main DOS kernel source file.

CORE-9370 #resolve #comment Committed in revision r66895.


svn path=/trunk/; revision=66895
This commit is contained in:
Aleksandar Andrejevic 2015-03-26 00:21:25 +00:00
parent 4817056662
commit 56063f930f
14 changed files with 1738 additions and 662 deletions

View file

@ -29,8 +29,12 @@ list(APPEND SOURCE
hardware/sound/speaker.c
hardware/video/vga.c
dos/dos32krnl/bios.c
dos/dos32krnl/condrv.c
dos/dos32krnl/device.c
dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
dos/dos32krnl/emsdrv.c
dos/dos32krnl/memory.c
dos/mouse32.c
dos/dem.c
clock.c

View file

@ -313,9 +313,9 @@ static VOID NTAPI EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
for (i = FirstPage; i <= LastPage; i++)
{
Offset = (i == FirstPage) ? Address & (EMS_PAGE_SIZE - 1) : 0;
Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
Length = ((i == LastPage)
? (Address + Size - (LastPage << EMS_PAGE_BITS))
? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
: EMS_PAGE_SIZE) - Offset;
if (Mapping[i]) RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Mapping[i] + Offset), Length);
@ -333,9 +333,9 @@ static BOOLEAN NTAPI EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
for (i = FirstPage; i <= LastPage; i++)
{
Offset = (i == FirstPage) ? Address & (EMS_PAGE_SIZE - 1) : 0;
Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
Length = ((i == LastPage)
? (Address + Size - (LastPage << EMS_PAGE_BITS))
? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
: EMS_PAGE_SIZE) - Offset;
if (Mapping[i]) RtlCopyMemory((PVOID)((ULONG_PTR)Mapping[i] + Offset), Buffer, Length);

View file

@ -31,8 +31,6 @@
#define EMS_STATUS_INV_PHYSICAL_PAGE 0x8B
#define EMS_STATUS_UNKNOWN_FUNCTION 0x8F
#define ARRAY_INDEX(ptr, array) ((ULONG)(((ULONG_PTR)(ptr) - (ULONG_PTR)(array)) / sizeof(*array)))
typedef struct _EMS_HANDLE
{
BOOLEAN Allocated;

View file

@ -14,6 +14,7 @@
#include "int32.h"
#include "dos.h"
#include "memory.h"
#include "bios/bios.h"
// This is needed because on UNICODE this symbol is redirected to
@ -27,6 +28,8 @@
#undef FreeEnvironmentStrings
#define FreeEnvironmentStrings FreeEnvironmentStringsA
#define CHARACTER_ADDRESS 0x007000FF /* 0070:00FF */
/* PRIVATE VARIABLES **********************************************************/
// static BYTE CurrentDrive;
@ -38,53 +41,60 @@
CHAR DosReadCharacter(WORD FileHandle)
{
CHAR Character = '\0';
PCHAR Character = (PCHAR)FAR_POINTER(CHARACTER_ADDRESS);
WORD BytesRead;
*Character = '\0';
DPRINT("DosReadCharacter\n");
/* Use the file reading function */
DosReadFile(FileHandle, &Character, 1, &BytesRead);
DosReadFile(FileHandle, CHARACTER_ADDRESS, 1, &BytesRead);
return Character;
return *Character;
}
BOOLEAN DosCheckInput(VOID)
{
HANDLE Handle = DosGetRealHandle(DOS_INPUT_HANDLE);
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(DOS_INPUT_HANDLE);
if (IsConsoleHandle(Handle))
switch (SftEntry->Type)
{
/* Save AX */
USHORT AX = getAX();
case DOS_SFT_ENTRY_WIN32:
{
DWORD FileSizeHigh;
DWORD FileSize = GetFileSize(SftEntry->Handle, &FileSizeHigh);
LONG LocationHigh = 0;
DWORD Location = SetFilePointer(SftEntry->Handle, 0, &LocationHigh, FILE_CURRENT);
/* Call the BIOS */
setAH(0x01); // or 0x11 for enhanced, but what to choose?
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
}
/* Restore AX */
setAX(AX);
case DOS_SFT_ENTRY_DEVICE:
{
WORD Result;
/* Return keyboard status */
return (getZF() == 0);
}
else
{
DWORD FileSizeHigh;
DWORD FileSize = GetFileSize(Handle, &FileSizeHigh);
LONG LocationHigh = 0;
DWORD Location = SetFilePointer(Handle, 0, &LocationHigh, FILE_CURRENT);
if (!SftEntry->DeviceNode->InputStatusRoutine) return FALSE;
Result = SftEntry->DeviceNode->InputStatusRoutine(SftEntry->DeviceNode);
return !(Result & DOS_DEVSTAT_BUSY);
}
return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
default:
{
/* Invalid handle */
DosLastError = ERROR_INVALID_HANDLE;
return FALSE;
}
}
}
VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
{
WORD BytesWritten;
*((PCHAR)FAR_POINTER(CHARACTER_ADDRESS)) = Character;
/* Use the file writing function */
DosWriteFile(FileHandle, &Character, 1, &BytesWritten);
DosWriteFile(FileHandle, CHARACTER_ADDRESS, 1, &BytesWritten);
}
BOOLEAN DosBIOSInitialize(VOID)

View file

@ -0,0 +1,155 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/condrv.c
* PURPOSE: DOS32 CON Driver
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
#include "dos.h"
#include "dos/dem.h"
#include "bios/bios.h"
/* PRIVATE VARIABLES **********************************************************/
PDOS_DEVICE_NODE ConIn = NULL, ConOut = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
WORD NTAPI ConDrvReadInput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
{
CHAR Character;
WORD BytesRead;
PCHAR Pointer = (PCHAR)FAR_POINTER(Buffer);
/* Save AX */
USHORT AX = getAX();
/*
* Use BIOS Get Keystroke function
*/
for (BytesRead = 0; BytesRead < *Length; BytesRead++)
{
/* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
setAH(0x00);
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
/* Retrieve the character in AL (scan code is in AH) */
Character = getAL();
if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
Pointer[BytesRead] = Character;
/* Stop on first carriage return */
if (Character == '\r')
{
if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
break;
}
}
*Length = BytesRead;
/* Restore AX */
setAX(AX);
return DOS_DEVSTAT_DONE;
}
WORD NTAPI ConDrvInputStatus(PDOS_DEVICE_NODE Device)
{
/* Save AX */
USHORT AX = getAX();
/* Call the BIOS */
setAH(0x01); // or 0x11 for enhanced, but what to choose?
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
/* Restore AX */
setAX(AX);
/* If ZF is set, set the busy bit */
if (getZF()) return DOS_DEVSTAT_BUSY;
else return DOS_DEVSTAT_DONE;
}
WORD NTAPI ConDrvWriteOutput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
{
WORD BytesWritten;
PCHAR Pointer = (PCHAR)FAR_POINTER(Buffer);
/*
* Use BIOS Teletype function
*/
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
// FIXME: Use BIOS Write String function INT 10h, AH=13h ??
for (BytesWritten = 0; BytesWritten < *Length; BytesWritten++)
{
/* Set the parameters */
setAL(Pointer[BytesWritten]);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
setAH(0x0E);
Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
}
/* Restore AX and BX */
setBX(BX);
setAX(AX);
return DOS_DEVSTAT_DONE;
}
WORD NTAPI ConDrvOpen(PDOS_DEVICE_NODE Device)
{
DPRINT("Handle to %Z opened\n", &Device->Name);
return DOS_DEVSTAT_DONE;
}
WORD NTAPI ConDrvClose(PDOS_DEVICE_NODE Device)
{
DPRINT("Handle to %Z closed\n", &Device->Name);
return DOS_DEVSTAT_DONE;
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID ConDrvInitialize(PDOS_DEVICE_NODE *InputDevice, PDOS_DEVICE_NODE *OutputDevice)
{
ConIn = DosCreateDevice(DOS_DEVATTR_STDIN
| DOS_DEVATTR_CON
| DOS_DEVATTR_CHARACTER,
"CONIN$");
ConOut = DosCreateDevice(DOS_DEVATTR_STDOUT
| DOS_DEVATTR_CON
| DOS_DEVATTR_CHARACTER,
"CONOUT$");
ASSERT(ConIn != NULL && ConOut != NULL);
ConIn->ReadRoutine = ConDrvReadInput;
ConIn->InputStatusRoutine = ConDrvInputStatus;
ConOut->WriteRoutine = ConDrvWriteOutput;
ConIn->OpenRoutine = ConOut->OpenRoutine = ConDrvOpen;
ConIn->CloseRoutine = ConOut->CloseRoutine = ConDrvClose;
if (InputDevice) *InputDevice = ConIn;
if (OutputDevice) *OutputDevice = ConOut;
}
VOID ConDrvCleanup(VOID)
{
if (ConIn) DosDeleteDevice(ConIn);
if (ConOut) DosDeleteDevice(ConOut);
}

View file

@ -0,0 +1,383 @@
/*
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: device.c
* PURPOSE: DOS Device Support
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
#include "dos.h"
#include "dos/dem.h"
#include "memory.h"
#include "device.h"
/* PRIVATE VARIABLES **********************************************************/
static LIST_ENTRY DeviceList = { &DeviceList, &DeviceList };
/* PRIVATE FUNCTIONS **********************************************************/
static VOID DosCallDriver(DWORD Driver, PDOS_REQUEST_HEADER Request)
{
PDOS_DRIVER DriverBlock = (PDOS_DRIVER)FAR_POINTER(Driver);
PDOS_REQUEST_HEADER RemoteRequest;
/* Call the strategy routine first */
Call16(HIWORD(Driver), DriverBlock->StrategyRoutine);
RemoteRequest = (PDOS_REQUEST_HEADER)SEG_OFF_TO_PTR(getES(), getBX());
/* Copy the request structure to ES:BX */
RtlMoveMemory(RemoteRequest, Request, Request->RequestLength);
/* Call the interrupt routine */
Call16(HIWORD(Driver), DriverBlock->InterruptRoutine);
/* Get the request structure from ES:BX */
RtlMoveMemory(Request, RemoteRequest, RemoteRequest->RequestLength);
}
static inline WORD NTAPI DosDriverReadInternal(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length,
BOOLEAN IoControl)
{
DOS_RW_REQUEST Request;
Request.Header.RequestLength = IoControl ? sizeof(DOS_IOCTL_RW_REQUEST)
: sizeof(DOS_RW_REQUEST);
Request.Header.CommandCode = IoControl ? DOS_DEVCMD_IOCTL_READ : DOS_DEVCMD_READ;
Request.BufferPointer = Buffer;
Request.Length = *Length;
DosCallDriver(DeviceNode->Driver, &Request.Header);
*Length = Request.Length;
return Request.Header.Status;
}
static inline WORD NTAPI DosDriverWriteInternal(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length,
BOOLEAN IoControl)
{
DOS_RW_REQUEST Request;
Request.Header.RequestLength = IoControl ? sizeof(DOS_IOCTL_RW_REQUEST)
: sizeof(DOS_RW_REQUEST);
Request.Header.CommandCode = IoControl ? DOS_DEVCMD_IOCTL_WRITE : DOS_DEVCMD_WRITE;
Request.BufferPointer = Buffer;
Request.Length = *Length;
DosCallDriver(DeviceNode->Driver, &Request.Header);
*Length = Request.Length;
return Request.Header.Status;
}
static inline WORD NTAPI DosDriverGenericRequest(PDOS_DEVICE_NODE DeviceNode,
BYTE CommandCode)
{
DOS_REQUEST_HEADER Request;
Request.RequestLength = sizeof(DOS_REQUEST_HEADER);
Request.CommandCode = CommandCode;
DosCallDriver(DeviceNode->Driver, &Request);
return Request.Status;
}
static WORD NTAPI DosDriverDispatchIoctlRead(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length)
{
return DosDriverReadInternal(DeviceNode, Buffer, Length, TRUE);
}
static WORD NTAPI DosDriverDispatchRead(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length)
{
return DosDriverReadInternal(DeviceNode, Buffer, Length, FALSE);
}
static WORD NTAPI DosDriverDispatchPeek(PDOS_DEVICE_NODE DeviceNode,
PBYTE Character)
{
DOS_PEEK_REQUEST Request;
Request.Header.RequestLength = sizeof(DOS_PEEK_REQUEST);
Request.Header.CommandCode = DOS_DEVCMD_PEEK;
DosCallDriver(DeviceNode->Driver, &Request.Header);
*Character = Request.Character;
return Request.Header.Status;
}
static WORD NTAPI DosDriverDispatchInputStatus(PDOS_DEVICE_NODE DeviceNode)
{
return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_INSTAT);
}
static WORD NTAPI DosDriverDispatchFlushInput(PDOS_DEVICE_NODE DeviceNode)
{
return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_FLUSH_INPUT);
}
static WORD NTAPI DosDriverDispatchIoctlWrite(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length)
{
return DosDriverWriteInternal(DeviceNode, Buffer, Length, TRUE);
}
static WORD NTAPI DosDriverDispatchWrite(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length)
{
return DosDriverWriteInternal(DeviceNode, Buffer, Length, FALSE);
}
static WORD NTAPI DosDriverDispatchOutputStatus(PDOS_DEVICE_NODE DeviceNode)
{
return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_OUTSTAT);
}
static WORD NTAPI DosDriverDispatchFlushOutput(PDOS_DEVICE_NODE DeviceNode)
{
return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_FLUSH_OUTPUT);
}
static WORD NTAPI DosDriverDispatchOpen(PDOS_DEVICE_NODE DeviceNode)
{
return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_OPEN);
}
static WORD NTAPI DosDriverDispatchClose(PDOS_DEVICE_NODE DeviceNode)
{
return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_CLOSE);
}
static WORD NTAPI DosDriverDispatchOutputUntilBusy(PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length)
{
DOS_OUTPUT_BUSY_REQUEST Request;
Request.Header.RequestLength = sizeof(DOS_OUTPUT_BUSY_REQUEST);
Request.Header.CommandCode = DOS_DEVCMD_OUTPUT_BUSY;
Request.BufferPointer = Buffer;
Request.Length = *Length;
DosCallDriver(DeviceNode->Driver, &Request.Header);
*Length = Request.Length;
return Request.Header.Status;
}
/* PUBLIC FUNCTIONS ***********************************************************/
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName)
{
PLIST_ENTRY i;
PDOS_DEVICE_NODE Node;
ANSI_STRING DeviceNameString;
RtlInitAnsiString(&DeviceNameString, DeviceName);
for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
{
Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
if (RtlEqualString(&Node->Name, &DeviceNameString, TRUE)) return Node;
}
return NULL;
}
PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName)
{
BYTE i;
PDOS_DEVICE_NODE Node;
/* Make sure this is a character device */
if (!(Attributes & DOS_DEVATTR_CHARACTER))
{
DPRINT1("ERROR: Block devices are not supported.\n");
return FALSE;
}
Node = (PDOS_DEVICE_NODE)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(DOS_DEVICE_NODE));
if (Node == NULL) return NULL;
Node->DeviceAttributes = Attributes;
/* Initialize the name string */
Node->Name.Buffer = Node->NameBuffer;
Node->Name.MaximumLength = MAX_DEVICE_NAME;
for (i = 0; i < MAX_DEVICE_NAME; i++)
{
if (DeviceName[i] == '\0' || DeviceName[i] == ' ') break;
Node->Name.Buffer[i] = DeviceName[i];
}
Node->Name.Length = i;
InsertTailList(&DeviceList, &Node->Entry);
return Node;
}
VOID DosDeleteDevice(PDOS_DEVICE_NODE DeviceNode)
{
RemoveEntryList(&DeviceNode->Entry);
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNode);
}
DWORD DosLoadDriver(LPCSTR DriverFile)
{
DWORD Result = ERROR_SUCCESS;
HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
LPBYTE Address = NULL;
DWORD Driver;
PDOS_DRIVER DriverHeader;
WORD Segment = 0;
DWORD FileSize;
DWORD DriversLoaded = 0;
DOS_INIT_REQUEST Request;
PDOS_DEVICE_NODE DeviceNode;
/* Open a handle to the driver file */
FileHandle = CreateFileA(DriverFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
Result = GetLastError();
goto Cleanup;
}
/* Get the file size */
FileSize = GetFileSize(FileHandle, NULL);
/* Allocate DOS memory for the driver */
Segment = DosAllocateMemory(FileSize >> 4, NULL);
if (Segment == 0)
{
Result = DosLastError;
goto Cleanup;
}
/* Create a mapping object for the file */
FileMapping = CreateFileMapping(FileHandle,
NULL,
PAGE_READONLY,
0,
0,
NULL);
if (FileMapping == NULL)
{
Result = GetLastError();
goto Cleanup;
}
/* Map the file into memory */
Address = (LPBYTE)MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);
if (Address == NULL)
{
Result = GetLastError();
goto Cleanup;
}
/* Copy the entire file to the DOS memory */
Driver = MAKELONG(0, Segment);
DriverHeader = (PDOS_DRIVER)FAR_POINTER(Driver);
RtlCopyMemory(DriverHeader, Address, FileSize);
/* Loop through all the drivers in this file */
while (TRUE)
{
if (!(DriverHeader->DeviceAttributes & DOS_DEVATTR_CHARACTER))
{
DPRINT1("Error loading driver at %04X:%04X: "
"Block device drivers are not supported.\n",
HIWORD(Driver),
LOWORD(Driver));
goto Next;
}
/* Send the driver an init request */
RtlZeroMemory(&Request, sizeof(Request));
Request.Header.RequestLength = sizeof(DOS_INIT_REQUEST);
Request.Header.CommandCode = DOS_DEVCMD_INIT;
// TODO: Set Request.DeviceString to the appropriate line in CONFIG.NT!
DosCallDriver(Driver, &Request.Header);
if (Request.Header.Status & DOS_DEVSTAT_ERROR)
{
DPRINT1("Error loading driver at %04X:%04X: "
"Initialization routine returned error %u.\n",
HIWORD(Driver),
LOWORD(Driver),
Request.Header.Status & 0x7F);
goto Next;
}
/* Create the device */
DeviceNode = DosCreateDevice(DriverHeader->DeviceAttributes,
DriverHeader->DeviceName);
DeviceNode->Driver = Driver;
DeviceNode->IoctlReadRoutine = DosDriverDispatchIoctlRead;
DeviceNode->ReadRoutine = DosDriverDispatchRead;
DeviceNode->PeekRoutine = DosDriverDispatchPeek;
DeviceNode->InputStatusRoutine = DosDriverDispatchInputStatus;
DeviceNode->FlushInputRoutine = DosDriverDispatchFlushInput;
DeviceNode->IoctlWriteRoutine = DosDriverDispatchIoctlWrite;
DeviceNode->WriteRoutine = DosDriverDispatchWrite;
DeviceNode->OutputStatusRoutine = DosDriverDispatchOutputStatus;
DeviceNode->FlushOutputRoutine = DosDriverDispatchFlushOutput;
DeviceNode->OpenRoutine = DosDriverDispatchOpen;
DeviceNode->CloseRoutine = DosDriverDispatchClose;
DeviceNode->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy;
DriversLoaded++;
Next:
if (LOWORD(DriverHeader->Link) == 0xFFFF) break;
Driver = DriverHeader->Link;
DriverHeader = (PDOS_DRIVER)FAR_POINTER(Driver);
}
DPRINT1("%u drivers loaded from %s.\n", DriversLoaded, DriverFile);
Cleanup:
if (Result != ERROR_SUCCESS)
{
/* It was not successful, cleanup the DOS memory */
if (Segment) DosFreeMemory(Segment);
}
/* Unmap the file */
if (Address != NULL) UnmapViewOfFile(Address);
/* Close the file mapping object */
if (FileMapping != NULL) CloseHandle(FileMapping);
/* Close the file handle */
if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
return Result;
}

View file

@ -0,0 +1,199 @@
/*
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: device.h
* PURPOSE: DOS Device Support
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
#ifndef _DEVICE_H_
#define _DEVICE_H_
#include <ndk/rtlfuncs.h>
/* DEFINITIONS ****************************************************************/
#define MAX_DEVICE_NAME 8
#define DOS_DEVATTR_STDIN (1 << 0)
#define DOS_DEVATTR_STDOUT (1 << 1)
#define DOS_DEVATTR_NUL (1 << 2)
#define DOS_DEVATTR_CLOCK (1 << 3)
#define DOS_DEVATTR_CON (1 << 4)
#define DOS_DEVATTR_OPENCLOSE (1 << 11)
#define DOS_DEVATTR_SPECIAL (1 << 13)
#define DOS_DEVATTR_IOCTL (1 << 14)
#define DOS_DEVATTR_CHARACTER (1 << 15)
#define DOS_DEVCMD_INIT 0
#define DOS_DEVCMD_MEDIACHK 1
#define DOS_DEVCMD_BUILDBPB 2
#define DOS_DEVCMD_IOCTL_READ 3
#define DOS_DEVCMD_READ 4
#define DOS_DEVCMD_PEEK 5
#define DOS_DEVCMD_INSTAT 6
#define DOS_DEVCMD_FLUSH_INPUT 7
#define DOS_DEVCMD_WRITE 8
#define DOS_DEVCMD_WRITE_VERIFY 9
#define DOS_DEVCMD_OUTSTAT 10
#define DOS_DEVCMD_FLUSH_OUTPUT 11
#define DOS_DEVCMD_IOCTL_WRITE 12
#define DOS_DEVCMD_OPEN 13
#define DOS_DEVCMD_CLOSE 14
#define DOS_DEVCMD_REMOVABLE 15
#define DOS_DEVCMD_OUTPUT_BUSY 16
#define DOS_DEVSTAT_DONE (1 << 8)
#define DOS_DEVSTAT_BUSY (1 << 9)
#define DOS_DEVSTAT_ERROR (1 << 15)
#define DOS_DEVERR_WRITE_PROTECT 0
#define DOS_DEVERR_UNKNOWN_UNIT 1
#define DOS_DEVERR_NOT_READY 2
#define DOS_DEVERR_UNKNOWN_COMMAND 3
#define DOS_DEVERR_BAD_DATA_CRC 4
#define DOS_DEVERR_BAD_REQUEST 5
#define DOS_DEVERR_INVALID_SEEK 6
#define DOS_DEVERR_UNKNOWN_MEDIUM 7
#define DOS_DEVERR_BAD_BLOCK 8
#define DOS_DEVERR_OUT_OF_PAPER 9
#define DOS_DEVERR_WRITE_FAULT 10
#define DOS_DEVERR_READ_FAULT 11
#define DOS_DEVERR_GENERAL 12
#define DOS_DEVERR_BAD_MEDIA_CHANGE 15
typedef struct _DOS_DEVICE_NODE DOS_DEVICE_NODE, *PDOS_DEVICE_NODE;
typedef WORD (NTAPI *PDOS_DEVICE_GENERIC_ROUTINE)(PDOS_DEVICE_NODE DeviceNode);
typedef WORD (NTAPI *PDOS_DEVICE_IO_ROUTINE)
(
PDOS_DEVICE_NODE DeviceNode,
DWORD Buffer,
PWORD Length
);
typedef WORD (NTAPI *PDOS_DEVICE_PEEK_ROUTINE)
(
PDOS_DEVICE_NODE DeviceNode,
PBYTE Character
);
struct _DOS_DEVICE_NODE
{
LIST_ENTRY Entry;
WORD DeviceAttributes;
ANSI_STRING Name;
CHAR NameBuffer[MAX_DEVICE_NAME];
PDOS_DEVICE_IO_ROUTINE IoctlReadRoutine;
PDOS_DEVICE_IO_ROUTINE ReadRoutine;
PDOS_DEVICE_PEEK_ROUTINE PeekRoutine;
PDOS_DEVICE_GENERIC_ROUTINE InputStatusRoutine;
PDOS_DEVICE_GENERIC_ROUTINE FlushInputRoutine;
PDOS_DEVICE_IO_ROUTINE IoctlWriteRoutine;
PDOS_DEVICE_IO_ROUTINE WriteRoutine;
PDOS_DEVICE_GENERIC_ROUTINE OutputStatusRoutine;
PDOS_DEVICE_GENERIC_ROUTINE FlushOutputRoutine;
PDOS_DEVICE_GENERIC_ROUTINE OpenRoutine;
PDOS_DEVICE_GENERIC_ROUTINE CloseRoutine;
PDOS_DEVICE_IO_ROUTINE OutputUntilBusyRoutine;
DWORD Driver;
};
#pragma pack(push, 1)
typedef struct _DOS_DRIVER
{
DWORD Link;
WORD DeviceAttributes;
WORD StrategyRoutine;
WORD InterruptRoutine;
union
{
CHAR DeviceName[MAX_DEVICE_NAME]; // for character devices
struct // for block devices
{
BYTE UnitCount;
BYTE Reserved[MAX_DEVICE_NAME - 1];
};
};
} DOS_DRIVER, *PDOS_DRIVER;
typedef struct _DOS_REQUEST_HEADER
{
IN BYTE RequestLength;
IN BYTE UnitNumber OPTIONAL;
IN BYTE CommandCode;
OUT WORD Status;
BYTE Reserved[8];
} DOS_REQUEST_HEADER, *PDOS_REQUEST_HEADER;
typedef struct _DOS_INIT_REQUEST
{
DOS_REQUEST_HEADER Header;
OUT BYTE UnitsInitialized;
OUT DWORD ReturnBreakAddress;
union
{
IN DWORD DeviceString; // for character devices
struct // for block devices
{
IN BYTE FirstDriveLetter;
OUT DWORD BpbPointer;
};
};
} DOS_INIT_REQUEST, *PDOS_INIT_REQUEST;
typedef struct _DOS_IOCTL_RW_REQUEST
{
DOS_REQUEST_HEADER Header;
IN BYTE MediaDescriptorByte OPTIONAL;
IN DWORD BufferPointer;
IN OUT WORD Length;
IN WORD StartingBlock OPTIONAL;
} DOS_IOCTL_RW_REQUEST, *PDOS_IOCTL_RW_REQUEST;
typedef struct _DOS_RW_REQUEST
{
DOS_REQUEST_HEADER Header;
IN BYTE MediaDescriptorByte OPTIONAL;
IN DWORD BufferPointer;
IN OUT WORD Length;
IN WORD StartingBlock OPTIONAL;
OUT DWORD VolumeLabelPtr OPTIONAL;
} DOS_RW_REQUEST, *PDOS_RW_REQUEST;
typedef struct _DOS_PEEK_REQUEST
{
DOS_REQUEST_HEADER Header;
OUT BYTE Character;
} DOS_PEEK_REQUEST, *PDOS_PEEK_REQUEST;
typedef struct _DOS_OUTPUT_BUSY_REQUEST
{
DOS_REQUEST_HEADER Header;
IN DWORD BufferPointer;
IN OUT WORD Length;
} DOS_OUTPUT_BUSY_REQUEST, *PDOS_OUTPUT_BUSY_REQUEST;
#pragma pack(pop)
/* FUNCTIONS ******************************************************************/
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName);
PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName);
VOID DosDeleteDevice(PDOS_DEVICE_NODE DeviceNode);
#endif // _DEVICE_H_
/* EOF */

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
#include "device.h"
/**/ #include "int32.h" /**/
@ -48,13 +49,7 @@
#define NUM_DRIVES ('Z' - 'A' + 1)
#define DOS_CHAR_ATTRIBUTE 0x07
#define DOS_PROGRAM_NAME_TAG 0x0001
enum DOS_ALLOC_STRATEGY
{
DOS_ALLOC_FIRST_FIT,
DOS_ALLOC_BEST_FIT,
DOS_ALLOC_LAST_FIT
};
#define DEFAULT_JFT_SIZE 20
typedef enum
{
@ -63,16 +58,26 @@ typedef enum
DOS_LOAD_OVERLAY = 0x03
} DOS_EXEC_TYPE;
#pragma pack(push, 1)
typedef struct _DOS_MCB
typedef enum
{
CHAR BlockType;
WORD OwnerPsp;
WORD Size;
BYTE Unused[3];
CHAR Name[8];
} DOS_MCB, *PDOS_MCB;
DOS_SFT_ENTRY_NONE,
DOS_SFT_ENTRY_WIN32,
DOS_SFT_ENTRY_DEVICE
} DOS_SFT_ENTRY_TYPE;
typedef struct _DOS_SFT_ENTRY
{
DOS_SFT_ENTRY_TYPE Type;
WORD RefCount;
union
{
HANDLE Handle;
PDOS_DEVICE_NODE DeviceNode;
};
} DOS_SFT_ENTRY, *PDOS_SFT_ENTRY;
#pragma pack(push, 1)
typedef struct _DOS_FCB
{
@ -169,7 +174,11 @@ typedef struct _DOS_COUNTRY_CODE_BUFFER
#pragma pack(pop)
/* VARIABLES ******************************************************************/
extern BOOLEAN DoEcho;
extern WORD CurrentPsp;
extern WORD DosLastError;
/* FUNCTIONS ******************************************************************/
@ -190,15 +199,17 @@ BOOLEAN DosCheckInput(VOID);
VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
BOOLEAN DosBIOSInitialize(VOID);
VOID EmsDrvInitialize(VOID);
VOID EmsDrvCleanup(VOID);
VOID ConDrvInitialize(PDOS_DEVICE_NODE *InputDevice, PDOS_DEVICE_NODE *OutputDevice);
VOID ConDrvCleanup(VOID);
/*
* DOS Kernel Functions
* See dos.c
*/
BOOL IsConsoleHandle(HANDLE hHandle);
WORD DosOpenHandle(HANDLE Handle);
HANDLE DosGetRealHandle(WORD DosHandle);
PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle);
WORD DosCreateFileEx(LPWORD Handle,
LPWORD CreationStatus,
@ -214,11 +225,11 @@ WORD DosOpenFile(LPWORD Handle,
LPCSTR FilePath,
BYTE AccessShareModes);
WORD DosReadFile(WORD FileHandle,
LPVOID Buffer,
DWORD Buffer,
WORD Count,
LPWORD BytesRead);
WORD DosWriteFile(WORD FileHandle,
LPVOID Buffer,
DWORD Buffer,
WORD Count,
LPWORD BytesWritten);
WORD DosSeekFile(WORD FileHandle,

View file

@ -394,129 +394,84 @@ WORD DosOpenFile(LPWORD Handle,
}
WORD DosReadFile(WORD FileHandle,
LPVOID Buffer,
DWORD Buffer,
WORD Count,
LPWORD BytesRead)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (IsConsoleHandle(Handle))
if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
{
CHAR Character;
DWORD BytesRead32 = 0;
/*
* Use BIOS Get Keystroke function
*/
/* Save AX */
USHORT AX = getAX();
for (BytesRead32 = 0; BytesRead32 < Count; BytesRead32++)
{
/* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
setAH(0x00);
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
/* Retrieve the character in AL (scan code is in AH) */
Character = getAL();
if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
((PCHAR)Buffer)[BytesRead32] = Character;
/* Stop on first carriage return */
if (Character == '\r')
{
if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
break;
}
// BytesRead32++;
}
/* Restore AX */
setAX(AX);
}
else
{
/* Read the file */
if (!ReadFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesRead32, NULL))
if (!ReadFile(SftEntry->Handle, FAR_POINTER(Buffer), Count, &BytesRead32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes read is always 16-bit */
*BytesRead = LOWORD(BytesRead32);
/* The number of bytes read is always 16-bit */
*BytesRead = LOWORD(BytesRead32);
}
else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
{
if (!SftEntry->DeviceNode->ReadRoutine) return ERROR_INVALID_FUNCTION;
/* Read the device */
SftEntry->DeviceNode->ReadRoutine(SftEntry->DeviceNode, Buffer, &Count);
*BytesRead = Count;
}
else
{
/* Invalid handle */
return ERROR_INVALID_HANDLE;
}
/* Return the error code */
return Result;
}
WORD DosWriteFile(WORD FileHandle,
LPVOID Buffer,
DWORD Buffer,
WORD Count,
LPWORD BytesWritten)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (IsConsoleHandle(Handle))
if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
{
/*
* Use BIOS Teletype function
*/
DWORD BytesWritten32 = 0;
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
// FIXME: Use BIOS Write String function INT 10h, AH=13h ??
for (BytesWritten32 = 0; BytesWritten32 < Count; BytesWritten32++)
{
/* Set the parameters */
setAL(((PCHAR)Buffer)[BytesWritten32]);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
setAH(0x0E);
Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
// BytesWritten32++;
}
/* Restore AX and BX */
setBX(BX);
setAX(AX);
}
else
{
/* Write the file */
if (!WriteFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesWritten32, NULL))
if (!WriteFile(SftEntry->Handle, FAR_POINTER(Buffer), Count, &BytesWritten32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes written is always 16-bit */
*BytesWritten = LOWORD(BytesWritten32);
/* The number of bytes written is always 16-bit */
*BytesWritten = LOWORD(BytesWritten32);
}
else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
{
if (!SftEntry->DeviceNode->WriteRoutine) return ERROR_INVALID_FUNCTION;
/* Read the device */
SftEntry->DeviceNode->WriteRoutine(SftEntry->DeviceNode, Buffer, &Count);
*BytesWritten = Count;
}
else
{
/* Invalid handle */
return ERROR_INVALID_HANDLE;
}
/* Return the error code */
return Result;
@ -529,15 +484,23 @@ WORD DosSeekFile(WORD FileHandle,
{
WORD Result = ERROR_SUCCESS;
DWORD FilePointer;
HANDLE Handle = DosGetRealHandle(FileHandle);
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
FileHandle,
Offset,
Origin);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (SftEntry->Type == DOS_SFT_ENTRY_NONE)
{
/* Invalid handle */
return ERROR_INVALID_HANDLE;
}
else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
{
/* For character devices, always return success */
return ERROR_SUCCESS;
}
/* Check if the origin is valid */
if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
@ -545,17 +508,7 @@ WORD DosSeekFile(WORD FileHandle,
return ERROR_INVALID_FUNCTION;
}
/* Move the file pointer */
if (IsConsoleHandle(Handle))
{
/* Always succeeds when seeking a console handle */
FilePointer = 0;
Result = ERROR_SUCCESS;
}
else
{
FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
}
FilePointer = SetFilePointer(SftEntry->Handle, Offset, NULL, Origin);
/* Check if there's a possibility the operation failed */
if (FilePointer == INVALID_SET_FILE_POINTER)
@ -579,17 +532,34 @@ WORD DosSeekFile(WORD FileHandle,
BOOL DosFlushFileBuffers(WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return FALSE;
switch (SftEntry->Type)
{
case DOS_SFT_ENTRY_WIN32:
{
return FlushFileBuffers(SftEntry->Handle);
}
/*
* This function can either flush files back to disks, or flush
* console input buffers, in which case there is no need to check
* whether the handle is a console handle. FlushFileBuffers()
* automatically does this check and calls FlushConsoleInputBuffer()
* if needed.
*/
return FlushFileBuffers(Handle);
case DOS_SFT_ENTRY_DEVICE:
{
if (SftEntry->DeviceNode->FlushInputRoutine)
{
SftEntry->DeviceNode->FlushInputRoutine(SftEntry->DeviceNode);
}
if (SftEntry->DeviceNode->FlushOutputRoutine)
{
SftEntry->DeviceNode->FlushOutputRoutine(SftEntry->DeviceNode);
}
return TRUE;
}
default:
{
/* Invalid handle */
return FALSE;
}
}
}

View file

@ -0,0 +1,48 @@
/*
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: emsdrv.c
* PURPOSE: DOS EMS Driver
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "dos.h"
#include "dos/dem.h"
#include "device.h"
#define EMS_DEVICE_NAME "EMMXXXX0"
/* PRIVATE VARIABLES **********************************************************/
static PDOS_DEVICE_NODE Node;
/* PRIVATE FUNCTIONS **********************************************************/
WORD NTAPI EmsDrvDispatchIoctlRead(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
return DOS_DEVSTAT_DONE;
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID EmsDrvInitialize(VOID)
{
/* Create the device */
Node = DosCreateDevice(DOS_DEVATTR_IOCTL
| DOS_DEVATTR_CHARACTER,
EMS_DEVICE_NAME);
Node->IoctlReadRoutine = EmsDrvDispatchIoctlRead;
}
VOID EmsDrvCleanup(VOID)
{
/* Delete the device */
DosDeleteDevice(Node);
}

View file

@ -0,0 +1,378 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/memory.c
* PURPOSE: DOS32 Memory Manager
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
#include "dos.h"
#include "dos/dem.h"
#include "memory.h"
/* PUBLIC VARIABLES ***********************************************************/
BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
BOOLEAN DosUmbLinked = FALSE;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID DosCombineFreeBlocks(WORD StartBlock)
{
PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
/* If this is the last block or it's not free, quit */
if (CurrentMcb->BlockType == 'Z' || CurrentMcb->OwnerPsp != 0) return;
while (TRUE)
{
/* Get a pointer to the next MCB */
NextMcb = SEGMENT_TO_MCB(StartBlock + CurrentMcb->Size + 1);
/* Check if the next MCB is free */
if (NextMcb->OwnerPsp == 0)
{
/* Combine them */
CurrentMcb->Size += NextMcb->Size + 1;
CurrentMcb->BlockType = NextMcb->BlockType;
NextMcb->BlockType = 'I';
}
else
{
/* No more adjoining free blocks */
break;
}
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
{
WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0;
PDOS_MCB CurrentMcb, NextMcb;
BOOLEAN SearchUmb = FALSE;
DPRINT("DosAllocateMemory: Size 0x%04X\n", Size);
if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)))
{
/* Search UMB first */
Segment = UMB_START_SEGMENT;
SearchUmb = TRUE;
}
while (TRUE)
{
/* Get a pointer to the MCB */
CurrentMcb = SEGMENT_TO_MCB(Segment);
/* Make sure it's valid */
if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z')
{
DPRINT("The DOS memory arena is corrupted!\n");
DosLastError = ERROR_ARENA_TRASHED;
return 0;
}
/* Only check free blocks */
if (CurrentMcb->OwnerPsp != 0) goto Next;
/* Combine this free block with adjoining free blocks */
DosCombineFreeBlocks(Segment);
/* Update the maximum block size */
if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size;
/* Check if this block is big enough */
if (CurrentMcb->Size < Size) goto Next;
switch (DosAllocStrategy & 0x3F)
{
case DOS_ALLOC_FIRST_FIT:
{
/* For first fit, stop immediately */
Result = Segment;
goto Done;
}
case DOS_ALLOC_BEST_FIT:
{
/* For best fit, update the smallest block found so far */
if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size))
{
Result = Segment;
}
break;
}
case DOS_ALLOC_LAST_FIT:
{
/* For last fit, make the current block the result, but keep searching */
Result = Segment;
break;
}
}
Next:
/* If this was the last MCB in the chain, quit */
if (CurrentMcb->BlockType == 'Z')
{
/* Check if nothing was found while searching through UMBs */
if ((Result == 0) && SearchUmb && (DosAllocStrategy & DOS_ALLOC_HIGH_LOW))
{
/* Search low memory */
Segment = FIRST_MCB_SEGMENT;
continue;
}
break;
}
/* Otherwise, update the segment and continue */
Segment += CurrentMcb->Size + 1;
}
Done:
/* If we didn't find a free block, return 0 */
if (Result == 0)
{
DosLastError = ERROR_NOT_ENOUGH_MEMORY;
if (MaxAvailable) *MaxAvailable = MaxSize;
return 0;
}
/* Get a pointer to the MCB */
CurrentMcb = SEGMENT_TO_MCB(Result);
/* Check if the block is larger than requested */
if (CurrentMcb->Size > Size)
{
/* It is, split it into two blocks */
NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
/* Initialize the new MCB structure */
NextMcb->BlockType = CurrentMcb->BlockType;
NextMcb->Size = CurrentMcb->Size - Size - 1;
NextMcb->OwnerPsp = 0;
/* Update the current block */
CurrentMcb->BlockType = 'M';
CurrentMcb->Size = Size;
}
/* Take ownership of the block */
CurrentMcb->OwnerPsp = CurrentPsp;
/* Return the segment of the data portion of the block */
return Result + 1;
}
BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
{
BOOLEAN Success = TRUE;
WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment;
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb;
DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n",
BlockData,
NewSize);
/* Make sure this is a valid, allocated block */
if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') || Mcb->OwnerPsp == 0)
{
Success = FALSE;
DosLastError = ERROR_INVALID_HANDLE;
goto Done;
}
ReturnSize = Mcb->Size;
/* Check if we need to expand or contract the block */
if (NewSize > Mcb->Size)
{
/* We can't expand the last block */
if (Mcb->BlockType != 'M')
{
Success = FALSE;
goto Done;
}
/* Get the pointer and segment of the next MCB */
NextSegment = Segment + Mcb->Size + 1;
NextMcb = SEGMENT_TO_MCB(NextSegment);
/* Make sure the next segment is free */
if (NextMcb->OwnerPsp != 0)
{
DPRINT("Cannot expand memory block: next segment is not free!\n");
DosLastError = ERROR_NOT_ENOUGH_MEMORY;
Success = FALSE;
goto Done;
}
/* Combine this free block with adjoining free blocks */
DosCombineFreeBlocks(NextSegment);
/* Set the maximum possible size of the block */
ReturnSize += NextMcb->Size + 1;
if (ReturnSize < NewSize)
{
DPRINT("Cannot expand memory block: insufficient free segments available!\n");
DosLastError = ERROR_NOT_ENOUGH_MEMORY;
Success = FALSE;
goto Done;
}
/* Maximize the current block */
Mcb->Size = ReturnSize;
Mcb->BlockType = NextMcb->BlockType;
/* Invalidate the next block */
NextMcb->BlockType = 'I';
/* Check if the block is larger than requested */
if (Mcb->Size > NewSize)
{
DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n",
Mcb->Size,
NewSize);
/* It is, split it into two blocks */
NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
/* Initialize the new MCB structure */
NextMcb->BlockType = Mcb->BlockType;
NextMcb->Size = Mcb->Size - NewSize - 1;
NextMcb->OwnerPsp = 0;
/* Update the current block */
Mcb->BlockType = 'M';
Mcb->Size = NewSize;
}
}
else if (NewSize < Mcb->Size)
{
DPRINT("Shrinking block from 0x%04X to 0x%04X\n",
Mcb->Size,
NewSize);
/* Just split the block */
NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
NextMcb->BlockType = Mcb->BlockType;
NextMcb->Size = Mcb->Size - NewSize - 1;
NextMcb->OwnerPsp = 0;
/* Update the MCB */
Mcb->BlockType = 'M';
Mcb->Size = NewSize;
}
Done:
/* Check if the operation failed */
if (!Success)
{
DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n",
ReturnSize);
/* Return the maximum possible size */
if (MaxAvailable) *MaxAvailable = ReturnSize;
}
return Success;
}
BOOLEAN DosFreeMemory(WORD BlockData)
{
PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1);
DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData);
/* Make sure the MCB is valid */
if (Mcb->BlockType != 'M' && Mcb->BlockType != 'Z')
{
DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType);
return FALSE;
}
/* Mark the block as free */
Mcb->OwnerPsp = 0;
return TRUE;
}
BOOLEAN DosLinkUmb(VOID)
{
DWORD Segment = FIRST_MCB_SEGMENT;
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
DPRINT("Linking UMB\n");
/* Check if UMBs are already linked */
if (DosUmbLinked) return FALSE;
/* Find the last block */
while ((Mcb->BlockType == 'M') && (Segment <= 0xFFFF))
{
Segment += Mcb->Size + 1;
Mcb = SEGMENT_TO_MCB(Segment);
}
/* Make sure it's valid */
if (Mcb->BlockType != 'Z') return FALSE;
/* Connect the MCB with the UMB chain */
Mcb->BlockType = 'M';
DosUmbLinked = TRUE;
return TRUE;
}
BOOLEAN DosUnlinkUmb(VOID)
{
DWORD Segment = FIRST_MCB_SEGMENT;
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
DPRINT("Unlinking UMB\n");
/* Check if UMBs are already unlinked */
if (!DosUmbLinked) return FALSE;
/* Find the block preceding the MCB that links it with the UMB chain */
while (Segment <= 0xFFFF)
{
if ((Segment + Mcb->Size) == (FIRST_MCB_SEGMENT + USER_MEMORY_SIZE))
{
/* This is the last non-UMB segment */
break;
}
/* Advance to the next MCB */
Segment += Mcb->Size + 1;
Mcb = SEGMENT_TO_MCB(Segment);
}
/* Mark the MCB as the last MCB */
Mcb->BlockType = 'Z';
DosUmbLinked = FALSE;
return TRUE;
}
VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner)
{
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment - 1);
/* Just set the owner */
Mcb->OwnerPsp = NewOwner;
}

View file

@ -0,0 +1,46 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/memory.h
* PURPOSE: DOS32 Memory Manager
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
#ifndef _MEMORY_H_
#define _MEMORY_H_
/* TYPEDEFS *******************************************************************/
enum DOS_ALLOC_STRATEGY
{
DOS_ALLOC_FIRST_FIT,
DOS_ALLOC_BEST_FIT,
DOS_ALLOC_LAST_FIT
};
typedef struct _DOS_MCB
{
CHAR BlockType;
WORD OwnerPsp;
WORD Size;
BYTE Unused[3];
CHAR Name[8];
} DOS_MCB, *PDOS_MCB;
/* VARIABLES ******************************************************************/
extern BYTE DosAllocStrategy;
extern BOOLEAN DosUmbLinked;
/* FUNCTIONS ******************************************************************/
WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable);
BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable);
BOOLEAN DosFreeMemory(WORD BlockData);
BOOLEAN DosLinkUmb(VOID);
BOOLEAN DosUnlinkUmb(VOID);
VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner);
#endif // _MEMORY_H_
/* EOF */

View file

@ -34,6 +34,7 @@
#define REAL_TO_PHYS(ptr) (PVOID)((ULONG_PTR)(ptr) + (ULONG_PTR)BaseAddress)
#define PHYS_TO_REAL(ptr) (PVOID)((ULONG_PTR)(ptr) - (ULONG_PTR)BaseAddress)
#define ARRAY_INDEX(ptr, array) ((ULONG)(((ULONG_PTR)(ptr) - (ULONG_PTR)(array)) / sizeof(*array)))
/* BCD-Binary conversion */