364 lines
8.8 KiB
C
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;
|
|
}
|