mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[NTVDM]
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:
parent
4817056662
commit
56063f930f
14 changed files with 1738 additions and 662 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
155
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c
Normal file
155
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c
Normal 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);
|
||||
}
|
383
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c
Normal file
383
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c
Normal 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;
|
||||
}
|
||||
|
||||
|
199
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h
Normal file
199
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h
Normal 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
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
48
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
Normal file
48
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
Normal 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);
|
||||
}
|
378
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
Normal file
378
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
Normal 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;
|
||||
}
|
||||
|
46
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
Normal file
46
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
Normal 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 */
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue