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. }