ProgramLoader.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Common;
  3. using Ryujinx.Common.Logging;
  4. using Ryujinx.HLE.HOS.Kernel;
  5. using Ryujinx.HLE.Loaders.Executables;
  6. using Ryujinx.HLE.Loaders.Npdm;
  7. namespace Ryujinx.HLE.HOS
  8. {
  9. class ProgramLoader
  10. {
  11. private const bool AslrEnabled = true;
  12. private const int ArgsHeaderSize = 8;
  13. private const int ArgsDataSize = 0x9000;
  14. private const int ArgsTotalSize = ArgsHeaderSize + ArgsDataSize;
  15. public static bool LoadKernelInitalProcess(Horizon System, KernelInitialProcess Kip)
  16. {
  17. int EndOffset = Kip.DataOffset + Kip.Data.Length;
  18. if (Kip.BssSize != 0)
  19. {
  20. EndOffset = Kip.BssOffset + Kip.BssSize;
  21. }
  22. int CodeSize = BitUtils.AlignUp(Kip.TextOffset + EndOffset, KMemoryManager.PageSize);
  23. int CodePagesCount = CodeSize / KMemoryManager.PageSize;
  24. ulong CodeBaseAddress = Kip.Addr39Bits ? 0x8000000UL : 0x200000UL;
  25. ulong CodeAddress = CodeBaseAddress + (ulong)Kip.TextOffset;
  26. int MmuFlags = 0;
  27. if (AslrEnabled)
  28. {
  29. //TODO: Randomization.
  30. MmuFlags |= 0x20;
  31. }
  32. if (Kip.Addr39Bits)
  33. {
  34. MmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
  35. }
  36. if (Kip.Is64Bits)
  37. {
  38. MmuFlags |= 1;
  39. }
  40. ProcessCreationInfo CreationInfo = new ProcessCreationInfo(
  41. Kip.Name,
  42. Kip.ProcessCategory,
  43. Kip.TitleId,
  44. CodeAddress,
  45. CodePagesCount,
  46. MmuFlags,
  47. 0,
  48. 0);
  49. MemoryRegion MemRegion = Kip.IsService
  50. ? MemoryRegion.Service
  51. : MemoryRegion.Application;
  52. KMemoryRegionManager Region = System.MemoryRegions[(int)MemRegion];
  53. KernelResult Result = Region.AllocatePages((ulong)CodePagesCount, false, out KPageList PageList);
  54. if (Result != KernelResult.Success)
  55. {
  56. Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
  57. return false;
  58. }
  59. KProcess Process = new KProcess(System);
  60. Result = Process.InitializeKip(
  61. CreationInfo,
  62. Kip.Capabilities,
  63. PageList,
  64. System.ResourceLimit,
  65. MemRegion);
  66. if (Result != KernelResult.Success)
  67. {
  68. Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
  69. return false;
  70. }
  71. Result = LoadIntoMemory(Process, Kip, CodeBaseAddress);
  72. if (Result != KernelResult.Success)
  73. {
  74. Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
  75. return false;
  76. }
  77. Result = Process.Start(Kip.MainThreadPriority, (ulong)Kip.MainThreadStackSize);
  78. if (Result != KernelResult.Success)
  79. {
  80. Logger.PrintError(LogClass.Loader, $"Process start returned error \"{Result}\".");
  81. return false;
  82. }
  83. System.Processes.Add(Process.Pid, Process);
  84. return true;
  85. }
  86. public static bool LoadStaticObjects(
  87. Horizon System,
  88. Npdm MetaData,
  89. IExecutable[] StaticObjects,
  90. byte[] Arguments = null)
  91. {
  92. ulong ArgsStart = 0;
  93. int ArgsSize = 0;
  94. ulong CodeStart = 0x8000000;
  95. int CodeSize = 0;
  96. ulong[] NsoBase = new ulong[StaticObjects.Length];
  97. for (int Index = 0; Index < StaticObjects.Length; Index++)
  98. {
  99. IExecutable StaticObject = StaticObjects[Index];
  100. int TextEnd = StaticObject.TextOffset + StaticObject.Text.Length;
  101. int ROEnd = StaticObject.ROOffset + StaticObject.RO.Length;
  102. int DataEnd = StaticObject.DataOffset + StaticObject.Data.Length + StaticObject.BssSize;
  103. int NsoSize = TextEnd;
  104. if ((uint)NsoSize < (uint)ROEnd)
  105. {
  106. NsoSize = ROEnd;
  107. }
  108. if ((uint)NsoSize < (uint)DataEnd)
  109. {
  110. NsoSize = DataEnd;
  111. }
  112. NsoSize = BitUtils.AlignUp(NsoSize, KMemoryManager.PageSize);
  113. NsoBase[Index] = CodeStart + (ulong)CodeSize;
  114. CodeSize += NsoSize;
  115. if (Arguments != null && ArgsSize == 0)
  116. {
  117. ArgsStart = (ulong)CodeSize;
  118. ArgsSize = BitUtils.AlignDown(Arguments.Length * 2 + ArgsTotalSize - 1, KMemoryManager.PageSize);
  119. CodeSize += ArgsSize;
  120. }
  121. }
  122. int CodePagesCount = CodeSize / KMemoryManager.PageSize;
  123. int PersonalMmHeapPagesCount = MetaData.PersonalMmHeapSize / KMemoryManager.PageSize;
  124. ProcessCreationInfo CreationInfo = new ProcessCreationInfo(
  125. MetaData.TitleName,
  126. MetaData.ProcessCategory,
  127. MetaData.ACI0.TitleId,
  128. CodeStart,
  129. CodePagesCount,
  130. MetaData.MmuFlags,
  131. 0,
  132. PersonalMmHeapPagesCount);
  133. KernelResult Result;
  134. KResourceLimit ResourceLimit = new KResourceLimit(System);
  135. long ApplicationRgSize = (long)System.MemoryRegions[(int)MemoryRegion.Application].Size;
  136. Result = ResourceLimit.SetLimitValue(LimitableResource.Memory, ApplicationRgSize);
  137. Result |= ResourceLimit.SetLimitValue(LimitableResource.Thread, 608);
  138. Result |= ResourceLimit.SetLimitValue(LimitableResource.Event, 700);
  139. Result |= ResourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
  140. Result |= ResourceLimit.SetLimitValue(LimitableResource.Session, 894);
  141. if (Result != KernelResult.Success)
  142. {
  143. Logger.PrintError(LogClass.Loader, $"Process initialization failed setting resource limit values.");
  144. return false;
  145. }
  146. KProcess Process = new KProcess(System);
  147. Result = Process.Initialize(
  148. CreationInfo,
  149. MetaData.ACI0.KernelAccessControl.Capabilities,
  150. ResourceLimit,
  151. MemoryRegion.Application);
  152. if (Result != KernelResult.Success)
  153. {
  154. Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
  155. return false;
  156. }
  157. for (int Index = 0; Index < StaticObjects.Length; Index++)
  158. {
  159. Logger.PrintInfo(LogClass.Loader, $"Loading image {Index} at 0x{NsoBase[Index]:x16}...");
  160. Result = LoadIntoMemory(Process, StaticObjects[Index], NsoBase[Index]);
  161. if (Result != KernelResult.Success)
  162. {
  163. Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
  164. return false;
  165. }
  166. }
  167. Result = Process.Start(MetaData.MainThreadPriority, (ulong)MetaData.MainThreadStackSize);
  168. if (Result != KernelResult.Success)
  169. {
  170. Logger.PrintError(LogClass.Loader, $"Process start returned error \"{Result}\".");
  171. return false;
  172. }
  173. System.Processes.Add(Process.Pid, Process);
  174. return true;
  175. }
  176. private static KernelResult LoadIntoMemory(KProcess Process, IExecutable Image, ulong BaseAddress)
  177. {
  178. ulong TextStart = BaseAddress + (ulong)Image.TextOffset;
  179. ulong ROStart = BaseAddress + (ulong)Image.ROOffset;
  180. ulong DataStart = BaseAddress + (ulong)Image.DataOffset;
  181. ulong BssStart = BaseAddress + (ulong)Image.BssOffset;
  182. ulong End = DataStart + (ulong)Image.Data.Length;
  183. if (Image.BssSize != 0)
  184. {
  185. End = BssStart + (ulong)Image.BssSize;
  186. }
  187. Process.CpuMemory.WriteBytes((long)TextStart, Image.Text);
  188. Process.CpuMemory.WriteBytes((long)ROStart, Image.RO);
  189. Process.CpuMemory.WriteBytes((long)DataStart, Image.Data);
  190. MemoryHelper.FillWithZeros(Process.CpuMemory, (long)BssStart, Image.BssSize);
  191. KernelResult SetProcessMemoryPermission(ulong Address, ulong Size, MemoryPermission Permission)
  192. {
  193. if (Size == 0)
  194. {
  195. return KernelResult.Success;
  196. }
  197. Size = BitUtils.AlignUp(Size, KMemoryManager.PageSize);
  198. return Process.MemoryManager.SetProcessMemoryPermission(Address, Size, Permission);
  199. }
  200. KernelResult Result = SetProcessMemoryPermission(TextStart, (ulong)Image.Text.Length, MemoryPermission.ReadAndExecute);
  201. if (Result != KernelResult.Success)
  202. {
  203. return Result;
  204. }
  205. Result = SetProcessMemoryPermission(ROStart, (ulong)Image.RO.Length, MemoryPermission.Read);
  206. if (Result != KernelResult.Success)
  207. {
  208. return Result;
  209. }
  210. return SetProcessMemoryPermission(DataStart, End - DataStart, MemoryPermission.ReadAndWrite);
  211. }
  212. }
  213. }