Horizon.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. using Ryujinx.Core.Loaders.Executables;
  2. using Ryujinx.Core.Logging;
  3. using Ryujinx.Core.OsHle.Handles;
  4. using System;
  5. using System.Collections.Concurrent;
  6. using System.IO;
  7. namespace Ryujinx.Core.OsHle
  8. {
  9. public class Horizon : IDisposable
  10. {
  11. internal const int HidSize = 0x40000;
  12. internal const int FontSize = 0x50;
  13. private Switch Ns;
  14. private KProcessScheduler Scheduler;
  15. private ConcurrentDictionary<int, Process> Processes;
  16. public SystemStateMgr SystemState { get; private set; }
  17. internal HSharedMem HidSharedMem { get; private set; }
  18. internal HSharedMem FontSharedMem { get; private set; }
  19. internal KEvent VsyncEvent { get; private set; }
  20. public Horizon(Switch Ns)
  21. {
  22. this.Ns = Ns;
  23. Scheduler = new KProcessScheduler(Ns.Log);
  24. Processes = new ConcurrentDictionary<int, Process>();
  25. SystemState = new SystemStateMgr();
  26. HidSharedMem = new HSharedMem();
  27. FontSharedMem = new HSharedMem();
  28. VsyncEvent = new KEvent();
  29. }
  30. public void LoadCart(string ExeFsDir, string RomFsFile = null)
  31. {
  32. if (RomFsFile != null)
  33. {
  34. Ns.VFs.LoadRomFs(RomFsFile);
  35. }
  36. Process MainProcess = MakeProcess();
  37. void LoadNso(string FileName)
  38. {
  39. foreach (string File in Directory.GetFiles(ExeFsDir, FileName))
  40. {
  41. if (Path.GetExtension(File) != string.Empty)
  42. {
  43. continue;
  44. }
  45. Ns.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}...");
  46. using (FileStream Input = new FileStream(File, FileMode.Open))
  47. {
  48. string Name = Path.GetFileNameWithoutExtension(File);
  49. Nso Program = new Nso(Input, Name);
  50. MainProcess.LoadProgram(Program);
  51. }
  52. }
  53. }
  54. LoadNso("rtld");
  55. MainProcess.SetEmptyArgs();
  56. LoadNso("main");
  57. LoadNso("subsdk*");
  58. LoadNso("sdk");
  59. MainProcess.Run();
  60. }
  61. public void LoadProgram(string FileName)
  62. {
  63. bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
  64. string Name = Path.GetFileNameWithoutExtension(FileName);
  65. Process MainProcess = MakeProcess();
  66. using (FileStream Input = new FileStream(FileName, FileMode.Open))
  67. {
  68. MainProcess.LoadProgram(IsNro
  69. ? (IExecutable)new Nro(Input, Name)
  70. : (IExecutable)new Nso(Input, Name));
  71. }
  72. MainProcess.SetEmptyArgs();
  73. MainProcess.Run(IsNro);
  74. }
  75. public void SignalVsync() => VsyncEvent.WaitEvent.Set();
  76. private Process MakeProcess()
  77. {
  78. Process Process;
  79. lock (Processes)
  80. {
  81. int ProcessId = 0;
  82. while (Processes.ContainsKey(ProcessId))
  83. {
  84. ProcessId++;
  85. }
  86. Process = new Process(Ns, Scheduler, ProcessId);
  87. Processes.TryAdd(ProcessId, Process);
  88. }
  89. InitializeProcess(Process);
  90. return Process;
  91. }
  92. private void InitializeProcess(Process Process)
  93. {
  94. Process.AppletState.SetFocus(true);
  95. }
  96. internal void ExitProcess(int ProcessId)
  97. {
  98. if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
  99. {
  100. string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
  101. Ns.Log.PrintInfo(LogClass.Loader, $"HbAbi NextLoadPath {NextNro}");
  102. if (NextNro == string.Empty)
  103. {
  104. NextNro = "sdmc:/hbmenu.nro";
  105. }
  106. NextNro = NextNro.Replace("sdmc:", string.Empty);
  107. NextNro = Ns.VFs.GetFullPath(Ns.VFs.GetSdCardPath(), NextNro);
  108. if (File.Exists(NextNro))
  109. {
  110. LoadProgram(NextNro);
  111. }
  112. }
  113. if (Processes.TryRemove(ProcessId, out Process))
  114. {
  115. Process.StopAllThreadsAsync();
  116. Process.Dispose();
  117. if (Processes.Count == 0)
  118. {
  119. Ns.OnFinish(EventArgs.Empty);
  120. }
  121. }
  122. }
  123. internal bool TryGetProcess(int ProcessId, out Process Process)
  124. {
  125. return Processes.TryGetValue(ProcessId, out Process);
  126. }
  127. public void Dispose()
  128. {
  129. Dispose(true);
  130. }
  131. protected virtual void Dispose(bool Disposing)
  132. {
  133. if (Disposing)
  134. {
  135. foreach (Process Process in Processes.Values)
  136. {
  137. Process.StopAllThreadsAsync();
  138. Process.Dispose();
  139. }
  140. VsyncEvent.Dispose();
  141. Scheduler.Dispose();
  142. }
  143. }
  144. }
  145. }