diff options
Diffstat (limited to 'Ryujinx.HLE/OsHle/Horizon.cs')
| -rw-r--r-- | Ryujinx.HLE/OsHle/Horizon.cs | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs new file mode 100644 index 00000000..a5bf0616 --- /dev/null +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -0,0 +1,200 @@ +using Ryujinx.HLE.Loaders.Executables; +using Ryujinx.HLE.Logging; +using Ryujinx.HLE.OsHle.Handles; +using System; +using System.Collections.Concurrent; +using System.IO; + +namespace Ryujinx.HLE.OsHle +{ + public class Horizon : IDisposable + { + internal const int HidSize = 0x40000; + internal const int FontSize = 0x50; + + private Switch Ns; + + private KProcessScheduler Scheduler; + + private ConcurrentDictionary<int, Process> Processes; + + public SystemStateMgr SystemState { get; private set; } + + internal MemoryAllocator Allocator { get; private set; } + + internal HSharedMem HidSharedMem { get; private set; } + internal HSharedMem FontSharedMem { get; private set; } + + internal KEvent VsyncEvent { get; private set; } + + public Horizon(Switch Ns) + { + this.Ns = Ns; + + Scheduler = new KProcessScheduler(Ns.Log); + + Processes = new ConcurrentDictionary<int, Process>(); + + SystemState = new SystemStateMgr(); + + Allocator = new MemoryAllocator(); + + HidSharedMem = new HSharedMem(); + FontSharedMem = new HSharedMem(); + + VsyncEvent = new KEvent(); + } + + public void LoadCart(string ExeFsDir, string RomFsFile = null) + { + if (RomFsFile != null) + { + Ns.VFs.LoadRomFs(RomFsFile); + } + + Process MainProcess = MakeProcess(); + + void LoadNso(string FileName) + { + foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) + { + if (Path.GetExtension(File) != string.Empty) + { + continue; + } + + Ns.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}..."); + + using (FileStream Input = new FileStream(File, FileMode.Open)) + { + string Name = Path.GetFileNameWithoutExtension(File); + + Nso Program = new Nso(Input, Name); + + MainProcess.LoadProgram(Program); + } + } + } + + LoadNso("rtld"); + + MainProcess.SetEmptyArgs(); + + LoadNso("main"); + LoadNso("subsdk*"); + LoadNso("sdk"); + + MainProcess.Run(); + } + + public void LoadProgram(string FileName) + { + bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro"; + + string Name = Path.GetFileNameWithoutExtension(FileName); + + Process MainProcess = MakeProcess(); + + using (FileStream Input = new FileStream(FileName, FileMode.Open)) + { + MainProcess.LoadProgram(IsNro + ? (IExecutable)new Nro(Input, Name) + : (IExecutable)new Nso(Input, Name)); + } + + MainProcess.SetEmptyArgs(); + MainProcess.Run(IsNro); + } + + public void SignalVsync() => VsyncEvent.WaitEvent.Set(); + + private Process MakeProcess() + { + Process Process; + + lock (Processes) + { + int ProcessId = 0; + + while (Processes.ContainsKey(ProcessId)) + { + ProcessId++; + } + + Process = new Process(Ns, Scheduler, ProcessId); + + Processes.TryAdd(ProcessId, Process); + } + + InitializeProcess(Process); + + return Process; + } + + private void InitializeProcess(Process Process) + { + Process.AppletState.SetFocus(true); + } + + internal void ExitProcess(int ProcessId) + { + if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi) + { + string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition); + + Ns.Log.PrintInfo(LogClass.Loader, $"HbAbi NextLoadPath {NextNro}"); + + if (NextNro == string.Empty) + { + NextNro = "sdmc:/hbmenu.nro"; + } + + NextNro = NextNro.Replace("sdmc:", string.Empty); + + NextNro = Ns.VFs.GetFullPath(Ns.VFs.GetSdCardPath(), NextNro); + + if (File.Exists(NextNro)) + { + LoadProgram(NextNro); + } + } + + if (Processes.TryRemove(ProcessId, out Process)) + { + Process.StopAllThreadsAsync(); + Process.Dispose(); + + if (Processes.Count == 0) + { + Ns.OnFinish(EventArgs.Empty); + } + } + } + + internal bool TryGetProcess(int ProcessId, out Process Process) + { + return Processes.TryGetValue(ProcessId, out Process); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + foreach (Process Process in Processes.Values) + { + Process.StopAllThreadsAsync(); + Process.Dispose(); + } + + VsyncEvent.Dispose(); + + Scheduler.Dispose(); + } + } + } +}
\ No newline at end of file |
