aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Process.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-11-28 20:18:09 -0200
committerGitHub <noreply@github.com>2018-11-28 20:18:09 -0200
commit00579927e43bf55ee06ae02933c1e755fb4120eb (patch)
tree0fd06db7b28e0accf87b465ec6f4dc74691febab /Ryujinx.HLE/HOS/Process.cs
parente7fe7d724778535f8eff390abef54274a343c0b7 (diff)
Better process implementation (#491)
* Initial implementation of KProcess * Some improvements to the memory manager, implement back guest stack trace printing * Better GetInfo implementation, improve checking in some places with information from process capabilities * Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary * Change long -> ulong for address/size on memory related methods to avoid unnecessary casts * Attempt at implementing ldr:ro with new KProcess * Allow BSS with size 0 on ldr:ro * Add checking for memory block slab heap usage, return errors if full, exit gracefully * Use KMemoryBlockSize const from KMemoryManager * Allow all methods to read from non-contiguous locations * Fix for TransactParcelAuto * Address PR feedback, additionally fix some small issues related to the KIP loader and implement SVCs GetProcessId, GetProcessList, GetSystemInfo, CreatePort and ManageNamedPort * Fix wrong check for source pages count from page list on MapPhysicalMemory * Fix some issues with UnloadNro on ldr:ro
Diffstat (limited to 'Ryujinx.HLE/HOS/Process.cs')
-rw-r--r--Ryujinx.HLE/HOS/Process.cs528
1 files changed, 0 insertions, 528 deletions
diff --git a/Ryujinx.HLE/HOS/Process.cs b/Ryujinx.HLE/HOS/Process.cs
deleted file mode 100644
index 93b2d68d..00000000
--- a/Ryujinx.HLE/HOS/Process.cs
+++ /dev/null
@@ -1,528 +0,0 @@
-using ChocolArm64;
-using ChocolArm64.Events;
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using LibHac;
-using Ryujinx.Common.Logging;
-using Ryujinx.HLE.Exceptions;
-using Ryujinx.HLE.HOS.Diagnostics.Demangler;
-using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Services.Nv;
-using Ryujinx.HLE.HOS.SystemState;
-using Ryujinx.HLE.Loaders;
-using Ryujinx.HLE.Loaders.Executables;
-using Ryujinx.HLE.Loaders.Npdm;
-using Ryujinx.HLE.Utilities;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
-namespace Ryujinx.HLE.HOS
-{
- class Process : IDisposable
- {
- private const int TickFreq = 19_200_000;
-
- public Switch Device { get; private set; }
-
- public bool NeedsHbAbi { get; private set; }
-
- public long HbAbiDataPosition { get; private set; }
-
- public int ProcessId { get; private set; }
-
- private Translator Translator;
-
- public MemoryManager Memory { get; private set; }
-
- public KMemoryManager MemoryManager { get; private set; }
-
- private List<KTlsPageManager> TlsPages;
-
- public Npdm MetaData { get; private set; }
-
- public Nacp ControlData { get; set; }
-
- public KProcessHandleTable HandleTable { get; private set; }
-
- public AppletStateMgr AppletState { get; private set; }
-
- private SvcHandler SvcHandler;
-
- private ConcurrentDictionary<long, KThread> Threads;
-
- private List<Executable> Executables;
-
- private long ImageBase;
-
- private bool Disposed;
-
- public Process(Switch Device, int ProcessId, Npdm MetaData)
- {
- this.Device = Device;
- this.MetaData = MetaData;
- this.ProcessId = ProcessId;
-
- Memory = new MemoryManager(Device.Memory.RamPointer);
-
- Memory.InvalidAccess += CpuInvalidAccessHandler;
-
- MemoryManager = new KMemoryManager(this);
-
- TlsPages = new List<KTlsPageManager>();
-
- int HandleTableSize = 1024;
-
- if (MetaData != null)
- {
- foreach (KernelAccessControlItem Item in MetaData.ACI0.KernelAccessControl.Items)
- {
- if (Item.HasHandleTableSize)
- {
- HandleTableSize = Item.HandleTableSize;
-
- break;
- }
- }
- }
-
- HandleTable = new KProcessHandleTable(Device.System, HandleTableSize);
-
- AppletState = new AppletStateMgr(Device.System);
-
- SvcHandler = new SvcHandler(Device, this);
-
- Threads = new ConcurrentDictionary<long, KThread>();
-
- Executables = new List<Executable>();
-
- ImageBase = MemoryManager.CodeRegionStart;
- }
-
- public void LoadProgram(IExecutable Program)
- {
- if (Disposed)
- {
- throw new ObjectDisposedException(nameof(Process));
- }
-
- long ImageEnd = LoadProgram(Program, ImageBase);
-
- ImageBase = IntUtils.AlignUp(ImageEnd, KMemoryManager.PageSize);
- }
-
- public long LoadProgram(IExecutable Program, long ExecutableBase)
- {
- if (Disposed)
- {
- throw new ObjectDisposedException(nameof(Process));
- }
-
- Logger.PrintInfo(LogClass.Loader, $"Image base at 0x{ExecutableBase:x16}.");
-
- Executable Executable = new Executable(Program, MemoryManager, Memory, ExecutableBase);
-
- Executables.Add(Executable);
-
- return Executable.ImageEnd;
- }
-
- public void RemoveProgram(long ExecutableBase)
- {
- foreach (Executable Executable in Executables)
- {
- if (Executable.ImageBase == ExecutableBase)
- {
- Executables.Remove(Executable);
- break;
- }
- }
- }
-
- public void SetEmptyArgs()
- {
- //TODO: This should be part of Run.
- ImageBase += KMemoryManager.PageSize;
- }
-
- public bool Run(bool NeedsHbAbi = false)
- {
- if (Disposed)
- {
- throw new ObjectDisposedException(nameof(Process));
- }
-
- this.NeedsHbAbi = NeedsHbAbi;
-
- if (Executables.Count == 0)
- {
- return false;
- }
-
- long MainStackTop = MemoryManager.CodeRegionEnd - KMemoryManager.PageSize;
-
- long MainStackSize = 1 * 1024 * 1024;
-
- long MainStackBottom = MainStackTop - MainStackSize;
-
- MemoryManager.HleMapCustom(
- MainStackBottom,
- MainStackSize,
- MemoryState.MappedMemory,
- MemoryPermission.ReadAndWrite);
-
- int Handle = MakeThread(Executables[0].ImageBase, MainStackTop, 0, 44, 0);
-
- if (Handle == -1)
- {
- return false;
- }
-
- KThread MainThread = HandleTable.GetKThread(Handle);
-
- if (NeedsHbAbi)
- {
- HbAbiDataPosition = IntUtils.AlignUp(Executables[0].ImageEnd, KMemoryManager.PageSize);
-
- const long HbAbiDataSize = KMemoryManager.PageSize;
-
- MemoryManager.HleMapCustom(
- HbAbiDataPosition,
- HbAbiDataSize,
- MemoryState.MappedMemory,
- MemoryPermission.ReadAndWrite);
-
- string SwitchPath = Device.FileSystem.SystemPathToSwitchPath(Executables[0].FilePath);
-
- Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle, SwitchPath);
-
- MainThread.Context.ThreadState.X0 = (ulong)HbAbiDataPosition;
- MainThread.Context.ThreadState.X1 = ulong.MaxValue;
- }
-
- MainThread.TimeUp();
-
- return true;
- }
-
- private int ThreadIdCtr = 1;
-
- public int MakeThread(
- long EntryPoint,
- long StackTop,
- long ArgsPtr,
- int Priority,
- int ProcessorId)
- {
- if (Disposed)
- {
- throw new ObjectDisposedException(nameof(Process));
- }
-
- CpuThread CpuThread = new CpuThread(GetTranslator(), Memory, EntryPoint);
-
- long Tpidr = GetFreeTls();
-
- int ThreadId = ThreadIdCtr++; //(int)((Tpidr - MemoryManager.TlsIoRegionStart) / 0x200) + 1;
-
- KThread Thread = new KThread(CpuThread, this, Device.System, ProcessorId, Priority, ThreadId);
-
- Thread.LastPc = EntryPoint;
-
- HandleTable.GenerateHandle(Thread, out int Handle);
-
- CpuThread.ThreadState.CntfrqEl0 = TickFreq;
- CpuThread.ThreadState.Tpidr = Tpidr;
-
- CpuThread.ThreadState.X0 = (ulong)ArgsPtr;
- CpuThread.ThreadState.X1 = (ulong)Handle;
- CpuThread.ThreadState.X31 = (ulong)StackTop;
-
- CpuThread.ThreadState.Interrupt += InterruptHandler;
- CpuThread.ThreadState.Break += BreakHandler;
- CpuThread.ThreadState.SvcCall += SvcHandler.SvcCall;
- CpuThread.ThreadState.Undefined += UndefinedHandler;
-
- CpuThread.WorkFinished += ThreadFinished;
-
- Threads.TryAdd(CpuThread.ThreadState.Tpidr, Thread);
-
- return Handle;
- }
-
- private long GetFreeTls()
- {
- long Position;
-
- lock (TlsPages)
- {
- for (int Index = 0; Index < TlsPages.Count; Index++)
- {
- if (TlsPages[Index].TryGetFreeTlsAddr(out Position))
- {
- return Position;
- }
- }
-
- long PagePosition = MemoryManager.HleMapTlsPage();
-
- KTlsPageManager TlsPage = new KTlsPageManager(PagePosition);
-
- TlsPages.Add(TlsPage);
-
- TlsPage.TryGetFreeTlsAddr(out Position);
- }
-
- return Position;
- }
-
- private void InterruptHandler(object sender, EventArgs e)
- {
- Device.System.Scheduler.ContextSwitch();
- }
-
- private void BreakHandler(object sender, InstExceptionEventArgs e)
- {
- PrintStackTraceForCurrentThread();
-
- throw new GuestBrokeExecutionException();
- }
-
- private void UndefinedHandler(object sender, InstUndefinedEventArgs e)
- {
- PrintStackTraceForCurrentThread();
-
- throw new UndefinedInstructionException(e.Position, e.RawOpCode);
- }
-
- public void EnableCpuTracing()
- {
- Translator.EnableCpuTrace = true;
- }
-
- public void DisableCpuTracing()
- {
- Translator.EnableCpuTrace = false;
- }
-
- private void CpuTraceHandler(object sender, CpuTraceEventArgs e)
- {
- Executable Exe = GetExecutable(e.Position);
-
- if (Exe == null)
- {
- return;
- }
-
- if (!TryGetSubName(Exe, e.Position, out string SubName))
- {
- SubName = string.Empty;
- }
-
- long Offset = e.Position - Exe.ImageBase;
-
- string ExeNameWithAddr = $"{Exe.Name}:0x{Offset:x8}";
-
- Logger.PrintDebug(LogClass.Cpu, ExeNameWithAddr + " " + SubName);
- }
-
- private Translator GetTranslator()
- {
- if (Translator == null)
- {
- Translator = new Translator();
-
- Translator.CpuTrace += CpuTraceHandler;
- }
-
- return Translator;
- }
-
- private void CpuInvalidAccessHandler(object sender, InvalidAccessEventArgs e)
- {
- PrintStackTraceForCurrentThread();
- }
-
- private void PrintStackTraceForCurrentThread()
- {
- foreach (KThread Thread in Threads.Values)
- {
- if (Thread.Context.IsCurrentThread())
- {
- PrintStackTrace(Thread.Context.ThreadState);
-
- break;
- }
- }
- }
-
- public void PrintStackTrace(CpuThreadState ThreadState)
- {
- StringBuilder Trace = new StringBuilder();
-
- Trace.AppendLine("Guest stack trace:");
-
- void AppendTrace(long Position)
- {
- Executable Exe = GetExecutable(Position);
-
- if (Exe == null)
- {
- return;
- }
-
- if (!TryGetSubName(Exe, Position, out string SubName))
- {
- SubName = $"Sub{Position:x16}";
- }
- else if (SubName.StartsWith("_Z"))
- {
- SubName = Demangler.Parse(SubName);
- }
-
- long Offset = Position - Exe.ImageBase;
-
- string ExeNameWithAddr = $"{Exe.Name}:0x{Offset:x8}";
-
- Trace.AppendLine(" " + ExeNameWithAddr + " " + SubName);
- }
-
- long FramePointer = (long)ThreadState.X29;
-
- while (FramePointer != 0)
- {
- AppendTrace(Memory.ReadInt64(FramePointer + 8));
-
- FramePointer = Memory.ReadInt64(FramePointer);
- }
-
- Logger.PrintInfo(LogClass.Cpu, Trace.ToString());
- }
-
- private bool TryGetSubName(Executable Exe, long Position, out string Name)
- {
- Position -= Exe.ImageBase;
-
- int Left = 0;
- int Right = Exe.SymbolTable.Count - 1;
-
- while (Left <= Right)
- {
- int Size = Right - Left;
-
- int Middle = Left + (Size >> 1);
-
- ElfSym Symbol = Exe.SymbolTable[Middle];
-
- long EndPosition = Symbol.Value + Symbol.Size;
-
- if ((ulong)Position >= (ulong)Symbol.Value && (ulong)Position < (ulong)EndPosition)
- {
- Name = Symbol.Name;
-
- return true;
- }
-
- if ((ulong)Position < (ulong)Symbol.Value)
- {
- Right = Middle - 1;
- }
- else
- {
- Left = Middle + 1;
- }
- }
-
- Name = null;
-
- return false;
- }
-
- private Executable GetExecutable(long Position)
- {
- string Name = string.Empty;
-
- for (int Index = Executables.Count - 1; Index >= 0; Index--)
- {
- if ((ulong)Position >= (ulong)Executables[Index].ImageBase)
- {
- return Executables[Index];
- }
- }
-
- return null;
- }
-
- private void ThreadFinished(object sender, EventArgs e)
- {
- if (sender is CpuThread Thread)
- {
- if (Threads.TryRemove(Thread.ThreadState.Tpidr, out KThread KernelThread))
- {
- Device.System.Scheduler.RemoveThread(KernelThread);
- }
- }
-
- if (Threads.Count == 0)
- {
- Device.System.ExitProcess(ProcessId);
- }
- }
-
- public KThread GetThread(long Tpidr)
- {
- if (!Threads.TryGetValue(Tpidr, out KThread Thread))
- {
- throw new InvalidOperationException();
- }
-
- return Thread;
- }
-
- private void Unload()
- {
- if (Disposed || Threads.Count > 0)
- {
- return;
- }
-
- Disposed = true;
-
- HandleTable.Destroy();
-
- INvDrvServices.UnloadProcess(this);
-
- if (NeedsHbAbi && Executables.Count > 0 && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix))
- {
- File.Delete(Executables[0].FilePath);
- }
-
- Logger.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting...");
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool Disposing)
- {
- if (Disposing)
- {
- if (Threads.Count > 0)
- {
- foreach (KThread Thread in Threads.Values)
- {
- Device.System.Scheduler.StopThread(Thread);
- }
- }
- else
- {
- Unload();
- }
- }
- }
- }
-} \ No newline at end of file