mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-02 15:57:09 +02:00
Move solution and projects to src
This commit is contained in:
parent
e210a51de6
commit
ea8eaea6c2
3466 changed files with 55 additions and 55 deletions
22
src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs
Normal file
22
src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
19
src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityType.cs
Normal file
19
src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityType.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
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
|
||||
}
|
||||
}
|
465
src/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
Normal file
465
src/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
Normal file
|
@ -0,0 +1,465 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
Normal file
15
src/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
interface IProcessContextFactory
|
||||
{
|
||||
IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit);
|
||||
}
|
||||
}
|
83
src/Ryujinx.HLE/HOS/Kernel/Process/KContextIdManager.cs
Normal file
83
src/Ryujinx.HLE/HOS/Kernel/Process/KContextIdManager.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
19
src/Ryujinx.HLE/HOS/Kernel/Process/KHandleEntry.cs
Normal file
19
src/Ryujinx.HLE/HOS/Kernel/Process/KHandleEntry.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
285
src/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
Normal file
285
src/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
Normal file
|
@ -0,0 +1,285 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1196
src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
Normal file
1196
src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
Normal file
File diff suppressed because it is too large
Load diff
328
src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
Normal file
328
src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
Normal file
|
@ -0,0 +1,328 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
77
src/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageInfo.cs
Normal file
77
src/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageInfo.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
61
src/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageManager.cs
Normal file
61
src/Ryujinx.HLE/HOS/Kernel/Process/KTlsPageManager.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
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--;
|
||||
}
|
||||
}
|
||||
}
|
34
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
Normal file
34
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
12
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
Normal file
12
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
41
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
Normal file
41
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
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
|
||||
}
|
||||
}
|
37
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
Normal file
37
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
14
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessState.cs
Normal file
14
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessState.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
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
|
||||
}
|
||||
}
|
24
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs
Normal file
24
src/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue