Some improvements to the memory manager, implement back guest stack trace printing
This commit is contained in:
parent
e6f2b1940a
commit
f79ce1271c
26 changed files with 1421 additions and 422 deletions
|
@ -22,6 +22,11 @@ namespace Ryujinx.Common
|
|||
return Value & -(long)Size;
|
||||
}
|
||||
|
||||
public static long DivRoundUp(long Value, int Dividend)
|
||||
{
|
||||
return (Value + Dividend - 1) / Dividend;
|
||||
}
|
||||
|
||||
public static bool IsPowerOfTwo32(int Value)
|
||||
{
|
||||
return Value != 0 && (Value & (Value - 1)) == 0;
|
||||
|
|
|
@ -78,13 +78,17 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public IntegrityCheckLevel FsIntegrityCheckLevel { get; set; }
|
||||
|
||||
internal long HidBaseAddress { get; private set; }
|
||||
|
||||
public Horizon(Switch Device)
|
||||
{
|
||||
this.Device = Device;
|
||||
|
||||
State = new SystemStateMgr();
|
||||
|
||||
ResourceLimit = new KResourceLimit();
|
||||
ResourceLimit = new KResourceLimit(this);
|
||||
|
||||
KernelInit.InitializeResourceLimit(ResourceLimit);
|
||||
|
||||
MemoryRegions = KernelInit.GetMemoryRegions();
|
||||
|
||||
|
@ -112,20 +116,27 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
KernelInitialized = true;
|
||||
|
||||
if (!Device.Memory.Allocator.TryAllocate(HidSize, out long HidPA) ||
|
||||
!Device.Memory.Allocator.TryAllocate(FontSize, out long FontPA))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.Service];
|
||||
|
||||
HidSharedMem = new KSharedMemory(HidPA, HidSize);
|
||||
FontSharedMem = new KSharedMemory(FontPA, FontSize);
|
||||
long HidPA = Region.Address;
|
||||
long FontPA = Region.Address + HidSize;
|
||||
|
||||
HidBaseAddress = HidPA - DramMemoryMap.DramBase;
|
||||
|
||||
KPageList HidPageList = new KPageList();
|
||||
KPageList FontPageList = new KPageList();
|
||||
|
||||
HidPageList .AddRange(HidPA, HidSize / KMemoryManager.PageSize);
|
||||
FontPageList.AddRange(FontPA, FontSize / KMemoryManager.PageSize);
|
||||
|
||||
HidSharedMem = new KSharedMemory(HidPageList, 0, 0, MemoryPermission.Read);
|
||||
FontSharedMem = new KSharedMemory(FontPageList, 0, 0, MemoryPermission.Read);
|
||||
|
||||
AppletState = new AppletStateMgr(this);
|
||||
|
||||
AppletState.SetFocus(true);
|
||||
|
||||
Font = new SharedFontManager(Device, FontSharedMem.PA);
|
||||
Font = new SharedFontManager(Device, FontPA - DramMemoryMap.DramBase);
|
||||
|
||||
VsyncEvent = new KEvent(this);
|
||||
|
||||
|
|
|
@ -10,5 +10,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
public const long SlabHeapBase = KernelReserveBase + 0x85000;
|
||||
public const long SlapHeapSize = 0xa21000;
|
||||
public const long SlabHeapEnd = SlabHeapBase + SlapHeapSize;
|
||||
}
|
||||
}
|
303
Ryujinx.HLE/HOS/Kernel/HleProcessDebugger.cs
Normal file
303
Ryujinx.HLE/HOS/Kernel/HleProcessDebugger.cs
Normal file
|
@ -0,0 +1,303 @@
|
|||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
||||
using Ryujinx.HLE.Loaders;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class HleProcessDebugger
|
||||
{
|
||||
private const int Mod0 = 'M' << 0 | 'O' << 8 | 'D' << 16 | '0' << 24;
|
||||
|
||||
private KProcess Owner;
|
||||
|
||||
private class Image
|
||||
{
|
||||
public long BaseAddress { get; private set; }
|
||||
|
||||
public ElfSym[] Symbols { get; private set; }
|
||||
|
||||
public Image(long BaseAddress, ElfSym[] Symbols)
|
||||
{
|
||||
this.BaseAddress = BaseAddress;
|
||||
this.Symbols = Symbols;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Image> Images;
|
||||
|
||||
private int Loaded;
|
||||
|
||||
public HleProcessDebugger(KProcess Owner)
|
||||
{
|
||||
this.Owner = Owner;
|
||||
|
||||
Images = new List<Image>();
|
||||
}
|
||||
|
||||
public void PrintGuestStackTrace(CpuThreadState ThreadState)
|
||||
{
|
||||
EnsureLoaded();
|
||||
|
||||
StringBuilder Trace = new StringBuilder();
|
||||
|
||||
Trace.AppendLine("Guest stack trace:");
|
||||
|
||||
void AppendTrace(long Address)
|
||||
{
|
||||
Image Image = GetImage(Address, out int ImageIndex);
|
||||
|
||||
if (Image == null || !TryGetSubName(Image, Address, out string SubName))
|
||||
{
|
||||
SubName = $"Sub{Address:x16}";
|
||||
}
|
||||
else if (SubName.StartsWith("_Z"))
|
||||
{
|
||||
SubName = Demangler.Parse(SubName);
|
||||
}
|
||||
|
||||
if (Image != null)
|
||||
{
|
||||
long Offset = Address - Image.BaseAddress;
|
||||
|
||||
string ImageName = GetGuessedNsoNameFromIndex(ImageIndex);
|
||||
|
||||
string ImageNameAndOffset = $"[{Owner.Name}] {ImageName}:0x{Offset:x8}";
|
||||
|
||||
Trace.AppendLine($" {ImageNameAndOffset} {SubName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.AppendLine($" [{Owner.Name}] ??? {SubName}");
|
||||
}
|
||||
}
|
||||
|
||||
long FramePointer = (long)ThreadState.X29;
|
||||
|
||||
while (FramePointer != 0)
|
||||
{
|
||||
if (!Owner.CpuMemory.IsMapped(FramePointer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//Note: This is the return address, we need to subtract one instruction
|
||||
//worth of bytes to get the branch instruction address.
|
||||
AppendTrace(Owner.CpuMemory.ReadInt64(FramePointer + 8) - 4);
|
||||
|
||||
FramePointer = Owner.CpuMemory.ReadInt64(FramePointer);
|
||||
}
|
||||
|
||||
Logger.PrintInfo(LogClass.Cpu, Trace.ToString());
|
||||
}
|
||||
|
||||
private bool TryGetSubName(Image Image, long Address, out string Name)
|
||||
{
|
||||
Address -= Image.BaseAddress;
|
||||
|
||||
int Left = 0;
|
||||
int Right = Image.Symbols.Length - 1;
|
||||
|
||||
while (Left <= Right)
|
||||
{
|
||||
int Size = Right - Left;
|
||||
|
||||
int Middle = Left + (Size >> 1);
|
||||
|
||||
ElfSym Symbol = Image.Symbols[Middle];
|
||||
|
||||
long EndAddr = Symbol.Value + Symbol.Size;
|
||||
|
||||
if ((ulong)Address >= (ulong)Symbol.Value && (ulong)Address < (ulong)EndAddr)
|
||||
{
|
||||
Name = Symbol.Name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((ulong)Address < (ulong)Symbol.Value)
|
||||
{
|
||||
Right = Middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Left = Middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
Name = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Image GetImage(long Address, out int Index)
|
||||
{
|
||||
lock (Images)
|
||||
{
|
||||
for (Index = Images.Count - 1; Index >= 0; Index--)
|
||||
{
|
||||
if ((ulong)Address >= (ulong)Images[Index].BaseAddress)
|
||||
{
|
||||
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()
|
||||
{
|
||||
long OldAddress = 0;
|
||||
long Address = 0;
|
||||
|
||||
while ((ulong)Address >= (ulong)OldAddress)
|
||||
{
|
||||
KMemoryInfo Info = Owner.MemoryManager.QueryMemory(Address);
|
||||
|
||||
if (Info.State == MemoryState.Reserved)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Info.State == MemoryState.CodeStatic && Info.Permission == MemoryPermission.ReadAndExecute)
|
||||
{
|
||||
LoadMod0Symbols(Owner.CpuMemory, Info.Address);
|
||||
}
|
||||
|
||||
OldAddress = Address;
|
||||
|
||||
Address = Info.Address + Info.Size;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadMod0Symbols(MemoryManager Memory, long TextOffset)
|
||||
{
|
||||
long Mod0Offset = TextOffset + Memory.ReadUInt32(TextOffset + 4);
|
||||
|
||||
if (Mod0Offset < TextOffset || !Memory.IsMapped(Mod0Offset) || (Mod0Offset & 3) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<ElfDynTag, long> Dynamic = new Dictionary<ElfDynTag, long>();
|
||||
|
||||
int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0);
|
||||
|
||||
if (Mod0Magic != Mod0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset;
|
||||
long BssStartOffset = Memory.ReadInt32(Mod0Offset + 0x8) + Mod0Offset;
|
||||
long BssEndOffset = Memory.ReadInt32(Mod0Offset + 0xc) + Mod0Offset;
|
||||
long EhHdrStartOffset = Memory.ReadInt32(Mod0Offset + 0x10) + Mod0Offset;
|
||||
long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset;
|
||||
long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset;
|
||||
|
||||
while (true)
|
||||
{
|
||||
long TagVal = Memory.ReadInt64(DynamicOffset + 0);
|
||||
long Value = Memory.ReadInt64(DynamicOffset + 8);
|
||||
|
||||
DynamicOffset += 0x10;
|
||||
|
||||
ElfDynTag Tag = (ElfDynTag)TagVal;
|
||||
|
||||
if (Tag == ElfDynTag.DT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Dynamic[Tag] = Value;
|
||||
}
|
||||
|
||||
long StrTblAddr = TextOffset + Dynamic[ElfDynTag.DT_STRTAB];
|
||||
long SymTblAddr = TextOffset + Dynamic[ElfDynTag.DT_SYMTAB];
|
||||
|
||||
long SymEntSize = Dynamic[ElfDynTag.DT_SYMENT];
|
||||
|
||||
List<ElfSym> Symbols = new List<ElfSym>();
|
||||
|
||||
while ((ulong)SymTblAddr < (ulong)StrTblAddr)
|
||||
{
|
||||
ElfSym Sym = GetSymbol(Memory, SymTblAddr, StrTblAddr);
|
||||
|
||||
Symbols.Add(Sym);
|
||||
|
||||
SymTblAddr += SymEntSize;
|
||||
}
|
||||
|
||||
lock (Images)
|
||||
{
|
||||
Images.Add(new Image(TextOffset, Symbols.OrderBy(x => x.Value).ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
private ElfSym GetSymbol(MemoryManager Memory, long Address, long StrTblAddr)
|
||||
{
|
||||
int NameIndex = Memory.ReadInt32(Address + 0);
|
||||
int Info = Memory.ReadByte (Address + 4);
|
||||
int Other = Memory.ReadByte (Address + 5);
|
||||
int SHIdx = Memory.ReadInt16(Address + 6);
|
||||
long Value = Memory.ReadInt64(Address + 8);
|
||||
long Size = Memory.ReadInt64(Address + 16);
|
||||
|
||||
string Name = string.Empty;
|
||||
|
||||
for (int Chr; (Chr = Memory.ReadByte(StrTblAddr + NameIndex++)) != 0;)
|
||||
{
|
||||
Name += (char)Chr;
|
||||
}
|
||||
|
||||
return new ElfSym(Name, Info, Other, SHIdx, Value, Size);
|
||||
}
|
||||
}
|
||||
}
|
71
Ryujinx.HLE/HOS/Kernel/KConditionVariable.cs
Normal file
71
Ryujinx.HLE/HOS/Kernel/KConditionVariable.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
static class KConditionVariable
|
||||
{
|
||||
public static void Wait(Horizon System, LinkedList<KThread> ThreadList, object Mutex, long Timeout)
|
||||
{
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
Monitor.Exit(Mutex);
|
||||
|
||||
CurrentThread.Withholder = ThreadList;
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
CurrentThread.WithholderNode = ThreadList.AddLast(CurrentThread);
|
||||
|
||||
if (CurrentThread.ShallBeTerminated ||
|
||||
CurrentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
{
|
||||
ThreadList.Remove(CurrentThread.WithholderNode);
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Running);
|
||||
|
||||
CurrentThread.Withholder = null;
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Timeout > 0)
|
||||
{
|
||||
System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
|
||||
if (Timeout > 0)
|
||||
{
|
||||
System.TimeManager.UnscheduleFutureInvocation(CurrentThread);
|
||||
}
|
||||
}
|
||||
|
||||
Monitor.Enter(Mutex);
|
||||
}
|
||||
|
||||
public static void NotifyAll(Horizon System, LinkedList<KThread> ThreadList)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
LinkedListNode<KThread> Node = ThreadList.First;
|
||||
|
||||
for (; Node != null; Node = ThreadList.First)
|
||||
{
|
||||
KThread Thread = Node.Value;
|
||||
|
||||
ThreadList.Remove(Thread.WithholderNode);
|
||||
|
||||
Thread.Withholder = null;
|
||||
|
||||
Thread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
class KMemoryBlock
|
||||
{
|
||||
public long BasePosition { get; set; }
|
||||
public long PagesCount { get; set; }
|
||||
public long BaseAddress { get; set; }
|
||||
public long PagesCount { get; set; }
|
||||
|
||||
public MemoryState State { get; set; }
|
||||
public MemoryPermission Permission { get; set; }
|
||||
|
@ -13,17 +13,17 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
public int DeviceRefCount { get; set; }
|
||||
|
||||
public KMemoryBlock(
|
||||
long BasePosition,
|
||||
long BaseAddress,
|
||||
long PagesCount,
|
||||
MemoryState State,
|
||||
MemoryPermission Permission,
|
||||
MemoryAttribute Attribute)
|
||||
{
|
||||
this.BasePosition = BasePosition;
|
||||
this.PagesCount = PagesCount;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
this.Permission = Permission;
|
||||
this.BaseAddress = BaseAddress;
|
||||
this.PagesCount = PagesCount;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
this.Permission = Permission;
|
||||
}
|
||||
|
||||
public KMemoryInfo GetInfo()
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
long Size = PagesCount * KMemoryManager.PageSize;
|
||||
|
||||
return new KMemoryInfo(
|
||||
BasePosition,
|
||||
BaseAddress,
|
||||
Size,
|
||||
State,
|
||||
Permission,
|
||||
|
|
|
@ -2,8 +2,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
class KMemoryInfo
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
public long Address { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
public MemoryState State { get; private set; }
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
public int DeviceRefCount { get; private set; }
|
||||
|
||||
public KMemoryInfo(
|
||||
long Position,
|
||||
long Address,
|
||||
long Size,
|
||||
MemoryState State,
|
||||
MemoryPermission Permission,
|
||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int IpcRefCount,
|
||||
int DeviceRefCount)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,10 +6,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
private static readonly int[] BlockOrders = new int[] { 12, 16, 21, 22, 25, 29, 30 };
|
||||
|
||||
private long Address;
|
||||
private long EndAddr;
|
||||
private long Size;
|
||||
private int BlockOrdersCount;
|
||||
public long Address { get; private set; }
|
||||
public long EndAddr { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
private int BlockOrdersCount;
|
||||
|
||||
private KMemoryRegionBlock[] Blocks;
|
||||
|
||||
|
@ -292,7 +293,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
public void FreePages(long Address, long PagesCount)
|
||||
public void FreePages(KPageList PageList)
|
||||
{
|
||||
lock (Blocks)
|
||||
{
|
||||
foreach (KPageNode PageNode in PageList)
|
||||
{
|
||||
FreePages(PageNode.Address, PageNode.PagesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FreePages(long Address, long PagesCount)
|
||||
{
|
||||
long EndAddr = Address + PagesCount * KMemoryManager.PageSize;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
class KPageList : IEnumerable<KPageNode>
|
||||
{
|
||||
private LinkedList<KPageNode> Nodes;
|
||||
public LinkedList<KPageNode> Nodes { get; private set; }
|
||||
|
||||
public KPageList()
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
KPageNode LastNode = Nodes.Last.Value;
|
||||
|
||||
if (LastNode.Address + LastNode.PagesCount * 4096 == Address)
|
||||
if (LastNode.Address + LastNode.PagesCount * KMemoryManager.PageSize == Address)
|
||||
{
|
||||
Address = LastNode.Address;
|
||||
PagesCount += LastNode.PagesCount;
|
||||
|
@ -47,6 +47,26 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return Sum;
|
||||
}
|
||||
|
||||
public bool IsEqual(KPageList Other)
|
||||
{
|
||||
LinkedListNode<KPageNode> ThisNode = Nodes.First;
|
||||
LinkedListNode<KPageNode> OtherNode = Other.Nodes.First;
|
||||
|
||||
while (ThisNode != null && OtherNode != null)
|
||||
{
|
||||
if (ThisNode.Value.Address != OtherNode.Value.Address ||
|
||||
ThisNode.Value.PagesCount != OtherNode.Value.PagesCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ThisNode = ThisNode.Next;
|
||||
OtherNode = OtherNode.Next;
|
||||
}
|
||||
|
||||
return ThisNode == null && OtherNode == null;
|
||||
}
|
||||
|
||||
public IEnumerator<KPageNode> GetEnumerator()
|
||||
{
|
||||
return Nodes.GetEnumerator();
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
private bool Signaled;
|
||||
private bool UseSystemMemBlocks;
|
||||
|
||||
private string Name;
|
||||
public string Name { get; private set; }
|
||||
|
||||
private int ThreadCount;
|
||||
|
||||
|
@ -79,6 +79,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
private SvcHandler SvcHandler;
|
||||
|
||||
public HleProcessDebugger Debugger { get; private set; }
|
||||
|
||||
public KProcess(Horizon System) : base(System)
|
||||
{
|
||||
ProcessLock = new object();
|
||||
|
@ -93,8 +95,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
FullTlsPages = new SortedDictionary<long, KTlsPageInfo>();
|
||||
FreeTlsPages = new SortedDictionary<long, KTlsPageInfo>();
|
||||
|
||||
ResourceLimit = new KResourceLimit();
|
||||
|
||||
Capabilities = new KProcessCapabilities();
|
||||
|
||||
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
||||
|
@ -103,7 +103,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
Translator = new Translator();
|
||||
|
||||
Translator.CpuTrace += CpuTraceHandler;
|
||||
|
||||
SvcHandler = new SvcHandler(System.Device, this);
|
||||
|
||||
Debugger = new HleProcessDebugger(this);
|
||||
}
|
||||
|
||||
public KernelResult InitializeKip(
|
||||
|
@ -175,7 +179,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
KResourceLimit ResourceLimit,
|
||||
MemoryRegion MemRegion)
|
||||
{
|
||||
long PersonalMmHeapSize = CreationInfo.PersonalMmHeapPagesCount * KMemoryManager.PageSize;
|
||||
this.ResourceLimit = ResourceLimit;
|
||||
this.MemRegion = MemRegion;
|
||||
|
||||
long PersonalMmHeapSize = GetPersonalMmHeapSize(CreationInfo.PersonalMmHeapPagesCount, MemRegion);
|
||||
|
||||
long CodePagesCount = (long)(uint)CreationInfo.CodePagesCount;
|
||||
|
||||
|
@ -273,7 +280,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return Result;
|
||||
}
|
||||
|
||||
private bool ValidateCodeAddressAndSize(long CodeAddress, long CodeSize)
|
||||
private bool ValidateCodeAddressAndSize(long Address, long Size)
|
||||
{
|
||||
long CodeRegionStart;
|
||||
long CodeRegionSize;
|
||||
|
@ -298,18 +305,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
default: throw new InvalidOperationException("Invalid address space width on memory manager.");
|
||||
}
|
||||
|
||||
long CodeEndAddr = CodeAddress + CodeSize;
|
||||
long EndAddr = Address + Size;
|
||||
|
||||
long CodeRegionEnd = CodeRegionStart + CodeRegionSize;
|
||||
|
||||
if ((ulong)CodeEndAddr <= (ulong)CodeAddress ||
|
||||
(ulong)CodeEndAddr - 1 > (ulong)CodeRegionEnd - 1)
|
||||
if ((ulong)EndAddr <= (ulong)Address ||
|
||||
(ulong)EndAddr - 1 > (ulong)CodeRegionEnd - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MemoryManager.InsideHeapRegion(CodeAddress, CodeSize) ||
|
||||
MemoryManager.InsideMapRegion (CodeAddress, CodeSize))
|
||||
if (MemoryManager.InsideHeapRegion(Address, Size) ||
|
||||
MemoryManager.InsideMapRegion (Address, Size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -445,8 +452,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
|
||||
long RegionStart = MemoryManager.TlsIoRegionStart;
|
||||
long RegionSize = MemoryManager.TlsIoRegionEnd - RegionStart;
|
||||
|
||||
long RegionPagesCount = (MemoryManager.TlsIoRegionEnd - RegionStart) / KMemoryManager.PageSize;
|
||||
long RegionPagesCount = (long)((ulong)RegionSize / KMemoryManager.PageSize);
|
||||
|
||||
KernelResult Result = MemoryManager.AllocateOrMapPa(
|
||||
1,
|
||||
|
@ -606,7 +614,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
long StackBottom = StackTop - MainThreadStackSize;
|
||||
|
||||
long StackPagesCount = MainThreadStackSize / KMemoryManager.PageSize;
|
||||
long StackPagesCount = (long)((ulong)MainThreadStackSize / KMemoryManager.PageSize);
|
||||
|
||||
MemoryManager.UnmapForKernel(StackBottom, StackPagesCount, MemoryState.Stack);
|
||||
}
|
||||
|
@ -617,10 +625,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (StackSizeRounded != 0)
|
||||
{
|
||||
long StackPagesCount = StackSizeRounded / KMemoryManager.PageSize;
|
||||
long StackPagesCount = (long)((ulong)StackSizeRounded / KMemoryManager.PageSize);
|
||||
|
||||
long RegionStart = MemoryManager.StackRegionStart;
|
||||
long RegionPagesCount = (MemoryManager.StackRegionEnd - RegionStart) / KMemoryManager.PageSize;
|
||||
long RegionStart = MemoryManager.StackRegionStart;
|
||||
long RegionSize = MemoryManager.StackRegionEnd - RegionStart;
|
||||
|
||||
long RegionPagesCount = (long)((ulong)RegionSize / KMemoryManager.PageSize);
|
||||
|
||||
Result = MemoryManager.AllocateOrMapPa(
|
||||
StackPagesCount,
|
||||
|
@ -715,7 +725,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
CleanUpForError();
|
||||
} */
|
||||
|
||||
MainThread.TimeUp();
|
||||
MainThread.Reschedule(ThreadSchedState.Running);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
@ -772,8 +782,20 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
public long GetMemoryCapacity()
|
||||
{
|
||||
//TODO: Personal Mm Heap.
|
||||
return 0xcd500000;
|
||||
long TotalCapacity = ResourceLimit.GetRemainingValue(LimitableResource.Memory);
|
||||
|
||||
TotalCapacity += MemoryManager.GetTotalHeapSize();
|
||||
|
||||
TotalCapacity += GetPersonalMmHeapSize();
|
||||
|
||||
TotalCapacity += ImageSize + MainThreadStackSize;
|
||||
|
||||
if ((ulong)TotalCapacity <= (ulong)MemoryUsageCapacity)
|
||||
{
|
||||
return TotalCapacity;
|
||||
}
|
||||
|
||||
return MemoryUsageCapacity;
|
||||
}
|
||||
|
||||
public long GetMemoryUsage()
|
||||
|
@ -782,6 +804,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize();
|
||||
}
|
||||
|
||||
private long GetPersonalMmHeapSize()
|
||||
{
|
||||
return GetPersonalMmHeapSize(PersonalMmHeapPagesCount, MemRegion);
|
||||
}
|
||||
|
||||
private static long GetPersonalMmHeapSize(long PersonalMmHeapPagesCount, MemoryRegion MemRegion)
|
||||
{
|
||||
if (MemRegion == MemoryRegion.Applet)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return PersonalMmHeapPagesCount * KMemoryManager.PageSize;
|
||||
}
|
||||
|
||||
public void AddThread(KThread Thread)
|
||||
{
|
||||
lock (ThreadingLock)
|
||||
|
@ -881,5 +918,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
System.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
private void CpuTraceHandler(object sender, EventArgs e)
|
||||
{
|
||||
System.Scheduler.GetCurrentThread().PrintGuestStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,135 @@
|
|||
using Ryujinx.Common;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KResourceLimit
|
||||
{
|
||||
private long[] Current;
|
||||
private long[] Limit;
|
||||
private long[] Available;
|
||||
|
||||
private object LockObj;
|
||||
|
||||
private LinkedList<KThread> WaitingThreads;
|
||||
|
||||
private int WaitingThreadsCount;
|
||||
|
||||
private Horizon System;
|
||||
|
||||
public KResourceLimit(Horizon System)
|
||||
{
|
||||
Current = new long[(int)LimitableResource.Count];
|
||||
Limit = new long[(int)LimitableResource.Count];
|
||||
Available = new long[(int)LimitableResource.Count];
|
||||
|
||||
LockObj = new object();
|
||||
|
||||
WaitingThreads = new LinkedList<KThread>();
|
||||
|
||||
this.System = System;
|
||||
}
|
||||
|
||||
public bool Reserve(LimitableResource Resource, long Amount)
|
||||
{
|
||||
//TODO.
|
||||
return true;
|
||||
//Wait 10 seconds for the resource if no timeout is specified.
|
||||
return Reserve(Resource, Amount, KTimeManager.ConvertMillisecondsToNanoseconds(10000));
|
||||
}
|
||||
|
||||
public bool Reserve(LimitableResource Resource, long Amount, long Timeout)
|
||||
{
|
||||
long EndTimePoint = KTimeManager.ConvertNanosecondsToMilliseconds(Timeout);
|
||||
|
||||
EndTimePoint += PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
bool Success = false;
|
||||
|
||||
int Index = GetIndex(Resource);
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
long NewCurrent = Current[Index] + Amount;
|
||||
|
||||
while (NewCurrent > Limit[Index] && Available[Index] + Amount <= Limit[Index])
|
||||
{
|
||||
WaitingThreadsCount++;
|
||||
|
||||
KConditionVariable.Wait(System, WaitingThreads, LockObj, Timeout);
|
||||
|
||||
WaitingThreadsCount--;
|
||||
|
||||
NewCurrent = Current[Index] + Amount;
|
||||
|
||||
if (Timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > EndTimePoint)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewCurrent <= Limit[Index])
|
||||
{
|
||||
Current[Index] = NewCurrent;
|
||||
|
||||
Success = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
public void Release(LimitableResource Resource, long Amount)
|
||||
{
|
||||
//TODO.
|
||||
Release(Resource, Amount, Amount);
|
||||
}
|
||||
|
||||
private void Release(LimitableResource Resource, long UsedAmount, long AvailableAmount)
|
||||
{
|
||||
int Index = GetIndex(Resource);
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
Current [Index] -= UsedAmount;
|
||||
Available[Index] -= AvailableAmount;
|
||||
|
||||
if (WaitingThreadsCount > 0)
|
||||
{
|
||||
KConditionVariable.NotifyAll(System, WaitingThreads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long GetRemainingValue(LimitableResource Resource)
|
||||
{
|
||||
int Index = GetIndex(Resource);
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
return Limit[Index] - Current[Index];
|
||||
}
|
||||
}
|
||||
|
||||
public KernelResult SetLimitValue(LimitableResource Resource, long Limit)
|
||||
{
|
||||
int Index = GetIndex(Resource);
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
if (Current[Index] <= Limit)
|
||||
{
|
||||
this.Limit[Index] = Limit;
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
return KernelResult.InvalidState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetIndex(LimitableResource Resource)
|
||||
{
|
||||
return (int)Resource;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,68 @@
|
|||
using Ryujinx.Common;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KSharedMemory
|
||||
{
|
||||
public long PA { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
private KPageList PageList;
|
||||
|
||||
public KSharedMemory(long PA, long Size)
|
||||
private long OwnerPid;
|
||||
|
||||
private MemoryPermission OwnerPermission;
|
||||
private MemoryPermission UserPermission;
|
||||
|
||||
public KSharedMemory(
|
||||
KPageList PageList,
|
||||
long OwnerPid,
|
||||
MemoryPermission OwnerPermission,
|
||||
MemoryPermission UserPermission)
|
||||
{
|
||||
this.PA = PA;
|
||||
this.Size = Size;
|
||||
this.PageList = PageList;
|
||||
this.OwnerPid = OwnerPid;
|
||||
this.OwnerPermission = OwnerPermission;
|
||||
this.UserPermission = UserPermission;
|
||||
}
|
||||
|
||||
public KernelResult MapIntoProcess(
|
||||
KMemoryManager MemoryManager,
|
||||
long Address,
|
||||
long Size,
|
||||
KProcess Process,
|
||||
MemoryPermission Permission)
|
||||
{
|
||||
long PagesCountRounded = BitUtils.DivRoundUp(Size, KMemoryManager.PageSize);
|
||||
|
||||
if (PageList.GetPagesCount() != PagesCountRounded)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
MemoryPermission ExpectedPermission = Process.Pid == OwnerPid
|
||||
? OwnerPermission
|
||||
: UserPermission;
|
||||
|
||||
if (Permission != ExpectedPermission)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
||||
return MemoryManager.MapPages(Address, PageList, MemoryState.SharedMemory, Permission);
|
||||
}
|
||||
|
||||
public KernelResult UnmapFromProcess(
|
||||
KMemoryManager MemoryManager,
|
||||
long Address,
|
||||
long Size,
|
||||
KProcess Process)
|
||||
{
|
||||
long PagesCountRounded = BitUtils.DivRoundUp(Size, KMemoryManager.PageSize);
|
||||
|
||||
if (PageList.GetPagesCount() != PagesCountRounded)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
return MemoryManager.UnmapPages(Address, PageList, MemoryState.SharedMemory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
|
||||
|
||||
private LinkedListNode<KThread> WithholderNode;
|
||||
public LinkedList<KThread> Withholder { get; set; }
|
||||
public LinkedListNode<KThread> WithholderNode { get; set; }
|
||||
|
||||
public LinkedListNode<KThread> ProcessListNode { get; set; }
|
||||
|
||||
|
@ -223,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
SetNewSchedFlags(ThreadSchedState.Running);
|
||||
|
||||
Result = 0;
|
||||
Result = KernelResult.Success;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -980,11 +981,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
public void TimeUp()
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
ReleaseAndResume();
|
||||
}
|
||||
|
||||
SetNewSchedFlags(ThreadSchedState.Running);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
public void PrintGuestStackTrace()
|
||||
{
|
||||
Owner.Debugger.PrintGuestStackTrace(Context.ThreadState);
|
||||
}
|
||||
|
||||
private void ThreadFinishedHandler(object sender, EventArgs e)
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
WaitEvent.Set();
|
||||
}
|
||||
|
||||
private long ConvertNanosecondsToMilliseconds(long Timeout)
|
||||
public static long ConvertNanosecondsToMilliseconds(long Timeout)
|
||||
{
|
||||
Timeout /= 1000000;
|
||||
|
||||
|
@ -68,6 +68,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return Timeout;
|
||||
}
|
||||
|
||||
public static long ConvertMillisecondsToNanoseconds(long Timeout)
|
||||
{
|
||||
return Timeout * 1000000;
|
||||
}
|
||||
|
||||
public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object)
|
||||
{
|
||||
lock (WaitingObjects)
|
||||
|
|
|
@ -1,7 +1,36 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
static class KernelInit
|
||||
{
|
||||
public static void InitializeResourceLimit(KResourceLimit ResourceLimit)
|
||||
{
|
||||
void EnsureSuccess(KernelResult Result)
|
||||
{
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected result \"{Result}\".");
|
||||
}
|
||||
}
|
||||
|
||||
int KernelMemoryCfg = 0;
|
||||
|
||||
long RamSize = GetRamSize(KernelMemoryCfg);
|
||||
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Memory, RamSize));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Thread, 800));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Event, 700));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.TransferMemory, 200));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Session, 900));
|
||||
|
||||
if (!ResourceLimit.Reserve(LimitableResource.Memory, 0) ||
|
||||
!ResourceLimit.Reserve(LimitableResource.Memory, 0x60000))
|
||||
{
|
||||
throw new InvalidOperationException("Unexpected failure reserving memory on resource limit.");
|
||||
}
|
||||
}
|
||||
|
||||
public static KMemoryRegionManager[] GetMemoryRegions()
|
||||
{
|
||||
KMemoryArrange Arrange = GetMemoryArrange();
|
||||
|
@ -17,10 +46,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
private static KMemoryRegionManager GetMemoryRegion(KMemoryArrangeRegion Region)
|
||||
{
|
||||
return new KMemoryRegionManager(
|
||||
Region.Address,
|
||||
Region.Size,
|
||||
Region.EndAddr);
|
||||
return new KMemoryRegionManager(Region.Address, Region.Size, Region.EndAddr);
|
||||
}
|
||||
|
||||
private static KMemoryArrange GetMemoryArrange()
|
||||
|
@ -31,14 +57,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
int KernelMemoryCfg = 0;
|
||||
|
||||
ulong RamSize;
|
||||
|
||||
switch ((KernelMemoryCfg >> 16) & 3)
|
||||
{
|
||||
case 1: RamSize = 0x180000000; break;
|
||||
case 2: RamSize = 0x200000000; break;
|
||||
default: RamSize = 0x100000000; break;
|
||||
}
|
||||
ulong RamSize = (ulong)GetRamSize(KernelMemoryCfg);
|
||||
|
||||
long RamPart0;
|
||||
long RamPart1;
|
||||
|
@ -97,11 +116,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
//Note: There is an extra region used by the kernel, however
|
||||
//since we are doing HLE we are not going to use that memory, so give all
|
||||
//the remaining memory space to services.
|
||||
long ServiceRgSize = NvServicesRg.Address - DramMemoryMap.KernelReserveBase;
|
||||
long ServiceRgSize = NvServicesRg.Address - DramMemoryMap.SlabHeapEnd;
|
||||
|
||||
ServiceRg = new KMemoryArrangeRegion(DramMemoryMap.KernelReserveBase, ServiceRgSize);
|
||||
ServiceRg = new KMemoryArrangeRegion(DramMemoryMap.SlabHeapEnd, ServiceRgSize);
|
||||
|
||||
return new KMemoryArrange(ServiceRg, NvServicesRg, AppletRg, ApplicationRg);
|
||||
}
|
||||
|
||||
private static long GetRamSize(int KernelMemoryCfg)
|
||||
{
|
||||
switch ((KernelMemoryCfg >> 16) & 3)
|
||||
{
|
||||
case 1: return 0x180000000;
|
||||
case 2: return 0x200000000;
|
||||
default: return 0x100000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
OutOfMemory = 0xd001,
|
||||
HandleTableFull = 0xd201,
|
||||
InvalidMemState = 0xd401,
|
||||
InvalidPermission = 0xd801,
|
||||
InvalidMemRange = 0xdc01,
|
||||
InvalidPriority = 0xe001,
|
||||
InvalidCpuCore = 0xe201,
|
||||
|
|
|
@ -2,10 +2,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
enum LimitableResource : byte
|
||||
{
|
||||
Memory,
|
||||
Thread,
|
||||
Event,
|
||||
TransferMemory,
|
||||
Session
|
||||
Memory = 0,
|
||||
Thread = 1,
|
||||
Event = 2,
|
||||
TransferMemory = 3,
|
||||
Session = 4,
|
||||
|
||||
Count = 5
|
||||
}
|
||||
}
|
|
@ -105,8 +105,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
CpuThreadState ThreadState = (CpuThreadState)sender;
|
||||
|
||||
//Process.GetThread(ThreadState.Tpidr).LastPc = e.Position;
|
||||
|
||||
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
||||
{
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
|
||||
|
|
|
@ -141,9 +141,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
long Result = Process.MemoryManager.Map(Src, Dst, Size);
|
||||
KernelResult Result = Process.MemoryManager.Map(Dst, Src, Size);
|
||||
|
||||
if (Result != 0)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
@ -202,9 +202,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
long Result = Process.MemoryManager.Unmap(Src, Dst, Size);
|
||||
KernelResult Result = Process.MemoryManager.Unmap(Dst, Src, Size);
|
||||
|
||||
if (Result != 0)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position);
|
||||
|
||||
Memory.WriteInt64(InfoPtr + 0x00, BlkInfo.Position);
|
||||
Memory.WriteInt64(InfoPtr + 0x00, BlkInfo.Address);
|
||||
Memory.WriteInt64(InfoPtr + 0x08, BlkInfo.Size);
|
||||
Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff);
|
||||
Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute);
|
||||
|
@ -234,13 +234,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
private void SvcMapSharedMemory(CpuThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
long Position = (long)ThreadState.X1;
|
||||
long Size = (long)ThreadState.X2;
|
||||
int Handle = (int)ThreadState.X0;
|
||||
long Address = (long)ThreadState.X1;
|
||||
long Size = (long)ThreadState.X2;
|
||||
|
||||
if (!PageAligned(Position))
|
||||
if (!PageAligned(Address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -256,9 +256,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
if ((ulong)(Position + Size) <= (ulong)Position)
|
||||
if ((ulong)(Address + Size) <= (ulong)Address)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Address:x16} / size 0x{Size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -276,7 +276,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
|
||||
KSharedMemory SharedMemory = CurrentProcess.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
|
||||
if (SharedMemory == null)
|
||||
{
|
||||
|
@ -287,29 +289,25 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size))
|
||||
if (!InsideAddrSpace(Address, Size) || InsideMapRegion(Address, Size) || InsideHeapRegion(Address, Size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SharedMemory.Size != Size)
|
||||
KernelResult Result = SharedMemory.MapIntoProcess(
|
||||
CurrentProcess.MemoryManager,
|
||||
Address,
|
||||
Size,
|
||||
CurrentProcess,
|
||||
Permission);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long Result = Process.MemoryManager.MapSharedMemory(SharedMemory, Permission, Position);
|
||||
|
||||
if (Result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -348,7 +346,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
|
||||
KSharedMemory SharedMemory = CurrentProcess.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
|
||||
if (SharedMemory == null)
|
||||
{
|
||||
|
@ -368,11 +368,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
long Result = Process.MemoryManager.UnmapSharedMemory(Position, Size);
|
||||
KernelResult Result = SharedMemory.UnmapFromProcess(
|
||||
CurrentProcess.MemoryManager,
|
||||
Position,
|
||||
Size,
|
||||
CurrentProcess);
|
||||
|
||||
if (Result != 0)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -472,9 +476,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
long Result = Process.MemoryManager.MapPhysicalMemory(Position, Size);
|
||||
KernelResult Result = Process.MemoryManager.MapPhysicalMemory(Position, Size);
|
||||
|
||||
if (Result != 0)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
@ -523,9 +527,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
long Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size);
|
||||
KernelResult Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size);
|
||||
|
||||
if (Result != 0)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Services;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -243,9 +243,20 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
long Unknown = (long)ThreadState.X1;
|
||||
long Info = (long)ThreadState.X2;
|
||||
|
||||
//Process.PrintStackTrace(ThreadState);
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
|
||||
throw new GuestBrokeExecutionException();
|
||||
if ((Reason & (1 << 31)) == 0)
|
||||
{
|
||||
CurrentThread.PrintGuestStackTrace();
|
||||
|
||||
throw new GuestBrokeExecutionException();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered.");
|
||||
|
||||
CurrentThread.PrintGuestStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcOutputDebugString(CpuThreadState ThreadState)
|
||||
|
|
|
@ -48,8 +48,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return KernelResult.InvalidPriority;
|
||||
}
|
||||
|
||||
long Timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
|
||||
|
||||
if (CurrentProcess.ResourceLimit != null &&
|
||||
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1))
|
||||
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, Timeout))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
|
|
@ -78,15 +78,34 @@ namespace Ryujinx.HLE.HOS
|
|||
0,
|
||||
PersonalMmHeapPagesCount);
|
||||
|
||||
KernelResult Result = Process.Initialize(
|
||||
KernelResult Result;
|
||||
|
||||
KResourceLimit ResourceLimit = new KResourceLimit(System);
|
||||
|
||||
long ApplicationRgSize = System.MemoryRegions[(int)MemoryRegion.Application].Size;
|
||||
|
||||
Result = ResourceLimit.SetLimitValue(LimitableResource.Memory, ApplicationRgSize);
|
||||
Result |= ResourceLimit.SetLimitValue(LimitableResource.Thread, 608);
|
||||
Result |= ResourceLimit.SetLimitValue(LimitableResource.Event, 700);
|
||||
Result |= ResourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
|
||||
Result |= ResourceLimit.SetLimitValue(LimitableResource.Session, 894);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintError(LogClass.Loader, $"Resource limit initialization returned error \"{Result}\".");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Result = Process.Initialize(
|
||||
CreationInfo,
|
||||
MetaData.ACI0.KernelAccessControl.Capabilities,
|
||||
System.ResourceLimit,
|
||||
ResourceLimit,
|
||||
MemoryRegion.Application);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintError(LogClass.KernelSvc, $"Process initialization returned error \"{Result}\".");
|
||||
Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -107,7 +126,7 @@ namespace Ryujinx.HLE.HOS
|
|||
Process.CpuMemory.WriteBytes(ROStart, StaticObject.RO);
|
||||
Process.CpuMemory.WriteBytes(DataStart, StaticObject.Data);
|
||||
|
||||
MemoryHelper.FillWithZeros(Process.CpuMemory, BssStart, (int)(BssEnd - BssStart));
|
||||
MemoryHelper.FillWithZeros(Process.CpuMemory, BssStart, (int)(BssEnd - BssStart));
|
||||
|
||||
Process.MemoryManager.SetProcessMemoryPermission(TextStart, ROStart - TextStart, MemoryPermission.ReadAndExecute);
|
||||
Process.MemoryManager.SetProcessMemoryPermission(ROStart, DataStart - ROStart, MemoryPermission.Read);
|
||||
|
@ -118,7 +137,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintError(LogClass.KernelSvc, $"Process start returned error \"{Result}\".");
|
||||
Logger.PrintError(LogClass.Loader, $"Process start returned error \"{Result}\".");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
|
@ -318,14 +319,14 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
|
||||
//Context.Process.RemoveProgram(Info.NroMappedAddress);
|
||||
|
||||
long Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(Info.NroMappedAddress, Info.Executable.SourceAddress, Info.TotalSize - Info.Executable.BssSize);
|
||||
KernelResult Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(Info.NroMappedAddress, Info.Executable.SourceAddress, Info.TotalSize - Info.Executable.BssSize);
|
||||
|
||||
if (Result == 0 && Info.Executable.BssSize != 0)
|
||||
if (Result == KernelResult.Success && Info.Executable.BssSize != 0)
|
||||
{
|
||||
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(Info.NroMappedAddress + Info.TotalSize - Info.Executable.BssSize, Info.Executable.BssAddress, Info.Executable.BssSize);
|
||||
}
|
||||
|
||||
return Result;
|
||||
return (long)Result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.HLE
|
|||
|
||||
Statistics = new PerformanceStatistics();
|
||||
|
||||
Hid = new Hid(this, System.HidSharedMem.PA);
|
||||
Hid = new Hid(this, System.HidBaseAddress);
|
||||
|
||||
VsyncEvent = new AutoResetEvent(true);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Ryujinx
|
|||
{ LogLevel.Error, ConsoleColor.Red }
|
||||
};
|
||||
|
||||
_messageQueue = new BlockingCollection<LogEventArgs>();
|
||||
_messageQueue = new BlockingCollection<LogEventArgs>(10);
|
||||
|
||||
_consoleLock = new object();
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace Ryujinx
|
|||
string formattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff");
|
||||
|
||||
string currentThread = Thread.CurrentThread.ManagedThreadId.ToString("d4");
|
||||
|
||||
|
||||
string message = formattedTime + " | " + currentThread + " " + e.Message;
|
||||
|
||||
if (_logColors.TryGetValue(e.Level, out ConsoleColor color))
|
||||
|
|
Loading…
Add table
Reference in a new issue