KProcess.cs 35 KB

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