#include #include #include #include #include #include "insignia.h" #include "host_def.h" #include #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; }