KProcess.cs 34 KB

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