/*++ Copyright (c) 1989 Microsoft Corporation Module Name: psinit.c Abstract: Process Structure Initialization. Author: Mark Lucovsky (markl) 20-Apr-1989 Revision History: --*/ #include "psp.h" #define ROUND_UP(VALUE,ROUND) ((ULONG)(((ULONG)VALUE + \ ((ULONG)ROUND - 1L)) & (~((ULONG)ROUND - 1L)))) extern ULONG PsMinimumWorkingSet; extern ULONG PsMaximumWorkingSet; ULONG PsPrioritySeperation; #if DBG PRTL_EVENT_ID_INFO PspExitProcessEventId; PRTL_EVENT_ID_INFO PspPageFaultEventId; #endif // DBG NTSTATUS MmCheckSystemImage( IN HANDLE ImageFileHandle ); NTSTATUS LookupEntryPoint ( IN PVOID DllBase, IN PSZ NameOfEntryPoint, OUT PVOID *AddressOfEntryPoint ); #ifdef i386 VOID KeSetup80387OrEmulate ( IN PVOID R3EmulatorTable ); #endif GENERIC_MAPPING PspProcessMapping = { STANDARD_RIGHTS_READ | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, STANDARD_RIGHTS_WRITE | PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION | PROCESS_SET_PORT, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, PROCESS_ALL_ACCESS }; GENERIC_MAPPING PspThreadMapping = { STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_ALERT | THREAD_SET_INFORMATION | THREAD_SET_CONTEXT, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, THREAD_ALL_ACCESS }; #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,PsInitSystem) #pragma alloc_text(INIT,PspInitPhase0) #pragma alloc_text(INIT,PspInitPhase1) #pragma alloc_text(INIT,PsLocateSystemDll) #pragma alloc_text(INIT,PspInitializeSystemDll) #pragma alloc_text(INIT,PspLookupSystemDllEntryPoint) #pragma alloc_text(INIT,PspNameToOrdinal) #pragma alloc_text(PAGE,PspMapSystemDll) #endif // // Process Structure Global Data // POBJECT_TYPE PsThreadType; POBJECT_TYPE PsProcessType; PHANDLE_TABLE PspCidTable; PEPROCESS PsInitialSystemProcess; HANDLE PspInitialSystemProcessHandle; PACCESS_TOKEN PspBootAccessToken; LIST_ENTRY PsLoadedModuleList; ERESOURCE PsLoadedModuleResource; extern KSPIN_LOCK PspEventPairLock; extern KSPIN_LOCK PsLoadedModuleSpinLock; UNICODE_STRING PsNtDllPathName; FAST_MUTEX PspProcessSecurityLock; PVOID PsSystemDllDllBase; ULONG PspDefaultPagedLimit; ULONG PspDefaultNonPagedLimit; ULONG PspDefaultPagefileLimit; SCHAR PspForegroundQuantum[3]; EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock; BOOLEAN PspDoingGiveBacks; #ifdef i386 PVOID PsNtosImageBase = (PVOID)0x80100000; PVOID PsHalImageBase = NULL; #else PVOID PsNtosImageBase; PVOID PsHalImageBase; #endif BOOLEAN PsReaperActive = FALSE; LIST_ENTRY PsReaperListHead; WORK_QUEUE_ITEM PsReaperWorkItem; SYSTEM_DLL PspSystemDll; PVOID PsSystemDllBase; #define PSP_1MB (1024*1024) // // List head and mutex that links all processes that have been initialized // FAST_MUTEX PspActiveProcessMutex; LIST_ENTRY PsActiveProcessHead; //extern PIMAGE_FILE_HEADER _header; PEPROCESS PsIdleProcess; BOOLEAN PsInitSystem ( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This function fermorms process structure initialization. It is called during phase 0 and phase 1 initialization. Its function is to dispatch to the appropriate phase initialization routine. Arguments: Phase - Supplies the initialization phase number. LoaderBlock - Supplies a pointer to a loader parameter block. Return Value: TRUE - Initialization succeeded. FALSE - Initialization failed. --*/ { switch ( InitializationPhase ) { case 0 : return PspInitPhase0(LoaderBlock); case 1 : return PspInitPhase1(LoaderBlock); default: KeBugCheck(UNEXPECTED_INITIALIZATION_CALL); } } BOOLEAN PspInitPhase0 ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This routine performs phase 0 process structure initialization. During this phase, the initial system process, phase 1 initialization thread, and reaper threads are created. All object types and other process structures are created and initialized. Arguments: None. Return Value: TRUE - Initialization was successful. FALSE - Initialization Failed. --*/ { PLDR_DATA_TABLE_ENTRY DataTableEntry1; PLDR_DATA_TABLE_ENTRY DataTableEntry2; UNICODE_STRING NameString; PLIST_ENTRY NextEntry; OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; HANDLE ThreadHandle; PETHREAD Thread; MM_SYSTEMSIZE SystemSize; PsPrioritySeperation = 2; SystemSize = MmQuerySystemSize(); PspDefaultPagefileLimit = (ULONG)-1; if ( sizeof(TEB) > 4096 || sizeof(PEB) > 4096 ) { KeBugCheckEx(PROCESS_INITIALIZATION_FAILED,99,sizeof(TEB),sizeof(PEB),99); } switch ( SystemSize ) { case MmMediumSystem : PsMinimumWorkingSet += 10; PsMaximumWorkingSet += 100; break; case MmLargeSystem : PsMinimumWorkingSet += 30; PsMaximumWorkingSet += 300; break; case MmSmallSystem : default: break; } if ( MmIsThisAnNtAsSystem() ) { PspForegroundQuantum[0] = 6*THREAD_QUANTUM; PspForegroundQuantum[1] = 6*THREAD_QUANTUM; PspForegroundQuantum[2] = 6*THREAD_QUANTUM; } else { // // For Workstation: // // BG is THREAD_QUANTUM // FG is THREAD_QUANTUM 50/50 fg/bg // FG is 2 * THREAD_QUANTUM 65/35 fg/bg // FG is 3 * THREAD_QUANTUM 75/25 fg/bg // PspForegroundQuantum[0] = THREAD_QUANTUM; PspForegroundQuantum[1] = 2*THREAD_QUANTUM; PspForegroundQuantum[2] = 3*THREAD_QUANTUM; } // // Quotas grow as needed automatically // if ( !PspDefaultPagedLimit ) { PspDefaultPagedLimit = 0; } if ( !PspDefaultNonPagedLimit ) { PspDefaultNonPagedLimit = 0; } if ( PspDefaultNonPagedLimit == 0 && PspDefaultPagedLimit == 0) { PspDoingGiveBacks = TRUE; } else { PspDoingGiveBacks = FALSE; } PspDefaultPagedLimit *= PSP_1MB; PspDefaultNonPagedLimit *= PSP_1MB; if (PspDefaultPagefileLimit != -1) { PspDefaultPagefileLimit *= PSP_1MB; } // // Initialize the process security fields lock and the process lock. // ExInitializeFastMutex( &PspProcessLockMutex ); ExInitializeFastMutex( &PspProcessSecurityLock ); // // Initialize the loaded module list executive resource and spin lock. // ExInitializeResource( &PsLoadedModuleResource ); KeInitializeSpinLock( &PsLoadedModuleSpinLock ); KeInitializeSpinLock( &PspEventPairLock ); // // Initialize the loaded module listheads. // PsIdleProcess = PsGetCurrentProcess(); PsIdleProcess->Pcb.KernelTime = 0; PsIdleProcess->Pcb.KernelTime = 0; InitializeListHead(&PsLoadedModuleList); // // Scan the loaded module list and allocate and initialize a data table // entry for each module. The data table entry is inserted in the loaded // module list and the initialization order list in the order specified // in the loader parameter block. The data table entry is inserted in the // memory order list in memory order. // NextEntry = LoaderBlock->LoadOrderListHead.Flink; DataTableEntry2 = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); PsNtosImageBase = DataTableEntry2->DllBase; DataTableEntry2 = (PLDR_DATA_TABLE_ENTRY) NextEntry->Flink; DataTableEntry2 = CONTAINING_RECORD(DataTableEntry2, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); PsHalImageBase = DataTableEntry2->DllBase; while (NextEntry != &LoaderBlock->LoadOrderListHead) { DataTableEntry2 = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); // // Allocate a data table entry. // DataTableEntry1 = ExAllocatePool(NonPagedPool, sizeof(LDR_DATA_TABLE_ENTRY) + DataTableEntry2->FullDllName.MaximumLength + DataTableEntry2->BaseDllName.MaximumLength + sizeof(ULONG) + sizeof(ULONG)); if (DataTableEntry1 == NULL) { return FALSE; } // // Copy the data table entry. // *DataTableEntry1 = *DataTableEntry2; // // Copy the strings. // DataTableEntry1->FullDllName.Buffer = (PWSTR)((PCHAR)DataTableEntry1 + ROUND_UP(sizeof(LDR_DATA_TABLE_ENTRY), sizeof(ULONG))); RtlMoveMemory (DataTableEntry1->FullDllName.Buffer, DataTableEntry2->FullDllName.Buffer, DataTableEntry1->FullDllName.MaximumLength); DataTableEntry1->BaseDllName.Buffer = (PWSTR)((PCHAR)DataTableEntry1->FullDllName.Buffer + ROUND_UP(DataTableEntry1->FullDllName.MaximumLength, sizeof(ULONG))); RtlMoveMemory (DataTableEntry1->BaseDllName.Buffer, DataTableEntry2->BaseDllName.Buffer, DataTableEntry1->BaseDllName.MaximumLength); // // Insert the data table entry in the load order list in the order // they are specified. // InsertTailList(&PsLoadedModuleList, &DataTableEntry1->InLoadOrderLinks); NextEntry = NextEntry->Flink; } // // Initialize the common fields of the Object Type Prototype record // RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) ); ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer ); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.SecurityRequired = TRUE; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.InvalidAttributes = OBJ_PERMANENT | OBJ_EXCLUSIVE | OBJ_OPENIF; // // Create Object types for Thread and Process Objects. // RtlInitUnicodeString(&NameString, L"Process"); ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_PROCESS_PAGED_CHARGE; ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_PROCESS_NONPAGED_CHARGE; ObjectTypeInitializer.DeleteProcedure = PspProcessDelete; ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = PspProcessMapping; if ( !NT_SUCCESS(ObCreateObjectType(&NameString, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR) NULL, &PsProcessType )) ){ return FALSE; } RtlInitUnicodeString(&NameString, L"Thread"); ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_THREAD_PAGED_CHARGE; ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_THREAD_NONPAGED_CHARGE; ObjectTypeInitializer.DeleteProcedure = PspThreadDelete; ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = PspThreadMapping; if ( !NT_SUCCESS(ObCreateObjectType(&NameString, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR) NULL, &PsThreadType )) ){ return FALSE; } // // Initialize active process list head and mutex // InitializeListHead(&PsActiveProcessHead); ExInitializeFastMutex(&PspActiveProcessMutex); // // Initialize CID handle table. // // N.B. The CID handle table is removed from the handle table list so // it will not be enumerated for object handle queries. // PspCidTable = ExCreateHandleTable(NULL, 0, 0); if ( ! PspCidTable ) { return FALSE; } ExRemoveHandleTable(PspCidTable); #ifdef i386 // // Ldt Initialization // if ( !NT_SUCCESS(PspLdtInitialize()) ) { return FALSE; } // // Vdm support Initialization // if ( !NT_SUCCESS(PspVdmInitialize()) ) { return FALSE; } #endif // // Initialize Reaper Data Structures // InitializeListHead(&PsReaperListHead); ExInitializeWorkItem(&PsReaperWorkItem, PspReaper, NULL); // // Get a pointer to the system access token. // This token is used by the boot process, so we can take the pointer // from there. // PspBootAccessToken = PsGetCurrentProcess()->Token; InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); // FIXFIX if ( !NT_SUCCESS(PspCreateProcess( &PspInitialSystemProcessHandle, PROCESS_ALL_ACCESS, &ObjectAttributes, 0L, FALSE, 0L, 0L, 0L )) ) { return FALSE; } if ( !NT_SUCCESS(ObReferenceObjectByHandle( PspInitialSystemProcessHandle, 0L, PsProcessType, KernelMode, (PVOID *)&PsInitialSystemProcess, NULL )) ) { return FALSE; } strcpy(&PsGetCurrentProcess()->ImageFileName[0],"Idle"); strcpy(&PsInitialSystemProcess->ImageFileName[0],"System"); // // Phase 1 System initialization // if ( !NT_SUCCESS(PsCreateSystemThread( &ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, 0L, NULL, Phase1Initialization, (PVOID)LoaderBlock )) ) { return FALSE; } if ( !NT_SUCCESS(ObReferenceObjectByHandle( ThreadHandle, 0L, PsThreadType, KernelMode, (PVOID *)&Thread, NULL )) ) { return FALSE; } ZwClose( ThreadHandle ); #if DBG PspExitProcessEventId = RtlCreateEventId( NULL, 0, "ExitProcess", 1, RTL_EVENT_STATUS_PARAM, "ExitStatus", 0 ); PspPageFaultEventId = RtlCreateEventId( NULL, 0, "PageFault", 3, RTL_EVENT_STATUS_PARAM, "", 0, RTL_EVENT_ADDRESS_PARAM, "PC", 0, RTL_EVENT_ADDRESS_PARAM, "Va", 0 ); #endif // DBG return TRUE; } BOOLEAN PspInitPhase1 ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This routine performs phase 1 process structure initialization. During this phase, the system DLL is located and relevant entry points are extracted. Arguments: None. Return Value: TRUE - Initialization was successful. FALSE - Initialization Failed. --*/ { NTSTATUS st; st = PspInitializeSystemDll(); if ( !NT_SUCCESS(st) ) { return FALSE; } return TRUE; } NTSTATUS PsLocateSystemDll ( VOID ) /*++ Routine Description: This function locates the system dll and creates a section for the DLL and maps it into the system process. Arguments: None. Return Value: TRUE - Initialization was successful. FALSE - Initialization Failed. --*/ { HANDLE File; HANDLE Section; NTSTATUS st; UNICODE_STRING DllPathName; WCHAR PathBuffer[DOS_MAX_PATH_LENGTH]; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; // // Initialize the system DLL // DllPathName.Length = 0; DllPathName.Buffer = PathBuffer; DllPathName.MaximumLength = 256; RtlInitUnicodeString(&DllPathName,L"\\SystemRoot\\System32\\ntdll.dll"); InitializeObjectAttributes( &ObjectAttributes, &DllPathName, OBJ_CASE_INSENSITIVE, NULL, NULL ); st = ZwOpenFile( &File, SYNCHRONIZE | FILE_EXECUTE, &ObjectAttributes, &IoStatus, FILE_SHARE_READ, 0 ); if (!NT_SUCCESS(st)) { #if DBG DbgPrint("PS: PsLocateSystemDll - NtOpenFile( NTDLL.DLL ) failed. Status == %lx\n", st ); #endif KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,2,0,0); return st; } st = MmCheckSystemImage(File); if ( st == STATUS_IMAGE_CHECKSUM_MISMATCH ) { ULONG ErrorParameters; ULONG ErrorResponse; // // Hard error time. A driver is corrupt. // ErrorParameters = (ULONG)&DllPathName; NtRaiseHardError( st, 1, 1, &ErrorParameters, OptionOk, &ErrorResponse ); return st; } PsNtDllPathName.MaximumLength = DllPathName.Length + sizeof( WCHAR ); PsNtDllPathName.Length = 0; PsNtDllPathName.Buffer = RtlAllocateStringRoutine( PsNtDllPathName.MaximumLength ); RtlCopyUnicodeString( &PsNtDllPathName, &DllPathName ); st = ZwCreateSection( &Section, SECTION_ALL_ACCESS, NULL, 0, PAGE_EXECUTE, SEC_IMAGE, File ); ZwClose( File ); if (!NT_SUCCESS(st)) { #if DBG DbgPrint("PS: PsLocateSystemDll: NtCreateSection Status == %lx\n",st); #endif KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,3,0,0); return st; } // // Now that we have the section, reference it, store its address in the // PspSystemDll and then close handle to the section. // st = ObReferenceObjectByHandle( Section, SECTION_ALL_ACCESS, MmSectionObjectType, KernelMode, &PspSystemDll.Section, NULL ); ZwClose(Section); if ( !NT_SUCCESS(st) ) { KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,4,0,0); return st; } // // Map the system dll into the user part of the address space // st = PspMapSystemDll(PsGetCurrentProcess(),&PspSystemDll.DllBase); PsSystemDllDllBase = PspSystemDll.DllBase; if ( !NT_SUCCESS(st) ) { KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,5,0,0); return st; } PsSystemDllBase = PspSystemDll.DllBase; return STATUS_SUCCESS; } NTSTATUS PspMapSystemDll ( IN PEPROCESS Process, OUT PVOID *DllBase OPTIONAL ) /*++ Routine Description: This function maps the system DLL into the specified process. Arguments: Process - Supplies the address of the process to map the DLL into. Return Value: TBD --*/ { NTSTATUS st; PVOID ViewBase; LARGE_INTEGER SectionOffset; ULONG ViewSize; PAGED_CODE(); ViewBase = NULL; SectionOffset.LowPart = 0; SectionOffset.HighPart = 0; ViewSize = 0; // // Map the system dll into the user part of the address space // st = MmMapViewOfSection( PspSystemDll.Section, Process, &ViewBase, 0L, 0L, &SectionOffset, &ViewSize, ViewShare, 0L, PAGE_READWRITE ); if ( st != STATUS_SUCCESS ) { #if DBG DbgPrint("PS: Unable to map system dll at based address.\n"); #endif st = STATUS_CONFLICTING_ADDRESSES; } if ( ARGUMENT_PRESENT(DllBase) ) { *DllBase = ViewBase; } return st; } NTSTATUS PspInitializeSystemDll ( VOID ) /*++ Routine Description: This function initializes the system DLL and locates various entrypoints within the DLL. Arguments: None. Return Value: TBD --*/ { NTSTATUS st; PSZ dll_entrypoint; PVOID R3EmulatorTable; // // Locate the important system dll entrypoints // dll_entrypoint = "LdrInitializeThunk"; st = PspLookupSystemDllEntryPoint( dll_entrypoint, (PVOID *)&PspSystemDll.LoaderInitRoutine ); if ( !NT_SUCCESS(st) ) { #if DBG DbgPrint("PS: Unable to locate LdrInitializeThunk in system dll\n"); #endif KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,6,0,0); return st; } #if i386 // // Find 80387 emulator. // st = PspLookupSystemDllEntryPoint( "NPXEMULATORTABLE", &R3EmulatorTable ); if ( !NT_SUCCESS(st) ) { #if DBG DbgPrint("PS: Unable to locate NPXNPHandler in system dll\n"); #endif KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,7,0,0); return st; } // // Pass emulator into kernel, and let it decide whether it should // use the emulator or set up to use the 80387 hardware. // KeSetup80387OrEmulate(R3EmulatorTable); #endif //i386 st = PspLookupKernelUserEntryPoints(); if ( !NT_SUCCESS(st) ) { KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,8,0,0); } return st; } NTSTATUS PspLookupSystemDllEntryPoint ( IN PSZ NameOfEntryPoint, OUT PVOID *AddressOfEntryPoint ) { return LookupEntryPoint ( PspSystemDll.DllBase, NameOfEntryPoint, AddressOfEntryPoint ); }