mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
7.5 KiB
447 lines
7.5 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Buffer.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines to perform the actual buffering of data
|
|
for dpmi api translation support.
|
|
|
|
Author:
|
|
|
|
Dave Hastings (daveh) 30-Nov-1992
|
|
|
|
Revision History:
|
|
|
|
Neil Sandlin (neilsa) 31-Jul-1995 - Updates for the 486 emulator
|
|
|
|
--*/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "softpc.h"
|
|
|
|
PUCHAR
|
|
DpmiMapAndCopyBuffer(
|
|
PUCHAR Buffer,
|
|
USHORT BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine selects the appropriate buffer for the translation,
|
|
and copies the high memory buffer to it.
|
|
|
|
Arguments:
|
|
|
|
Buffer -- Supplies buffer in high memory
|
|
BufferLength -- Supplies the length of the buffer
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the translation buffer
|
|
|
|
--*/
|
|
{
|
|
PUCHAR NewBuffer;
|
|
|
|
//
|
|
// if the buffer is already in low memory, don't do anything
|
|
//
|
|
|
|
if ((ULONG)(Buffer + BufferLength - IntelBase) < MAX_V86_ADDRESS) {
|
|
return Buffer;
|
|
}
|
|
|
|
NewBuffer = DpmiAllocateBuffer(BufferLength);
|
|
|
|
CopyMemory(NewBuffer, Buffer, BufferLength);
|
|
|
|
return NewBuffer;
|
|
}
|
|
|
|
VOID
|
|
DpmiUnmapAndCopyBuffer(
|
|
PUCHAR Destination,
|
|
PUCHAR Source,
|
|
USHORT BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the information back to the high memory buffer
|
|
|
|
Arguments:
|
|
|
|
Destination -- Supplies the destination buffer
|
|
Source -- Supplies the source buffer
|
|
BufferLength -- Supplies the length of the information to copy
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// If the addresses are the same, don't do anything
|
|
//
|
|
if (Source == Destination) {
|
|
return;
|
|
}
|
|
|
|
CopyMemory(Destination, Source, BufferLength);
|
|
|
|
//
|
|
// Free the buffer
|
|
//
|
|
|
|
DpmiFreeBuffer(Source, BufferLength);
|
|
}
|
|
|
|
VOID
|
|
DpmiUnmapBuffer(
|
|
PUCHAR Buffer,
|
|
USHORT BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the buffer.
|
|
|
|
Arguments:
|
|
|
|
Buffer -- Supplies the buffer
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DpmiFreeBuffer(Buffer, BufferLength);
|
|
}
|
|
|
|
USHORT
|
|
DpmiCalcFcbLength(
|
|
PUCHAR FcbPointer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calculates the length of an FCB.
|
|
|
|
Arguments:
|
|
|
|
FcbPointer -- Supplies the Fcb
|
|
|
|
Return Value:
|
|
|
|
Length of the fcb in bytes
|
|
|
|
--*/
|
|
{
|
|
if (*FcbPointer == 0xFF) {
|
|
return 0x2c;
|
|
} else {
|
|
return 0x25;
|
|
}
|
|
}
|
|
|
|
PUCHAR
|
|
DpmiMapString(
|
|
USHORT StringSeg,
|
|
ULONG StringOff,
|
|
PWORD16 Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine maps an asciiz string to low memory
|
|
|
|
Arguments:
|
|
|
|
StringSeg -- Supplies the segment of the string
|
|
StringOff -- Supplies the offset of the string
|
|
|
|
Return Value:
|
|
|
|
Pointer to the buffered string
|
|
|
|
; NOTE:
|
|
; DOS has a tendency to look one byte past the end of the string "\"
|
|
; to look for ":\" followed by a zero. For this reason, we always
|
|
; map three extra bytes of every string.
|
|
|
|
--*/
|
|
{
|
|
USHORT CurrentChar = 0;
|
|
PUCHAR String;
|
|
ULONG Limit;
|
|
|
|
String = Sim32GetVDMPointer(
|
|
((ULONG)StringSeg << 16),
|
|
1,
|
|
TRUE
|
|
);
|
|
|
|
String += StringOff;
|
|
|
|
|
|
//
|
|
// Scan string for NULL
|
|
//
|
|
|
|
GET_SELECTOR_LIMIT(StringSeg, Limit);
|
|
Limit -= StringOff;
|
|
while (CurrentChar <= (USHORT)Limit) {
|
|
if (String[CurrentChar] == '\0') {
|
|
break;
|
|
}
|
|
CurrentChar++;
|
|
}
|
|
|
|
//
|
|
// If we didn't reach the end of the segment, we stopped because
|
|
// of the null, and need to include that in the string
|
|
//
|
|
if (CurrentChar < (USHORT)Limit) {
|
|
CurrentChar++;
|
|
}
|
|
|
|
//
|
|
// If we didn't find the end, copy 100h bytes
|
|
//
|
|
if ((String[CurrentChar] != '\0') && CurrentChar > 0x100) {
|
|
CurrentChar = 0x100;
|
|
}
|
|
|
|
//
|
|
// If there are 3 bytes after the string, copy the extra 3 bytes
|
|
//
|
|
if ((CurrentChar + 3) <= (USHORT)Limit) {
|
|
CurrentChar += 3;
|
|
}
|
|
|
|
//
|
|
// The length is one based. The index is zero based
|
|
//
|
|
*Length = CurrentChar + 1;
|
|
|
|
return DpmiMapAndCopyBuffer(String, (USHORT) (CurrentChar + 1));
|
|
|
|
}
|
|
|
|
VOID
|
|
DpmiUnmapString(
|
|
PUCHAR String,
|
|
USHORT Length
|
|
)
|
|
{
|
|
DpmiUnmapBuffer(String, Length);
|
|
return;
|
|
}
|
|
|
|
USHORT
|
|
DpmiSegmentToSelector(
|
|
USHORT Segment
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a specfied segment to a Data selector. If there
|
|
is a approprate selector in the LDT, that is returned. If not a new
|
|
selector is created. This routine can only be called in protectedmode.
|
|
|
|
Arguments:
|
|
|
|
Segment -- Segment to convert
|
|
|
|
Return Value:
|
|
|
|
Selector for the specified segment
|
|
|
|
--*/
|
|
{
|
|
USHORT ClientAX, ClientBX, ClientCS, ClientIP, ClientDS, ClientES, Selector;
|
|
PWORD16 Stack;
|
|
VSAVEDSTATE State;
|
|
|
|
ASSERT(getMSW() & MSW_PE);
|
|
|
|
DpmiSaveSegmentsAndStack(&State);
|
|
ClientAX = getAX();
|
|
ClientBX = getBX();
|
|
ClientCS = getCS();
|
|
ClientIP = getIP();
|
|
ClientDS = getDS();
|
|
ClientES = getES();
|
|
|
|
DpmiSwitchToDosxStack(TRUE);
|
|
|
|
//
|
|
// Make room for return address
|
|
//
|
|
setSP(getSP() - 4);
|
|
|
|
//
|
|
// Push a return to a bop
|
|
//
|
|
Stack = (PWORD16)Sim32GetVDMPointer(
|
|
((ULONG)getSS() << 16) | getSP(),
|
|
1,
|
|
TRUE
|
|
);
|
|
|
|
*Stack = (USHORT)(RmBopFe & 0x0000FFFF);
|
|
*(Stack + 1) = DosxRmCodeSelector;
|
|
|
|
//
|
|
// Set up the parameters
|
|
//
|
|
setAX(Segment);
|
|
setBX(0xF2);
|
|
if (CurrentAppFlags & DPMI_32BIT) {
|
|
setBX(getBX() | 0xF000);
|
|
}
|
|
|
|
//
|
|
// Make the call
|
|
//
|
|
setES(0);
|
|
setCS((USHORT) (DosxSegmentToSelector >> 16));
|
|
setIP((USHORT) (DosxSegmentToSelector & 0xFFFF));
|
|
setDS(DosxPmDataSelector);
|
|
|
|
host_simulate();
|
|
|
|
if (!getCF()) {
|
|
Selector = getAX();
|
|
} else {
|
|
Selector = 0xFFF0; // Guaranteed non-existant GDT selector
|
|
}
|
|
|
|
DpmiSwitchFromDosxStack();
|
|
setAX(ClientAX);
|
|
setBX(ClientBX);
|
|
setIP(ClientIP);
|
|
setCS(ClientCS);
|
|
DpmiRestoreSegmentsAndStack();
|
|
|
|
return Selector;
|
|
|
|
}
|
|
|
|
PUCHAR
|
|
DpmiAllocateBuffer(
|
|
USHORT Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates buffer space from the static buffer in low
|
|
memory.
|
|
|
|
Arguments:
|
|
|
|
Length -- Length of the buffer needed
|
|
|
|
Return Value:
|
|
|
|
Returns pointer to the buffer space allocated
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// If the data fits in the small buffer, use it
|
|
//
|
|
if ((Length <= SMALL_XLAT_BUFFER_SIZE) && !SmallBufferInUse) {
|
|
SmallBufferInUse = TRUE;
|
|
return SmallXlatBuffer;
|
|
}
|
|
|
|
if (Length <= (LARGE_XLAT_BUFFER_SIZE - LargeBufferInUseCount)) {
|
|
LargeBufferInUseCount += Length;
|
|
return (LargeXlatBuffer + LargeBufferInUseCount - Length);
|
|
}
|
|
|
|
//
|
|
// Whoops! No buffer space available. Bomb with a predictable
|
|
// address.
|
|
//
|
|
ASSERT(0); // this is an internal error
|
|
return (PUCHAR)0xf00df00d;
|
|
|
|
}
|
|
|
|
VOID
|
|
DpmiFreeBuffer(
|
|
PUCHAR Buffer,
|
|
USHORT Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees buffer space allocated using DpmiAllocateBuffer
|
|
|
|
Arguments:
|
|
|
|
Buffer -- Supplies a pointer to the buffer allocated above
|
|
Length -- Length of the buffer allocated
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Free the buffer
|
|
//
|
|
|
|
if (Buffer == SmallXlatBuffer) {
|
|
SmallBufferInUse = FALSE;
|
|
}
|
|
|
|
if ((Buffer >= LargeXlatBuffer) &&
|
|
(Buffer < (LargeXlatBuffer + LARGE_XLAT_BUFFER_SIZE))
|
|
) {
|
|
LargeBufferInUseCount -= Length;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DpmiFreeAllBuffers(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees all of the currently allocated buffer space.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
SmallBufferInUse = FALSE;
|
|
LargeBufferInUseCount = 0;
|
|
}
|
|
|