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;
|
return Value & -(long)Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long DivRoundUp(long Value, int Dividend)
|
||||||
|
{
|
||||||
|
return (Value + Dividend - 1) / Dividend;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsPowerOfTwo32(int Value)
|
public static bool IsPowerOfTwo32(int Value)
|
||||||
{
|
{
|
||||||
return Value != 0 && (Value & (Value - 1)) == 0;
|
return Value != 0 && (Value & (Value - 1)) == 0;
|
||||||
|
|
|
@ -78,13 +78,17 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
public IntegrityCheckLevel FsIntegrityCheckLevel { get; set; }
|
public IntegrityCheckLevel FsIntegrityCheckLevel { get; set; }
|
||||||
|
|
||||||
|
internal long HidBaseAddress { get; private set; }
|
||||||
|
|
||||||
public Horizon(Switch Device)
|
public Horizon(Switch Device)
|
||||||
{
|
{
|
||||||
this.Device = Device;
|
this.Device = Device;
|
||||||
|
|
||||||
State = new SystemStateMgr();
|
State = new SystemStateMgr();
|
||||||
|
|
||||||
ResourceLimit = new KResourceLimit();
|
ResourceLimit = new KResourceLimit(this);
|
||||||
|
|
||||||
|
KernelInit.InitializeResourceLimit(ResourceLimit);
|
||||||
|
|
||||||
MemoryRegions = KernelInit.GetMemoryRegions();
|
MemoryRegions = KernelInit.GetMemoryRegions();
|
||||||
|
|
||||||
|
@ -112,20 +116,27 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
KernelInitialized = true;
|
KernelInitialized = true;
|
||||||
|
|
||||||
if (!Device.Memory.Allocator.TryAllocate(HidSize, out long HidPA) ||
|
KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.Service];
|
||||||
!Device.Memory.Allocator.TryAllocate(FontSize, out long FontPA))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
HidSharedMem = new KSharedMemory(HidPA, HidSize);
|
long HidPA = Region.Address;
|
||||||
FontSharedMem = new KSharedMemory(FontPA, FontSize);
|
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 = new AppletStateMgr(this);
|
||||||
|
|
||||||
AppletState.SetFocus(true);
|
AppletState.SetFocus(true);
|
||||||
|
|
||||||
Font = new SharedFontManager(Device, FontSharedMem.PA);
|
Font = new SharedFontManager(Device, FontPA - DramMemoryMap.DramBase);
|
||||||
|
|
||||||
VsyncEvent = new KEvent(this);
|
VsyncEvent = new KEvent(this);
|
||||||
|
|
||||||
|
|
|
@ -10,5 +10,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
public const long SlabHeapBase = KernelReserveBase + 0x85000;
|
public const long SlabHeapBase = KernelReserveBase + 0x85000;
|
||||||
public const long SlapHeapSize = 0xa21000;
|
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
|
class KMemoryBlock
|
||||||
{
|
{
|
||||||
public long BasePosition { get; set; }
|
public long BaseAddress { get; set; }
|
||||||
public long PagesCount { get; set; }
|
public long PagesCount { get; set; }
|
||||||
|
|
||||||
public MemoryState State { get; set; }
|
public MemoryState State { get; set; }
|
||||||
public MemoryPermission Permission { get; set; }
|
public MemoryPermission Permission { get; set; }
|
||||||
|
@ -13,17 +13,17 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
public int DeviceRefCount { get; set; }
|
public int DeviceRefCount { get; set; }
|
||||||
|
|
||||||
public KMemoryBlock(
|
public KMemoryBlock(
|
||||||
long BasePosition,
|
long BaseAddress,
|
||||||
long PagesCount,
|
long PagesCount,
|
||||||
MemoryState State,
|
MemoryState State,
|
||||||
MemoryPermission Permission,
|
MemoryPermission Permission,
|
||||||
MemoryAttribute Attribute)
|
MemoryAttribute Attribute)
|
||||||
{
|
{
|
||||||
this.BasePosition = BasePosition;
|
this.BaseAddress = BaseAddress;
|
||||||
this.PagesCount = PagesCount;
|
this.PagesCount = PagesCount;
|
||||||
this.State = State;
|
this.State = State;
|
||||||
this.Attribute = Attribute;
|
this.Attribute = Attribute;
|
||||||
this.Permission = Permission;
|
this.Permission = Permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KMemoryInfo GetInfo()
|
public KMemoryInfo GetInfo()
|
||||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
long Size = PagesCount * KMemoryManager.PageSize;
|
long Size = PagesCount * KMemoryManager.PageSize;
|
||||||
|
|
||||||
return new KMemoryInfo(
|
return new KMemoryInfo(
|
||||||
BasePosition,
|
BaseAddress,
|
||||||
Size,
|
Size,
|
||||||
State,
|
State,
|
||||||
Permission,
|
Permission,
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
class KMemoryInfo
|
class KMemoryInfo
|
||||||
{
|
{
|
||||||
public long Position { get; private set; }
|
public long Address { get; private set; }
|
||||||
public long Size { get; private set; }
|
public long Size { get; private set; }
|
||||||
|
|
||||||
public MemoryState State { get; private set; }
|
public MemoryState State { get; private set; }
|
||||||
public MemoryPermission Permission { 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 int DeviceRefCount { get; private set; }
|
||||||
|
|
||||||
public KMemoryInfo(
|
public KMemoryInfo(
|
||||||
long Position,
|
long Address,
|
||||||
long Size,
|
long Size,
|
||||||
MemoryState State,
|
MemoryState State,
|
||||||
MemoryPermission Permission,
|
MemoryPermission Permission,
|
||||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
int IpcRefCount,
|
int IpcRefCount,
|
||||||
int DeviceRefCount)
|
int DeviceRefCount)
|
||||||
{
|
{
|
||||||
this.Position = Position;
|
this.Address = Address;
|
||||||
this.Size = Size;
|
this.Size = Size;
|
||||||
this.State = State;
|
this.State = State;
|
||||||
this.Attribute = Attribute;
|
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 static readonly int[] BlockOrders = new int[] { 12, 16, 21, 22, 25, 29, 30 };
|
||||||
|
|
||||||
private long Address;
|
public long Address { get; private set; }
|
||||||
private long EndAddr;
|
public long EndAddr { get; private set; }
|
||||||
private long Size;
|
public long Size { get; private set; }
|
||||||
private int BlockOrdersCount;
|
|
||||||
|
private int BlockOrdersCount;
|
||||||
|
|
||||||
private KMemoryRegionBlock[] Blocks;
|
private KMemoryRegionBlock[] Blocks;
|
||||||
|
|
||||||
|
@ -292,7 +293,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return KernelResult.OutOfMemory;
|
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;
|
long EndAddr = Address + PagesCount * KMemoryManager.PageSize;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
class KPageList : IEnumerable<KPageNode>
|
class KPageList : IEnumerable<KPageNode>
|
||||||
{
|
{
|
||||||
private LinkedList<KPageNode> Nodes;
|
public LinkedList<KPageNode> Nodes { get; private set; }
|
||||||
|
|
||||||
public KPageList()
|
public KPageList()
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
KPageNode LastNode = Nodes.Last.Value;
|
KPageNode LastNode = Nodes.Last.Value;
|
||||||
|
|
||||||
if (LastNode.Address + LastNode.PagesCount * 4096 == Address)
|
if (LastNode.Address + LastNode.PagesCount * KMemoryManager.PageSize == Address)
|
||||||
{
|
{
|
||||||
Address = LastNode.Address;
|
Address = LastNode.Address;
|
||||||
PagesCount += LastNode.PagesCount;
|
PagesCount += LastNode.PagesCount;
|
||||||
|
@ -47,6 +47,26 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return Sum;
|
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()
|
public IEnumerator<KPageNode> GetEnumerator()
|
||||||
{
|
{
|
||||||
return Nodes.GetEnumerator();
|
return Nodes.GetEnumerator();
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
private bool Signaled;
|
private bool Signaled;
|
||||||
private bool UseSystemMemBlocks;
|
private bool UseSystemMemBlocks;
|
||||||
|
|
||||||
private string Name;
|
public string Name { get; private set; }
|
||||||
|
|
||||||
private int ThreadCount;
|
private int ThreadCount;
|
||||||
|
|
||||||
|
@ -79,6 +79,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
private SvcHandler SvcHandler;
|
private SvcHandler SvcHandler;
|
||||||
|
|
||||||
|
public HleProcessDebugger Debugger { get; private set; }
|
||||||
|
|
||||||
public KProcess(Horizon System) : base(System)
|
public KProcess(Horizon System) : base(System)
|
||||||
{
|
{
|
||||||
ProcessLock = new object();
|
ProcessLock = new object();
|
||||||
|
@ -93,8 +95,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
FullTlsPages = new SortedDictionary<long, KTlsPageInfo>();
|
FullTlsPages = new SortedDictionary<long, KTlsPageInfo>();
|
||||||
FreeTlsPages = new SortedDictionary<long, KTlsPageInfo>();
|
FreeTlsPages = new SortedDictionary<long, KTlsPageInfo>();
|
||||||
|
|
||||||
ResourceLimit = new KResourceLimit();
|
|
||||||
|
|
||||||
Capabilities = new KProcessCapabilities();
|
Capabilities = new KProcessCapabilities();
|
||||||
|
|
||||||
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
||||||
|
@ -103,7 +103,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
Translator = new Translator();
|
Translator = new Translator();
|
||||||
|
|
||||||
|
Translator.CpuTrace += CpuTraceHandler;
|
||||||
|
|
||||||
SvcHandler = new SvcHandler(System.Device, this);
|
SvcHandler = new SvcHandler(System.Device, this);
|
||||||
|
|
||||||
|
Debugger = new HleProcessDebugger(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult InitializeKip(
|
public KernelResult InitializeKip(
|
||||||
|
@ -175,7 +179,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
KResourceLimit ResourceLimit,
|
KResourceLimit ResourceLimit,
|
||||||
MemoryRegion MemRegion)
|
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;
|
long CodePagesCount = (long)(uint)CreationInfo.CodePagesCount;
|
||||||
|
|
||||||
|
@ -273,7 +280,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateCodeAddressAndSize(long CodeAddress, long CodeSize)
|
private bool ValidateCodeAddressAndSize(long Address, long Size)
|
||||||
{
|
{
|
||||||
long CodeRegionStart;
|
long CodeRegionStart;
|
||||||
long CodeRegionSize;
|
long CodeRegionSize;
|
||||||
|
@ -298,18 +305,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
default: throw new InvalidOperationException("Invalid address space width on memory manager.");
|
default: throw new InvalidOperationException("Invalid address space width on memory manager.");
|
||||||
}
|
}
|
||||||
|
|
||||||
long CodeEndAddr = CodeAddress + CodeSize;
|
long EndAddr = Address + Size;
|
||||||
|
|
||||||
long CodeRegionEnd = CodeRegionStart + CodeRegionSize;
|
long CodeRegionEnd = CodeRegionStart + CodeRegionSize;
|
||||||
|
|
||||||
if ((ulong)CodeEndAddr <= (ulong)CodeAddress ||
|
if ((ulong)EndAddr <= (ulong)Address ||
|
||||||
(ulong)CodeEndAddr - 1 > (ulong)CodeRegionEnd - 1)
|
(ulong)EndAddr - 1 > (ulong)CodeRegionEnd - 1)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MemoryManager.InsideHeapRegion(CodeAddress, CodeSize) ||
|
if (MemoryManager.InsideHeapRegion(Address, Size) ||
|
||||||
MemoryManager.InsideMapRegion (CodeAddress, CodeSize))
|
MemoryManager.InsideMapRegion (Address, Size))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -445,8 +452,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
long RegionStart = MemoryManager.TlsIoRegionStart;
|
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(
|
KernelResult Result = MemoryManager.AllocateOrMapPa(
|
||||||
1,
|
1,
|
||||||
|
@ -606,7 +614,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
long StackBottom = StackTop - MainThreadStackSize;
|
long StackBottom = StackTop - MainThreadStackSize;
|
||||||
|
|
||||||
long StackPagesCount = MainThreadStackSize / KMemoryManager.PageSize;
|
long StackPagesCount = (long)((ulong)MainThreadStackSize / KMemoryManager.PageSize);
|
||||||
|
|
||||||
MemoryManager.UnmapForKernel(StackBottom, StackPagesCount, MemoryState.Stack);
|
MemoryManager.UnmapForKernel(StackBottom, StackPagesCount, MemoryState.Stack);
|
||||||
}
|
}
|
||||||
|
@ -617,10 +625,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
if (StackSizeRounded != 0)
|
if (StackSizeRounded != 0)
|
||||||
{
|
{
|
||||||
long StackPagesCount = StackSizeRounded / KMemoryManager.PageSize;
|
long StackPagesCount = (long)((ulong)StackSizeRounded / KMemoryManager.PageSize);
|
||||||
|
|
||||||
long RegionStart = MemoryManager.StackRegionStart;
|
long RegionStart = MemoryManager.StackRegionStart;
|
||||||
long RegionPagesCount = (MemoryManager.StackRegionEnd - RegionStart) / KMemoryManager.PageSize;
|
long RegionSize = MemoryManager.StackRegionEnd - RegionStart;
|
||||||
|
|
||||||
|
long RegionPagesCount = (long)((ulong)RegionSize / KMemoryManager.PageSize);
|
||||||
|
|
||||||
Result = MemoryManager.AllocateOrMapPa(
|
Result = MemoryManager.AllocateOrMapPa(
|
||||||
StackPagesCount,
|
StackPagesCount,
|
||||||
|
@ -715,7 +725,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
CleanUpForError();
|
CleanUpForError();
|
||||||
} */
|
} */
|
||||||
|
|
||||||
MainThread.TimeUp();
|
MainThread.Reschedule(ThreadSchedState.Running);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -772,8 +782,20 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
public long GetMemoryCapacity()
|
public long GetMemoryCapacity()
|
||||||
{
|
{
|
||||||
//TODO: Personal Mm Heap.
|
long TotalCapacity = ResourceLimit.GetRemainingValue(LimitableResource.Memory);
|
||||||
return 0xcd500000;
|
|
||||||
|
TotalCapacity += MemoryManager.GetTotalHeapSize();
|
||||||
|
|
||||||
|
TotalCapacity += GetPersonalMmHeapSize();
|
||||||
|
|
||||||
|
TotalCapacity += ImageSize + MainThreadStackSize;
|
||||||
|
|
||||||
|
if ((ulong)TotalCapacity <= (ulong)MemoryUsageCapacity)
|
||||||
|
{
|
||||||
|
return TotalCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemoryUsageCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetMemoryUsage()
|
public long GetMemoryUsage()
|
||||||
|
@ -782,6 +804,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize();
|
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)
|
public void AddThread(KThread Thread)
|
||||||
{
|
{
|
||||||
lock (ThreadingLock)
|
lock (ThreadingLock)
|
||||||
|
@ -881,5 +918,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
System.CriticalSection.Leave();
|
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
|
namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
class KResourceLimit
|
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)
|
public bool Reserve(LimitableResource Resource, long Amount)
|
||||||
{
|
{
|
||||||
//TODO.
|
//Wait 10 seconds for the resource if no timeout is specified.
|
||||||
return true;
|
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)
|
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
|
namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
class KSharedMemory
|
class KSharedMemory
|
||||||
{
|
{
|
||||||
public long PA { get; private set; }
|
private KPageList PageList;
|
||||||
public long Size { get; private set; }
|
|
||||||
|
|
||||||
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.PageList = PageList;
|
||||||
this.Size = Size;
|
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; }
|
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; }
|
public LinkedListNode<KThread> ProcessListNode { get; set; }
|
||||||
|
|
||||||
|
@ -223,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
SetNewSchedFlags(ThreadSchedState.Running);
|
SetNewSchedFlags(ThreadSchedState.Running);
|
||||||
|
|
||||||
Result = 0;
|
Result = KernelResult.Success;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -980,11 +981,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
public void TimeUp()
|
public void TimeUp()
|
||||||
{
|
{
|
||||||
System.CriticalSection.Enter();
|
ReleaseAndResume();
|
||||||
|
}
|
||||||
|
|
||||||
SetNewSchedFlags(ThreadSchedState.Running);
|
public void PrintGuestStackTrace()
|
||||||
|
{
|
||||||
System.CriticalSection.Leave();
|
Owner.Debugger.PrintGuestStackTrace(Context.ThreadState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThreadFinishedHandler(object sender, EventArgs e)
|
private void ThreadFinishedHandler(object sender, EventArgs e)
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
WaitEvent.Set();
|
WaitEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
private long ConvertNanosecondsToMilliseconds(long Timeout)
|
public static long ConvertNanosecondsToMilliseconds(long Timeout)
|
||||||
{
|
{
|
||||||
Timeout /= 1000000;
|
Timeout /= 1000000;
|
||||||
|
|
||||||
|
@ -68,6 +68,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return Timeout;
|
return Timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long ConvertMillisecondsToNanoseconds(long Timeout)
|
||||||
|
{
|
||||||
|
return Timeout * 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object)
|
public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object)
|
||||||
{
|
{
|
||||||
lock (WaitingObjects)
|
lock (WaitingObjects)
|
||||||
|
|
|
@ -1,7 +1,36 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel
|
namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
static class KernelInit
|
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()
|
public static KMemoryRegionManager[] GetMemoryRegions()
|
||||||
{
|
{
|
||||||
KMemoryArrange Arrange = GetMemoryArrange();
|
KMemoryArrange Arrange = GetMemoryArrange();
|
||||||
|
@ -17,10 +46,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
private static KMemoryRegionManager GetMemoryRegion(KMemoryArrangeRegion Region)
|
private static KMemoryRegionManager GetMemoryRegion(KMemoryArrangeRegion Region)
|
||||||
{
|
{
|
||||||
return new KMemoryRegionManager(
|
return new KMemoryRegionManager(Region.Address, Region.Size, Region.EndAddr);
|
||||||
Region.Address,
|
|
||||||
Region.Size,
|
|
||||||
Region.EndAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KMemoryArrange GetMemoryArrange()
|
private static KMemoryArrange GetMemoryArrange()
|
||||||
|
@ -31,14 +57,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
int KernelMemoryCfg = 0;
|
int KernelMemoryCfg = 0;
|
||||||
|
|
||||||
ulong RamSize;
|
ulong RamSize = (ulong)GetRamSize(KernelMemoryCfg);
|
||||||
|
|
||||||
switch ((KernelMemoryCfg >> 16) & 3)
|
|
||||||
{
|
|
||||||
case 1: RamSize = 0x180000000; break;
|
|
||||||
case 2: RamSize = 0x200000000; break;
|
|
||||||
default: RamSize = 0x100000000; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
long RamPart0;
|
long RamPart0;
|
||||||
long RamPart1;
|
long RamPart1;
|
||||||
|
@ -97,11 +116,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
//Note: There is an extra region used by the kernel, however
|
//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
|
//since we are doing HLE we are not going to use that memory, so give all
|
||||||
//the remaining memory space to services.
|
//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);
|
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,
|
OutOfMemory = 0xd001,
|
||||||
HandleTableFull = 0xd201,
|
HandleTableFull = 0xd201,
|
||||||
InvalidMemState = 0xd401,
|
InvalidMemState = 0xd401,
|
||||||
|
InvalidPermission = 0xd801,
|
||||||
InvalidMemRange = 0xdc01,
|
InvalidMemRange = 0xdc01,
|
||||||
InvalidPriority = 0xe001,
|
InvalidPriority = 0xe001,
|
||||||
InvalidCpuCore = 0xe201,
|
InvalidCpuCore = 0xe201,
|
||||||
|
|
|
@ -2,10 +2,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
enum LimitableResource : byte
|
enum LimitableResource : byte
|
||||||
{
|
{
|
||||||
Memory,
|
Memory = 0,
|
||||||
Thread,
|
Thread = 1,
|
||||||
Event,
|
Event = 2,
|
||||||
TransferMemory,
|
TransferMemory = 3,
|
||||||
Session
|
Session = 4,
|
||||||
|
|
||||||
|
Count = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -105,8 +105,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
CpuThreadState ThreadState = (CpuThreadState)sender;
|
CpuThreadState ThreadState = (CpuThreadState)sender;
|
||||||
|
|
||||||
//Process.GetThread(ThreadState.Tpidr).LastPc = e.Position;
|
|
||||||
|
|
||||||
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
||||||
{
|
{
|
||||||
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
|
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
|
||||||
|
|
|
@ -141,9 +141,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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}!");
|
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||||
}
|
}
|
||||||
|
@ -202,9 +202,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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}!");
|
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);
|
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.WriteInt64(InfoPtr + 0x08, BlkInfo.Size);
|
||||||
Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff);
|
Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff);
|
||||||
Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute);
|
Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute);
|
||||||
|
@ -234,13 +234,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
private void SvcMapSharedMemory(CpuThreadState ThreadState)
|
private void SvcMapSharedMemory(CpuThreadState ThreadState)
|
||||||
{
|
{
|
||||||
int Handle = (int)ThreadState.X0;
|
int Handle = (int)ThreadState.X0;
|
||||||
long Position = (long)ThreadState.X1;
|
long Address = (long)ThreadState.X1;
|
||||||
long Size = (long)ThreadState.X2;
|
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);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||||
|
|
||||||
|
@ -256,9 +256,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||||
|
|
||||||
|
@ -276,7 +276,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
|
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||||
|
|
||||||
|
KSharedMemory SharedMemory = CurrentProcess.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||||
|
|
||||||
if (SharedMemory == null)
|
if (SharedMemory == null)
|
||||||
{
|
{
|
||||||
|
@ -287,29 +289,25 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||||
|
|
||||||
return;
|
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}!");
|
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||||
|
|
||||||
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}!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadState.X0 = (ulong)Result;
|
ThreadState.X0 = (ulong)Result;
|
||||||
|
@ -348,7 +346,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
|
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||||
|
|
||||||
|
KSharedMemory SharedMemory = CurrentProcess.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||||
|
|
||||||
if (SharedMemory == null)
|
if (SharedMemory == null)
|
||||||
{
|
{
|
||||||
|
@ -368,11 +368,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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;
|
ThreadState.X0 = (ulong)Result;
|
||||||
|
@ -472,9 +476,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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}!");
|
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||||
}
|
}
|
||||||
|
@ -523,9 +527,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
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}!");
|
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Services;
|
using Ryujinx.HLE.HOS.Services;
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -243,9 +243,20 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
long Unknown = (long)ThreadState.X1;
|
long Unknown = (long)ThreadState.X1;
|
||||||
long Info = (long)ThreadState.X2;
|
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)
|
private void SvcOutputDebugString(CpuThreadState ThreadState)
|
||||||
|
|
|
@ -48,8 +48,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return KernelResult.InvalidPriority;
|
return KernelResult.InvalidPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long Timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
|
||||||
|
|
||||||
if (CurrentProcess.ResourceLimit != null &&
|
if (CurrentProcess.ResourceLimit != null &&
|
||||||
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1))
|
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, Timeout))
|
||||||
{
|
{
|
||||||
return KernelResult.ResLimitExceeded;
|
return KernelResult.ResLimitExceeded;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,15 +78,34 @@ namespace Ryujinx.HLE.HOS
|
||||||
0,
|
0,
|
||||||
PersonalMmHeapPagesCount);
|
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,
|
CreationInfo,
|
||||||
MetaData.ACI0.KernelAccessControl.Capabilities,
|
MetaData.ACI0.KernelAccessControl.Capabilities,
|
||||||
System.ResourceLimit,
|
ResourceLimit,
|
||||||
MemoryRegion.Application);
|
MemoryRegion.Application);
|
||||||
|
|
||||||
if (Result != KernelResult.Success)
|
if (Result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
Logger.PrintError(LogClass.KernelSvc, $"Process initialization returned error \"{Result}\".");
|
Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +126,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
Process.CpuMemory.WriteBytes(ROStart, StaticObject.RO);
|
Process.CpuMemory.WriteBytes(ROStart, StaticObject.RO);
|
||||||
Process.CpuMemory.WriteBytes(DataStart, StaticObject.Data);
|
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(TextStart, ROStart - TextStart, MemoryPermission.ReadAndExecute);
|
||||||
Process.MemoryManager.SetProcessMemoryPermission(ROStart, DataStart - ROStart, MemoryPermission.Read);
|
Process.MemoryManager.SetProcessMemoryPermission(ROStart, DataStart - ROStart, MemoryPermission.Read);
|
||||||
|
@ -118,7 +137,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
if (Result != KernelResult.Success)
|
if (Result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
Logger.PrintError(LogClass.KernelSvc, $"Process start returned error \"{Result}\".");
|
Logger.PrintError(LogClass.Loader, $"Process start returned error \"{Result}\".");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
@ -318,14 +319,14 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
||||||
|
|
||||||
//Context.Process.RemoveProgram(Info.NroMappedAddress);
|
//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);
|
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();
|
Statistics = new PerformanceStatistics();
|
||||||
|
|
||||||
Hid = new Hid(this, System.HidSharedMem.PA);
|
Hid = new Hid(this, System.HidBaseAddress);
|
||||||
|
|
||||||
VsyncEvent = new AutoResetEvent(true);
|
VsyncEvent = new AutoResetEvent(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Ryujinx
|
||||||
{ LogLevel.Error, ConsoleColor.Red }
|
{ LogLevel.Error, ConsoleColor.Red }
|
||||||
};
|
};
|
||||||
|
|
||||||
_messageQueue = new BlockingCollection<LogEventArgs>();
|
_messageQueue = new BlockingCollection<LogEventArgs>(10);
|
||||||
|
|
||||||
_consoleLock = new object();
|
_consoleLock = new object();
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace Ryujinx
|
||||||
string formattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff");
|
string formattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff");
|
||||||
|
|
||||||
string currentThread = Thread.CurrentThread.ManagedThreadId.ToString("d4");
|
string currentThread = Thread.CurrentThread.ManagedThreadId.ToString("d4");
|
||||||
|
|
||||||
string message = formattedTime + " | " + currentThread + " " + e.Message;
|
string message = formattedTime + " | " + currentThread + " " + e.Message;
|
||||||
|
|
||||||
if (_logColors.TryGetValue(e.Level, out ConsoleColor color))
|
if (_logColors.TryGetValue(e.Level, out ConsoleColor color))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue