KProcess.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  1. using ARMeilleure.State;
  2. using Ryujinx.Common;
  3. using Ryujinx.Common.Logging;
  4. using Ryujinx.Cpu;
  5. using Ryujinx.HLE.Exceptions;
  6. using Ryujinx.HLE.HOS.Kernel.Common;
  7. using Ryujinx.HLE.HOS.Kernel.Memory;
  8. using Ryujinx.HLE.HOS.Kernel.Threading;
  9. using Ryujinx.Memory;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Threading;
  14. namespace Ryujinx.HLE.HOS.Kernel.Process
  15. {
  16. class KProcess : KSynchronizationObject
  17. {
  18. public const int KernelVersionMajor = 10;
  19. public const int KernelVersionMinor = 4;
  20. public const int KernelVersionRevision = 0;
  21. public const int KernelVersionPacked =
  22. (KernelVersionMajor << 19) |
  23. (KernelVersionMinor << 15) |
  24. (KernelVersionRevision << 0);
  25. public KPageTableBase MemoryManager { get; private set; }
  26. private SortedDictionary<ulong, KTlsPageInfo> _fullTlsPages;
  27. private SortedDictionary<ulong, KTlsPageInfo> _freeTlsPages;
  28. public int DefaultCpuCore { get; set; }
  29. public bool Debug { get; private set; }
  30. public KResourceLimit ResourceLimit { get; private set; }
  31. public ulong PersonalMmHeapPagesCount { get; private set; }
  32. public ProcessState State { get; private set; }
  33. private object _processLock;
  34. private object _threadingLock;
  35. public KAddressArbiter AddressArbiter { get; private set; }
  36. public long[] RandomEntropy { get; private set; }
  37. private bool _signaled;
  38. public string Name { get; private set; }
  39. private int _threadCount;
  40. public ProcessCreationFlags Flags { get; private set; }
  41. private MemoryRegion _memRegion;
  42. public KProcessCapabilities Capabilities { get; private set; }
  43. public ulong TitleId { get; private set; }
  44. public bool IsApplication { get; private set; }
  45. public long Pid { get; private set; }
  46. private long _creationTimestamp;
  47. private ulong _entrypoint;
  48. private ThreadStart _customThreadStart;
  49. private ulong _imageSize;
  50. private ulong _mainThreadStackSize;
  51. private ulong _memoryUsageCapacity;
  52. private int _version;
  53. public KHandleTable HandleTable { get; private set; }
  54. public ulong UserExceptionContextAddress { get; private set; }
  55. private LinkedList<KThread> _threads;
  56. public bool IsPaused { get; private set; }
  57. private long _totalTimeRunning;
  58. public long TotalTimeRunning => _totalTimeRunning;
  59. private IProcessContextFactory _contextFactory;
  60. public IProcessContext Context { get; private set; }
  61. public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
  62. public HleProcessDebugger Debugger { get; private set; }
  63. public KProcess(KernelContext context) : base(context)
  64. {
  65. _processLock = new object();
  66. _threadingLock = new object();
  67. AddressArbiter = new KAddressArbiter(context);
  68. _fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>();
  69. _freeTlsPages = new SortedDictionary<ulong, KTlsPageInfo>();
  70. Capabilities = new KProcessCapabilities();
  71. RandomEntropy = new long[KScheduler.CpuCoresCount];
  72. // TODO: Remove once we no longer need to initialize it externally.
  73. HandleTable = new KHandleTable(context);
  74. _threads = new LinkedList<KThread>();
  75. Debugger = new HleProcessDebugger(this);
  76. }
  77. public KernelResult InitializeKip(
  78. ProcessCreationInfo creationInfo,
  79. ReadOnlySpan<int> capabilities,
  80. KPageList pageList,
  81. KResourceLimit resourceLimit,
  82. MemoryRegion memRegion,
  83. IProcessContextFactory contextFactory,
  84. ThreadStart customThreadStart = null)
  85. {
  86. ResourceLimit = resourceLimit;
  87. _memRegion = memRegion;
  88. _contextFactory = contextFactory ?? new ProcessContextFactory();
  89. _customThreadStart = customThreadStart;
  90. AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
  91. Pid = KernelContext.NewKipId();
  92. if (Pid == 0 || (ulong)Pid >= KernelConstants.InitialProcessId)
  93. {
  94. throw new InvalidOperationException($"Invalid KIP Id {Pid}.");
  95. }
  96. InitializeMemoryManager(creationInfo.Flags);
  97. bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
  98. ulong codeAddress = creationInfo.CodeAddress;
  99. ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
  100. KMemoryBlockSlabManager slabManager = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
  101. ? KernelContext.LargeMemoryBlockSlabManager
  102. : KernelContext.SmallMemoryBlockSlabManager;
  103. KernelResult result = MemoryManager.InitializeForProcess(
  104. addrSpaceType,
  105. aslrEnabled,
  106. !aslrEnabled,
  107. memRegion,
  108. codeAddress,
  109. codeSize,
  110. slabManager);
  111. if (result != KernelResult.Success)
  112. {
  113. return result;
  114. }
  115. if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
  116. {
  117. return KernelResult.InvalidMemRange;
  118. }
  119. result = MemoryManager.MapPages(codeAddress, pageList, MemoryState.CodeStatic, KMemoryPermission.None);
  120. if (result != KernelResult.Success)
  121. {
  122. return result;
  123. }
  124. result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
  125. if (result != KernelResult.Success)
  126. {
  127. return result;
  128. }
  129. return ParseProcessInfo(creationInfo);
  130. }
  131. public KernelResult Initialize(
  132. ProcessCreationInfo creationInfo,
  133. ReadOnlySpan<int> capabilities,
  134. KResourceLimit resourceLimit,
  135. MemoryRegion memRegion,
  136. IProcessContextFactory contextFactory,
  137. ThreadStart customThreadStart = null)
  138. {
  139. ResourceLimit = resourceLimit;
  140. _memRegion = memRegion;
  141. _contextFactory = contextFactory ?? new ProcessContextFactory();
  142. _customThreadStart = customThreadStart;
  143. IsApplication = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication);
  144. ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion);
  145. ulong codePagesCount = (ulong)creationInfo.CodePagesCount;
  146. ulong neededSizeForProcess = personalMmHeapSize + codePagesCount * KPageTableBase.PageSize;
  147. if (neededSizeForProcess != 0 && resourceLimit != null)
  148. {
  149. if (!resourceLimit.Reserve(LimitableResource.Memory, neededSizeForProcess))
  150. {
  151. return KernelResult.ResLimitExceeded;
  152. }
  153. }
  154. void CleanUpForError()
  155. {
  156. if (neededSizeForProcess != 0 && resourceLimit != null)
  157. {
  158. resourceLimit.Release(LimitableResource.Memory, neededSizeForProcess);
  159. }
  160. }
  161. PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount;
  162. KMemoryBlockSlabManager slabManager;
  163. if (PersonalMmHeapPagesCount != 0)
  164. {
  165. slabManager = new KMemoryBlockSlabManager(PersonalMmHeapPagesCount * KPageTableBase.PageSize);
  166. }
  167. else
  168. {
  169. slabManager = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
  170. ? KernelContext.LargeMemoryBlockSlabManager
  171. : KernelContext.SmallMemoryBlockSlabManager;
  172. }
  173. AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
  174. Pid = KernelContext.NewProcessId();
  175. if (Pid == -1 || (ulong)Pid < KernelConstants.InitialProcessId)
  176. {
  177. throw new InvalidOperationException($"Invalid Process Id {Pid}.");
  178. }
  179. InitializeMemoryManager(creationInfo.Flags);
  180. bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
  181. ulong codeAddress = creationInfo.CodeAddress;
  182. ulong codeSize = codePagesCount * KPageTableBase.PageSize;
  183. KernelResult result = MemoryManager.InitializeForProcess(
  184. addrSpaceType,
  185. aslrEnabled,
  186. !aslrEnabled,
  187. memRegion,
  188. codeAddress,
  189. codeSize,
  190. slabManager);
  191. if (result != KernelResult.Success)
  192. {
  193. CleanUpForError();
  194. return result;
  195. }
  196. if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
  197. {
  198. CleanUpForError();
  199. return KernelResult.InvalidMemRange;
  200. }
  201. result = MemoryManager.MapPages(
  202. codeAddress,
  203. codePagesCount,
  204. MemoryState.CodeStatic,
  205. KMemoryPermission.None);
  206. if (result != KernelResult.Success)
  207. {
  208. CleanUpForError();
  209. return result;
  210. }
  211. result = Capabilities.InitializeForUser(capabilities, MemoryManager);
  212. if (result != KernelResult.Success)
  213. {
  214. CleanUpForError();
  215. return result;
  216. }
  217. result = ParseProcessInfo(creationInfo);
  218. if (result != KernelResult.Success)
  219. {
  220. CleanUpForError();
  221. }
  222. return result;
  223. }
  224. private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
  225. {
  226. // Ensure that the current kernel version is equal or above to the minimum required.
  227. uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
  228. uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
  229. if (KernelContext.EnableVersionChecks)
  230. {
  231. if (requiredKernelVersionMajor > KernelVersionMajor)
  232. {
  233. return KernelResult.InvalidCombination;
  234. }
  235. if (requiredKernelVersionMajor != KernelVersionMajor && requiredKernelVersionMajor < 3)
  236. {
  237. return KernelResult.InvalidCombination;
  238. }
  239. if (requiredKernelVersionMinor > KernelVersionMinor)
  240. {
  241. return KernelResult.InvalidCombination;
  242. }
  243. }
  244. KernelResult result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress);
  245. if (result != KernelResult.Success)
  246. {
  247. return result;
  248. }
  249. UserExceptionContextAddress = userExceptionContextAddress;
  250. MemoryHelper.FillWithZeros(CpuMemory, userExceptionContextAddress, KTlsPageInfo.TlsEntrySize);
  251. Name = creationInfo.Name;
  252. State = ProcessState.Created;
  253. _creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
  254. Flags = creationInfo.Flags;
  255. _version = creationInfo.Version;
  256. TitleId = creationInfo.TitleId;
  257. _entrypoint = creationInfo.CodeAddress;
  258. _imageSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
  259. switch (Flags & ProcessCreationFlags.AddressSpaceMask)
  260. {
  261. case ProcessCreationFlags.AddressSpace32Bit:
  262. case ProcessCreationFlags.AddressSpace64BitDeprecated:
  263. case ProcessCreationFlags.AddressSpace64Bit:
  264. _memoryUsageCapacity = MemoryManager.HeapRegionEnd -
  265. MemoryManager.HeapRegionStart;
  266. break;
  267. case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
  268. _memoryUsageCapacity = MemoryManager.HeapRegionEnd -
  269. MemoryManager.HeapRegionStart +
  270. MemoryManager.AliasRegionEnd -
  271. MemoryManager.AliasRegionStart;
  272. break;
  273. default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
  274. }
  275. GenerateRandomEntropy();
  276. return KernelResult.Success;
  277. }
  278. public KernelResult AllocateThreadLocalStorage(out ulong address)
  279. {
  280. KernelContext.CriticalSection.Enter();
  281. KernelResult result;
  282. if (_freeTlsPages.Count > 0)
  283. {
  284. // If we have free TLS pages available, just use the first one.
  285. KTlsPageInfo pageInfo = _freeTlsPages.Values.First();
  286. if (!pageInfo.TryGetFreePage(out address))
  287. {
  288. throw new InvalidOperationException("Unexpected failure getting free TLS page!");
  289. }
  290. if (pageInfo.IsFull())
  291. {
  292. _freeTlsPages.Remove(pageInfo.PageVirtualAddress);
  293. _fullTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo);
  294. }
  295. result = KernelResult.Success;
  296. }
  297. else
  298. {
  299. // Otherwise, we need to create a new one.
  300. result = AllocateTlsPage(out KTlsPageInfo pageInfo);
  301. if (result == KernelResult.Success)
  302. {
  303. if (!pageInfo.TryGetFreePage(out address))
  304. {
  305. throw new InvalidOperationException("Unexpected failure getting free TLS page!");
  306. }
  307. _freeTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo);
  308. }
  309. else
  310. {
  311. address = 0;
  312. }
  313. }
  314. KernelContext.CriticalSection.Leave();
  315. return result;
  316. }
  317. private KernelResult AllocateTlsPage(out KTlsPageInfo pageInfo)
  318. {
  319. pageInfo = default;
  320. if (!KernelContext.UserSlabHeapPages.TryGetItem(out ulong tlsPagePa))
  321. {
  322. return KernelResult.OutOfMemory;
  323. }
  324. ulong regionStart = MemoryManager.TlsIoRegionStart;
  325. ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
  326. ulong regionPagesCount = regionSize / KPageTableBase.PageSize;
  327. KernelResult result = MemoryManager.MapPages(
  328. 1,
  329. KPageTableBase.PageSize,
  330. tlsPagePa,
  331. true,
  332. regionStart,
  333. regionPagesCount,
  334. MemoryState.ThreadLocal,
  335. KMemoryPermission.ReadAndWrite,
  336. out ulong tlsPageVa);
  337. if (result != KernelResult.Success)
  338. {
  339. KernelContext.UserSlabHeapPages.Free(tlsPagePa);
  340. }
  341. else
  342. {
  343. pageInfo = new KTlsPageInfo(tlsPageVa, tlsPagePa);
  344. MemoryHelper.FillWithZeros(CpuMemory, tlsPageVa, KPageTableBase.PageSize);
  345. }
  346. return result;
  347. }
  348. public KernelResult FreeThreadLocalStorage(ulong tlsSlotAddr)
  349. {
  350. ulong tlsPageAddr = BitUtils.AlignDown(tlsSlotAddr, KPageTableBase.PageSize);
  351. KernelContext.CriticalSection.Enter();
  352. KernelResult result = KernelResult.Success;
  353. KTlsPageInfo pageInfo;
  354. if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
  355. {
  356. // TLS page was full, free slot and move to free pages tree.
  357. _fullTlsPages.Remove(tlsPageAddr);
  358. _freeTlsPages.Add(tlsPageAddr, pageInfo);
  359. }
  360. else if (!_freeTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
  361. {
  362. result = KernelResult.InvalidAddress;
  363. }
  364. if (pageInfo != null)
  365. {
  366. pageInfo.FreeTlsSlot(tlsSlotAddr);
  367. if (pageInfo.IsEmpty())
  368. {
  369. // TLS page is now empty, we should ensure it is removed
  370. // from all trees, and free the memory it was using.
  371. _freeTlsPages.Remove(tlsPageAddr);
  372. KernelContext.CriticalSection.Leave();
  373. FreeTlsPage(pageInfo);
  374. return KernelResult.Success;
  375. }
  376. }
  377. KernelContext.CriticalSection.Leave();
  378. return result;
  379. }
  380. private KernelResult FreeTlsPage(KTlsPageInfo pageInfo)
  381. {
  382. KernelResult result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal);
  383. if (result == KernelResult.Success)
  384. {
  385. KernelContext.UserSlabHeapPages.Free(pageInfo.PagePhysicalAddress);
  386. }
  387. return result;
  388. }
  389. private void GenerateRandomEntropy()
  390. {
  391. // TODO.
  392. }
  393. public KernelResult Start(int mainThreadPriority, ulong stackSize)
  394. {
  395. lock (_processLock)
  396. {
  397. if (State > ProcessState.CreatedAttached)
  398. {
  399. return KernelResult.InvalidState;
  400. }
  401. if (ResourceLimit != null && !ResourceLimit.Reserve(LimitableResource.Thread, 1))
  402. {
  403. return KernelResult.ResLimitExceeded;
  404. }
  405. KResourceLimit threadResourceLimit = ResourceLimit;
  406. KResourceLimit memoryResourceLimit = null;
  407. if (_mainThreadStackSize != 0)
  408. {
  409. throw new InvalidOperationException("Trying to start a process with a invalid state!");
  410. }
  411. ulong stackSizeRounded = BitUtils.AlignUp(stackSize, KPageTableBase.PageSize);
  412. ulong neededSize = stackSizeRounded + _imageSize;
  413. // Check if the needed size for the code and the stack will fit on the
  414. // memory usage capacity of this Process. Also check for possible overflow
  415. // on the above addition.
  416. if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
  417. {
  418. threadResourceLimit?.Release(LimitableResource.Thread, 1);
  419. return KernelResult.OutOfMemory;
  420. }
  421. if (stackSizeRounded != 0 && ResourceLimit != null)
  422. {
  423. memoryResourceLimit = ResourceLimit;
  424. if (!memoryResourceLimit.Reserve(LimitableResource.Memory, stackSizeRounded))
  425. {
  426. threadResourceLimit?.Release(LimitableResource.Thread, 1);
  427. return KernelResult.ResLimitExceeded;
  428. }
  429. }
  430. KernelResult result;
  431. KThread mainThread = null;
  432. ulong stackTop = 0;
  433. void CleanUpForError()
  434. {
  435. HandleTable.Destroy();
  436. mainThread?.DecrementReferenceCount();
  437. if (_mainThreadStackSize != 0)
  438. {
  439. ulong stackBottom = stackTop - _mainThreadStackSize;
  440. ulong stackPagesCount = _mainThreadStackSize / KPageTableBase.PageSize;
  441. MemoryManager.UnmapForKernel(stackBottom, stackPagesCount, MemoryState.Stack);
  442. _mainThreadStackSize = 0;
  443. }
  444. memoryResourceLimit?.Release(LimitableResource.Memory, stackSizeRounded);
  445. threadResourceLimit?.Release(LimitableResource.Thread, 1);
  446. }
  447. if (stackSizeRounded != 0)
  448. {
  449. ulong stackPagesCount = stackSizeRounded / KPageTableBase.PageSize;
  450. ulong regionStart = MemoryManager.StackRegionStart;
  451. ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
  452. ulong regionPagesCount = regionSize / KPageTableBase.PageSize;
  453. result = MemoryManager.MapPages(
  454. stackPagesCount,
  455. KPageTableBase.PageSize,
  456. 0,
  457. false,
  458. regionStart,
  459. regionPagesCount,
  460. MemoryState.Stack,
  461. KMemoryPermission.ReadAndWrite,
  462. out ulong stackBottom);
  463. if (result != KernelResult.Success)
  464. {
  465. CleanUpForError();
  466. return result;
  467. }
  468. _mainThreadStackSize += stackSizeRounded;
  469. stackTop = stackBottom + stackSizeRounded;
  470. }
  471. ulong heapCapacity = _memoryUsageCapacity - _mainThreadStackSize - _imageSize;
  472. result = MemoryManager.SetHeapCapacity(heapCapacity);
  473. if (result != KernelResult.Success)
  474. {
  475. CleanUpForError();
  476. return result;
  477. }
  478. HandleTable = new KHandleTable(KernelContext);
  479. result = HandleTable.Initialize(Capabilities.HandleTableSize);
  480. if (result != KernelResult.Success)
  481. {
  482. CleanUpForError();
  483. return result;
  484. }
  485. mainThread = new KThread(KernelContext);
  486. result = mainThread.Initialize(
  487. _entrypoint,
  488. 0,
  489. stackTop,
  490. mainThreadPriority,
  491. DefaultCpuCore,
  492. this,
  493. ThreadType.User,
  494. _customThreadStart);
  495. if (result != KernelResult.Success)
  496. {
  497. CleanUpForError();
  498. return result;
  499. }
  500. result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle);
  501. if (result != KernelResult.Success)
  502. {
  503. CleanUpForError();
  504. return result;
  505. }
  506. mainThread.SetEntryArguments(0, mainThreadHandle);
  507. ProcessState oldState = State;
  508. ProcessState newState = State != ProcessState.Created
  509. ? ProcessState.Attached
  510. : ProcessState.Started;
  511. SetState(newState);
  512. result = mainThread.Start();
  513. if (result != KernelResult.Success)
  514. {
  515. SetState(oldState);
  516. CleanUpForError();
  517. }
  518. if (result == KernelResult.Success)
  519. {
  520. mainThread.IncrementReferenceCount();
  521. }
  522. mainThread.DecrementReferenceCount();
  523. return result;
  524. }
  525. }
  526. private void SetState(ProcessState newState)
  527. {
  528. if (State != newState)
  529. {
  530. State = newState;
  531. _signaled = true;
  532. Signal();
  533. }
  534. }
  535. public KernelResult InitializeThread(
  536. KThread thread,
  537. ulong entrypoint,
  538. ulong argsPtr,
  539. ulong stackTop,
  540. int priority,
  541. int cpuCore)
  542. {
  543. lock (_processLock)
  544. {
  545. return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null);
  546. }
  547. }
  548. public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
  549. {
  550. context.Interrupt += InterruptHandler;
  551. context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
  552. context.Undefined += UndefinedInstructionHandler;
  553. }
  554. private void InterruptHandler(object sender, EventArgs e)
  555. {
  556. KThread currentThread = KernelStatic.GetCurrentThread();
  557. if (currentThread.IsSchedulable)
  558. {
  559. KernelContext.Schedulers[currentThread.CurrentCore].Schedule();
  560. }
  561. currentThread.HandlePostSyscall();
  562. }
  563. public void IncrementThreadCount()
  564. {
  565. Interlocked.Increment(ref _threadCount);
  566. }
  567. public void DecrementThreadCountAndTerminateIfZero()
  568. {
  569. if (Interlocked.Decrement(ref _threadCount) == 0)
  570. {
  571. Terminate();
  572. }
  573. }
  574. public void DecrementToZeroWhileTerminatingCurrent()
  575. {
  576. while (Interlocked.Decrement(ref _threadCount) != 0)
  577. {
  578. Destroy();
  579. TerminateCurrentProcess();
  580. }
  581. // Nintendo panic here because if it reaches this point, the current thread should be already dead.
  582. // As we handle the death of the thread in the post SVC handler and inside the CPU emulator, we don't panic here.
  583. }
  584. public ulong GetMemoryCapacity()
  585. {
  586. ulong totalCapacity = (ulong)ResourceLimit.GetRemainingValue(LimitableResource.Memory);
  587. totalCapacity += MemoryManager.GetTotalHeapSize();
  588. totalCapacity += GetPersonalMmHeapSize();
  589. totalCapacity += _imageSize + _mainThreadStackSize;
  590. if (totalCapacity <= _memoryUsageCapacity)
  591. {
  592. return totalCapacity;
  593. }
  594. return _memoryUsageCapacity;
  595. }
  596. public ulong GetMemoryUsage()
  597. {
  598. return _imageSize + _mainThreadStackSize + MemoryManager.GetTotalHeapSize() + GetPersonalMmHeapSize();
  599. }
  600. public ulong GetMemoryCapacityWithoutPersonalMmHeap()
  601. {
  602. return GetMemoryCapacity() - GetPersonalMmHeapSize();
  603. }
  604. public ulong GetMemoryUsageWithoutPersonalMmHeap()
  605. {
  606. return GetMemoryUsage() - GetPersonalMmHeapSize();
  607. }
  608. private ulong GetPersonalMmHeapSize()
  609. {
  610. return GetPersonalMmHeapSize(PersonalMmHeapPagesCount, _memRegion);
  611. }
  612. private static ulong GetPersonalMmHeapSize(ulong personalMmHeapPagesCount, MemoryRegion memRegion)
  613. {
  614. if (memRegion == MemoryRegion.Applet)
  615. {
  616. return 0;
  617. }
  618. return personalMmHeapPagesCount * KPageTableBase.PageSize;
  619. }
  620. public void AddCpuTime(long ticks)
  621. {
  622. Interlocked.Add(ref _totalTimeRunning, ticks);
  623. }
  624. public void AddThread(KThread thread)
  625. {
  626. lock (_threadingLock)
  627. {
  628. thread.ProcessListNode = _threads.AddLast(thread);
  629. }
  630. }
  631. public void RemoveThread(KThread thread)
  632. {
  633. lock (_threadingLock)
  634. {
  635. _threads.Remove(thread.ProcessListNode);
  636. }
  637. }
  638. public bool IsCpuCoreAllowed(int core)
  639. {
  640. return (Capabilities.AllowedCpuCoresMask & (1L << core)) != 0;
  641. }
  642. public bool IsPriorityAllowed(int priority)
  643. {
  644. return (Capabilities.AllowedThreadPriosMask & (1L << priority)) != 0;
  645. }
  646. public override bool IsSignaled()
  647. {
  648. return _signaled;
  649. }
  650. public KernelResult Terminate()
  651. {
  652. KernelResult result;
  653. bool shallTerminate = false;
  654. KernelContext.CriticalSection.Enter();
  655. lock (_processLock)
  656. {
  657. if (State >= ProcessState.Started)
  658. {
  659. if (State == ProcessState.Started ||
  660. State == ProcessState.Crashed ||
  661. State == ProcessState.Attached ||
  662. State == ProcessState.DebugSuspended)
  663. {
  664. SetState(ProcessState.Exiting);
  665. shallTerminate = true;
  666. }
  667. result = KernelResult.Success;
  668. }
  669. else
  670. {
  671. result = KernelResult.InvalidState;
  672. }
  673. }
  674. KernelContext.CriticalSection.Leave();
  675. if (shallTerminate)
  676. {
  677. UnpauseAndTerminateAllThreadsExcept(KernelStatic.GetCurrentThread());
  678. HandleTable.Destroy();
  679. SignalExitToDebugTerminated();
  680. SignalExit();
  681. }
  682. return result;
  683. }
  684. public void TerminateCurrentProcess()
  685. {
  686. bool shallTerminate = false;
  687. KernelContext.CriticalSection.Enter();
  688. lock (_processLock)
  689. {
  690. if (State >= ProcessState.Started)
  691. {
  692. if (State == ProcessState.Started ||
  693. State == ProcessState.Attached ||
  694. State == ProcessState.DebugSuspended)
  695. {
  696. SetState(ProcessState.Exiting);
  697. shallTerminate = true;
  698. }
  699. }
  700. }
  701. KernelContext.CriticalSection.Leave();
  702. if (shallTerminate)
  703. {
  704. UnpauseAndTerminateAllThreadsExcept(KernelStatic.GetCurrentThread());
  705. HandleTable.Destroy();
  706. // NOTE: this is supposed to be called in receiving of the mailbox.
  707. SignalExitToDebugExited();
  708. SignalExit();
  709. }
  710. }
  711. private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread)
  712. {
  713. lock (_threadingLock)
  714. {
  715. KernelContext.CriticalSection.Enter();
  716. foreach (KThread thread in _threads)
  717. {
  718. if ((thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
  719. {
  720. thread.PrepareForTermination();
  721. }
  722. }
  723. KernelContext.CriticalSection.Leave();
  724. }
  725. while (true)
  726. {
  727. KThread blockedThread = null;
  728. lock (_threadingLock)
  729. {
  730. foreach (KThread thread in _threads)
  731. {
  732. if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
  733. {
  734. thread.IncrementReferenceCount();
  735. blockedThread = thread;
  736. break;
  737. }
  738. }
  739. }
  740. if (blockedThread == null)
  741. {
  742. break;
  743. }
  744. blockedThread.Terminate();
  745. blockedThread.DecrementReferenceCount();
  746. }
  747. }
  748. private void SignalExitToDebugTerminated()
  749. {
  750. // TODO: Debug events.
  751. }
  752. private void SignalExitToDebugExited()
  753. {
  754. // TODO: Debug events.
  755. }
  756. private void SignalExit()
  757. {
  758. if (ResourceLimit != null)
  759. {
  760. ResourceLimit.Release(LimitableResource.Memory, GetMemoryUsage());
  761. }
  762. KernelContext.CriticalSection.Enter();
  763. SetState(ProcessState.Exited);
  764. KernelContext.CriticalSection.Leave();
  765. }
  766. public KernelResult ClearIfNotExited()
  767. {
  768. KernelResult result;
  769. KernelContext.CriticalSection.Enter();
  770. lock (_processLock)
  771. {
  772. if (State != ProcessState.Exited && _signaled)
  773. {
  774. _signaled = false;
  775. result = KernelResult.Success;
  776. }
  777. else
  778. {
  779. result = KernelResult.InvalidState;
  780. }
  781. }
  782. KernelContext.CriticalSection.Leave();
  783. return result;
  784. }
  785. private void InitializeMemoryManager(ProcessCreationFlags flags)
  786. {
  787. int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch
  788. {
  789. ProcessCreationFlags.AddressSpace32Bit => 32,
  790. ProcessCreationFlags.AddressSpace64BitDeprecated => 36,
  791. ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32,
  792. ProcessCreationFlags.AddressSpace64Bit => 39,
  793. _ => 39
  794. };
  795. bool for64Bit = flags.HasFlag(ProcessCreationFlags.Is64Bit);
  796. Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit);
  797. if (Context.AddressSpace is MemoryManagerHostMapped)
  798. {
  799. MemoryManager = new KPageTableHostMapped(KernelContext, CpuMemory);
  800. }
  801. else
  802. {
  803. MemoryManager = new KPageTable(KernelContext, CpuMemory);
  804. }
  805. }
  806. private bool InvalidAccessHandler(ulong va)
  807. {
  808. KernelStatic.GetCurrentThread()?.PrintGuestStackTrace();
  809. KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
  810. Logger.Error?.Print(LogClass.Cpu, $"Invalid memory access at virtual address 0x{va:X16}.");
  811. return false;
  812. }
  813. private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e)
  814. {
  815. KernelStatic.GetCurrentThread().PrintGuestStackTrace();
  816. KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
  817. throw new UndefinedInstructionException(e.Address, e.OpCode);
  818. }
  819. protected override void Destroy() => Context.Dispose();
  820. public KernelResult SetActivity(bool pause)
  821. {
  822. KernelContext.CriticalSection.Enter();
  823. if (State != ProcessState.Exiting && State != ProcessState.Exited)
  824. {
  825. if (pause)
  826. {
  827. if (IsPaused)
  828. {
  829. KernelContext.CriticalSection.Leave();
  830. return KernelResult.InvalidState;
  831. }
  832. lock (_threadingLock)
  833. {
  834. foreach (KThread thread in _threads)
  835. {
  836. thread.Suspend(ThreadSchedState.ProcessPauseFlag);
  837. }
  838. }
  839. IsPaused = true;
  840. }
  841. else
  842. {
  843. if (!IsPaused)
  844. {
  845. KernelContext.CriticalSection.Leave();
  846. return KernelResult.InvalidState;
  847. }
  848. lock (_threadingLock)
  849. {
  850. foreach (KThread thread in _threads)
  851. {
  852. thread.Resume(ThreadSchedState.ProcessPauseFlag);
  853. }
  854. }
  855. IsPaused = false;
  856. }
  857. KernelContext.CriticalSection.Leave();
  858. return KernelResult.Success;
  859. }
  860. KernelContext.CriticalSection.Leave();
  861. return KernelResult.InvalidState;
  862. }
  863. }
  864. }