reactos/ntoskrnl/ps/psmgr.c
Hervé Poussineau f7ec84eea0 [NTOS:KD] Remove some _WINDK_ usages
- Always include kd64.h
- Change KdpPrompt() prototype to be compatible between KDBG and _WINDK_
- Rename KdComponentTable to KdpComponentTable to prevent a conflict
- Add some functions stubs and global variables
2019-05-23 11:04:40 +02:00

679 lines
21 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ps/psmgr.c
* PURPOSE: Process Manager: Initialization Code
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
extern ULONG ExpInitializationPhase;
PVOID KeUserPopEntrySListEnd;
PVOID KeUserPopEntrySListFault;
PVOID KeUserPopEntrySListResume;
GENERIC_MAPPING PspProcessMapping =
{
STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
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_SUSPEND_RESUME,
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
};
PVOID PspSystemDllBase;
PVOID PspSystemDllSection;
PVOID PspSystemDllEntryPoint;
UNICODE_STRING PsNtDllPathName =
RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\ntdll.dll");
PHANDLE_TABLE PspCidTable;
PEPROCESS PsInitialSystemProcess = NULL;
PEPROCESS PsIdleProcess = NULL;
HANDLE PspInitialSystemProcessHandle = NULL;
ULONG PsMinimumWorkingSet, PsMaximumWorkingSet;
struct
{
LIST_ENTRY List;
KGUARDED_MUTEX Lock;
} PspWorkingSetChangeHead;
ULONG PspDefaultPagedLimit, PspDefaultNonPagedLimit, PspDefaultPagefileLimit;
BOOLEAN PspDoingGiveBacks;
/* PRIVATE FUNCTIONS *********************************************************/
INIT_FUNCTION
USHORT
NTAPI
NameToOrdinal(IN PCHAR Name,
IN PVOID DllBase,
IN ULONG NumberOfNames,
IN PULONG NameTable,
IN PUSHORT OrdinalTable)
{
ULONG Mid;
LONG Ret;
/* Fail if no names */
if (!NumberOfNames) return -1;
/* Do binary search */
Mid = NumberOfNames >> 1;
Ret = strcmp(Name, (PCHAR)((ULONG_PTR)DllBase + NameTable[Mid]));
/* Check if we found it */
if (!Ret) return OrdinalTable[Mid];
/* We didn't. Check if we only had one name to check */
if (NumberOfNames == 1) return -1;
/* Check if we should look up or down */
if (Ret < 0)
{
/* Loop down */
NumberOfNames = Mid;
}
else
{
/* Look up, update tables */
NameTable = &NameTable[Mid + 1];
OrdinalTable = &OrdinalTable[Mid + 1];
NumberOfNames -= (Mid - 1);
}
/* Call us recursively */
return NameToOrdinal(Name, DllBase, NumberOfNames, NameTable, OrdinalTable);
}
INIT_FUNCTION
NTSTATUS
NTAPI
LookupEntryPoint(IN PVOID DllBase,
IN PCHAR Name,
OUT PVOID *EntryPoint)
{
PULONG NameTable;
PUSHORT OrdinalTable;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
ULONG ExportSize;
CHAR Buffer[64];
USHORT Ordinal;
PULONG ExportTable;
/* Get the export directory */
ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize);
/* Validate the name and copy it */
if (strlen(Name) > sizeof(Buffer) - 2) return STATUS_INVALID_PARAMETER;
strcpy(Buffer, Name);
/* Setup name tables */
NameTable = (PULONG)((ULONG_PTR)DllBase +
ExportDirectory->AddressOfNames);
OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
ExportDirectory->AddressOfNameOrdinals);
/* Get the ordinal */
Ordinal = NameToOrdinal(Buffer,
DllBase,
ExportDirectory->NumberOfNames,
NameTable,
OrdinalTable);
/* Make sure the ordinal is valid */
if (Ordinal >= ExportDirectory->NumberOfFunctions)
{
/* It's not, fail */
return STATUS_PROCEDURE_NOT_FOUND;
}
/* Resolve the address and write it */
ExportTable = (PULONG)((ULONG_PTR)DllBase +
ExportDirectory->AddressOfFunctions);
*EntryPoint = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
return STATUS_SUCCESS;
}
INIT_FUNCTION
NTSTATUS
NTAPI
PspLookupSystemDllEntryPoint(IN PCHAR Name,
IN PVOID *EntryPoint)
{
/* Call the LDR Routine */
return LookupEntryPoint(PspSystemDllBase, Name, EntryPoint);
}
INIT_FUNCTION
NTSTATUS
NTAPI
PspLookupKernelUserEntryPoints(VOID)
{
NTSTATUS Status;
/* Get user-mode APC trampoline */
Status = PspLookupSystemDllEntryPoint("KiUserApcDispatcher",
&KeUserApcDispatcher);
if (!NT_SUCCESS(Status)) return Status;
/* Get user-mode exception dispatcher */
Status = PspLookupSystemDllEntryPoint("KiUserExceptionDispatcher",
&KeUserExceptionDispatcher);
if (!NT_SUCCESS(Status)) return Status;
/* Get user-mode callback dispatcher */
Status = PspLookupSystemDllEntryPoint("KiUserCallbackDispatcher",
&KeUserCallbackDispatcher);
if (!NT_SUCCESS(Status)) return Status;
/* Get user-mode exception raise trampoline */
Status = PspLookupSystemDllEntryPoint("KiRaiseUserExceptionDispatcher",
&KeRaiseUserExceptionDispatcher);
if (!NT_SUCCESS(Status)) return Status;
/* Get user-mode SLIST exception functions for page fault rollback race hack */
Status = PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListEnd",
&KeUserPopEntrySListEnd);
if (!NT_SUCCESS(Status)) { DPRINT1("this not found\n"); return Status; }
Status = PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListFault",
&KeUserPopEntrySListFault);
if (!NT_SUCCESS(Status)) { DPRINT1("this not found\n"); return Status; }
Status = PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListResume",
&KeUserPopEntrySListResume);
if (!NT_SUCCESS(Status)) { DPRINT1("this not found\n"); return Status; }
/* On x86, there are multiple ways to do a system call, find the right stubs */
#if defined(_X86_)
/* Check if this is a machine that supports SYSENTER */
if (KeFeatureBits & KF_FAST_SYSCALL)
{
/* Get user-mode sysenter stub */
SharedUserData->SystemCall = (PsNtosImageBase >> (PAGE_SHIFT + 1));
Status = PspLookupSystemDllEntryPoint("KiFastSystemCall",
(PVOID)&SharedUserData->
SystemCall);
if (!NT_SUCCESS(Status)) return Status;
/* Get user-mode sysenter return stub */
Status = PspLookupSystemDllEntryPoint("KiFastSystemCallRet",
(PVOID)&SharedUserData->
SystemCallReturn);
if (!NT_SUCCESS(Status)) return Status;
}
else
{
/* Get the user-mode interrupt stub */
Status = PspLookupSystemDllEntryPoint("KiIntSystemCall",
(PVOID)&SharedUserData->
SystemCall);
if (!NT_SUCCESS(Status)) return Status;
}
/* Set the test instruction */
SharedUserData->TestRetInstruction = 0xC3;
#endif
/* Return the status */
return Status;
}
NTSTATUS
NTAPI
PspMapSystemDll(IN PEPROCESS Process,
IN PVOID *DllBase,
IN BOOLEAN UseLargePages)
{
NTSTATUS Status;
LARGE_INTEGER Offset = {{0, 0}};
SIZE_T ViewSize = 0;
PVOID ImageBase = 0;
/* Map the System DLL */
Status = MmMapViewOfSection(PspSystemDllSection,
Process,
(PVOID*)&ImageBase,
0,
0,
&Offset,
&ViewSize,
ViewShare,
0,
PAGE_READWRITE);
if (Status != STATUS_SUCCESS)
{
/* Normalize status code */
Status = STATUS_CONFLICTING_ADDRESSES;
}
/* Write the image base and return status */
if (DllBase) *DllBase = ImageBase;
return Status;
}
INIT_FUNCTION
NTSTATUS
NTAPI
PsLocateSystemDll(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle, SectionHandle;
NTSTATUS Status;
ULONG_PTR HardErrorParameters;
ULONG HardErrorResponse;
/* Locate and open NTDLL to determine ImageBase and LdrStartup */
InitializeObjectAttributes(&ObjectAttributes,
&PsNtDllPathName,
0,
NULL,
NULL);
Status = ZwOpenFile(&FileHandle,
FILE_READ_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ,
0);
if (!NT_SUCCESS(Status))
{
/* Failed, bugcheck */
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 2, 0, 0);
}
/* Check if the image is valid */
Status = MmCheckSystemImage(FileHandle, TRUE);
if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH)
{
/* Raise a hard error */
HardErrorParameters = (ULONG_PTR)&PsNtDllPathName;
NtRaiseHardError(Status,
1,
1,
&HardErrorParameters,
OptionOk,
&HardErrorResponse);
return Status;
}
/* Create a section for NTDLL */
Status = ZwCreateSection(&SectionHandle,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_EXECUTE,
SEC_IMAGE,
FileHandle);
ZwClose(FileHandle);
if (!NT_SUCCESS(Status))
{
/* Failed, bugcheck */
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 3, 0, 0);
}
/* Reference the Section */
Status = ObReferenceObjectByHandle(SectionHandle,
SECTION_ALL_ACCESS,
MmSectionObjectType,
KernelMode,
(PVOID*)&PspSystemDllSection,
NULL);
ZwClose(SectionHandle);
if (!NT_SUCCESS(Status))
{
/* Failed, bugcheck */
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 4, 0, 0);
}
/* Map it */
Status = PspMapSystemDll(PsGetCurrentProcess(), &PspSystemDllBase, FALSE);
if (!NT_SUCCESS(Status))
{
/* Failed, bugcheck */
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 5, 0, 0);
}
/* Return status */
return Status;
}
INIT_FUNCTION
NTSTATUS
NTAPI
PspInitializeSystemDll(VOID)
{
NTSTATUS Status;
/* Get user-mode startup thunk */
Status = PspLookupSystemDllEntryPoint("LdrInitializeThunk",
&PspSystemDllEntryPoint);
if (!NT_SUCCESS(Status))
{
/* Failed, bugcheck */
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 7, 0, 0);
}
/* Get all the other entrypoints */
Status = PspLookupKernelUserEntryPoints();
if (!NT_SUCCESS(Status))
{
/* Failed, bugcheck */
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 8, 0, 0);
}
/* Let KD know we are done */
KdUpdateDataBlock();
/* Return status */
return Status;
}
INIT_FUNCTION
BOOLEAN
NTAPI
PspInitPhase1(VOID)
{
/* Initialize the System DLL and return status of operation */
if (!NT_SUCCESS(PspInitializeSystemDll())) return FALSE;
return TRUE;
}
INIT_FUNCTION
BOOLEAN
NTAPI
PspInitPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE SysThreadHandle;
PETHREAD SysThread;
MM_SYSTEMSIZE SystemSize;
UNICODE_STRING Name;
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
ULONG i;
/* Get the system size */
SystemSize = MmQuerySystemSize();
/* Setup some memory options */
PspDefaultPagefileLimit = -1;
switch (SystemSize)
{
/* Medimum systems */
case MmMediumSystem:
/* Increase the WS sizes a bit */
PsMinimumWorkingSet += 10;
PsMaximumWorkingSet += 100;
/* Large systems */
case MmLargeSystem:
/* Increase the WS sizes a bit more */
PsMinimumWorkingSet += 30;
PsMaximumWorkingSet += 300;
/* Small and other systems */
default:
break;
}
/* Setup callbacks */
for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
{
ExInitializeCallBack(&PspThreadNotifyRoutine[i]);
}
for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
{
ExInitializeCallBack(&PspProcessNotifyRoutine[i]);
}
for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
{
ExInitializeCallBack(&PspLoadImageNotifyRoutine[i]);
}
/* Setup the quantum table */
PsChangeQuantumTable(FALSE, PsRawPrioritySeparation);
/* Set quota settings */
if (!PspDefaultPagedLimit) PspDefaultPagedLimit = 0;
if (!PspDefaultNonPagedLimit) PspDefaultNonPagedLimit = 0;
if (!(PspDefaultNonPagedLimit) && !(PspDefaultPagedLimit))
{
/* Enable give-backs */
PspDoingGiveBacks = TRUE;
}
else
{
/* Disable them */
PspDoingGiveBacks = FALSE;
}
/* Now multiply limits by 1MB */
PspDefaultPagedLimit <<= 20;
PspDefaultNonPagedLimit <<= 20;
if (PspDefaultPagefileLimit != MAXULONG) PspDefaultPagefileLimit <<= 20;
/* Initialize the Active Process List */
InitializeListHead(&PsActiveProcessHead);
KeInitializeGuardedMutex(&PspActiveProcessMutex);
/* Get the idle process */
PsIdleProcess = PsGetCurrentProcess();
/* Setup the locks */
PsIdleProcess->ProcessLock.Value = 0;
ExInitializeRundownProtection(&PsIdleProcess->RundownProtect);
/* Initialize the thread list */
InitializeListHead(&PsIdleProcess->ThreadListHead);
/* Clear kernel time */
PsIdleProcess->Pcb.KernelTime = 0;
/* Initialize Object Initializer */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.InvalidAttributes = OBJ_PERMANENT |
OBJ_EXCLUSIVE |
OBJ_OPENIF;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.SecurityRequired = TRUE;
/* Initialize the Process type */
RtlInitUnicodeString(&Name, L"Process");
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPROCESS);
ObjectTypeInitializer.GenericMapping = PspProcessMapping;
ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess;
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &PsProcessType);
/* Initialize the Thread type */
RtlInitUnicodeString(&Name, L"Thread");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ETHREAD);
ObjectTypeInitializer.GenericMapping = PspThreadMapping;
ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
ObjectTypeInitializer.DeleteProcedure = PspDeleteThread;
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &PsThreadType);
/* Initialize the Job type */
RtlInitUnicodeString(&Name, L"Job");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EJOB);
ObjectTypeInitializer.GenericMapping = PspJobMapping;
ObjectTypeInitializer.InvalidAttributes = 0;
ObjectTypeInitializer.ValidAccessMask = JOB_OBJECT_ALL_ACCESS;
ObjectTypeInitializer.DeleteProcedure = PspDeleteJob;
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &PsJobType);
/* Initialize job structures external to this file */
PspInitializeJobStructures();
/* Initialize the Working Set data */
InitializeListHead(&PspWorkingSetChangeHead.List);
KeInitializeGuardedMutex(&PspWorkingSetChangeHead.Lock);
/* Create the CID Handle table */
PspCidTable = ExCreateHandleTable(NULL);
if (!PspCidTable) return FALSE;
/* FIXME: Initialize LDT/VDM support */
/* Setup the reaper */
ExInitializeWorkItem(&PspReaperWorkItem, PspReapRoutine, NULL);
/* Set the boot access token */
PspBootAccessToken = (PTOKEN)(PsIdleProcess->Token.Value & ~MAX_FAST_REFS);
/* Setup default object attributes */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL);
/* Create the Initial System Process */
Status = PspCreateProcess(&PspInitialSystemProcessHandle,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
0,
FALSE,
0,
0,
0,
FALSE);
if (!NT_SUCCESS(Status)) return FALSE;
/* Get a reference to it */
ObReferenceObjectByHandle(PspInitialSystemProcessHandle,
0,
PsProcessType,
KernelMode,
(PVOID*)&PsInitialSystemProcess,
NULL);
/* Copy the process names */
strcpy(PsIdleProcess->ImageFileName, "Idle");
strcpy(PsInitialSystemProcess->ImageFileName, "System");
/* Allocate a structure for the audit name */
PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName =
ExAllocatePoolWithTag(PagedPool,
sizeof(OBJECT_NAME_INFORMATION),
TAG_SEPA);
if (!PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName)
{
/* Allocation failed */
return FALSE;
}
/* Zero it */
RtlZeroMemory(PsInitialSystemProcess->
SeAuditProcessCreationInfo.ImageFileName,
sizeof(OBJECT_NAME_INFORMATION));
/* Setup the system initialization thread */
Status = PsCreateSystemThread(&SysThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
Phase1Initialization,
LoaderBlock);
if (!NT_SUCCESS(Status)) return FALSE;
/* Create a handle to it */
ObReferenceObjectByHandle(SysThreadHandle,
0,
PsThreadType,
KernelMode,
(PVOID*)&SysThread,
NULL);
ObCloseHandle(SysThreadHandle, KernelMode);
/* Return success */
return TRUE;
}
INIT_FUNCTION
BOOLEAN
NTAPI
PsInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
/* Check the initialization phase */
switch (ExpInitializationPhase)
{
case 0:
/* Do Phase 0 */
return PspInitPhase0(LoaderBlock);
case 1:
/* Do Phase 1 */
return PspInitPhase1();
default:
/* Don't know any other phase! Bugcheck! */
KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL,
1,
ExpInitializationPhase,
0,
0);
return FALSE;
}
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
BOOLEAN
NTAPI
PsGetVersion(OUT PULONG MajorVersion OPTIONAL,
OUT PULONG MinorVersion OPTIONAL,
OUT PULONG BuildNumber OPTIONAL,
OUT PUNICODE_STRING CSDVersion OPTIONAL)
{
if (MajorVersion) *MajorVersion = NtMajorVersion;
if (MinorVersion) *MinorVersion = NtMinorVersion;
if (BuildNumber ) *BuildNumber = NtBuildNumber & 0x3FFF;
if (CSDVersion)
{
CSDVersion->Length = CmCSDVersionString.Length;
CSDVersion->MaximumLength = CmCSDVersionString.MaximumLength;
CSDVersion->Buffer = CmCSDVersionString.Buffer;
}
/* Return TRUE if this is a Checked Build */
return (NtBuildNumber >> 28) == 0xC;
}
/* EOF */