diff options
author | gdkchan <gab.dark.100@gmail.com> | 2020-12-01 20:23:43 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-02 00:23:43 +0100 |
commit | cf6cd714884c41e9550757e364c2f4f5b04fc7f3 (patch) | |
tree | bea748b4d1a350e5b8075d63ec9d39d49693829d /Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | |
parent | 461c24092ae6e148d896c18aa3e86220c89981f8 (diff) |
IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel (#1458)
* IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel
* Fix for applet transfer memory + some nits
* Keep handles if possible to avoid server handle table exhaustion
* Fix IPC ZeroFill bug
* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer
CreateManagedDisplaySeparableLayer is requires since 10.x+ when appletResourceUserId != 0
* Make it exit properly
* Make ServiceNotImplementedException show the full message again
* Allow yielding execution to avoid starving other threads
* Only wait if active
* Merge IVirtualMemoryManager and IAddressSpaceManager
* Fix Ro loading data from the wrong process
Co-authored-by: Thog <me@thog.eu>
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs')
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 234 |
1 files changed, 97 insertions, 137 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index d02e25a3..8e914f19 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -6,6 +6,7 @@ using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Memory; using System; using System.Collections.Generic; using System.Linq; @@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { class KProcess : KSynchronizationObject { - public const int KernelVersionMajor = 10; - public const int KernelVersionMinor = 4; + public const int KernelVersionMajor = 10; + public const int KernelVersionMinor = 4; public const int KernelVersionRevision = 0; public const int KernelVersionPacked = - (KernelVersionMajor << 19) | - (KernelVersionMinor << 15) | + (KernelVersionMajor << 19) | + (KernelVersionMinor << 15) | (KernelVersionRevision << 0); public KMemoryManager MemoryManager { get; private set; } @@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public long[] RandomEntropy { get; private set; } private bool _signaled; - private bool _useSystemMemBlocks; public string Name { get; private set; } private int _threadCount; - public int MmuFlags { get; private set; } + public ProcessCreationFlags Flags { get; private set; } private MemoryRegion _memRegion; public KProcessCapabilities Capabilities { get; private set; } public ulong TitleId { get; private set; } - public long Pid { get; private set; } + public long Pid { get; private set; } - private long _creationTimestamp; + private long _creationTimestamp; private ulong _entrypoint; + private ThreadStart _customThreadStart; private ulong _imageSize; private ulong _mainThreadStackSize; private ulong _memoryUsageCapacity; - private int _version; + private int _version; public KHandleTable HandleTable { get; private set; } @@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public bool IsPaused { get; private set; } - public MemoryManager CpuMemory { get; private set; } - public CpuContext CpuContext { get; private set; } + private IProcessContextFactory _contextFactory; + public IProcessContext Context { get; private set; } + public IVirtualMemoryManager CpuMemory => Context.AddressSpace; public HleProcessDebugger Debugger { get; private set; } public KProcess(KernelContext context) : base(context) { - _processLock = new object(); + _processLock = new object(); _threadingLock = new object(); AddressArbiter = new KAddressArbiter(context); @@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process RandomEntropy = new long[KScheduler.CpuCoresCount]; + // TODO: Remove once we no longer need to initialize it externally. + HandleTable = new KHandleTable(context); + _threads = new LinkedList<KThread>(); Debugger = new HleProcessDebugger(this); @@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KernelResult InitializeKip( ProcessCreationInfo creationInfo, - int[] caps, - KPageList pageList, - KResourceLimit resourceLimit, - MemoryRegion memRegion) + ReadOnlySpan<int> capabilities, + KPageList pageList, + KResourceLimit resourceLimit, + MemoryRegion memRegion, + IProcessContextFactory contextFactory) { ResourceLimit = resourceLimit; - _memRegion = memRegion; + _memRegion = memRegion; + _contextFactory = contextFactory ?? new ProcessContextFactory(); - AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); + AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - InitializeMemoryManager(addrSpaceType, memRegion); + InitializeMemoryManager(creationInfo.Flags); - bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; + bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); ulong codeAddress = creationInfo.CodeAddress; ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; - KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0 + KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) ? KernelContext.LargeMemoryBlockAllocator : KernelContext.SmallMemoryBlockAllocator; @@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - if (!ValidateCodeAddressAndSize(codeAddress, codeSize)) + if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) { return KernelResult.InvalidMemRange; } @@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process codeAddress, pageList, MemoryState.CodeStatic, - MemoryPermission.None); + KMemoryPermission.None); if (result != KernelResult.Success) { return result; } - result = Capabilities.InitializeForKernel(caps, MemoryManager); + result = Capabilities.InitializeForKernel(capabilities, MemoryManager); if (result != KernelResult.Success) { @@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KernelResult Initialize( ProcessCreationInfo creationInfo, - int[] caps, - KResourceLimit resourceLimit, - MemoryRegion memRegion) + ReadOnlySpan<int> capabilities, + KResourceLimit resourceLimit, + MemoryRegion memRegion, + IProcessContextFactory contextFactory, + ThreadStart customThreadStart = null) { ResourceLimit = resourceLimit; - _memRegion = memRegion; + _memRegion = memRegion; + _contextFactory = contextFactory ?? new ProcessContextFactory(); - ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.PersonalMmHeapPagesCount, memRegion); + ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion); ulong codePagesCount = (ulong)creationInfo.CodePagesCount; @@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } } - PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount; + PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount; KMemoryBlockAllocator memoryBlockAllocator; @@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } else { - memoryBlockAllocator = (MmuFlags & 0x40) != 0 + memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) ? KernelContext.LargeMemoryBlockAllocator : KernelContext.SmallMemoryBlockAllocator; } - AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); + AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - InitializeMemoryManager(addrSpaceType, memRegion); + InitializeMemoryManager(creationInfo.Flags); - bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; + bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); ulong codeAddress = creationInfo.CodeAddress; @@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - if (!ValidateCodeAddressAndSize(codeAddress, codeSize)) + if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) { CleanUpForError(); @@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process codeAddress, codePagesCount, MemoryState.CodeStatic, - MemoryPermission.None); + KMemoryPermission.None); if (result != KernelResult.Success) { @@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - result = Capabilities.InitializeForUser(caps, MemoryManager); + result = Capabilities.InitializeForUser(capabilities, MemoryManager); if (result != KernelResult.Success) { @@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process CleanUpForError(); } - return result; - } - - private bool ValidateCodeAddressAndSize(ulong address, ulong size) - { - ulong codeRegionStart; - ulong codeRegionSize; - - switch (MemoryManager.AddrSpaceWidth) - { - case 32: - codeRegionStart = 0x200000; - codeRegionSize = 0x3fe00000; - break; - - case 36: - codeRegionStart = 0x8000000; - codeRegionSize = 0x78000000; - break; - - case 39: - codeRegionStart = 0x8000000; - codeRegionSize = 0x7ff8000000; - break; - - default: throw new InvalidOperationException("Invalid address space width on memory manager."); - } - - ulong endAddr = address + size; - - ulong codeRegionEnd = codeRegionStart + codeRegionSize; - - if (endAddr <= address || - endAddr - 1 > codeRegionEnd - 1) - { - return false; - } - - if (MemoryManager.InsideHeapRegion (address, size) || - MemoryManager.InsideAliasRegion(address, size)) - { - return false; - } + _customThreadStart = customThreadStart; - return true; + return result; } private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo) { // Ensure that the current kernel version is equal or above to the minimum required. - uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; + uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf; if (KernelContext.EnableVersionChecks) @@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process _creationTimestamp = PerformanceCounter.ElapsedMilliseconds; - MmuFlags = creationInfo.MmuFlags; - _version = creationInfo.Version; - TitleId = creationInfo.TitleId; + Flags = creationInfo.Flags; + _version = creationInfo.Version; + TitleId = creationInfo.TitleId; _entrypoint = creationInfo.CodeAddress; - _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; - - _useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0; + _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; - switch ((AddressSpaceType)((MmuFlags >> 1) & 7)) + switch (Flags & ProcessCreationFlags.AddressSpaceMask) { - case AddressSpaceType.Addr32Bits: - case AddressSpaceType.Addr36Bits: - case AddressSpaceType.Addr39Bits: + case ProcessCreationFlags.AddressSpace32Bit: + case ProcessCreationFlags.AddressSpace64BitDeprecated: + case ProcessCreationFlags.AddressSpace64Bit: _memoryUsageCapacity = MemoryManager.HeapRegionEnd - MemoryManager.HeapRegionStart; break; - case AddressSpaceType.Addr32BitsNoMap: + case ProcessCreationFlags.AddressSpace32BitWithoutAlias: _memoryUsageCapacity = MemoryManager.HeapRegionEnd - MemoryManager.HeapRegionStart + MemoryManager.AliasRegionEnd - MemoryManager.AliasRegionStart; break; - default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}."); + default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}."); } GenerateRandomEntropy(); @@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } ulong regionStart = MemoryManager.TlsIoRegionStart; - ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; + ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; ulong regionPagesCount = regionSize / KMemoryManager.PageSize; @@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process regionStart, regionPagesCount, MemoryState.ThreadLocal, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, out ulong tlsPageVa); if (result != KernelResult.Success) @@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process KernelResult result = KernelResult.Success; - KTlsPageInfo pageInfo = null; + KTlsPageInfo pageInfo; if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) { @@ -594,8 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process // Check if the needed size for the code and the stack will fit on the // memory usage capacity of this Process. Also check for possible overflow // on the above addition. - if (neededSize > _memoryUsageCapacity || - neededSize < stackSizeRounded) + if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded) { threadResourceLimit?.Release(LimitableResource.Thread, 1); @@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize; ulong regionStart = MemoryManager.StackRegionStart; - ulong regionSize = MemoryManager.StackRegionEnd - regionStart; + ulong regionSize = MemoryManager.StackRegionEnd - regionStart; ulong regionPagesCount = regionSize / KMemoryManager.PageSize; @@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process regionStart, regionPagesCount, MemoryState.Stack, - MemoryPermission.ReadAndWrite, + KMemoryPermission.ReadAndWrite, out ulong stackBottom); if (result != KernelResult.Success) @@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process stackTop, mainThreadPriority, DefaultCpuCore, - this); + this, + ThreadType.User, + _customThreadStart); if (result != KernelResult.Success) { @@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process SetState(newState); - // TODO: We can't call KThread.Start from a non-guest thread. - // We will need to make some changes to allow the creation of - // dummy threads that will be used to initialize the current - // thread on KCoreContext so that GetCurrentThread doesn't fail. - /* Result = MainThread.Start(); + result = mainThread.Start(); - if (Result != KernelResult.Success) + if (result != KernelResult.Success) { - SetState(OldState); + SetState(oldState); CleanUpForError(); - } */ - - mainThread.Reschedule(ThreadSchedState.Running); + } if (result == KernelResult.Success) { @@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { if (State != newState) { - State = newState; + State = newState; _signaled = true; Signal(); @@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KernelResult InitializeThread( KThread thread, - ulong entrypoint, - ulong argsPtr, - ulong stackTop, - int priority, - int cpuCore) + ulong entrypoint, + ulong argsPtr, + ulong stackTop, + int priority, + int cpuCore) { lock (_processLock) { - return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this); + return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null); } } public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context) { - context.Interrupt += InterruptHandler; + context.Interrupt += InterruptHandler; context.SupervisorCall += KernelContext.SyscallHandler.SvcCall; - context.Undefined += UndefinedInstructionHandler; + context.Undefined += UndefinedInstructionHandler; } private void InterruptHandler(object sender, EventArgs e) @@ -910,8 +871,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { if (State >= ProcessState.Started) { - if (State == ProcessState.Started || - State == ProcessState.Crashed || + if (State == ProcessState.Started || + State == ProcessState.Crashed || State == ProcessState.Attached || State == ProcessState.DebugSuspended) { @@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion) + private void InitializeMemoryManager(ProcessCreationFlags flags) { - int addrSpaceBits = addrSpaceType switch + int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch { - AddressSpaceType.Addr32Bits => 32, - AddressSpaceType.Addr36Bits => 36, - AddressSpaceType.Addr32BitsNoMap => 32, - AddressSpaceType.Addr39Bits => 39, - _ => throw new ArgumentException(nameof(addrSpaceType)) + ProcessCreationFlags.AddressSpace32Bit => 32, + ProcessCreationFlags.AddressSpace64BitDeprecated => 36, + ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32, + ProcessCreationFlags.AddressSpace64Bit => 39, + _ => 39 }; - CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler); - CpuContext = new CpuContext(CpuMemory); + Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler); // TODO: This should eventually be removed. // The GPU shouldn't depend on the CPU memory manager at all. - KernelContext.Device.Gpu.SetVmm(CpuMemory); + if (flags.HasFlag(ProcessCreationFlags.IsApplication)) + { + KernelContext.Device.Gpu.SetVmm((MemoryManager)CpuMemory); + } MemoryManager = new KMemoryManager(KernelContext, CpuMemory); } @@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process throw new UndefinedInstructionException(e.Address, e.OpCode); } - protected override void Destroy() - { - CpuMemory.Dispose(); - } + protected override void Destroy() => Context.Dispose(); } }
\ No newline at end of file |