/// <summary> /// Process the read/write queues of the specified pipe. /// </summary> /// <param name="pipe">The pipe to process.</param> /// <param name="OutProcess">The process which owns the pipe's outpoint.</param> /// <param name="InProcess">The process which owns the pipe's inpoint.</param> private static void ProcessPipeQueue(Pipe pipe, Process OutProcess, Process InProcess) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Checking first loop condition"); #endif while ((pipe.AreThreadsWaitingToWrite() && pipe.CanWrite()) || (pipe.AreThreadsWaitingToRead() && pipe.CanRead())) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Loop start"); #endif if (pipe.AreThreadsWaitingToWrite() && pipe.CanWrite()) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Pipe can write"); #endif /* - Dequeue thread to write * - Find thread to write * - Load pointer to request structure from thread's stack * - Write pipe * - Setup return values for thread * - Wake thread * - Loop back */ #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Dequeuing out thread id"); #endif UInt32 ThreadId; if (!pipe.DequeueToWrite(out ThreadId)) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Getting out thread"); #endif Thread WriteThread = ProcessManager.GetThreadById(ThreadId, OutProcess); if (WriteThread == null) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Writing pipe"); #endif WritePipeRequest* Request = (WritePipeRequest*)WriteThread.Param1; bool Successful = pipe.Write(Request->InBuffer, Request->Offset, Request->Length); if (Successful) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Write successful"); #endif WriteThread.Return1 = (uint)SystemCallResults.OK; WriteThread._Wake(); } else { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Write failed"); #endif WriteThread.Return1 = (uint)SystemCallResults.Fail; WriteThread._Wake(); } } else if (pipe.AreThreadsWaitingToRead() && pipe.CanRead()) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Pipe can read"); #endif /* - Dequeue thread to read * - Find thread to read * - Load pointer to request structure from thread's stack * - Read pipe * - Setup return values for thread * - Wake thread * - Loop back */ #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Dequeuing in thread id"); #endif UInt32 ThreadId; if (!pipe.DequeueToRead(out ThreadId)) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Getting in thread"); #endif Thread ReadThread = ProcessManager.GetThreadById(ThreadId, InProcess); if (ReadThread == null) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Reading pipe"); #endif ReadPipeRequest* Request = (ReadPipeRequest*)ReadThread.Param1; int BytesRead; bool Successful = pipe.Read(Request->OutBuffer, Request->Offset, Request->Length, out BytesRead); if (Successful) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Read successful"); #endif ReadThread.Return1 = (uint)SystemCallResults.OK; ReadThread.Return2 = (uint)BytesRead; ReadThread._Wake(); } else { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Read failed"); #endif ReadThread.Return1 = (uint)SystemCallResults.Fail; ReadThread._Wake(); } } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Looping..."); #endif } }
public static void RegisterProcess(Process process, Scheduler.Priority priority) { #if PROCESSMANAGER_TRACE BasicConsole.WriteLine("Registering process..."); BasicConsole.WriteLine("Disabling scheduler..."); #endif if (process == null) { ExceptionMethods.Throw(new FOS_System.Exception("Attempted to register null process!")); } //bool reenable = Scheduler.Enabled; //if (reenable) //{ // Scheduler.Disable(); //} #if PROCESSMANAGER_TRACE BasicConsole.WriteLine("Initialising process..."); #endif Scheduler.InitProcess(process, priority); #if PROCESSMANAGER_TRACE BasicConsole.WriteLine("Adding process..."); #endif Processes.Add(process); #if PROCESSMANAGER_TRACE BasicConsole.WriteLine("Enabling scheduler..."); #endif //if (reenable) //{ // Scheduler.Enable(); //} }
public static void InitThread(Process process, Thread t) { t.TimeToRunReload = (int)process.Priority; t.TimeToRun = t.TimeToRunReload; UpdateList(t, false); }
public static MemoryLayout EnableAccessToMemoryOfProcess(Process ProcessToAccess) { MemoryLayout OriginalMemoryLayout = ProcessManager.CurrentProcess.TheMemoryLayout; MemoryLayout NewMemoryLayout = ProcessManager.CurrentProcess.TheMemoryLayout.Merge(ProcessToAccess.TheMemoryLayout); ProcessManager.CurrentProcess.TheMemoryLayout = NewMemoryLayout; NewMemoryLayout.Load(ProcessManager.CurrentProcess.UserMode); return OriginalMemoryLayout; }
//private static int LockupCounter = 0; public static void InitProcess(Process process, Priority priority) { process.Priority = priority; for (int i = 0; i < process.Threads.Count; i++) { Thread t = (Thread)process.Threads[i]; InitThread(process, t); } process.Registered = true; }
public static Thread GetThreadById(uint threadId, Process parent) { for (int i = 0; i < parent.Threads.Count; i++) { if (((Thread)parent.Threads[i]).Id == threadId) { return (Thread)parent.Threads[i]; } } return null; }
public static unsafe SystemCallResults HandleDeferredSystemCall( Process CallerProcess, Thread CallerThread, SystemCallNumbers syscallNumber, uint Param1, uint Param2, uint Param3, ref uint Return2, ref uint Return3, ref uint Return4) { SystemCallResults result = SystemCallResults.Unhandled; switch (syscallNumber) { case SystemCallNumbers.StartThread: //BasicConsole.WriteLine("DSC: Start Thread"); Return2 = CallerProcess.CreateThread((ThreadStartMethod)Utilities.ObjectUtilities.GetObject((void*)Param1), "[From sys call]").Id; //BasicConsole.WriteLine("DSC: Start Thread - done."); result = SystemCallResults.OK; break; case SystemCallNumbers.RegisterPipeOutpoint: { //BasicConsole.WriteLine("DSC: Register Pipe Outpoint"); Pipes.PipeOutpoint outpoint; bool registered = Pipes.PipeManager.RegisterPipeOutpoint(CallerProcess.Id, (Pipes.PipeClasses)Param1, (Pipes.PipeSubclasses)Param2, (int)Param3, out outpoint); if (registered) { result = SystemCallResults.OK; } else { result = SystemCallResults.Fail; } //BasicConsole.WriteLine("DSC: Register Pipe Outpoint - done."); } break; case SystemCallNumbers.GetNumPipeOutpoints: { //BasicConsole.WriteLine("DSC: Get Num Pipe Outpoints"); int numOutpoints; bool obtained = Pipes.PipeManager.GetNumPipeOutpoints((Pipes.PipeClasses)Param1, (Pipes.PipeSubclasses)Param2, out numOutpoints); if (obtained) { result = SystemCallResults.OK; Return2 = (uint)numOutpoints; } else { result = SystemCallResults.Fail; } //BasicConsole.WriteLine("DSC: Get Num Pipe Outpoints - done"); } break; case SystemCallNumbers.GetPipeOutpoints: { //BasicConsole.WriteLine("DSC: Get Pipe Outpoints"); bool obtained = Pipes.PipeManager.GetPipeOutpoints(CallerProcess, (Pipes.PipeClasses)Param1, (Pipes.PipeSubclasses)Param2, (Pipes.PipeOutpointsRequest*)Param3); if (obtained) { result = SystemCallResults.OK; } else { result = SystemCallResults.Fail; } //BasicConsole.WriteLine("DSC: Get Pipe Outpoints - done"); } break; case SystemCallNumbers.CreatePipe: { //BasicConsole.WriteLine("DSC: Create Pipe"); bool created = Pipes.PipeManager.CreatePipe(CallerProcess.Id, Param1, (Pipes.CreatePipeRequest*)Param2); if (created) { result = SystemCallResults.OK; } else { result = SystemCallResults.Fail; } //BasicConsole.WriteLine("DSC: Create Pipe - done"); } break; case SystemCallNumbers.WaitOnPipeCreate: { //BasicConsole.WriteLine("DSC: Wait On Pipe Create"); bool waiting = Pipes.PipeManager.WaitOnPipeCreate(CallerProcess.Id, CallerThread.Id, (Pipes.PipeClasses)Param1, (Pipes.PipeSubclasses)Param2); if (waiting) { result = SystemCallResults.Deferred; } else { result = SystemCallResults.Fail; } //BasicConsole.WriteLine("DSC: Wait On Pipe Create - done"); } break; case SystemCallNumbers.ReadPipe: { //BasicConsole.WriteLine("DSC: Read Pipe"); // Need access to calling process' memory to be able to set values in request structure(s) MemoryLayout OriginalMemoryLayout = SystemCallsHelpers.EnableAccessToMemoryOfProcess(CallerProcess); Pipes.ReadPipeRequest* RequestPtr = (Pipes.ReadPipeRequest*)Param1; Pipes.PipeManager.RWResults RWResult = Pipes.PipeManager.ReadPipe(RequestPtr->PipeId, RequestPtr->Blocking, CallerProcess, CallerThread); if (RWResult == Pipes.PipeManager.RWResults.Error) { result = SystemCallResults.Fail; } else { // Returning Deferred state from here will leave the caller thread // in whatever state ReadPipe decided it should be in. result = SystemCallResults.Deferred; } SystemCallsHelpers.DisableAccessToMemoryOfProcess(OriginalMemoryLayout); //BasicConsole.WriteLine("DSC: Read Pipe - done"); } break; case SystemCallNumbers.WritePipe: { //BasicConsole.WriteLine("DSC: Write Pipe"); // Need access to calling process' memory to be able to set values in request structure(s) MemoryLayout OriginalMemoryLayout = SystemCallsHelpers.EnableAccessToMemoryOfProcess(CallerProcess); Pipes.WritePipeRequest* RequestPtr = (Pipes.WritePipeRequest*)Param1; Pipes.PipeManager.RWResults RWResult = Pipes.PipeManager.WritePipe(RequestPtr->PipeId, RequestPtr->Blocking, CallerProcess, CallerThread); if (RWResult == Pipes.PipeManager.RWResults.Error) { result = SystemCallResults.Fail; } else { // Returning Deferred state from here will leave the caller thread // in whatever state WritePipe decided it should be in. result = SystemCallResults.Deferred; } SystemCallsHelpers.DisableAccessToMemoryOfProcess(OriginalMemoryLayout); //BasicConsole.WriteLine("DSC: Write Pipe - done"); } break; default: BasicConsole.WriteLine("DSC: Unrecognised call number."); BasicConsole.WriteLine((uint)syscallNumber); break; } return result; }
/// <remarks> /// Specifying threadId=-1 accepts any thread from the specified process. /// No guarantees are made about the thread chosen. This is used when you /// mainly want to switch process context and don't care about the specific /// thread context e.g. during an interrupt. /// </remarks> public static void SwitchProcess(uint processId, int threadId) { //Switch the current memory layout across. // Don't touch register state etc, just the memory layout bool dontSwitchOutIn = false; if (CurrentProcess != null && CurrentProcess.Id == processId) { if (CurrentThread != null && (CurrentThread.Id == threadId || threadId == -1)) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("No switch. (1)"); #endif return; } else { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("No switch. (2)"); #endif dontSwitchOutIn = true; } } if (!dontSwitchOutIn) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Switching out: " + CurrentProcess.Name); #endif CurrentProcess.UnloadMemLayout(); CurrentProcess = null; for (int i = 0; i < Processes.Count; i++) { if (((Process)Processes[i]).Id == processId) { CurrentProcess = ((Process)Processes[i]); break; } } // Process not found if (CurrentProcess == null) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Process not found."); #endif return; } #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Process found. " + CurrentProcess.Name); #endif } CurrentThread = null; CurrentThread_State = null; if (threadId == -1) { if (CurrentProcess.Threads.Count > 0) { CurrentThread = (Thread)CurrentProcess.Threads[0]; } } else { for (int i = 0; i < CurrentProcess.Threads.Count; i++) { if (((Thread)CurrentProcess.Threads[i]).Id == threadId) { CurrentThread = (Thread)CurrentProcess.Threads[i]; break; } } } // No threads in the process (?!) or process not found if (CurrentThread == null) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Thread not found."); #endif return; } #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Thread found."); #endif CurrentThread_State = CurrentThread.State; #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Thread state updated."); #endif if (!dontSwitchOutIn) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Switching in: " + CurrentProcess.Name); #endif CurrentProcess.LoadMemLayout(); } }
public static bool Semaphore_AddOwner(int semaphoreId, uint processId, Process aProcess) { if (Semaphore_VerifyOwner(semaphoreId, aProcess)) { ((Semaphore)Semaphores[semaphoreId]).OwnerProcesses.Add(processId); return true; } return false; }
public Thread(Process AnOwner, ThreadStartMethod StartMethod, uint AnId, bool UserMode, FOS_System.String AName) { #if THREAD_TRACE BasicConsole.WriteLine("Constructing thread object..."); #endif LastActiveState = ActiveStates.NotStarted; Owner = AnOwner; //Init thread state #if THREAD_TRACE BasicConsole.WriteLine("Allocating state memory..."); #endif State = (ThreadState*)FOS_System.Heap.Alloc((uint)sizeof(ThreadState), "Thread : Thread() (1)"); // Init Id and EIP // Set EIP to the first instruction of the main method #if THREAD_TRACE BasicConsole.WriteLine("Setting thread info..."); #endif Id = AnId; Name = AName; State->StartEIP = (uint)Utilities.ObjectUtilities.GetHandle(StartMethod); // Allocate kernel memory for the kernel stack for this thread // Used when this thread is preempted or does a sys call. Stack is switched to // this thread-specific kernel stack #if THREAD_TRACE BasicConsole.WriteLine("Allocating kernel stack..."); #endif // TODO: Allocate using virt mem manager not the heap (see ThreadStackTop below) State->KernelStackTop = (byte*)FOS_System.Heap.Alloc(0x1000, 4) + 0xFFC; //4KiB, 4-byte aligned // Allocate free memory for the user stack for this thread // Used by this thread in normal execution #if THREAD_TRACE BasicConsole.WriteLine("Mapping thread stack page..."); #endif State->UserMode = UserMode; State->ThreadStackTop = (byte*)Hardware.VirtMemManager.MapFreePage( UserMode ? Hardware.VirtMem.VirtMemImpl.PageFlags.None : Hardware.VirtMem.VirtMemImpl.PageFlags.KernelOnly) + 4092; //4 KiB, page-aligned // Set ESP to the top of the stack - 4 byte aligned, high address since x86 stack works // downwards #if THREAD_TRACE BasicConsole.WriteLine("Setting ESP..."); #endif State->ESP = (uint)State->ThreadStackTop; // TimeToRun and TimeToRunReload are set up in Scheduler.InitProcess which // is called when a process is registered. // Init SS // Stack Segment = User or Kernel space data segment selector offset // Kernel data segment selector offset (offset in GDT) = 0x10 (16) // User data segment selector offset (offset in GDT) = 0x23 (32|3) // User data segment selector must also be or'ed with 3 for User Privilege level #if THREAD_TRACE BasicConsole.WriteLine("Setting SS..."); #endif State->SS = UserMode ? (ushort)0x23 : (ushort)0x10; // Init Started // Not started yet so set to false #if THREAD_TRACE BasicConsole.WriteLine("Setting started..."); #endif State->Started = false; #if THREAD_TRACE BasicConsole.WriteLine("Allocating exception state..."); #endif //TODO: This is currently incorrectly allocated from the current process's heap instead of the heap of the owner process // Init Exception State State->ExState = (ExceptionState*)FOS_System.Heap.AllocZeroed((uint)sizeof(ExceptionState), "Thread : Thread() (2)"); #if THREAD_TRACE BasicConsole.WriteLine("Done."); #endif }
public static int Semaphore_Allocate(int limit, Process aProcess) { int result = -1; Semaphore theSemaphore = null; SemaphoresLock.Enter(); for (int i = 0; i < Semaphores.Count; i++) { Semaphore aSemaphore = (Semaphore)Semaphores[i]; if (aSemaphore == null) { Semaphores[i] = theSemaphore = new Semaphore(i, limit); result = i; break; } } if (result == -1) { result = Semaphores.Count; Semaphores.Add(theSemaphore = new Semaphore(result, limit)); } SemaphoresLock.Exit(); theSemaphore.OwnerProcesses.Add(aProcess.Id); return result; }
public static int Semaphore_Wait(int id, Process aProcess, Thread aThread) { if (Semaphore_VerifyOwner(id, aProcess)) { return ((Semaphore)Semaphores[id]).WaitOnBehalf(aProcess, aThread) ? 1 : 0; } return -1; }
public static void SwitchProcess(uint processId, int threadId) { //Switch the current memory layout across. // Don't touch register state etc, just the memory layout bool dontSwitchOutIn = false; if (CurrentProcess != null && CurrentProcess.Id == processId) { if (CurrentThread != null && (CurrentThread.Id == threadId || threadId == THREAD_DONT_CARE)) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("No switch. (1)"); #endif return; } else { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("No switch. (2)"); #endif dontSwitchOutIn = true; } } if (!dontSwitchOutIn) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.Write("Switching out: "); BasicConsole.WriteLine(CurrentProcess.Name); #endif CurrentProcess.UnloadHeap(); CurrentProcess.UnloadMemLayout(); CurrentProcess = GetProcessById(processId); // Process not found if (CurrentProcess == null) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Process not found."); #endif return; } #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.Write("Switching in: "); BasicConsole.WriteLine(CurrentProcess.Name); #endif CurrentProcess.LoadMemLayout(); CurrentProcess.LoadHeap(); } CurrentThread = null; CurrentThread_State = null; if (threadId == THREAD_DONT_CARE) { if (CurrentProcess.Threads.Count > 0) { CurrentThread = (Thread)CurrentProcess.Threads[0]; } } else { CurrentThread = GetThreadById((uint)threadId, CurrentProcess); } // No threads in the process (?!) or process not found if (CurrentThread == null) { #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Thread not found."); #endif return; } #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Thread found."); #endif CurrentThread_State = CurrentThread.State; #if PROCESSMANAGER_SWITCH_TRACE BasicConsole.WriteLine("Thread state updated."); #endif }
/// <summary> /// Attempts to write to the specified pipe. /// </summary> /// <remarks> /// Note that this function is non-blocking. It will, however, block a system caller thread by simply not returning it from /// the deferred system call. /// </remarks> /// <param name="PipeId">The Id of the pipe to write.</param> /// <param name="Blocking">Whether the write should be blocking or non-blocking.</param> /// <param name="CallerProcess">The process which made the call.</param> /// <param name="CallerThread">The thread which made the call.</param> /// <returns>See descriptions on <see cref="PipeManager.RWResults"/> values.</returns> public static RWResults WritePipe(int PipeId, bool Blocking, Process CallerProcess, Thread CallerThread) { #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Validating inputs"); #endif // Validate inputs // - Check pipe exists Pipe pipe = GetPipe(PipeId); if (pipe == null) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Checking caller allowed to write"); #endif // Check the caller is allowed to access the pipe if (!AllowedToWritePipe(pipe, CallerProcess.Id)) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Getting out process"); #endif // Get outpoint process Process OutProcess = ProcessManager.GetProcessById(pipe.Outpoint.ProcessId); if (OutProcess == null) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Getting in process"); #endif // Get inpoint process Process InProcess = ProcessManager.GetProcessById(pipe.Inpoint.ProcessId); if (InProcess == null) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Merging memory layouts"); #endif // Merge memory layouts of in process (out process should already have been done by caller) // so we can access the request structure(s) and buffers MemoryLayout OriginalMemoryLayout = SystemCallsHelpers.EnableAccessToMemoryOfProcess(InProcess); #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Adding caller to write queue"); #endif // Add caller thread to the write queue WritePipeRequest* Request = (WritePipeRequest*)CallerThread.Param1; pipe.QueueToWrite(CallerThread.Id, Request->Length); // Set up initial failure return value CallerThread.Return1 = (uint)SystemCallResults.Fail; #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Processing pipe queue"); #endif // Process the pipe queue ProcessPipeQueue(pipe, OutProcess, InProcess); #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Unmerging memory layouts"); #endif // Unmerge memory layouts SystemCallsHelpers.DisableAccessToMemoryOfProcess(OriginalMemoryLayout); bool Completed = !pipe.AreThreadsWaitingToWrite(); if (!Blocking) { if (!Completed) { uint temp; bool removed = pipe.RemoveLastToWrite(out temp); if (!removed || temp != CallerThread.Id) { BasicConsole.WriteLine("PipeManager: Error! Async write failed and then removing last from queue resulted in thread Id mismatch!"); } CallerThread.Return1 = (uint)SystemCallResults.Fail; CallerThread._Wake(); } } return Completed ? RWResults.Complete : RWResults.Queued; }
/// <summary> /// Attempts to get descriptors of the outpoints of the specified class and subclass. /// </summary> /// <param name="CallerProcess">The process which owns the memory containing the <paramref cref="request"/>.</param> /// <param name="Class">The class of outpoint to search for.</param> /// <param name="Subclass">The subclass of outpoint to search for.</param> /// <param name="request">A pointer to the request structure (Also used to store the result(s)).</param> /// <returns>True if the request was successful. Otherwise, false.</returns> public static bool GetPipeOutpoints(Process CallerProcess, PipeClasses Class, PipeSubclasses Subclass, PipeOutpointsRequest* request) { // Validate inputs & get caller process if (CallerProcess == null) { return false; } // Merge memory layouts // so we can access the request structure MemoryLayout OriginalMemoryLayout = SystemCallsHelpers.EnableAccessToMemoryOfProcess(CallerProcess); bool OK = true; // More validate inputs // - Check request exists (should've been pre-allocated by caller) // - Check request->Outpoints exists (should've been pre-allocated by caller) // - Check request->MaxDescriptors was set correctly if (request == null) { // Should have been pre-allocated by the calling thread (/process) OK = false; } else if (request->Outpoints == null) { // Should have been pre-allocated by the calling thread (/process) OK = false; } else if (request->MaxDescriptors == 0) { // Not technically an error but let's not waste time processing 0 descriptors OK = true; } if (OK) { // Search for all outpoints of correct class and subclass int maxDescriptors = request->MaxDescriptors; for (int i = 0, j = 0; i < PipeOutpoints.Count && j < maxDescriptors; i++) { PipeOutpoint anOutpoint = (PipeOutpoint)PipeOutpoints[i]; if (anOutpoint.Class == Class && anOutpoint.Subclass == Subclass && ( anOutpoint.MaxConnections == PipeConstants.UnlimitedConnections || anOutpoint.NumConnections < anOutpoint.MaxConnections)) { // Set the resultant values request->Outpoints[j++].ProcessId = anOutpoint.ProcessId; } } } SystemCallsHelpers.DisableAccessToMemoryOfProcess(OriginalMemoryLayout); return OK; }
public static void DisableKernelAccessToProcessMemory(Process TargetProcess) { if (KernelProcess != null && KernelProcess != TargetProcess) { #if PROCESSMANAGER_KERNEL_ACCESS_TRACE BasicConsole.WriteLine("~D~"); #endif KernelProcess.TheMemoryLayout.Unmerge(TargetProcess.TheMemoryLayout); TargetProcess.TheMemoryLayout.Unload(); } }
public static void EnableKernelAccessToProcessMemory(Process TargetProcess) { if (KernelProcess != null && KernelProcess != TargetProcess) { #if PROCESSMANAGER_KERNEL_ACCESS_TRACE BasicConsole.WriteLine("~E~"); #endif KernelProcess.TheMemoryLayout.Merge(TargetProcess.TheMemoryLayout); KernelProcess.TheMemoryLayout.Load(KernelProcess.UserMode); } }
public static bool WakeThread(Process theProcess, uint threadId) { bool Woken = false; if (theProcess != null) { Thread theThread = GetThreadById(threadId, theProcess); if (theThread != null) { theThread._Wake(); Woken = true; } } return Woken; }
public static void InitProcess(Process process, Priority priority) { process.Priority = priority; }
public static bool Semaphore_Deallocate(int id, Process aProcess) { if (Semaphore_VerifyOwner(id, aProcess)) { SemaphoresLock.Enter(); Semaphores[id] = null; SemaphoresLock.Exit(); return true; } return false; }
public static void EndDeferredSystemCall(Process CallerProcess, Thread CallerThread, SystemCallResults result, uint Return2, uint Return3, uint Return4) { ProcessManager.EnableKernelAccessToProcessMemory(CallerProcess); CallerThread.Return1 = (uint)result; CallerThread.Return2 = Return2; CallerThread.Return3 = Return3; CallerThread.Return4 = Return4; ProcessManager.DisableKernelAccessToProcessMemory(CallerProcess); CallerThread._Wake(); }
public static bool Semaphore_Signal(int id, Process aProcess) { if (Semaphore_VerifyOwner(id, aProcess)) { ((Semaphore)Semaphores[id]).SignalOnBehalf(); return true; } return false; }
public void Load(bool UserMode) { bool OK = true; try { bool DynamicLinkingRequired = false; ThreadStartMethod mainMethod = (ThreadStartMethod)Utilities.ObjectUtilities.GetObject(theFile.Header.EntryPoint); theProcess = ProcessManager.CreateProcess( mainMethod, theFile.TheFile.Name, UserMode); uint threadStackVirtAddr = (uint)((Thread)theProcess.Threads[0]).State->ThreadStackTop - 4092; uint threadStackPhysAddr = (uint)Hardware.VirtMemManager.GetPhysicalAddress(threadStackVirtAddr); ProcessManager.CurrentProcess.TheMemoryLayout.AddDataPage(threadStackPhysAddr, threadStackVirtAddr); // Load the ELF segments (i.e. the program code and data) BaseAddress = theFile.BaseAddress; LoadSegments(theFile, ref OK, ref DynamicLinkingRequired, BaseAddress); //BasicConsole.WriteLine(); #region Relocations // Useful articles / specifications on Relocations: // - Useful / practical explanation of various relocation types: http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries/#id20 // - Orcale : ELF Specification copy: http://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html if (DynamicLinkingRequired) { Console.Default.WriteLine("Dynamic Linking"); BasicConsole.WriteLine("Dynamic Linking"); ELFDynamicSection dynamicSection = theFile.DynamicSection; ELFDynamicSymbolTableSection dynamicSymbolsSection = theFile.DynamicSymbolsSection; ELFStringTable DynamicsStringTable = new ELFStringTable( dynamicSection.StrTabDynamic.Val_Ptr, dynamicSection.StrTabSizeDynamic.Val_Ptr); for (uint i = 0; i < dynamicSection.Dynamics.Count; i++) { ELFDynamicSection.Dynamic theDyn = dynamicSection[i]; //BasicConsole.WriteLine(" - Dynamic : "); //BasicConsole.Write(" - Tag : "); //BasicConsole.WriteLine((int)theDyn.Tag); //BasicConsole.Write(" - Value or Pointer : "); //BasicConsole.WriteLine(theDyn.Val_Ptr); if (theDyn.Tag == ELFDynamicSection.DynamicTag.Needed) { BasicConsole.Write(" - Needed library name : "); FOS_System.String libFullPath = DynamicsStringTable[theDyn.Val_Ptr]; Console.Default.WriteLine(libFullPath); BasicConsole.WriteLine(libFullPath); FOS_System.String libFileName = (FOS_System.String)libFullPath.Split('\\').Last(); libFileName = (FOS_System.String)libFileName.Split('/').Last(); FOS_System.String libTestPath = theFile.TheFile.Parent.GetFullPath() + libFileName; File sharedObjectFile = File.Open(libTestPath); if (sharedObjectFile == null) { Console.Default.WarningColour(); Console.Default.WriteLine("Failed to find needed library file!"); BasicConsole.WriteLine("Failed to find needed library file!"); Console.Default.DefaultColour(); OK = false; } else { Console.Default.WriteLine("Found library file. Loading library..."); BasicConsole.WriteLine("Found library file. Loading library..."); ELFSharedObject sharedObject = DynamicLinkerLoader.LoadLibrary_FromELFSO(sharedObjectFile, this); SharedObjectDependencies.Add(sharedObject); Console.Default.WriteLine("Library loaded."); BasicConsole.WriteLine("Library loaded."); } } } Console.Default.WriteLine("Library Relocations"); BasicConsole.WriteLine("Library Relocations"); // Perform relocation / dynamic linking of all libraries for (int i = 0; i < SharedObjectDependencies.Count; i++) { ELFSharedObject SO = (ELFSharedObject)SharedObjectDependencies[i]; //BasicConsole.WriteLine("Shared Object base address : " + (FOS_System.String)SO.BaseAddress); //BasicConsole.WriteLine("Shared Object file base address : " + (FOS_System.String)SO.TheFile.BaseAddress); List SOSections = SO.TheFile.Sections; for (int j = 0; j < SOSections.Count; j++) { ELFSection SOSection = (ELFSection)SOSections[j]; if (SOSection is ELFRelocationTableSection) { //BasicConsole.WriteLine(" - Normal Relocation"); ELFRelocationTableSection relocTableSection = (ELFRelocationTableSection)SOSection; ELFSymbolTableSection symbolTable = (ELFSymbolTableSection)SO.TheFile.Sections[relocTableSection.SymbolTableSectionIndex]; ELFStringTableSection symbolNamesTable = (ELFStringTableSection)SO.TheFile.Sections[symbolTable.StringsSectionIndex]; List Relocations = relocTableSection.Relocations; for (int k = 0; k < Relocations.Count; k++) { // Reference: http://docs.oracle.com/cd/E19683-01/817-3677/chapter6-26/index.html ELFRelocationTableSection.Relocation relocation = (ELFRelocationTableSection.Relocation)Relocations[k]; if (relocation.Type == ELFRelocationTableSection.RelocationType.R_386_NONE) { continue; } uint* resolvedRelLocation = (uint*)(SO.BaseAddress + (relocation.Offset - SO.TheFile.BaseAddress)); ELFSymbolTableSection.Symbol symbol = (ELFSymbolTableSection.Symbol)symbolTable[relocation.Symbol]; FOS_System.String symbolName = symbolNamesTable[symbol.NameIdx]; //BasicConsole.WriteLine("Relocation:"); ////BasicConsole.WriteLine(" > Symbol index : " + (FOS_System.String)relocation.Symbol); //BasicConsole.WriteLine(" > Type : " + (FOS_System.String)(uint)relocation.Type); //BasicConsole.WriteLine(" > Offset : " + (FOS_System.String)(uint)relocation.Offset); //BasicConsole.WriteLine(((FOS_System.String)" > Resolved location address: ") + (uint)resolvedRelLocation); ////BasicConsole.WriteLine(((FOS_System.String)" > Resolved location start value: ") + *resolvedRelLocation); //BasicConsole.Write(" > Symbol name : "); //BasicConsole.WriteLine(symbolName); uint newValue = 0; switch (relocation.Type) { case ELFRelocationTableSection.RelocationType.R_386_32: newValue = GetSymbolAddress(symbol, symbolName) + *resolvedRelLocation; break; case ELFRelocationTableSection.RelocationType.R_386_PC32: newValue = GetSymbolAddress(symbol, symbolName) + *resolvedRelLocation - (uint)resolvedRelLocation; break; case ELFRelocationTableSection.RelocationType.R_386_RELATIVE: newValue = SO.BaseAddress + *resolvedRelLocation; break; //TODO: Support more relocation types default: Console.Default.WarningColour(); Console.Default.Write("WARNING: Unrecognised relocation type! ("); Console.Default.Write_AsDecimal((uint)relocation.Type); Console.Default.WriteLine(")"); Console.Default.DefaultColour(); BasicConsole.Write("WARNING: Unrecognised relocation type! ("); BasicConsole.Write((uint)relocation.Type); BasicConsole.WriteLine(")"); break; } *resolvedRelLocation = newValue; //BasicConsole.WriteLine(" > New value: " + (FOS_System.String)(newValue)); //BasicConsole.WriteLine(" > Resolved location end value: " + (FOS_System.String)(*resolvedRelLocation)); } } else if (SOSection is ELFRelocationAddendTableSection) { //BasicConsole.WriteLine(" - Addend Relocation"); ELFRelocationAddendTableSection relocTableSection = (ELFRelocationAddendTableSection)SOSection; ELFSymbolTableSection symbolTable = (ELFSymbolTableSection)SO.TheFile.Sections[relocTableSection.SymbolTableSectionIndex]; ELFStringTableSection symbolNamesTable = (ELFStringTableSection)SO.TheFile.Sections[symbolTable.StringsSectionIndex]; List Relocations = relocTableSection.Relocations; for (int k = 0; k < Relocations.Count; k++) { ELFRelocationAddendTableSection.RelocationAddend relocation = (ELFRelocationAddendTableSection.RelocationAddend)Relocations[k]; if (relocation.Type == ELFRelocationTableSection.RelocationType.R_386_NONE) { continue; } ELFSymbolTableSection.Symbol symbol = (ELFSymbolTableSection.Symbol)symbolTable[relocation.Symbol]; FOS_System.String symbolName = symbolNamesTable[symbol.NameIdx]; uint* resolvedRelLocation = (uint*)(SO.BaseAddress + (relocation.Offset - SO.TheFile.BaseAddress)); //BasicConsole.WriteLine("Relocation:"); ////BasicConsole.WriteLine(" > Symbol index : " + (FOS_System.String)relocation.Symbol); //BasicConsole.WriteLine(" > Type : " + (FOS_System.String)(uint)relocation.Type); //BasicConsole.WriteLine(" > Offset : " + (FOS_System.String)(uint)relocation.Offset); //BasicConsole.WriteLine(((FOS_System.String)" > Resolved location address: ") + (uint)resolvedRelLocation); ////BasicConsole.WriteLine(((FOS_System.String)" > Resolved location start value: ") + *resolvedRelLocation); //BasicConsole.Write(" > Symbol name : "); //BasicConsole.WriteLine(symbolName); uint newValue = 0; switch (relocation.Type) { //TODO: Support more relocation types default: Console.Default.WarningColour(); Console.Default.Write("WARNING: Unrecognised relocation type! ("); Console.Default.Write_AsDecimal((uint)relocation.Type); Console.Default.WriteLine(")"); Console.Default.DefaultColour(); BasicConsole.Write("WARNING: Unrecognised relocation type! ("); BasicConsole.Write((uint)relocation.Type); BasicConsole.WriteLine(")"); break; } *resolvedRelLocation = newValue; //BasicConsole.WriteLine(" > New value: " + (FOS_System.String)(newValue)); //BasicConsole.WriteLine(" > Resolved location end value: " + (FOS_System.String)(*resolvedRelLocation)); } } } } Console.Default.WriteLine("Executable Relocations"); BasicConsole.WriteLine("Executable Relocations"); //BasicConsole.WriteLine("Executable base address : " + (FOS_System.String)BaseAddress); //BasicConsole.WriteLine("Executable file base address : " + (FOS_System.String)theFile.BaseAddress); // Perform dynamic linking of executable List ExeSections = theFile.Sections; for (int j = 0; j < ExeSections.Count; j++) { ELFSection ExeSection = (ELFSection)ExeSections[j]; if (ExeSection is ELFRelocationTableSection) { //BasicConsole.WriteLine(" - Normal Relocations"); ELFRelocationTableSection relocTableSection = (ELFRelocationTableSection)ExeSection; ELFSymbolTableSection symbolTable = (ELFSymbolTableSection)theFile.Sections[relocTableSection.SymbolTableSectionIndex]; ELFStringTableSection symbolNamesTable = (ELFStringTableSection)theFile.Sections[symbolTable.StringsSectionIndex]; List Relocations = relocTableSection.Relocations; for (int k = 0; k < Relocations.Count; k++) { ELFRelocationTableSection.Relocation relocation = (ELFRelocationTableSection.Relocation)Relocations[k]; if (relocation.Type == ELFRelocationTableSection.RelocationType.R_386_NONE) { continue; } uint* resolvedRelLocation = (uint*)(BaseAddress + (relocation.Offset - theFile.BaseAddress)); ELFSymbolTableSection.Symbol symbol = (ELFSymbolTableSection.Symbol)symbolTable[relocation.Symbol]; FOS_System.String symbolName = symbolNamesTable[symbol.NameIdx]; //BasicConsole.WriteLine("Relocation:"); ////BasicConsole.WriteLine(" > Symbol index : " + (FOS_System.String)relocation.Symbol); //BasicConsole.WriteLine(" > Type : " + (FOS_System.String)(uint)relocation.Type); //BasicConsole.WriteLine(" > Offset : " + (FOS_System.String)(uint)relocation.Offset); //BasicConsole.WriteLine(((FOS_System.String)" > Resolved location address: ") + (uint)resolvedRelLocation); ////BasicConsole.WriteLine(((FOS_System.String)" > Resolved location start value: ") + *resolvedRelLocation); //BasicConsole.Write(" > Symbol name : "); //BasicConsole.WriteLine(symbolName); bool setFromNewValue = true; uint newValue = 0; switch (relocation.Type) { //TODO: Support more relocation types case ELFRelocationTableSection.RelocationType.R_386_JMP_SLOT: newValue = GetSymbolAddress(symbol, symbolName); break; case ELFRelocationTableSection.RelocationType.R_386_COPY: // Created by the link-editor for dynamic executables to preserve a read-only text segment. // Its offset member refers to a location in a writable segment. The symbol table index // specifies a symbol that should exist both in the current object file and in a shared object. // During execution, the runtime linker copies data associated with the shared object's symbol // to the location specified by the offset. // See Copy Relocations: // http://docs.oracle.com/cd/E19683-01/817-3677/6mj8mbtbs/index.html#chapter4-84604 setFromNewValue = false; uint symbolAddress = 0; uint symbolSize = 0; if (GetSymbolAddressAndSize(symbol, symbolName, ref symbolAddress, ref symbolSize)) { byte* symbolValuePtr = (byte*)symbolAddress; //BasicConsole.Write(" > Symbol size : "); //BasicConsole.WriteLine(symbolSize); for (int i = 0; i < symbolSize; i++) { resolvedRelLocation[i] = symbolValuePtr[i]; } } else { BasicConsole.WriteLine("Failed to get symbol address and size for R_386_COPY relocation!"); } break; default: Console.Default.WarningColour(); Console.Default.Write("WARNING: Unrecognised relocation type! ("); Console.Default.Write_AsDecimal((uint)relocation.Type); Console.Default.WriteLine(")"); Console.Default.DefaultColour(); BasicConsole.Write("WARNING: Unrecognised relocation type! ("); BasicConsole.Write((uint)relocation.Type); BasicConsole.WriteLine(")"); break; } if (setFromNewValue) { *resolvedRelLocation = newValue; //BasicConsole.WriteLine(" > New value: " + (FOS_System.String)(newValue)); //BasicConsole.WriteLine(" > Resolved location end value: " + (FOS_System.String)(*resolvedRelLocation)); } } } else if (ExeSection is ELFRelocationAddendTableSection) { //BasicConsole.WriteLine(" - Addend Relocations"); ELFRelocationAddendTableSection relocTableSection = (ELFRelocationAddendTableSection)ExeSection; ELFSymbolTableSection symbolTable = (ELFSymbolTableSection)theFile.Sections[relocTableSection.SymbolTableSectionIndex]; ELFStringTableSection symbolNamesTable = (ELFStringTableSection)theFile.Sections[symbolTable.StringsSectionIndex]; List Relocations = relocTableSection.Relocations; for (int k = 0; k < Relocations.Count; k++) { ELFRelocationAddendTableSection.RelocationAddend relocation = (ELFRelocationAddendTableSection.RelocationAddend)Relocations[k]; if (relocation.Type == ELFRelocationTableSection.RelocationType.R_386_NONE) { continue; } uint* resolvedRelLocation = (uint*)(BaseAddress + (relocation.Offset - theFile.BaseAddress)); ELFSymbolTableSection.Symbol symbol = (ELFSymbolTableSection.Symbol)symbolTable[relocation.Symbol]; FOS_System.String symbolName = symbolNamesTable[symbol.NameIdx]; //BasicConsole.WriteLine("Relocation:"); ////BasicConsole.WriteLine(" > Symbol index : " + (FOS_System.String)relocation.Symbol); //BasicConsole.WriteLine(" > Type : " + (FOS_System.String)(uint)relocation.Type); //BasicConsole.WriteLine(" > Offset : " + (FOS_System.String)(uint)relocation.Offset); //BasicConsole.WriteLine(((FOS_System.String)" > Resolved location address: ") + (uint)resolvedRelLocation); ////BasicConsole.WriteLine(((FOS_System.String)" > Resolved location start value: ") + *resolvedRelLocation); //BasicConsole.Write(" > Symbol name : "); //BasicConsole.WriteLine(symbolName); uint newValue = 0; switch (relocation.Type) { //TODO: Support more relocation types default: Console.Default.WarningColour(); Console.Default.Write("WARNING: Unrecognised relocation type! ("); Console.Default.Write_AsDecimal((uint)relocation.Type); Console.Default.WriteLine(")"); Console.Default.DefaultColour(); BasicConsole.Write("WARNING: Unrecognised relocation type! ("); BasicConsole.Write((uint)relocation.Type); BasicConsole.WriteLine(")"); break; } *resolvedRelLocation = newValue; //BasicConsole.WriteLine(" > New value: " + (FOS_System.String)(newValue)); //BasicConsole.WriteLine(" > Resolved location end value: " + (FOS_System.String)(*resolvedRelLocation)); } } } // TODO: Call Init functions of libraries } // Unmap processes' memory from current processes' memory for (int i = 0; i < SharedObjectDependencies.Count; i++) { ELFSharedObject SO = (ELFSharedObject)SharedObjectDependencies[i]; uint FileBaseAddress = SO.TheFile.BaseAddress; uint MemBaseAddress = SO.BaseAddress; List SOSegments = SO.TheFile.Segments; for (int j = 0; j < SOSegments.Count; j++) { ELFSegment SOSegment = (ELFSegment)SOSegments[j]; ProcessManager.CurrentProcess.TheMemoryLayout.RemovePage( (MemBaseAddress + ((uint)SOSegment.Header.VAddr - FileBaseAddress)) & 0xFFFFF000); } } { uint FileBaseAddress = theFile.BaseAddress; uint MemBaseAddress = BaseAddress; List ExeSegments = theFile.Segments; for (int j = 0; j < ExeSegments.Count; j++) { ELFSegment ExeSegment = (ELFSegment)ExeSegments[j]; ProcessManager.CurrentProcess.TheMemoryLayout.RemovePage( (MemBaseAddress + ((uint)ExeSegment.Header.VAddr - FileBaseAddress)) & 0xFFFFF000); } } #endregion ProcessManager.CurrentProcess.TheMemoryLayout.RemovePage(threadStackVirtAddr); } finally { if (!OK) { theProcess = null; } } }
private static bool Semaphore_VerifyOwner(int id, Process aProcess) { if (id > -1 && id < Semaphores.Count && Semaphores[id] != null) { Semaphore theSemaphore = ((Semaphore)Semaphores[id]); return theSemaphore.OwnerProcesses.IndexOf(aProcess.Id) > -1; } return false; }
/// <summary> /// Attempts to read from the specified pipe. /// </summary> /// <remarks> /// Note that this function is non-blocking. It will, however, block a system caller thread by simply not returning it from /// the deferred system call. /// </remarks> /// <param name="PipeId">The Id of the pipe to read.</param> /// <param name="Blocking">Whether the read should be blocking or non-blocking.</param> /// <param name="CallerProcess">The process which made the call.</param> /// <param name="CallerThread">The thread which made the call.</param> /// <returns>See descriptions on <see cref="PipeManager.RWResults"/> values.</returns> public static RWResults ReadPipe(int PipeId, bool Blocking, Process CallerProcess, Thread CallerThread) { #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Validating inputs"); #endif // Validate inputs // - Check pipe exists Pipe pipe = GetPipe(PipeId); if (pipe == null) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Checking caller allowed to write"); #endif // Check the caller is allowed to access the pipe if (!AllowedToReadPipe(pipe, CallerProcess.Id)) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Getting out process"); #endif // Get outpoint process Process OutProcess = ProcessManager.GetProcessById(pipe.Outpoint.ProcessId); if (OutProcess == null) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Getting in process"); #endif // Get inpoint process Process InProcess = ProcessManager.GetProcessById(pipe.Inpoint.ProcessId); if (InProcess == null) { return RWResults.Error; } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Adding caller to read queue"); #endif // Add caller thread to the read queue pipe.QueueToRead(CallerThread.Id); ProcessManager.EnableKernelAccessToProcessMemory(CallerProcess); // Set up initial failure return value CallerThread.Return1 = (uint)SystemCallResults.Fail; ProcessManager.DisableKernelAccessToProcessMemory(CallerProcess); #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Processing pipe queue"); #endif // Process the pipe queue ProcessPipeQueue(pipe, OutProcess, InProcess); bool Completed = !pipe.AreThreadsWaitingToRead(); if (!Blocking) { if (!Completed) { uint temp; bool removed = pipe.RemoveLastToRead(out temp); if (!removed || temp != CallerThread.Id) { BasicConsole.WriteLine("PipeManager: Error! Async read failed and then removing last from queue resulted in thread Id mismatch!"); } ProcessManager.EnableKernelAccessToProcessMemory(CallerProcess); CallerThread.Return1 = (uint)SystemCallResults.Fail; ProcessManager.DisableKernelAccessToProcessMemory(CallerProcess); CallerThread._Wake(); } } return Completed ? RWResults.Complete : RWResults.Queued; }