/// <summary> /// Starts a new process based on the given path and arguments /// </summary> /// <param name="path">The path</param> /// <param name="argv">The arguments</param> /// <param name="flags">Spawn flags</param> /// <returns>Errorcode or PID</returns> public static int StartProcess(string path, string[] argv, Task.SpawnFlags flags) { if (argv == null) { Panic.DoPanic("argv == null"); } Node node = VFS.GetByAbsolutePath(path); if (node == null) { return(-(int)ErrorCode.ENOENT); } // Open and create buffer VFS.Open(node, (int)FileMode.O_RDONLY); byte[] buffer = new byte[node.Size]; if (buffer == null) { Heap.Free(node); VFS.Close(node); return(-(int)ErrorCode.ENOMEM); } // Fill buffer contents VFS.Read(node, 0, node.Size, buffer); VFS.Close(node); // Pass execution to ELF loader int status = ELFLoader.Execute(buffer, node.Size, argv, flags); Heap.Free(buffer); Heap.Free(node); return(status); }
/// <summary> /// Executes an ELF file /// </summary> /// <param name="buffer">The buffer</param> /// <param name="size">The size of the ELF</param> /// <param name="argv">The arguments</param> /// <param name="flags">Spawn flags</param> /// <returns>The error code or PID</returns> public static unsafe int Execute(byte[] buffer, uint size, string[] argv, Task.SpawnFlags flags) { ELF32 *elf; fixed(byte *ptr = buffer) elf = (ELF32 *)ptr; if (!isValidELF(elf)) { return(-(int)ErrorCode.EINVAL); } // Get program header ProgramHeader *programHeader = (ProgramHeader *)((int)elf + elf->PhOff); uint virtAddress = programHeader->VirtAddress; void * allocated = Heap.AlignedAlloc(0x1000, (int)size); // Loop through every section for (uint i = 0; i < elf->ShNum; i++) { SectionHeader *section = getSection(elf, i); // Only loadable sections if (section->Address == 0) { continue; } uint offset = section->Address - virtAddress; // BSS if (section->Type == SectionHeaderType.SHT_NOBITS) { Memory.Memclear((void *)((uint)allocated + offset), (int)section->Size); } // Copy else { Memory.Memcpy((void *)((uint)allocated + offset), (void *)((uint)elf + section->Offset), (int)section->Size); } } // Count arguments int argc = 0; while (argv[argc] != null) { argc++; } // Make sure arguments are safe by copying them string[] argvClone = new string[argc + 1]; for (int i = 0; i < argc; i++) { argvClone[i] = String.Clone(argv[i]); } // Stack int[] initialStack = new int[2]; initialStack[0] = (int)Util.ObjectToVoidPtr(argvClone); initialStack[1] = argc; // Create thread Thread thread = new Thread(); thread.Context.CreateNewContext((void *)elf->Entry, 2, initialStack, false); Heap.Free(initialStack); CPU.CLI(); // Create task Task newTask = new Task(TaskPriority.NORMAL, flags); X86Context context = (X86Context)newTask.Context; context.CreateNewContext(false); newTask.AddThread(thread); newTask.AddUsedAddress(allocated); // Task info newTask.Name = argvClone[0]; newTask.CMDLine = Array.Join(argvClone, argc, " "); newTask.AddUsedAddress(newTask.CMDLine); // Argv clone freeing newTask.AddUsedAddress(argvClone); for (int i = 0; i < argc; i++) { newTask.AddUsedAddress(argvClone[i]); } // Map memory Paging.PageDirectory *newDirectory = context.PageDirVirtual; Paging.PageFlags pageFlags = Paging.PageFlags.Present | Paging.PageFlags.Writable | Paging.PageFlags.UserMode; for (uint j = 0; j < size; j += 0x1000) { // Note: the physical memory is not always a continuous block Paging.MapPage(newDirectory, (int)Paging.GetPhysicalFromVirtual((void *)((int)allocated + j)), (int)(virtAddress + j), pageFlags); } // Schedule task Tasking.ScheduleTask(newTask); CPU.STI(); return(newTask.PID); }