windows-nt/Source/XPSP1/NT/base/mvdm/softpc.new/obj.vdm/ntvdm.c
2020-09-26 16:20:57 +08:00

364 lines
8.8 KiB
C

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <vdm.h>
#include "insignia.h"
#include "host_def.h"
#include <stdlib.h>
#include "xt.h"
#include "error.h"
#include "host_rrr.h"
#include "host_nls.h"
#include "nt_timer.h"
void CpuEnvInit(void);
typedef struct _CpuEnvironmentVariable {
struct _CpuEnvironmentVariable *Next;
char *Data;
char Name[1];
} CPUENVVAR, *PCPUENVVAR;
PCPUENVVAR CpuEnvVarListHead=NULL;
#if DBG
BOOLEAN verboseGetenv;
#endif
INT host_main(INT argc, CHAR **argv); // located in base\support\main.c
__cdecl main(int argc, CHAR ** argv)
{
int ret=-1;
/*
* Intialize synchronization events for the timer\heartbeat
* so that we can always suspend the heartbeat when an exception
* occurs.
*/
TimerInit();
try {
CpuEnvInit();
/*
* Load in the default system error message, since a resource load
* will fail when we are out of memory, if this fails we must exit
* to avoid confusion.
*/
nls_init();
ret = host_main(argc, argv);
}
except(VdmUnhandledExceptionFilter(GetExceptionInformation())) {
; // we shouldn't arrive here
}
return ret;
}
//
// The following function is placed here, so build will resolve references to
// DbgBreakPoint here, instead of NTDLL.
//
VOID
DbgBreakPoint(
VOID
)
/*++
Routine Description:
This routine is a substitute for the NT DbgBreakPoint routine.
If a user mode debugger is atached we invoke the real DbgBreakPoint()
thru the win32 api DebugBreak.
If no usermode debugger is attached:
- free build no effect
- checked build raise an acces violation to invoke the system
hard error popup which will give user a chance to invoke
ntsd.
Arguments:
None.
Return Value:
None.
--*/
{
HANDLE MyDebugPort;
DWORD dw;
// are we being debugged ??
dw = NtQueryInformationProcess(
NtCurrentProcess(),
ProcessDebugPort,
&MyDebugPort,
sizeof(MyDebugPort),
NULL );
if (!NT_SUCCESS(dw) || MyDebugPort == NULL) {
#ifndef PROD
RaiseException(STATUS_ACCESS_VIOLATION, 0L, 0L, NULL);
#endif
return;
}
DebugBreak();
}
/*
* Softpc env variables are mapped to the registry
*
* "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\WOW\CpuEnv"
*
* The string values for the CpuEnv key are read at initialization
* into the CpuEnv linked list. The Environment variables are defined
* as string key values, where the name of the value is equivalent to
* the Cpu Environment Variable name, and the string value is equivalent
* to the value of the environment variable value. This allows the
* emulator defaults to be overridden, by adding the appropriate value
* to CpuEnv subkey. Under standard retail setup there won't normally
* be a CpuEnv subkey, and NO cpu env variables defined to minimize
* code\data on a standard retail system.
*
*/
/*
* Adds a CpuEnv KEY_VALUE_FULL_INFORMATION to the CpuEnvList
*/
BOOLEAN
AddToCpuEnvList(
PKEY_VALUE_FULL_INFORMATION KeyValueInfo
)
{
NTSTATUS Status;
ULONG BufferSize;
PCPUENVVAR CpuEnvVar;
UNICODE_STRING UnicodeString;
ANSI_STRING ValueName;
ANSI_STRING ValueData;
char NameBuffer[MAX_PATH+sizeof(WCHAR)];
char DataBuffer[MAX_PATH+sizeof(WCHAR)];
/*
* Convert Value Name and Data strings from unicode to ansi
*/
ValueName.Buffer = NameBuffer;
ValueName.MaximumLength = sizeof(NameBuffer) - sizeof(WCHAR);
ValueName.Length = 0;
UnicodeString.Buffer = (PWSTR)KeyValueInfo->Name;
UnicodeString.MaximumLength =
UnicodeString.Length = (USHORT)KeyValueInfo->NameLength;
Status = RtlUnicodeStringToAnsiString(&ValueName, &UnicodeString,FALSE);
if (!NT_SUCCESS(Status)) {
return FALSE;
}
ValueData.Buffer = DataBuffer;
ValueData.MaximumLength = sizeof(DataBuffer) - sizeof(WCHAR);
ValueData.Length = 0;
UnicodeString.Buffer = (PWSTR)((PBYTE)KeyValueInfo + KeyValueInfo->DataOffset);
UnicodeString.MaximumLength =
UnicodeString.Length = (USHORT)KeyValueInfo->DataLength;
Status = RtlUnicodeStringToAnsiString(&ValueData, &UnicodeString, FALSE);
if (!NT_SUCCESS(Status)) {
return FALSE;
}
/*
* Allocate CPUENVLIST structure, with space for the ansi strings
*/
CpuEnvVar = malloc(sizeof(CPUENVVAR)+ // list structure size
ValueName.Length + // strlen Name
ValueData.Length + // strlen Data
1 // Null for Data
);
if (!CpuEnvVar) {
return FALSE;
}
/*
* Copy in the ansi strings, and link it into CpuEnvVar List
*/
memcpy(CpuEnvVar->Name, ValueName.Buffer, ValueName.Length);
*(CpuEnvVar->Name + ValueName.Length) = '\0';
CpuEnvVar->Data = CpuEnvVar->Name + ValueName.Length + 1;
memcpy(CpuEnvVar->Data, ValueData.Buffer, ValueData.Length);
*(CpuEnvVar->Data + ValueData.Length) = '\0';
CpuEnvVar->Next = CpuEnvVarListHead;
CpuEnvVarListHead = CpuEnvVar;
return TRUE;
}
/*
* Reads the CpuEnv values from the registry, into CpuEnvList
*/
void
CpuEnvInit(
void
)
{
int Index;
NTSTATUS Status;
HANDLE CpuEnvKey = NULL;
ULONG ResultLength;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
BYTE NameDataBuffer[sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH*2*sizeof(WCHAR)];
//
// Initialize TEB->Vdm to current version number
//
Index = (GetTickCount() << 16) | 0x80000000;
Index |= sizeof(VDM_TIB) + sizeof(VDMVIRTUALICA) + sizeof(VDMICAUSERDATA);
NtCurrentTeb()->Vdm = (PVOID)Index;
KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) NameDataBuffer;
#ifndef MONITOR
/*
* BUGBUG temp hack code to add two env var, which aren't properly
* defaulted to in the risc cpu emulator
*
* THIS is to be removed before SUR ship 19-Dec-1995 Jonle
*/
{
PWCHAR Data;
wcscpy(KeyValueInfo->Name, L"Soft486Buffers");
KeyValueInfo->NameLength = wcslen(KeyValueInfo->Name) * sizeof(WCHAR);
Data = (PWCH)((PBYTE)KeyValueInfo->Name + KeyValueInfo->NameLength + sizeof(WCHAR));
wcscpy(Data, L"511");
KeyValueInfo->DataLength = wcslen(Data) * sizeof(WCHAR);
KeyValueInfo->DataOffset = (PBYTE)Data - (PBYTE)KeyValueInfo;
AddToCpuEnvList(KeyValueInfo);
wcscpy(KeyValueInfo->Name, L"LCIF_FILENAME");
KeyValueInfo->NameLength = wcslen(KeyValueInfo->Name) * sizeof(WCHAR);
Data = (PWCH)((PBYTE)KeyValueInfo->Name + KeyValueInfo->NameLength + sizeof(WCHAR));
wcscpy(Data, L"R lcif");
KeyValueInfo->DataLength = wcslen(Data) * sizeof(WCHAR);
KeyValueInfo->DataOffset = (PBYTE)Data - (PBYTE)KeyValueInfo;
AddToCpuEnvList(KeyValueInfo);
}
#endif
RtlInitUnicodeString(
&UnicodeString,
L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Wow\\CpuEnv"
);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL
);
Status = NtOpenKey(&CpuEnvKey,
KEY_READ,
&ObjectAttributes
);
//
// If there is no CpuEnv key, CpuEnvList is empty.
//
if (!NT_SUCCESS(Status)) {
return;
}
Index = 0;
while (TRUE) {
Status = NtEnumerateValueKey(CpuEnvKey,
Index,
KeyValueFullInformation,
KeyValueInfo,
sizeof(NameDataBuffer),
&ResultLength
);
if (!NT_SUCCESS(Status) || !AddToCpuEnvList(KeyValueInfo)) {
break;
}
Index++;
};
NtClose(CpuEnvKey);
#if DBG
{
char *pEnvStr;
pEnvStr = getenv("VERBOSE_GETENV");
verboseGetenv = pEnvStr && !_stricmp(pEnvStr, "TRUE");
}
#endif
}
/*
* In order to catch all references, we define our own
* version of the CRT getenv, which does the mapping.
*/
char * __cdecl getenv(const char *Name)
{
PCPUENVVAR CpuEnvVar;
char *Value = NULL;
CpuEnvVar = CpuEnvVarListHead;
while (CpuEnvVar) {
if (!_stricmp(CpuEnvVar->Name, Name)) {
Value = CpuEnvVar->Data;
break;
}
CpuEnvVar = CpuEnvVar->Next;
}
#if DBG
if (verboseGetenv) {
DbgPrint("getenv %s:<%s>\n", Name, Value);
}
#endif
return Value;
}