123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- /*++
- Copyright (c) 2012 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- init.c
- Abstract:
- This module initializes the process and thread subsystem.
- Author:
- Evan Green 6-Aug-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/lib/bconf.h>
- #include <minoca/kernel/bootload.h>
- #include "psp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define IDLE_THREAD_NAME_LENGTH 10
- //
- // Define the initialization file, the contents of which are run as the first
- // user mode process.
- //
- #define INITIALIZATION_COMMAND_FILE "config/init.set"
- //
- // Define the location of the OS base library, loaded into every user
- // application.
- //
- #define SYSTEM_OS_BASE_LIBRARY_PATH "system/" OS_BASE_LIBRARY
- //
- // Define the initially enforced maximum number of files.
- //
- #define INITIAL_MAX_FILE_COUNT 1024
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- PspAddIdleThread (
- PKPROCESS KernelProcess,
- PVOID IdleThreadStackBase,
- ULONG IdleThreadStackSize
- );
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- extern LIST_ENTRY PsProcessGroupList;
- PROCESS_GROUP PsKernelProcessGroup;
- //
- // Define the path from the system volume to the system directory. Set it to a
- // default in case there is no boot entry (which there should really always be).
- //
- PSTR PsSystemDirectoryPath = "minoca";
- //
- // Store the initial resource limits to set.
- //
- RESOURCE_LIMIT PsInitialResourceLimits[ResourceLimitCount] = {
- {0, RESOURCE_LIMIT_INFINITE}, // ResourceLimitCore
- {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitCpuTime
- {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitData
- {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitFileSize
- {INITIAL_MAX_FILE_COUNT, OB_MAX_HANDLES}, // ResourceLimitFileCount
- {DEFAULT_USER_STACK_SIZE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitStack
- {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // AddressSpace
- {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ProcessCount
- {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitSignals
- {0, 0} // ResourceLimitNice
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- PsInitialize (
- ULONG Phase,
- PKERNEL_INITIALIZATION_BLOCK Parameters,
- PVOID IdleThreadStackBase,
- ULONG IdleThreadStackSize
- )
- /*++
- Routine Description:
- This routine initializes the process and thread subsystem.
- Arguments:
- Phase - Supplies the initialization phase. Valid values are 0 and 1.
- Parameters - Supplies an optional pointer to the kernel initialization
- block. It's only required for processor 0.
- IdleThreadStackBase - Supplies the base of the stack for the one thread
- currently running.
- IdleThreadStackSize - Supplies the size of the stack for the one thread
- currently running.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES if memory for the kernel process or thread
- could not be allocated.
- --*/
- {
- PBOOT_ENTRY BootEntry;
- PSTR KernelBinaryName;
- ULONG KernelBinaryNameSize;
- PSTR KernelNameCopy;
- PKPROCESS KernelProcess;
- RUNLEVEL OldRunLevel;
- ULONG Processor;
- KSTATUS Status;
- UINTN SystemDirectorySize;
- //
- // If this is the boot processor, initialize PS structures.
- //
- Processor = KeGetCurrentProcessorNumber();
- if (Phase == 0) {
- if (Processor == 0) {
- INITIALIZE_LIST_HEAD(&PsProcessListHead);
- PsProcessCount = 0;
- PsProcessListLock = KeCreateQueuedLock();
- if (PsProcessListLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeEnd;
- }
- Status = PspInitializeProcessGroupSupport();
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Create the process object directory.
- //
- PsProcessDirectory = ObCreateObject(ObjectDirectory,
- NULL,
- "Process",
- sizeof("Process"),
- sizeof(OBJECT_HEADER),
- NULL,
- OBJECT_FLAG_USE_NAME_DIRECTLY,
- PS_ALLOCATION_TAG);
- if (PsProcessDirectory == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeEnd;
- }
- //
- // Create the kernel process.
- //
- KernelBinaryName = Parameters->KernelModule->BinaryName;
- KernelBinaryNameSize = RtlStringLength(KernelBinaryName) + 1;
- KernelNameCopy = MmAllocateNonPagedPool(KernelBinaryNameSize,
- PS_ALLOCATION_TAG);
- if (KernelNameCopy == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeEnd;
- }
- RtlStringCopy(KernelNameCopy,
- KernelBinaryName,
- KernelBinaryNameSize);
- KernelProcess = PspCreateProcess(KernelNameCopy,
- KernelBinaryNameSize,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL);
- if (KernelProcess == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeEnd;
- }
- PsKernelProcess = KernelProcess;
- //
- // Copy the system directory path.
- //
- BootEntry = Parameters->BootEntry;
- if ((BootEntry != NULL) && (BootEntry->SystemPath != NULL)) {
- SystemDirectorySize =
- RtlStringLength(BootEntry->SystemPath) + 1;
- PsSystemDirectoryPath = MmAllocateNonPagedPool(
- SystemDirectorySize,
- PS_ALLOCATION_TAG);
- if (PsSystemDirectoryPath == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeEnd;
- }
- RtlStringCopy(PsSystemDirectoryPath,
- BootEntry->SystemPath,
- SystemDirectorySize);
- }
- PspInitializeUserLocking();
- } else {
- KernelProcess = PsKernelProcess;
- }
- //
- // Create the idle thread for this processor.
- //
- OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
- Status = PspAddIdleThread(KernelProcess,
- IdleThreadStackBase,
- IdleThreadStackSize);
- KeLowerRunLevel(OldRunLevel);
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Perform one-time thread initialization.
- //
- if (Processor == 0) {
- Status = PspInitializeThreadSupport();
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- //
- // Give the kernel process it's own session (and process group).
- //
- ASSERT(KernelProcess->Identifiers.ProcessId == 0);
- PsKernelProcessGroup.ReferenceCount = 1;
- INITIALIZE_LIST_HEAD(&(PsKernelProcessGroup.ProcessListHead));
- INSERT_BEFORE(&(PsKernelProcessGroup.ListEntry),
- &PsProcessGroupList);
- }
- //
- // In phase 1, set up image support.
- //
- } else {
- ASSERT(Phase == 1);
- ASSERT(Processor == 0);
- Status = PspInitializeImageSupport(
- Parameters->KernelModule->LowestAddress,
- &(Parameters->ImageList));
- if (!KSUCCESS(Status)) {
- goto InitializeEnd;
- }
- }
- Status = STATUS_SUCCESS;
- InitializeEnd:
- return Status;
- }
- VOID
- PsVolumeArrival (
- PSTR VolumeName,
- ULONG VolumeNameLength,
- BOOL SystemVolume
- )
- /*++
- Routine Description:
- This routine implements actions that the process library takes in response
- to a new volume arrival.
- Arguments:
- VolumeName - Supplies the full path to the new volume.
- VolumeNameLength - Supplies the length of the volume name buffer, including
- the null terminator, in bytes.
- SystemVolume - Supplies a boolean indicating whether or not this is the
- system volume.
- Return Value:
- None.
- --*/
- {
- UINTN BytesRead;
- PSTR Command;
- PIO_HANDLE File;
- ULONGLONG FileSize;
- IO_BUFFER IoBuffer;
- PKPROCESS Process;
- KSTATUS Status;
- PIO_HANDLE SystemDirectory;
- PIO_HANDLE Volume;
- Command = NULL;
- File = NULL;
- SystemDirectory = NULL;
- Volume = NULL;
- //
- // Do nothing unless this is the system volume.
- //
- if (SystemVolume == FALSE) {
- Status = STATUS_SUCCESS;
- goto VolumeArrivalEnd;
- }
- //
- // Copy the system volume path. Synchronization would be needed if this
- // path changes.
- //
- ASSERT(VolumeNameLength != 0);
- Status = IoOpen(TRUE,
- NULL,
- VolumeName,
- VolumeNameLength,
- IO_ACCESS_READ,
- OPEN_FLAG_DIRECTORY,
- 0,
- &Volume);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Failed to open system volume: %d\n", Status);
- goto VolumeArrivalEnd;
- }
- //
- // Attempt to open the system directory.
- //
- Status = IoOpen(TRUE,
- Volume,
- PsSystemDirectoryPath,
- RtlStringLength(PsSystemDirectoryPath) + 1,
- IO_ACCESS_READ,
- OPEN_FLAG_DIRECTORY,
- 0,
- &SystemDirectory);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Failed to open system directory '%s': %d\n",
- PsSystemDirectoryPath,
- Status);
- goto VolumeArrivalEnd;
- }
- //
- // Attempt to open the OS base library.
- //
- Status = IoOpen(TRUE,
- SystemDirectory,
- SYSTEM_OS_BASE_LIBRARY_PATH,
- sizeof(SYSTEM_OS_BASE_LIBRARY_PATH),
- IO_ACCESS_READ | IO_ACCESS_EXECUTE,
- 0,
- FILE_PERMISSION_NONE,
- &PsOsBaseLibrary);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Failed to open OS base library '%s/%s': %d\n",
- PsSystemDirectoryPath,
- SYSTEM_OS_BASE_LIBRARY_PATH,
- Status);
- goto VolumeArrivalEnd;
- }
- //
- // Attempt to open the initialization command file.
- //
- Status = IoOpen(TRUE,
- SystemDirectory,
- INITIALIZATION_COMMAND_FILE,
- sizeof(INITIALIZATION_COMMAND_FILE),
- IO_ACCESS_READ,
- 0,
- FILE_PERMISSION_NONE,
- &File);
- if (!KSUCCESS(Status)) {
- goto VolumeArrivalEnd;
- }
- Status = IoGetFileSize(File, &FileSize);
- if (!KSUCCESS(Status)) {
- goto VolumeArrivalEnd;
- }
- if (FileSize > (UINTN)FileSize) {
- Status = STATUS_BUFFER_OVERRUN;
- goto VolumeArrivalEnd;
- }
- //
- // Create an I/O buffer from paged pool so that a contiguous virtual buffer
- // can be supplied to process creation.
- //
- Command = MmAllocatePagedPool(FileSize, PS_ALLOCATION_TAG);
- if (Command == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto VolumeArrivalEnd;
- }
- Status = MmInitializeIoBuffer(&IoBuffer,
- Command,
- INVALID_PHYSICAL_ADDRESS,
- FileSize,
- IO_BUFFER_FLAG_KERNEL_MODE_DATA);
- if (!KSUCCESS(Status)) {
- goto VolumeArrivalEnd;
- }
- Status = IoRead(File,
- &IoBuffer,
- (UINTN)FileSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesRead);
- if (!KSUCCESS(Status)) {
- goto VolumeArrivalEnd;
- }
- if (BytesRead != FileSize) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto VolumeArrivalEnd;
- }
- Command[FileSize] = '\0';
- //
- // Fire up the process.
- //
- Process = PsCreateProcess(Command,
- (ULONG)FileSize + 1,
- NULL,
- IoGetPathPoint(Volume),
- NULL);
- if (Process == NULL) {
- RtlDebugPrint("Failed to create initial process: \"%s\"\n",
- Command);
- goto VolumeArrivalEnd;
- }
- //
- // Release the reference on the process, as no one is waiting around for
- // its completion.
- //
- ObReleaseReference(Process);
- VolumeArrivalEnd:
- if (Volume != NULL) {
- IoClose(Volume);
- }
- if (SystemDirectory != NULL) {
- IoClose(SystemDirectory);
- }
- if (File != NULL) {
- IoClose(File);
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- PspAddIdleThread (
- PKPROCESS KernelProcess,
- PVOID IdleThreadStackBase,
- ULONG IdleThreadStackSize
- )
- /*++
- Routine Description:
- This routine adds the processor's initial thread to the thread accounting
- system.
- Arguments:
- KernelProcess - Supplies a pointer to the system process.
- IdleThreadStackBase - Supplies the base of the stack for the one thread
- currently running on this processor.
- IdleThreadStackSize - Supplies the size of the stack for the one thread
- currently running on this processor.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES if memory for the thread could not be
- allocated.
- --*/
- {
- PKTHREAD CurrentThread;
- CHAR Name[IDLE_THREAD_NAME_LENGTH];
- PPROCESSOR_BLOCK Processor;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() >= RunLevelDispatch);
- CurrentThread = NULL;
- Processor = KeGetCurrentProcessorBlock();
- RtlPrintToString(Name,
- IDLE_THREAD_NAME_LENGTH,
- CharacterEncodingDefault,
- "Idle%d",
- Processor->ProcessorNumber);
- //
- // Manually create the idle thread. Locks don't need to be acquired here
- // because preemption has not yet been turned on.
- //
- CurrentThread = ObCreateObject(ObjectThread,
- KernelProcess,
- Name,
- IDLE_THREAD_NAME_LENGTH,
- sizeof(KTHREAD),
- NULL,
- 0,
- PS_ALLOCATION_TAG);
- if (CurrentThread == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddIdleThreadEnd;
- }
- //
- // Initialize pieces of the thread.
- //
- CurrentThread->OwningProcess = KernelProcess;
- CurrentThread->ThreadId = RtlAtomicAdd32((PULONG)&PsNextThreadId, 1);
- CurrentThread->KernelStack = IdleThreadStackBase;
- CurrentThread->KernelStackSize = IdleThreadStackSize;
- CurrentThread->State = ThreadStateRunning;
- CurrentThread->SchedulerEntry.Type = SchedulerEntryThread;
- CurrentThread->SchedulerEntry.Parent = &(Processor->Scheduler.Group.Entry);
- CurrentThread->ThreadPointer = PsInitialThreadPointer;
- CurrentThread->BuiltinWaitBlock = ObCreateWaitBlock(0);
- if (CurrentThread->BuiltinWaitBlock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddIdleThreadEnd;
- }
- INSERT_BEFORE(&(CurrentThread->ProcessEntry),
- &(KernelProcess->ThreadListHead));
- KernelProcess->ThreadCount += 1;
- //
- // Make this initial thread all-powerful.
- //
- CurrentThread->Permissions.Limit = PERMISSION_SET_FULL;
- CurrentThread->Permissions.Permitted = PERMISSION_SET_FULL;
- CurrentThread->Permissions.Inheritable = PERMISSION_SET_FULL;
- CurrentThread->Permissions.Effective = PERMISSION_SET_FULL;
- RtlCopyMemory(&(CurrentThread->Limits),
- PsInitialResourceLimits,
- sizeof(CurrentThread->Limits));
- //
- // Again, it's okay not to raise the run-level because preemption is not
- // yet enabled in the system.
- //
- Processor->RunningThread = CurrentThread;
- //
- // Set this thread as the idle thread.
- //
- Processor->IdleThread = CurrentThread;
- Status = STATUS_SUCCESS;
- AddIdleThreadEnd:
- if (!KSUCCESS(Status)) {
- if (CurrentThread != NULL) {
- if (CurrentThread->BuiltinTimer != NULL) {
- KeDestroyTimer(CurrentThread->BuiltinTimer);
- }
- if (CurrentThread->BuiltinWaitBlock != NULL) {
- ObDestroyWaitBlock(CurrentThread->BuiltinWaitBlock);
- }
- ObReleaseReference(CurrentThread);
- }
- }
- return Status;
- }
|