diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Process')
19 files changed, 0 insertions, 2787 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs b/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs deleted file mode 100644 index 66d56fe3..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Numerics; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - static class CapabilityExtensions - { - public static CapabilityType GetCapabilityType(this uint cap) - { - return (CapabilityType)(((cap + 1) & ~cap) - 1); - } - - public static uint GetFlag(this CapabilityType type) - { - return (uint)type + 1; - } - - public static uint GetId(this CapabilityType type) - { - return (uint)BitOperations.TrailingZeroCount(type.GetFlag()); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/CapabilityType.cs b/Ryujinx.HLE/HOS/Kernel/Process/CapabilityType.cs deleted file mode 100644 index 51d92316..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/CapabilityType.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - enum CapabilityType : uint - { - CorePriority = (1u << 3) - 1, - SyscallMask = (1u << 4) - 1, - MapRange = (1u << 6) - 1, - MapIoPage = (1u << 7) - 1, - MapRegion = (1u << 10) - 1, - InterruptPair = (1u << 11) - 1, - ProgramType = (1u << 13) - 1, - KernelVersion = (1u << 14) - 1, - HandleTable = (1u << 15) - 1, - DebugFlags = (1u << 16) - 1, - - Invalid = 0u, - Padding = ~0u - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs deleted file mode 100644 index 8fee5c0d..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs +++ /dev/null @@ -1,465 +0,0 @@ -using Ryujinx.HLE.HOS.Diagnostics.Demangler; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.Loaders.Elf; -using Ryujinx.Memory; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class HleProcessDebugger - { - private const int Mod0 = 'M' << 0 | 'O' << 8 | 'D' << 16 | '0' << 24; - - private KProcess _owner; - - private class Image - { - public ulong BaseAddress { get; } - public ulong Size { get; } - public ulong EndAddress => BaseAddress + Size; - - public ElfSymbol[] Symbols { get; } - - public Image(ulong baseAddress, ulong size, ElfSymbol[] symbols) - { - BaseAddress = baseAddress; - Size = size; - Symbols = symbols; - } - } - - private List<Image> _images; - - private int _loaded; - - public HleProcessDebugger(KProcess owner) - { - _owner = owner; - - _images = new List<Image>(); - } - - public string GetGuestStackTrace(KThread thread) - { - EnsureLoaded(); - - var context = thread.Context; - - StringBuilder trace = new StringBuilder(); - - trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}"); - - void AppendTrace(ulong address) - { - if (AnalyzePointer(out PointerInfo info, address, thread)) - { - trace.AppendLine($" 0x{address:x16}\t{info.ImageDisplay}\t{info.SubDisplay}"); - } - else - { - trace.AppendLine($" 0x{address:x16}"); - } - } - - if (context.IsAarch32) - { - ulong framePointer = context.GetX(11); - - while (framePointer != 0) - { - if ((framePointer & 3) != 0 || - !_owner.CpuMemory.IsMapped(framePointer) || - !_owner.CpuMemory.IsMapped(framePointer + 4)) - { - break; - } - - AppendTrace(_owner.CpuMemory.Read<uint>(framePointer + 4)); - - framePointer = _owner.CpuMemory.Read<uint>(framePointer); - } - } - else - { - ulong framePointer = context.GetX(29); - - while (framePointer != 0) - { - if ((framePointer & 7) != 0 || - !_owner.CpuMemory.IsMapped(framePointer) || - !_owner.CpuMemory.IsMapped(framePointer + 8)) - { - break; - } - - AppendTrace(_owner.CpuMemory.Read<ulong>(framePointer + 8)); - - framePointer = _owner.CpuMemory.Read<ulong>(framePointer); - } - } - - return trace.ToString(); - } - - public string GetCpuRegisterPrintout(KThread thread) - { - EnsureLoaded(); - - var context = thread.Context; - - StringBuilder sb = new StringBuilder(); - - string GetReg(int x) - { - var v = x == 32 ? context.Pc : context.GetX(x); - if (!AnalyzePointer(out PointerInfo info, v, thread)) - { - return $"0x{v:x16}"; - } - else - { - if (!string.IsNullOrEmpty(info.ImageName)) - { - return $"0x{v:x16} ({info.ImageDisplay})\t=> {info.SubDisplay}"; - } - else - { - return $"0x{v:x16} ({info.SpDisplay})"; - } - } - } - - for (int i = 0; i <= 28; i++) - { - sb.AppendLine($"\tX[{i:d2}]:\t{GetReg(i)}"); - } - sb.AppendLine($"\tFP:\t{GetReg(29)}"); - sb.AppendLine($"\tLR:\t{GetReg(30)}"); - sb.AppendLine($"\tSP:\t{GetReg(31)}"); - sb.AppendLine($"\tPC:\t{GetReg(32)}"); - - return sb.ToString(); - } - - private bool TryGetSubName(Image image, ulong address, out ElfSymbol symbol) - { - address -= image.BaseAddress; - - int left = 0; - int right = image.Symbols.Length - 1; - - while (left <= right) - { - int size = right - left; - - int middle = left + (size >> 1); - - symbol = image.Symbols[middle]; - - ulong endAddr = symbol.Value + symbol.Size; - - if (address >= symbol.Value && address < endAddr) - { - return true; - } - - if (address < symbol.Value) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - symbol = default; - - return false; - } - - struct PointerInfo - { - public string ImageName; - public string SubName; - - public ulong Offset; - public ulong SubOffset; - - public string ImageDisplay => $"{ImageName}:0x{Offset:x4}"; - public string SubDisplay => SubOffset == 0 ? SubName : $"{SubName}:0x{SubOffset:x4}"; - public string SpDisplay => SubOffset == 0 ? "SP" : $"SP:-0x{SubOffset:x4}"; - } - - private bool AnalyzePointer(out PointerInfo info, ulong address, KThread thread) - { - if (AnalyzePointerFromImages(out info, address)) - { - return true; - } - - if (AnalyzePointerFromStack(out info, address, thread)) - { - return true; - } - - return false; - } - - private bool AnalyzePointerFromImages(out PointerInfo info, ulong address) - { - info = default; - - Image image = GetImage(address, out int imageIndex); - - if (image == null) - { - // Value isn't a pointer to a known image... - return false; - } - - info.Offset = address - image.BaseAddress; - - // Try to find what this pointer is referring to - if (TryGetSubName(image, address, out ElfSymbol symbol)) - { - info.SubName = symbol.Name; - - // Demangle string if possible - if (info.SubName.StartsWith("_Z")) - { - info.SubName = Demangler.Parse(info.SubName); - } - info.SubOffset = info.Offset - symbol.Value; - } - else - { - info.SubName = ""; - } - - info.ImageName = GetGuessedNsoNameFromIndex(imageIndex); - - return true; - } - - private bool AnalyzePointerFromStack(out PointerInfo info, ulong address, KThread thread) - { - info = default; - - ulong sp = thread.Context.GetX(31); - var memoryInfo = _owner.MemoryManager.QueryMemory(address); - MemoryState memoryState = memoryInfo.State; - - if (!memoryState.HasFlag(MemoryState.Stack)) // Is this pointer within the stack? - { - return false; - } - - info.SubOffset = address - sp; - - return true; - } - - private Image GetImage(ulong address, out int index) - { - lock (_images) - { - for (index = _images.Count - 1; index >= 0; index--) - { - if (address >= _images[index].BaseAddress && address < _images[index].EndAddress) - { - return _images[index]; - } - } - } - - return null; - } - - private string GetGuessedNsoNameFromIndex(int index) - { - if ((uint)index > 11) - { - return "???"; - } - - if (index == 0) - { - return "rtld"; - } - else if (index == 1) - { - return "main"; - } - else if (index == GetImagesCount() - 1) - { - return "sdk"; - } - else - { - return "subsdk" + (index - 2); - } - } - - private int GetImagesCount() - { - lock (_images) - { - return _images.Count; - } - } - - private void EnsureLoaded() - { - if (Interlocked.CompareExchange(ref _loaded, 1, 0) == 0) - { - ScanMemoryForTextSegments(); - } - } - - private void ScanMemoryForTextSegments() - { - ulong oldAddress = 0; - ulong address = 0; - - while (address >= oldAddress) - { - KMemoryInfo info = _owner.MemoryManager.QueryMemory(address); - - if (info.State == MemoryState.Reserved) - { - break; - } - - if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute) - { - LoadMod0Symbols(_owner.CpuMemory, info.Address, info.Size); - } - - oldAddress = address; - - address = info.Address + info.Size; - } - } - - private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset, ulong textSize) - { - ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4); - - if (mod0Offset < textOffset || !memory.IsMapped(mod0Offset) || (mod0Offset & 3) != 0) - { - return; - } - - Dictionary<ElfDynamicTag, ulong> dynamic = new Dictionary<ElfDynamicTag, ulong>(); - - int mod0Magic = memory.Read<int>(mod0Offset + 0x0); - - if (mod0Magic != Mod0) - { - return; - } - - ulong dynamicOffset = memory.Read<uint>(mod0Offset + 0x4) + mod0Offset; - ulong bssStartOffset = memory.Read<uint>(mod0Offset + 0x8) + mod0Offset; - ulong bssEndOffset = memory.Read<uint>(mod0Offset + 0xc) + mod0Offset; - ulong ehHdrStartOffset = memory.Read<uint>(mod0Offset + 0x10) + mod0Offset; - ulong ehHdrEndOffset = memory.Read<uint>(mod0Offset + 0x14) + mod0Offset; - ulong modObjOffset = memory.Read<uint>(mod0Offset + 0x18) + mod0Offset; - - bool isAArch32 = memory.Read<ulong>(dynamicOffset) > 0xFFFFFFFF || memory.Read<ulong>(dynamicOffset + 0x10) > 0xFFFFFFFF; - - while (true) - { - ulong tagVal; - ulong value; - - if (isAArch32) - { - tagVal = memory.Read<uint>(dynamicOffset + 0); - value = memory.Read<uint>(dynamicOffset + 4); - - dynamicOffset += 0x8; - } - else - { - tagVal = memory.Read<ulong>(dynamicOffset + 0); - value = memory.Read<ulong>(dynamicOffset + 8); - - dynamicOffset += 0x10; - } - - ElfDynamicTag tag = (ElfDynamicTag)tagVal; - - if (tag == ElfDynamicTag.DT_NULL) - { - break; - } - - dynamic[tag] = value; - } - - if (!dynamic.TryGetValue(ElfDynamicTag.DT_STRTAB, out ulong strTab) || - !dynamic.TryGetValue(ElfDynamicTag.DT_SYMTAB, out ulong symTab) || - !dynamic.TryGetValue(ElfDynamicTag.DT_SYMENT, out ulong symEntSize)) - { - return; - } - - ulong strTblAddr = textOffset + strTab; - ulong symTblAddr = textOffset + symTab; - - List<ElfSymbol> symbols = new List<ElfSymbol>(); - - while (symTblAddr < strTblAddr) - { - ElfSymbol sym = isAArch32 ? GetSymbol32(memory, symTblAddr, strTblAddr) : GetSymbol64(memory, symTblAddr, strTblAddr); - - symbols.Add(sym); - - symTblAddr += symEntSize; - } - - lock (_images) - { - _images.Add(new Image(textOffset, textSize, symbols.OrderBy(x => x.Value).ToArray())); - } - } - - private ElfSymbol GetSymbol64(IVirtualMemoryManager memory, ulong address, ulong strTblAddr) - { - ElfSymbol64 sym = memory.Read<ElfSymbol64>(address); - - uint nameIndex = sym.NameOffset; - - string name = string.Empty; - - for (int chr; (chr = memory.Read<byte>(strTblAddr + nameIndex++)) != 0;) - { - name += (char)chr; - } - - return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size); - } - - private ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr) - { - ElfSymbol32 sym = memory.Read<ElfSymbol32>(address); - - uint nameIndex = sym.NameOffset; - - string name = string.Empty; - - for (int chr; (chr = memory.Read<byte>(strTblAddr + nameIndex++)) != 0;) - { - name += (char)chr; - } - - return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size); - } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs deleted file mode 100644 index c8063a62..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Ryujinx.Cpu; -using Ryujinx.Memory; -using System; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - interface IProcessContext : IDisposable - { - IVirtualMemoryManager AddressSpace { get; } - - IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks); - void Execute(IExecutionContext context, ulong codeAddress); - void InvalidateCacheRegion(ulong address, ulong size); - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs deleted file mode 100644 index 0a24a524..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ryujinx.Memory; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - interface IProcessContextFactory - { - IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit); - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KContextIdManager.cs b/Ryujinx.HLE/HOS/Kernel/Process/KContextIdManager.cs deleted file mode 100644 index 104fe578..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KContextIdManager.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Numerics; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KContextIdManager - { - private const int IdMasksCount = 8; - - private int[] _idMasks; - - private int _nextFreeBitHint; - - public KContextIdManager() - { - _idMasks = new int[IdMasksCount]; - } - - public int GetId() - { - lock (_idMasks) - { - int id = 0; - - if (!TestBit(_nextFreeBitHint)) - { - id = _nextFreeBitHint; - } - else - { - for (int index = 0; index < IdMasksCount; index++) - { - int mask = _idMasks[index]; - - int firstFreeBit = BitOperations.LeadingZeroCount((uint)((mask + 1) & ~mask)); - - if (firstFreeBit < 32) - { - int baseBit = index * 32 + 31; - - id = baseBit - firstFreeBit; - - break; - } - else if (index == IdMasksCount - 1) - { - throw new InvalidOperationException("Maximum number of Ids reached!"); - } - } - } - - _nextFreeBitHint = id + 1; - - SetBit(id); - - return id; - } - } - - public void PutId(int id) - { - lock (_idMasks) - { - ClearBit(id); - } - } - - private bool TestBit(int bit) - { - return (_idMasks[_nextFreeBitHint / 32] & (1 << (_nextFreeBitHint & 31))) != 0; - } - - private void SetBit(int bit) - { - _idMasks[_nextFreeBitHint / 32] |= (1 << (_nextFreeBitHint & 31)); - } - - private void ClearBit(int bit) - { - _idMasks[_nextFreeBitHint / 32] &= ~(1 << (_nextFreeBitHint & 31)); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KHandleEntry.cs b/Ryujinx.HLE/HOS/Kernel/Process/KHandleEntry.cs deleted file mode 100644 index b5ca9b5e..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KHandleEntry.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Common; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KHandleEntry - { - public KHandleEntry Next { get; set; } - - public int Index { get; private set; } - - public ushort HandleId { get; set; } - public KAutoObject Obj { get; set; } - - public KHandleEntry(int index) - { - Index = index; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs deleted file mode 100644 index 50f04e90..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs +++ /dev/null @@ -1,285 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using System; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KHandleTable - { - public const int SelfThreadHandle = (0x1ffff << 15) | 0; - public const int SelfProcessHandle = (0x1ffff << 15) | 1; - - private readonly KernelContext _context; - - private KHandleEntry[] _table; - - private KHandleEntry _tableHead; - private KHandleEntry _nextFreeEntry; - - private int _activeSlotsCount; - - private uint _size; - - private ushort _idCounter; - - public KHandleTable(KernelContext context) - { - _context = context; - } - - public Result Initialize(uint size) - { - if (size > 1024) - { - return KernelResult.OutOfMemory; - } - - if (size < 1) - { - size = 1024; - } - - _size = size; - - _idCounter = 1; - - _table = new KHandleEntry[size]; - - _tableHead = new KHandleEntry(0); - - KHandleEntry entry = _tableHead; - - for (int index = 0; index < size; index++) - { - _table[index] = entry; - - entry.Next = new KHandleEntry(index + 1); - - entry = entry.Next; - } - - _table[size - 1].Next = null; - - _nextFreeEntry = _tableHead; - - return Result.Success; - } - - public Result GenerateHandle(KAutoObject obj, out int handle) - { - handle = 0; - - lock (_table) - { - if (_activeSlotsCount >= _size) - { - return KernelResult.HandleTableFull; - } - - KHandleEntry entry = _nextFreeEntry; - - _nextFreeEntry = entry.Next; - - entry.Obj = obj; - entry.HandleId = _idCounter; - - _activeSlotsCount++; - - handle = (_idCounter << 15) | entry.Index; - - obj.IncrementReferenceCount(); - - if ((short)(_idCounter + 1) >= 0) - { - _idCounter++; - } - else - { - _idCounter = 1; - } - } - - return Result.Success; - } - - public Result ReserveHandle(out int handle) - { - handle = 0; - - lock (_table) - { - if (_activeSlotsCount >= _size) - { - return KernelResult.HandleTableFull; - } - - KHandleEntry entry = _nextFreeEntry; - - _nextFreeEntry = entry.Next; - - _activeSlotsCount++; - - handle = (_idCounter << 15) | entry.Index; - - if ((short)(_idCounter + 1) >= 0) - { - _idCounter++; - } - else - { - _idCounter = 1; - } - } - - return Result.Success; - } - - public void CancelHandleReservation(int handle) - { - int index = (handle >> 0) & 0x7fff; - - lock (_table) - { - KHandleEntry entry = _table[index]; - - entry.Obj = null; - entry.Next = _nextFreeEntry; - - _nextFreeEntry = entry; - - _activeSlotsCount--; - } - } - - public void SetReservedHandleObj(int handle, KAutoObject obj) - { - int index = (handle >> 0) & 0x7fff; - int handleId = (handle >> 15); - - lock (_table) - { - KHandleEntry entry = _table[index]; - - entry.Obj = obj; - entry.HandleId = (ushort)handleId; - - obj.IncrementReferenceCount(); - } - } - - public bool CloseHandle(int handle) - { - if ((handle >> 30) != 0 || - handle == SelfThreadHandle || - handle == SelfProcessHandle) - { - return false; - } - - int index = (handle >> 0) & 0x7fff; - int handleId = (handle >> 15); - - KAutoObject obj = null; - - bool result = false; - - lock (_table) - { - if (handleId != 0 && index < _size) - { - KHandleEntry entry = _table[index]; - - if ((obj = entry.Obj) != null && entry.HandleId == handleId) - { - entry.Obj = null; - entry.Next = _nextFreeEntry; - - _nextFreeEntry = entry; - - _activeSlotsCount--; - - result = true; - } - } - } - - if (result) - { - obj.DecrementReferenceCount(); - } - - return result; - } - - public T GetObject<T>(int handle) where T : KAutoObject - { - int index = (handle >> 0) & 0x7fff; - int handleId = (handle >> 15); - - lock (_table) - { - if ((handle >> 30) == 0 && handleId != 0 && index < _size) - { - KHandleEntry entry = _table[index]; - - if (entry.HandleId == handleId && entry.Obj is T obj) - { - return obj; - } - } - } - - return default; - } - - public KThread GetKThread(int handle) - { - if (handle == SelfThreadHandle) - { - return KernelStatic.GetCurrentThread(); - } - else - { - return GetObject<KThread>(handle); - } - } - - public KProcess GetKProcess(int handle) - { - if (handle == SelfProcessHandle) - { - return KernelStatic.GetCurrentProcess(); - } - else - { - return GetObject<KProcess>(handle); - } - } - - public void Destroy() - { - lock (_table) - { - for (int index = 0; index < _size; index++) - { - KHandleEntry entry = _table[index]; - - if (entry.Obj != null) - { - if (entry.Obj is IDisposable disposableObj) - { - disposableObj.Dispose(); - } - - entry.Obj.DecrementReferenceCount(); - entry.Obj = null; - entry.Next = _nextFreeEntry; - - _nextFreeEntry = entry; - } - } - } - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs deleted file mode 100644 index 21e89944..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ /dev/null @@ -1,1196 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.Exceptions; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using Ryujinx.Memory; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KProcess : KSynchronizationObject - { - public const uint KernelVersionMajor = 10; - public const uint KernelVersionMinor = 4; - public const uint KernelVersionRevision = 0; - - public const uint KernelVersionPacked = - (KernelVersionMajor << 19) | - (KernelVersionMinor << 15) | - (KernelVersionRevision << 0); - - public KPageTableBase MemoryManager { get; private set; } - - private SortedDictionary<ulong, KTlsPageInfo> _fullTlsPages; - private SortedDictionary<ulong, KTlsPageInfo> _freeTlsPages; - - public int DefaultCpuCore { get; set; } - - public bool Debug { get; private set; } - - public KResourceLimit ResourceLimit { get; private set; } - - public ulong PersonalMmHeapPagesCount { get; private set; } - - public ProcessState State { get; private set; } - - private object _processLock; - private object _threadingLock; - - public KAddressArbiter AddressArbiter { get; private set; } - - public ulong[] RandomEntropy { get; private set; } - public KThread[] PinnedThreads { get; private set; } - - private bool _signaled; - - public string Name { get; private set; } - - private int _threadCount; - - public ProcessCreationFlags Flags { get; private set; } - - private MemoryRegion _memRegion; - - public KProcessCapabilities Capabilities { get; private set; } - - public bool AllowCodeMemoryForJit { get; private set; } - - public ulong TitleId { get; private set; } - public bool IsApplication { get; private set; } - public ulong Pid { get; private set; } - - private long _creationTimestamp; - private ulong _entrypoint; - private ThreadStart _customThreadStart; - private ulong _imageSize; - private ulong _mainThreadStackSize; - private ulong _memoryUsageCapacity; - private int _version; - - public KHandleTable HandleTable { get; private set; } - - public ulong UserExceptionContextAddress { get; private set; } - - private LinkedList<KThread> _threads; - - public bool IsPaused { get; private set; } - - private long _totalTimeRunning; - - public long TotalTimeRunning => _totalTimeRunning; - - private IProcessContextFactory _contextFactory; - public IProcessContext Context { get; private set; } - public IVirtualMemoryManager CpuMemory => Context.AddressSpace; - - public HleProcessDebugger Debugger { get; private set; } - - public KProcess(KernelContext context, bool allowCodeMemoryForJit = false) : base(context) - { - _processLock = new object(); - _threadingLock = new object(); - - AddressArbiter = new KAddressArbiter(context); - - _fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>(); - _freeTlsPages = new SortedDictionary<ulong, KTlsPageInfo>(); - - Capabilities = new KProcessCapabilities(); - - AllowCodeMemoryForJit = allowCodeMemoryForJit; - - RandomEntropy = new ulong[KScheduler.CpuCoresCount]; - PinnedThreads = new KThread[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); - } - - public Result InitializeKip( - ProcessCreationInfo creationInfo, - ReadOnlySpan<uint> capabilities, - KPageList pageList, - KResourceLimit resourceLimit, - MemoryRegion memRegion, - IProcessContextFactory contextFactory, - ThreadStart customThreadStart = null) - { - ResourceLimit = resourceLimit; - _memRegion = memRegion; - _contextFactory = contextFactory ?? new ProcessContextFactory(); - _customThreadStart = customThreadStart; - - AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - - Pid = KernelContext.NewKipId(); - - if (Pid == 0 || Pid >= KernelConstants.InitialProcessId) - { - throw new InvalidOperationException($"Invalid KIP Id {Pid}."); - } - - InitializeMemoryManager(creationInfo.Flags); - - bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); - - ulong codeAddress = creationInfo.CodeAddress; - - ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; - - KMemoryBlockSlabManager slabManager = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) - ? KernelContext.LargeMemoryBlockSlabManager - : KernelContext.SmallMemoryBlockSlabManager; - - Result result = MemoryManager.InitializeForProcess( - addrSpaceType, - aslrEnabled, - !aslrEnabled, - memRegion, - codeAddress, - codeSize, - slabManager); - - if (result != Result.Success) - { - return result; - } - - if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) - { - return KernelResult.InvalidMemRange; - } - - result = MemoryManager.MapPages(codeAddress, pageList, MemoryState.CodeStatic, KMemoryPermission.None); - - if (result != Result.Success) - { - return result; - } - - result = Capabilities.InitializeForKernel(capabilities, MemoryManager); - - if (result != Result.Success) - { - return result; - } - - return ParseProcessInfo(creationInfo); - } - - public Result Initialize( - ProcessCreationInfo creationInfo, - ReadOnlySpan<uint> capabilities, - KResourceLimit resourceLimit, - MemoryRegion memRegion, - IProcessContextFactory contextFactory, - ThreadStart customThreadStart = null) - { - ResourceLimit = resourceLimit; - _memRegion = memRegion; - _contextFactory = contextFactory ?? new ProcessContextFactory(); - _customThreadStart = customThreadStart; - IsApplication = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication); - - ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion); - - ulong codePagesCount = (ulong)creationInfo.CodePagesCount; - - ulong neededSizeForProcess = personalMmHeapSize + codePagesCount * KPageTableBase.PageSize; - - if (neededSizeForProcess != 0 && resourceLimit != null) - { - if (!resourceLimit.Reserve(LimitableResource.Memory, neededSizeForProcess)) - { - return KernelResult.ResLimitExceeded; - } - } - - void CleanUpForError() - { - if (neededSizeForProcess != 0 && resourceLimit != null) - { - resourceLimit.Release(LimitableResource.Memory, neededSizeForProcess); - } - } - - PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount; - - KMemoryBlockSlabManager slabManager; - - if (PersonalMmHeapPagesCount != 0) - { - slabManager = new KMemoryBlockSlabManager(PersonalMmHeapPagesCount * KPageTableBase.PageSize); - } - else - { - slabManager = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) - ? KernelContext.LargeMemoryBlockSlabManager - : KernelContext.SmallMemoryBlockSlabManager; - } - - AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - - Pid = KernelContext.NewProcessId(); - - if (Pid == ulong.MaxValue || Pid < KernelConstants.InitialProcessId) - { - throw new InvalidOperationException($"Invalid Process Id {Pid}."); - } - - InitializeMemoryManager(creationInfo.Flags); - - bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); - - ulong codeAddress = creationInfo.CodeAddress; - - ulong codeSize = codePagesCount * KPageTableBase.PageSize; - - Result result = MemoryManager.InitializeForProcess( - addrSpaceType, - aslrEnabled, - !aslrEnabled, - memRegion, - codeAddress, - codeSize, - slabManager); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) - { - CleanUpForError(); - - return KernelResult.InvalidMemRange; - } - - result = MemoryManager.MapPages( - codeAddress, - codePagesCount, - MemoryState.CodeStatic, - KMemoryPermission.None); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - result = Capabilities.InitializeForUser(capabilities, MemoryManager); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - result = ParseProcessInfo(creationInfo); - - if (result != Result.Success) - { - CleanUpForError(); - } - - return result; - } - - private Result ParseProcessInfo(ProcessCreationInfo creationInfo) - { - // Ensure that the current kernel version is equal or above to the minimum required. - uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; - uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf; - - if (KernelContext.EnableVersionChecks) - { - if (requiredKernelVersionMajor > KernelVersionMajor) - { - return KernelResult.InvalidCombination; - } - - if (requiredKernelVersionMajor != KernelVersionMajor && requiredKernelVersionMajor < 3) - { - return KernelResult.InvalidCombination; - } - - if (requiredKernelVersionMinor > KernelVersionMinor) - { - return KernelResult.InvalidCombination; - } - } - - Result result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress); - - if (result != Result.Success) - { - return result; - } - - UserExceptionContextAddress = userExceptionContextAddress; - - MemoryHelper.FillWithZeros(CpuMemory, userExceptionContextAddress, KTlsPageInfo.TlsEntrySize); - - Name = creationInfo.Name; - - State = ProcessState.Created; - - _creationTimestamp = PerformanceCounter.ElapsedMilliseconds; - - Flags = creationInfo.Flags; - _version = creationInfo.Version; - TitleId = creationInfo.TitleId; - _entrypoint = creationInfo.CodeAddress; - _imageSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; - - switch (Flags & ProcessCreationFlags.AddressSpaceMask) - { - case ProcessCreationFlags.AddressSpace32Bit: - case ProcessCreationFlags.AddressSpace64BitDeprecated: - case ProcessCreationFlags.AddressSpace64Bit: - _memoryUsageCapacity = MemoryManager.HeapRegionEnd - - MemoryManager.HeapRegionStart; - break; - - case ProcessCreationFlags.AddressSpace32BitWithoutAlias: - _memoryUsageCapacity = MemoryManager.HeapRegionEnd - - MemoryManager.HeapRegionStart + - MemoryManager.AliasRegionEnd - - MemoryManager.AliasRegionStart; - break; - - default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}."); - } - - GenerateRandomEntropy(); - - return Result.Success; - } - - public Result AllocateThreadLocalStorage(out ulong address) - { - KernelContext.CriticalSection.Enter(); - - Result result; - - if (_freeTlsPages.Count > 0) - { - // If we have free TLS pages available, just use the first one. - KTlsPageInfo pageInfo = _freeTlsPages.Values.First(); - - if (!pageInfo.TryGetFreePage(out address)) - { - throw new InvalidOperationException("Unexpected failure getting free TLS page!"); - } - - if (pageInfo.IsFull()) - { - _freeTlsPages.Remove(pageInfo.PageVirtualAddress); - - _fullTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo); - } - - result = Result.Success; - } - else - { - // Otherwise, we need to create a new one. - result = AllocateTlsPage(out KTlsPageInfo pageInfo); - - if (result == Result.Success) - { - if (!pageInfo.TryGetFreePage(out address)) - { - throw new InvalidOperationException("Unexpected failure getting free TLS page!"); - } - - _freeTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo); - } - else - { - address = 0; - } - } - - KernelContext.CriticalSection.Leave(); - - return result; - } - - private Result AllocateTlsPage(out KTlsPageInfo pageInfo) - { - pageInfo = default; - - if (!KernelContext.UserSlabHeapPages.TryGetItem(out ulong tlsPagePa)) - { - return KernelResult.OutOfMemory; - } - - ulong regionStart = MemoryManager.TlsIoRegionStart; - ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; - - ulong regionPagesCount = regionSize / KPageTableBase.PageSize; - - Result result = MemoryManager.MapPages( - 1, - KPageTableBase.PageSize, - tlsPagePa, - true, - regionStart, - regionPagesCount, - MemoryState.ThreadLocal, - KMemoryPermission.ReadAndWrite, - out ulong tlsPageVa); - - if (result != Result.Success) - { - KernelContext.UserSlabHeapPages.Free(tlsPagePa); - } - else - { - pageInfo = new KTlsPageInfo(tlsPageVa, tlsPagePa); - - MemoryHelper.FillWithZeros(CpuMemory, tlsPageVa, KPageTableBase.PageSize); - } - - return result; - } - - public Result FreeThreadLocalStorage(ulong tlsSlotAddr) - { - ulong tlsPageAddr = BitUtils.AlignDown<ulong>(tlsSlotAddr, KPageTableBase.PageSize); - - KernelContext.CriticalSection.Enter(); - - Result result = Result.Success; - - KTlsPageInfo pageInfo; - - if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) - { - // TLS page was full, free slot and move to free pages tree. - _fullTlsPages.Remove(tlsPageAddr); - - _freeTlsPages.Add(tlsPageAddr, pageInfo); - } - else if (!_freeTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) - { - result = KernelResult.InvalidAddress; - } - - if (pageInfo != null) - { - pageInfo.FreeTlsSlot(tlsSlotAddr); - - if (pageInfo.IsEmpty()) - { - // TLS page is now empty, we should ensure it is removed - // from all trees, and free the memory it was using. - _freeTlsPages.Remove(tlsPageAddr); - - KernelContext.CriticalSection.Leave(); - - FreeTlsPage(pageInfo); - - return Result.Success; - } - } - - KernelContext.CriticalSection.Leave(); - - return result; - } - - private Result FreeTlsPage(KTlsPageInfo pageInfo) - { - Result result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal); - - if (result == Result.Success) - { - KernelContext.UserSlabHeapPages.Free(pageInfo.PagePhysicalAddress); - } - - return result; - } - - private void GenerateRandomEntropy() - { - // TODO. - } - - public Result Start(int mainThreadPriority, ulong stackSize) - { - lock (_processLock) - { - if (State > ProcessState.CreatedAttached) - { - return KernelResult.InvalidState; - } - - if (ResourceLimit != null && !ResourceLimit.Reserve(LimitableResource.Thread, 1)) - { - return KernelResult.ResLimitExceeded; - } - - KResourceLimit threadResourceLimit = ResourceLimit; - KResourceLimit memoryResourceLimit = null; - - if (_mainThreadStackSize != 0) - { - throw new InvalidOperationException("Trying to start a process with a invalid state!"); - } - - ulong stackSizeRounded = BitUtils.AlignUp<ulong>(stackSize, KPageTableBase.PageSize); - - ulong neededSize = stackSizeRounded + _imageSize; - - // 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) - { - threadResourceLimit?.Release(LimitableResource.Thread, 1); - - return KernelResult.OutOfMemory; - } - - if (stackSizeRounded != 0 && ResourceLimit != null) - { - memoryResourceLimit = ResourceLimit; - - if (!memoryResourceLimit.Reserve(LimitableResource.Memory, stackSizeRounded)) - { - threadResourceLimit?.Release(LimitableResource.Thread, 1); - - return KernelResult.ResLimitExceeded; - } - } - - Result result; - - KThread mainThread = null; - - ulong stackTop = 0; - - void CleanUpForError() - { - HandleTable.Destroy(); - - mainThread?.DecrementReferenceCount(); - - if (_mainThreadStackSize != 0) - { - ulong stackBottom = stackTop - _mainThreadStackSize; - - ulong stackPagesCount = _mainThreadStackSize / KPageTableBase.PageSize; - - MemoryManager.UnmapForKernel(stackBottom, stackPagesCount, MemoryState.Stack); - - _mainThreadStackSize = 0; - } - - memoryResourceLimit?.Release(LimitableResource.Memory, stackSizeRounded); - threadResourceLimit?.Release(LimitableResource.Thread, 1); - } - - if (stackSizeRounded != 0) - { - ulong stackPagesCount = stackSizeRounded / KPageTableBase.PageSize; - - ulong regionStart = MemoryManager.StackRegionStart; - ulong regionSize = MemoryManager.StackRegionEnd - regionStart; - - ulong regionPagesCount = regionSize / KPageTableBase.PageSize; - - result = MemoryManager.MapPages( - stackPagesCount, - KPageTableBase.PageSize, - 0, - false, - regionStart, - regionPagesCount, - MemoryState.Stack, - KMemoryPermission.ReadAndWrite, - out ulong stackBottom); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - _mainThreadStackSize += stackSizeRounded; - - stackTop = stackBottom + stackSizeRounded; - } - - ulong heapCapacity = _memoryUsageCapacity - _mainThreadStackSize - _imageSize; - - result = MemoryManager.SetHeapCapacity(heapCapacity); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - HandleTable = new KHandleTable(KernelContext); - - result = HandleTable.Initialize(Capabilities.HandleTableSize); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - mainThread = new KThread(KernelContext); - - result = mainThread.Initialize( - _entrypoint, - 0, - stackTop, - mainThreadPriority, - DefaultCpuCore, - this, - ThreadType.User, - _customThreadStart); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - mainThread.SetEntryArguments(0, mainThreadHandle); - - ProcessState oldState = State; - ProcessState newState = State != ProcessState.Created - ? ProcessState.Attached - : ProcessState.Started; - - SetState(newState); - - result = mainThread.Start(); - - if (result != Result.Success) - { - SetState(oldState); - - CleanUpForError(); - } - - if (result == Result.Success) - { - mainThread.IncrementReferenceCount(); - } - - mainThread.DecrementReferenceCount(); - - return result; - } - } - - private void SetState(ProcessState newState) - { - if (State != newState) - { - State = newState; - _signaled = true; - - Signal(); - } - } - - public Result InitializeThread( - KThread thread, - ulong entrypoint, - ulong argsPtr, - ulong stackTop, - int priority, - int cpuCore, - ThreadStart customThreadStart = null) - { - lock (_processLock) - { - return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, customThreadStart); - } - } - - public IExecutionContext CreateExecutionContext() - { - return Context?.CreateExecutionContext(new ExceptionCallbacks( - InterruptHandler, - null, - KernelContext.SyscallHandler.SvcCall, - UndefinedInstructionHandler)); - } - - private void InterruptHandler(IExecutionContext context) - { - KThread currentThread = KernelStatic.GetCurrentThread(); - - if (currentThread.Context.Running && - currentThread.Owner != null && - currentThread.GetUserDisableCount() != 0 && - currentThread.Owner.PinnedThreads[currentThread.CurrentCore] == null) - { - KernelContext.CriticalSection.Enter(); - - currentThread.Owner.PinThread(currentThread); - - currentThread.SetUserInterruptFlag(); - - KernelContext.CriticalSection.Leave(); - } - - if (currentThread.IsSchedulable) - { - KernelContext.Schedulers[currentThread.CurrentCore].Schedule(); - } - - currentThread.HandlePostSyscall(); - } - - public void IncrementThreadCount() - { - Interlocked.Increment(ref _threadCount); - } - - public void DecrementThreadCountAndTerminateIfZero() - { - if (Interlocked.Decrement(ref _threadCount) == 0) - { - Terminate(); - } - } - - public void DecrementToZeroWhileTerminatingCurrent() - { - while (Interlocked.Decrement(ref _threadCount) != 0) - { - Destroy(); - TerminateCurrentProcess(); - } - - // Nintendo panic here because if it reaches this point, the current thread should be already dead. - // As we handle the death of the thread in the post SVC handler and inside the CPU emulator, we don't panic here. - } - - public ulong GetMemoryCapacity() - { - ulong totalCapacity = (ulong)ResourceLimit.GetRemainingValue(LimitableResource.Memory); - - totalCapacity += MemoryManager.GetTotalHeapSize(); - - totalCapacity += GetPersonalMmHeapSize(); - - totalCapacity += _imageSize + _mainThreadStackSize; - - if (totalCapacity <= _memoryUsageCapacity) - { - return totalCapacity; - } - - return _memoryUsageCapacity; - } - - public ulong GetMemoryUsage() - { - return _imageSize + _mainThreadStackSize + MemoryManager.GetTotalHeapSize() + GetPersonalMmHeapSize(); - } - - public ulong GetMemoryCapacityWithoutPersonalMmHeap() - { - return GetMemoryCapacity() - GetPersonalMmHeapSize(); - } - - public ulong GetMemoryUsageWithoutPersonalMmHeap() - { - return GetMemoryUsage() - GetPersonalMmHeapSize(); - } - - private ulong GetPersonalMmHeapSize() - { - return GetPersonalMmHeapSize(PersonalMmHeapPagesCount, _memRegion); - } - - private static ulong GetPersonalMmHeapSize(ulong personalMmHeapPagesCount, MemoryRegion memRegion) - { - if (memRegion == MemoryRegion.Applet) - { - return 0; - } - - return personalMmHeapPagesCount * KPageTableBase.PageSize; - } - - public void AddCpuTime(long ticks) - { - Interlocked.Add(ref _totalTimeRunning, ticks); - } - - public void AddThread(KThread thread) - { - lock (_threadingLock) - { - thread.ProcessListNode = _threads.AddLast(thread); - } - } - - public void RemoveThread(KThread thread) - { - lock (_threadingLock) - { - _threads.Remove(thread.ProcessListNode); - } - } - - public bool IsCpuCoreAllowed(int core) - { - return (Capabilities.AllowedCpuCoresMask & (1UL << core)) != 0; - } - - public bool IsPriorityAllowed(int priority) - { - return (Capabilities.AllowedThreadPriosMask & (1UL << priority)) != 0; - } - - public override bool IsSignaled() - { - return _signaled; - } - - public Result Terminate() - { - Result result; - - bool shallTerminate = false; - - KernelContext.CriticalSection.Enter(); - - lock (_processLock) - { - if (State >= ProcessState.Started) - { - if (State == ProcessState.Started || - State == ProcessState.Crashed || - State == ProcessState.Attached || - State == ProcessState.DebugSuspended) - { - SetState(ProcessState.Exiting); - - shallTerminate = true; - } - - result = Result.Success; - } - else - { - result = KernelResult.InvalidState; - } - } - - KernelContext.CriticalSection.Leave(); - - if (shallTerminate) - { - UnpauseAndTerminateAllThreadsExcept(KernelStatic.GetCurrentThread()); - - HandleTable.Destroy(); - - SignalExitToDebugTerminated(); - SignalExit(); - } - - return result; - } - - public void TerminateCurrentProcess() - { - bool shallTerminate = false; - - KernelContext.CriticalSection.Enter(); - - lock (_processLock) - { - if (State >= ProcessState.Started) - { - if (State == ProcessState.Started || - State == ProcessState.Attached || - State == ProcessState.DebugSuspended) - { - SetState(ProcessState.Exiting); - - shallTerminate = true; - } - } - } - - KernelContext.CriticalSection.Leave(); - - if (shallTerminate) - { - UnpauseAndTerminateAllThreadsExcept(KernelStatic.GetCurrentThread()); - - HandleTable.Destroy(); - - // NOTE: this is supposed to be called in receiving of the mailbox. - SignalExitToDebugExited(); - SignalExit(); - } - - KernelStatic.GetCurrentThread().Exit(); - } - - private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread) - { - lock (_threadingLock) - { - KernelContext.CriticalSection.Enter(); - - if (currentThread != null && PinnedThreads[currentThread.CurrentCore] == currentThread) - { - UnpinThread(currentThread); - } - - foreach (KThread thread in _threads) - { - if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending) - { - thread.PrepareForTermination(); - } - } - - KernelContext.CriticalSection.Leave(); - } - - while (true) - { - KThread blockedThread = null; - - lock (_threadingLock) - { - foreach (KThread thread in _threads) - { - if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending) - { - thread.IncrementReferenceCount(); - - blockedThread = thread; - break; - } - } - } - - if (blockedThread == null) - { - break; - } - - blockedThread.Terminate(); - blockedThread.DecrementReferenceCount(); - } - } - - private void SignalExitToDebugTerminated() - { - // TODO: Debug events. - } - - private void SignalExitToDebugExited() - { - // TODO: Debug events. - } - - private void SignalExit() - { - if (ResourceLimit != null) - { - ResourceLimit.Release(LimitableResource.Memory, GetMemoryUsage()); - } - - KernelContext.CriticalSection.Enter(); - - SetState(ProcessState.Exited); - - KernelContext.CriticalSection.Leave(); - } - - public Result ClearIfNotExited() - { - Result result; - - KernelContext.CriticalSection.Enter(); - - lock (_processLock) - { - if (State != ProcessState.Exited && _signaled) - { - _signaled = false; - - result = Result.Success; - } - else - { - result = KernelResult.InvalidState; - } - } - - KernelContext.CriticalSection.Leave(); - - return result; - } - - private void InitializeMemoryManager(ProcessCreationFlags flags) - { - int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch - { - ProcessCreationFlags.AddressSpace32Bit => 32, - ProcessCreationFlags.AddressSpace64BitDeprecated => 36, - ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32, - ProcessCreationFlags.AddressSpace64Bit => 39, - _ => 39 - }; - - bool for64Bit = flags.HasFlag(ProcessCreationFlags.Is64Bit); - - Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit); - - MemoryManager = new KPageTable(KernelContext, CpuMemory); - } - - private bool InvalidAccessHandler(ulong va) - { - KernelStatic.GetCurrentThread()?.PrintGuestStackTrace(); - KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout(); - - Logger.Error?.Print(LogClass.Cpu, $"Invalid memory access at virtual address 0x{va:X16}."); - - return false; - } - - private void UndefinedInstructionHandler(IExecutionContext context, ulong address, int opCode) - { - KernelStatic.GetCurrentThread().PrintGuestStackTrace(); - KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout(); - - throw new UndefinedInstructionException(address, opCode); - } - - protected override void Destroy() => Context.Dispose(); - - public Result SetActivity(bool pause) - { - KernelContext.CriticalSection.Enter(); - - if (State != ProcessState.Exiting && State != ProcessState.Exited) - { - if (pause) - { - if (IsPaused) - { - KernelContext.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - lock (_threadingLock) - { - foreach (KThread thread in _threads) - { - thread.Suspend(ThreadSchedState.ProcessPauseFlag); - } - } - - IsPaused = true; - } - else - { - if (!IsPaused) - { - KernelContext.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - lock (_threadingLock) - { - foreach (KThread thread in _threads) - { - thread.Resume(ThreadSchedState.ProcessPauseFlag); - } - } - - IsPaused = false; - } - - KernelContext.CriticalSection.Leave(); - - return Result.Success; - } - - KernelContext.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - public void PinThread(KThread thread) - { - if (!thread.TerminationRequested) - { - PinnedThreads[thread.CurrentCore] = thread; - - thread.Pin(); - - KernelContext.ThreadReselectionRequested = true; - } - } - - public void UnpinThread(KThread thread) - { - if (!thread.TerminationRequested) - { - thread.Unpin(); - - PinnedThreads[thread.CurrentCore] = null; - - KernelContext.ThreadReselectionRequested = true; - } - } - - public bool IsExceptionUserThread(KThread thread) - { - // TODO - return false; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs deleted file mode 100644 index c99e3112..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs +++ /dev/null @@ -1,328 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using System; -using System.Numerics; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KProcessCapabilities - { - public byte[] SvcAccessMask { get; } - public byte[] IrqAccessMask { get; } - - public ulong AllowedCpuCoresMask { get; private set; } - public ulong AllowedThreadPriosMask { get; private set; } - - public uint DebuggingFlags { get; private set; } - public uint HandleTableSize { get; private set; } - public uint KernelReleaseVersion { get; private set; } - public uint ApplicationType { get; private set; } - - public KProcessCapabilities() - { - // length / number of bits of the underlying type - SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / 8]; - IrqAccessMask = new byte[0x80]; - } - - public Result InitializeForKernel(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager) - { - AllowedCpuCoresMask = 0xf; - AllowedThreadPriosMask = ulong.MaxValue; - DebuggingFlags &= ~3u; - KernelReleaseVersion = KProcess.KernelVersionPacked; - - return Parse(capabilities, memoryManager); - } - - public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager) - { - return Parse(capabilities, memoryManager); - } - - private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager) - { - int mask0 = 0; - int mask1 = 0; - - for (int index = 0; index < capabilities.Length; index++) - { - uint cap = capabilities[index]; - - if (cap.GetCapabilityType() != CapabilityType.MapRange) - { - Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager); - - if (result != Result.Success) - { - return result; - } - } - else - { - if ((uint)index + 1 >= capabilities.Length) - { - return KernelResult.InvalidCombination; - } - - uint prevCap = cap; - - cap = capabilities[++index]; - - if (((cap + 1) & ~cap) != 0x40) - { - return KernelResult.InvalidCombination; - } - - if ((cap & 0x78000000) != 0) - { - return KernelResult.MaximumExceeded; - } - - if ((cap & 0x7ffff80) == 0) - { - return KernelResult.InvalidSize; - } - - long address = ((long)prevCap << 5) & 0xffffff000; - long size = ((long)cap << 5) & 0xfffff000; - - if (((ulong)(address + size - 1) >> 36) != 0) - { - return KernelResult.InvalidAddress; - } - - KMemoryPermission perm = (prevCap >> 31) != 0 - ? KMemoryPermission.Read - : KMemoryPermission.ReadAndWrite; - - Result result; - - if ((cap >> 31) != 0) - { - result = memoryManager.MapNormalMemory(address, size, perm); - } - else - { - result = memoryManager.MapIoMemory(address, size, perm); - } - - if (result != Result.Success) - { - return result; - } - } - } - - return Result.Success; - } - - private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager) - { - CapabilityType code = cap.GetCapabilityType(); - - if (code == CapabilityType.Invalid) - { - return KernelResult.InvalidCapability; - } - else if (code == CapabilityType.Padding) - { - return Result.Success; - } - - int codeMask = 1 << (32 - BitOperations.LeadingZeroCount(code.GetFlag() + 1)); - - // Check if the property was already set. - if (((mask0 & codeMask) & 0x1e008) != 0) - { - return KernelResult.InvalidCombination; - } - - mask0 |= codeMask; - - switch (code) - { - case CapabilityType.CorePriority: - { - if (AllowedCpuCoresMask != 0 || AllowedThreadPriosMask != 0) - { - return KernelResult.InvalidCapability; - } - - uint lowestCpuCore = (cap >> 16) & 0xff; - uint highestCpuCore = (cap >> 24) & 0xff; - - if (lowestCpuCore > highestCpuCore) - { - return KernelResult.InvalidCombination; - } - - uint highestThreadPrio = (cap >> 4) & 0x3f; - uint lowestThreadPrio = (cap >> 10) & 0x3f; - - if (lowestThreadPrio > highestThreadPrio) - { - return KernelResult.InvalidCombination; - } - - if (highestCpuCore >= KScheduler.CpuCoresCount) - { - return KernelResult.InvalidCpuCore; - } - - AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore); - AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio); - - break; - } - - case CapabilityType.SyscallMask: - { - int slot = ((int)cap >> 29) & 7; - - int svcSlotMask = 1 << slot; - - if ((mask1 & svcSlotMask) != 0) - { - return KernelResult.InvalidCombination; - } - - mask1 |= svcSlotMask; - - uint svcMask = (cap >> 5) & 0xffffff; - - int baseSvc = slot * 24; - - for (int index = 0; index < 24; index++) - { - if (((svcMask >> index) & 1) == 0) - { - continue; - } - - int svcId = baseSvc + index; - - if (svcId >= KernelConstants.SupervisorCallCount) - { - return KernelResult.MaximumExceeded; - } - - SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7)); - } - - break; - } - - case CapabilityType.MapIoPage: - { - long address = ((long)cap << 4) & 0xffffff000; - - memoryManager.MapIoMemory(address, KPageTableBase.PageSize, KMemoryPermission.ReadAndWrite); - - break; - } - - case CapabilityType.MapRegion: - { - // TODO: Implement capabilities for MapRegion - - break; - } - - case CapabilityType.InterruptPair: - { - // TODO: GIC distributor check. - int irq0 = ((int)cap >> 12) & 0x3ff; - int irq1 = ((int)cap >> 22) & 0x3ff; - - if (irq0 != 0x3ff) - { - IrqAccessMask[irq0 / 8] |= (byte)(1 << (irq0 & 7)); - } - - if (irq1 != 0x3ff) - { - IrqAccessMask[irq1 / 8] |= (byte)(1 << (irq1 & 7)); - } - - break; - } - - case CapabilityType.ProgramType: - { - uint applicationType = (cap >> 14); - - if (applicationType > 7) - { - return KernelResult.ReservedValue; - } - - ApplicationType = applicationType; - - break; - } - - case CapabilityType.KernelVersion: - { - // Note: This check is bugged on kernel too, we are just replicating the bug here. - if ((KernelReleaseVersion >> 17) != 0 || cap < 0x80000) - { - return KernelResult.ReservedValue; - } - - KernelReleaseVersion = cap; - - break; - } - - case CapabilityType.HandleTable: - { - uint handleTableSize = cap >> 26; - - if (handleTableSize > 0x3ff) - { - return KernelResult.ReservedValue; - } - - HandleTableSize = handleTableSize; - - break; - } - - case CapabilityType.DebugFlags: - { - uint debuggingFlags = cap >> 19; - - if (debuggingFlags > 3) - { - return KernelResult.ReservedValue; - } - - DebuggingFlags &= ~3u; - DebuggingFlags |= debuggingFlags; - - break; - } - - default: return KernelResult.InvalidCapability; - } - - return Result.Success; - } - - private static ulong GetMaskFromMinMax(uint min, uint max) - { - uint range = max - min + 1; - - if (range == 64) - { - return ulong.MaxValue; - } - - ulong mask = (1UL << (int)range) - 1; - - return mask << (int)min; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageInfo.cs deleted file mode 100644 index f55e3c10..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageInfo.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Memory; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KTlsPageInfo - { - public const int TlsEntrySize = 0x200; - - public ulong PageVirtualAddress { get; } - public ulong PagePhysicalAddress { get; } - - private readonly bool[] _isSlotFree; - - public KTlsPageInfo(ulong pageVirtualAddress, ulong pagePhysicalAddress) - { - PageVirtualAddress = pageVirtualAddress; - PagePhysicalAddress = pagePhysicalAddress; - - _isSlotFree = new bool[KPageTableBase.PageSize / TlsEntrySize]; - - for (int index = 0; index < _isSlotFree.Length; index++) - { - _isSlotFree[index] = true; - } - } - - public bool TryGetFreePage(out ulong address) - { - address = PageVirtualAddress; - - for (int index = 0; index < _isSlotFree.Length; index++) - { - if (_isSlotFree[index]) - { - _isSlotFree[index] = false; - - return true; - } - - address += TlsEntrySize; - } - - address = 0; - - return false; - } - - public bool IsFull() - { - bool hasFree = false; - - for (int index = 0; index < _isSlotFree.Length; index++) - { - hasFree |= _isSlotFree[index]; - } - - return !hasFree; - } - - public bool IsEmpty() - { - bool allFree = true; - - for (int index = 0; index < _isSlotFree.Length; index++) - { - allFree &= _isSlotFree[index]; - } - - return allFree; - } - - public void FreeTlsSlot(ulong address) - { - _isSlotFree[(address - PageVirtualAddress) / TlsEntrySize] = true; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageManager.cs b/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageManager.cs deleted file mode 100644 index 0fde495c..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageManager.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Memory; -using System; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KTlsPageManager - { - private const int TlsEntrySize = 0x200; - - private long _pagePosition; - - private int _usedSlots; - - private bool[] _slots; - - public bool IsEmpty => _usedSlots == 0; - public bool IsFull => _usedSlots == _slots.Length; - - public KTlsPageManager(long pagePosition) - { - _pagePosition = pagePosition; - - _slots = new bool[KPageTableBase.PageSize / TlsEntrySize]; - } - - public bool TryGetFreeTlsAddr(out long position) - { - position = _pagePosition; - - for (int index = 0; index < _slots.Length; index++) - { - if (!_slots[index]) - { - _slots[index] = true; - - _usedSlots++; - - return true; - } - - position += TlsEntrySize; - } - - position = 0; - - return false; - } - - public void FreeTlsSlot(int slot) - { - if ((uint)slot > _slots.Length) - { - throw new ArgumentOutOfRangeException(nameof(slot)); - } - - _slots[slot] = false; - - _usedSlots--; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs deleted file mode 100644 index 87296830..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Ryujinx.Cpu; -using Ryujinx.Memory; -using System; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class ProcessContext : IProcessContext - { - public IVirtualMemoryManager AddressSpace { get; } - - public ProcessContext(IVirtualMemoryManager asManager) - { - AddressSpace = asManager; - } - - public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks) - { - return new ProcessExecutionContext(); - } - - public void Execute(IExecutionContext context, ulong codeAddress) - { - throw new NotSupportedException(); - } - - public void InvalidateCacheRegion(ulong address, ulong size) - { - } - - public void Dispose() - { - } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs deleted file mode 100644 index 1c5798b4..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ryujinx.Memory; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class ProcessContextFactory : IProcessContextFactory - { - public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit) - { - return new ProcessContext(new AddressSpaceManager(context.Memory, addressSpaceSize)); - } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs deleted file mode 100644 index a79978ac..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - [Flags] - enum ProcessCreationFlags - { - Is64Bit = 1 << 0, - - AddressSpaceShift = 1, - AddressSpace32Bit = 0 << AddressSpaceShift, - AddressSpace64BitDeprecated = 1 << AddressSpaceShift, - AddressSpace32BitWithoutAlias = 2 << AddressSpaceShift, - AddressSpace64Bit = 3 << AddressSpaceShift, - AddressSpaceMask = 7 << AddressSpaceShift, - - EnableDebug = 1 << 4, - EnableAslr = 1 << 5, - IsApplication = 1 << 6, - DeprecatedUseSecureMemory = 1 << 7, - - PoolPartitionShift = 7, - PoolPartitionApplication = 0 << PoolPartitionShift, - PoolPartitionApplet = 1 << PoolPartitionShift, - PoolPartitionSystem = 2 << PoolPartitionShift, - PoolPartitionSystemNonSecure = 3 << PoolPartitionShift, - PoolPartitionMask = 0xf << PoolPartitionShift, - - OptimizeMemoryAllocation = 1 << 11, - - All = - Is64Bit | - AddressSpaceMask | - EnableDebug | - EnableAslr | - IsApplication | - DeprecatedUseSecureMemory | - PoolPartitionMask | - OptimizeMemoryAllocation - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs deleted file mode 100644 index c05bb574..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - readonly struct ProcessCreationInfo - { - public string Name { get; } - - public int Version { get; } - public ulong TitleId { get; } - - public ulong CodeAddress { get; } - public int CodePagesCount { get; } - - public ProcessCreationFlags Flags { get; } - public int ResourceLimitHandle { get; } - public int SystemResourcePagesCount { get; } - - public ProcessCreationInfo( - string name, - int version, - ulong titleId, - ulong codeAddress, - int codePagesCount, - ProcessCreationFlags flags, - int resourceLimitHandle, - int systemResourcePagesCount) - { - Name = name; - Version = version; - TitleId = titleId; - CodeAddress = codeAddress; - CodePagesCount = codePagesCount; - Flags = flags; - ResourceLimitHandle = resourceLimitHandle; - SystemResourcePagesCount = systemResourcePagesCount; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs deleted file mode 100644 index 77fcdf33..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs +++ /dev/null @@ -1,46 +0,0 @@ -using ARMeilleure.State; -using Ryujinx.Cpu; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class ProcessExecutionContext : IExecutionContext - { - public ulong Pc => 0UL; - - public ulong CntfrqEl0 { get; set; } - public ulong CntpctEl0 => 0UL; - - public long TpidrEl0 { get; set; } - public long TpidrroEl0 { get; set; } - - public uint Pstate { get; set; } - - public uint Fpcr { get; set; } - public uint Fpsr { get; set; } - - public bool IsAarch32 { get => false; set { } } - - public bool Running { get; private set; } = true; - - private readonly ulong[] _x = new ulong[32]; - - public ulong GetX(int index) => _x[index]; - public void SetX(int index, ulong value) => _x[index] = value; - - public V128 GetV(int index) => default; - public void SetV(int index, V128 value) { } - - public void RequestInterrupt() - { - } - - public void StopRunning() - { - Running = false; - } - - public void Dispose() - { - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessState.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessState.cs deleted file mode 100644 index 5ef3077e..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessState.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - enum ProcessState : byte - { - Created = 0, - CreatedAttached = 1, - Started = 2, - Crashed = 3, - Attached = 4, - Exiting = 5, - Exited = 6, - DebugSuspended = 7 - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs deleted file mode 100644 index 4cf67172..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class ProcessTamperInfo - { - public KProcess Process { get; } - public IEnumerable<string> BuildIds { get; } - public IEnumerable<ulong> CodeAddresses { get; } - public ulong HeapAddress { get; } - public ulong AliasAddress { get; } - public ulong AslrAddress { get; } - - public ProcessTamperInfo(KProcess process, IEnumerable<string> buildIds, IEnumerable<ulong> codeAddresses, ulong heapAddress, ulong aliasAddress, ulong aslrAddress) - { - Process = process; - BuildIds = buildIds; - CodeAddresses = codeAddresses; - HeapAddress = heapAddress; - AliasAddress = aliasAddress; - AslrAddress = aslrAddress; - } - } -}
\ No newline at end of file |
