Better GetInfo implementation, improve checking in some places with information from process capabilities

This commit is contained in:
gdkchan 2018-11-11 01:09:11 -03:00
parent f79ce1271c
commit aa16232977
26 changed files with 529 additions and 433 deletions

View file

@ -13,7 +13,7 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using Nso = Ryujinx.HLE.Loaders.Executables.Nso;
using NxStaticObject = Ryujinx.HLE.Loaders.Executables.NxStaticObject;
namespace Ryujinx.HLE.HOS
{
@ -49,8 +49,6 @@ namespace Ryujinx.HLE.HOS
internal KSynchronization Synchronization { get; private set; }
internal LinkedList<KThread> Withholders { get; private set; }
internal KContextIdManager ContextIdManager { get; private set; }
private long KipId;
@ -105,8 +103,6 @@ namespace Ryujinx.HLE.HOS
Synchronization = new KSynchronization(this);
Withholders = new LinkedList<KThread>();
ContextIdManager = new KContextIdManager();
KipId = InitialKipId;
@ -118,16 +114,16 @@ namespace Ryujinx.HLE.HOS
KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.Service];
long HidPA = Region.Address;
long FontPA = Region.Address + HidSize;
long HidPa = Region.Address;
long FontPa = Region.Address + HidSize;
HidBaseAddress = HidPA - DramMemoryMap.DramBase;
HidBaseAddress = HidPa - DramMemoryMap.DramBase;
KPageList HidPageList = new KPageList();
KPageList FontPageList = new KPageList();
HidPageList .AddRange(HidPA, HidSize / KMemoryManager.PageSize);
FontPageList.AddRange(FontPA, FontSize / KMemoryManager.PageSize);
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);
@ -136,7 +132,7 @@ namespace Ryujinx.HLE.HOS
AppletState.SetFocus(true);
Font = new SharedFontManager(Device, FontPA - DramMemoryMap.DramBase);
Font = new SharedFontManager(Device, FontPa - DramMemoryMap.DramBase);
VsyncEvent = new KEvent(this);
@ -187,9 +183,7 @@ namespace Ryujinx.HLE.HOS
using (FileStream Input = new FileStream(File, FileMode.Open))
{
string Name = Path.GetFileNameWithoutExtension(File);
Nso StaticObject = new Nso(Input, Name);
NxStaticObject StaticObject = new NxStaticObject(Input);
StaticObjects.Add(StaticObject);
}
@ -420,9 +414,7 @@ namespace Ryujinx.HLE.HOS
Logger.PrintInfo(LogClass.Loader, $"Loading {Filename}...");
string Name = Path.GetFileNameWithoutExtension(File.Name);
Nso StaticObject = new Nso(Exefs.OpenFile(File), Name);
NxStaticObject StaticObject = new NxStaticObject(Exefs.OpenFile(File));
StaticObjects.Add(StaticObject);
}
@ -448,6 +440,15 @@ namespace Ryujinx.HLE.HOS
return ControlData;
}
if (ControlNca != null)
{
ReadControlData();
}
else
{
CurrentTitle = MetaData.ACI0.TitleId.ToString("x16");
}
if (!MetaData.Is64Bits)
{
throw new NotImplementedException("32-bit titles are not supported!");
@ -472,8 +473,8 @@ namespace Ryujinx.HLE.HOS
using (FileStream Input = new FileStream(FilePath, FileMode.Open))
{
IExecutable StaticObject = IsNro
? (IExecutable)new Nro(Input, FilePath)
: (IExecutable)new Nso(Input, FilePath);
? (IExecutable)new NxRelocatableObject(Input)
: (IExecutable)new NxStaticObject(Input);
ProgramLoader.LoadStaticObjects(this, MetaData, new IExecutable[] { StaticObject });
}
@ -489,11 +490,6 @@ namespace Ryujinx.HLE.HOS
}
}
private Stream GetHomebrewNpdmStream()
{
return Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.Homebrew.npdm");
}
public void LoadKeySet()
{
string KeyFile = null;

View file

@ -2,7 +2,7 @@ using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
using Ryujinx.HLE.Loaders;
using Ryujinx.HLE.Loaders.Elf;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -20,9 +20,9 @@ namespace Ryujinx.HLE.HOS.Kernel
{
public long BaseAddress { get; private set; }
public ElfSym[] Symbols { get; private set; }
public ElfSymbol[] Symbols { get; private set; }
public Image(long BaseAddress, ElfSym[] Symbols)
public Image(long BaseAddress, ElfSymbol[] Symbols)
{
this.BaseAddress = BaseAddress;
this.Symbols = Symbols;
@ -81,7 +81,9 @@ namespace Ryujinx.HLE.HOS.Kernel
while (FramePointer != 0)
{
if (!Owner.CpuMemory.IsMapped(FramePointer))
if ((FramePointer & 7) != 0 ||
!Owner.CpuMemory.IsMapped(FramePointer) ||
!Owner.CpuMemory.IsMapped(FramePointer + 8))
{
break;
}
@ -109,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Kernel
int Middle = Left + (Size >> 1);
ElfSym Symbol = Image.Symbols[Middle];
ElfSymbol Symbol = Image.Symbols[Middle];
long EndAddr = Symbol.Value + Symbol.Size;
@ -226,7 +228,7 @@ namespace Ryujinx.HLE.HOS.Kernel
return;
}
Dictionary<ElfDynTag, long> Dynamic = new Dictionary<ElfDynTag, long>();
Dictionary<ElfDynamicTag, long> Dynamic = new Dictionary<ElfDynamicTag, long>();
int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0);
@ -249,9 +251,9 @@ namespace Ryujinx.HLE.HOS.Kernel
DynamicOffset += 0x10;
ElfDynTag Tag = (ElfDynTag)TagVal;
ElfDynamicTag Tag = (ElfDynamicTag)TagVal;
if (Tag == ElfDynTag.DT_NULL)
if (Tag == ElfDynamicTag.DT_NULL)
{
break;
}
@ -259,16 +261,16 @@ namespace Ryujinx.HLE.HOS.Kernel
Dynamic[Tag] = Value;
}
long StrTblAddr = TextOffset + Dynamic[ElfDynTag.DT_STRTAB];
long SymTblAddr = TextOffset + Dynamic[ElfDynTag.DT_SYMTAB];
long StrTblAddr = TextOffset + Dynamic[ElfDynamicTag.DT_STRTAB];
long SymTblAddr = TextOffset + Dynamic[ElfDynamicTag.DT_SYMTAB];
long SymEntSize = Dynamic[ElfDynTag.DT_SYMENT];
long SymEntSize = Dynamic[ElfDynamicTag.DT_SYMENT];
List<ElfSym> Symbols = new List<ElfSym>();
List<ElfSymbol> Symbols = new List<ElfSymbol>();
while ((ulong)SymTblAddr < (ulong)StrTblAddr)
{
ElfSym Sym = GetSymbol(Memory, SymTblAddr, StrTblAddr);
ElfSymbol Sym = GetSymbol(Memory, SymTblAddr, StrTblAddr);
Symbols.Add(Sym);
@ -281,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Kernel
}
}
private ElfSym GetSymbol(MemoryManager Memory, long Address, long StrTblAddr)
private ElfSymbol GetSymbol(MemoryManager Memory, long Address, long StrTblAddr)
{
int NameIndex = Memory.ReadInt32(Address + 0);
int Info = Memory.ReadByte (Address + 4);
@ -297,7 +299,7 @@ namespace Ryujinx.HLE.HOS.Kernel
Name += (char)Chr;
}
return new ElfSym(Name, Info, Other, SHIdx, Value, Size);
return new ElfSymbol(Name, Info, Other, SHIdx, Value, Size);
}
}
}

View file

@ -10,6 +10,10 @@ namespace Ryujinx.HLE.HOS.Kernel
public bool ContextSwitchNeeded { get; private set; }
public long LastContextSwitchTime { get; private set; }
public long TotalIdleTimeTicks { get; private set; } //TODO
public KThread CurrentThread { get; private set; }
public KThread SelectedThread { get; private set; }
@ -23,11 +27,6 @@ namespace Ryujinx.HLE.HOS.Kernel
{
SelectedThread = Thread;
if (Thread != null)
{
Thread.LastScheduledTicks = PerformanceCounter.ElapsedMilliseconds;
}
if (SelectedThread != CurrentThread)
{
ContextSwitchNeeded = true;
@ -38,13 +37,25 @@ namespace Ryujinx.HLE.HOS.Kernel
{
ContextSwitchNeeded = false;
LastContextSwitchTime = PerformanceCounter.ElapsedMilliseconds;
CurrentThread = SelectedThread;
if (CurrentThread != null)
{
long CurrentTime = PerformanceCounter.ElapsedMilliseconds;
CurrentThread.TotalTimeRunning += CurrentTime - CurrentThread.LastScheduledTime;
CurrentThread.LastScheduledTime = CurrentTime;
}
}
public void ContextSwitch()
{
ContextSwitchNeeded = false;
LastContextSwitchTime = PerformanceCounter.ElapsedMilliseconds;
if (CurrentThread != null)
{
CoreManager.Reset(CurrentThread.Context.Work);
@ -54,6 +65,11 @@ namespace Ryujinx.HLE.HOS.Kernel
if (CurrentThread != null)
{
long CurrentTime = PerformanceCounter.ElapsedMilliseconds;
CurrentThread.TotalTimeRunning += CurrentTime - CurrentThread.LastScheduledTime;
CurrentThread.LastScheduledTime = CurrentTime;
CurrentThread.ClearExclusive();
CoreManager.Set(CurrentThread.Context.Work);

View file

@ -2,7 +2,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel
{
class KProcessHandleTable
class KHandleTable
{
private const int SelfThreadHandle = (0x1ffff << 15) | 0;
private const int SelfProcessHandle = (0x1ffff << 15) | 1;
@ -20,38 +20,11 @@ namespace Ryujinx.HLE.HOS.Kernel
private ushort IdCounter;
public KProcessHandleTable(Horizon System)
public KHandleTable(Horizon System)
{
this.System = System;
}
public KProcessHandleTable(Horizon System, int Size = 1024)
{
this.System = System;
this.Size = Size;
IdCounter = 1;
Table = new KHandleEntry[Size];
TableHead = new KHandleEntry(0);
KHandleEntry Entry = TableHead;
for (int Index = 0; Index < Size; Index++)
{
Table[Index] = Entry;
Entry.Next = new KHandleEntry(Index + 1);
Entry = Entry.Next;
}
Table[Size - 1].Next = null;
NextFreeEntry = TableHead;
}
public KernelResult Initialize(int Size)
{
if ((uint)Size > 1024)
@ -195,6 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel
}
}
public KProcess GetKProcess(int Handle)
{
if (Handle == SelfProcessHandle)
{
return System.Scheduler.GetCurrentProcess();
}
else
{
return GetObject<KProcess>(Handle);
}
}
public void Destroy()
{
lock (Table)

View file

@ -12,6 +12,8 @@ namespace Ryujinx.HLE.HOS.Kernel
{
public const int PageSize = 0x1000;
private const int KMemoryBlockSize = 0x40;
private LinkedList<KMemoryBlock> Blocks;
private MemoryManager CpuMemory;
@ -1953,7 +1955,7 @@ namespace Ryujinx.HLE.HOS.Kernel
throw new ArgumentException($"Invalid state value \"{State}\".");
}
private long GetAddrSpaceBaseAddr()
public long GetAddrSpaceBaseAddr()
{
if (AddrSpaceWidth == 36 || AddrSpaceWidth == 39)
{
@ -1969,7 +1971,7 @@ namespace Ryujinx.HLE.HOS.Kernel
}
}
private long GetAddrSpaceSize()
public long GetAddrSpaceSize()
{
if (AddrSpaceWidth == 36)
{
@ -2147,6 +2149,19 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success;
}
public long GetMmUsedPages()
{
lock (Blocks)
{
return BitUtils.DivRoundUp(GetMmUsedSize(), PageSize);
}
}
private long GetMmUsedSize()
{
return Blocks.Count * KMemoryBlockSize;
}
public bool InsideAddrSpace(long Address, long Size)
{
ulong Start = (ulong)Address;

View file

@ -28,10 +28,11 @@ namespace Ryujinx.HLE.HOS.Kernel
public int DefaultCpuCore { get; private set; }
public bool Debug { get; private set; }
public KResourceLimit ResourceLimit { get; private set; }
private long PersonalMmHeapBase;
private long PersonalMmHeapPagesCount;
public long PersonalMmHeapPagesCount { get; private set; }
private ProcessState State;
@ -40,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel
public KAddressArbiter AddressArbiter { get; private set; }
private long[] RandomEntropy;
public long[] RandomEntropy { get; private set; }
private bool Signaled;
private bool UseSystemMemBlocks;
@ -65,9 +66,9 @@ namespace Ryujinx.HLE.HOS.Kernel
private long MemoryUsageCapacity;
private int Category;
public KProcessHandleTable HandleTable { get; private set; }
public KHandleTable HandleTable { get; private set; }
private long TlsAddress;
public long UserExceptionContextAddress { get; private set; }
private LinkedList<KThread> Threads;
@ -345,14 +346,16 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.InvalidCombination;
}
KernelResult Result = AllocateThreadLocalStorage(out TlsAddress);
KernelResult Result = AllocateThreadLocalStorage(out long UserExceptionContextAddress);
if (Result != KernelResult.Success)
{
return Result;
}
MemoryHelper.FillWithZeros(CpuMemory, TlsAddress, KTlsPageInfo.TlsEntrySize);
this.UserExceptionContextAddress = UserExceptionContextAddress;
MemoryHelper.FillWithZeros(CpuMemory, UserExceptionContextAddress, KTlsPageInfo.TlsEntrySize);
Name = CreationInfo.Name;
@ -666,7 +669,7 @@ namespace Ryujinx.HLE.HOS.Kernel
return Result;
}
HandleTable = new KProcessHandleTable(System);
HandleTable = new KHandleTable(System);
Result = HandleTable.Initialize(Capabilities.HandleTableSize);
@ -804,6 +807,16 @@ namespace Ryujinx.HLE.HOS.Kernel
return ImageSize + MainThreadStackSize + MemoryManager.GetTotalHeapSize();
}
public long GetMemoryCapacityWithoutPersonalMmHeap()
{
return GetMemoryCapacity() - GetPersonalMmHeapSize();
}
public long GetMemoryUsageWithoutPersonalMmHeap()
{
return GetMemoryUsage() - GetPersonalMmHeapSize();
}
private long GetPersonalMmHeapSize()
{
return GetPersonalMmHeapSize(PersonalMmHeapPagesCount, MemRegion);
@ -835,12 +848,12 @@ namespace Ryujinx.HLE.HOS.Kernel
}
}
public bool IsAllowedCpuCore(int Core)
public bool IsCpuCoreAllowed(int Core)
{
return (Capabilities.AllowedCpuCoresMask & (1L << Core)) != 0;
}
public bool IsAllowedPriority(int Priority)
public bool IsPriorityAllowed(int Priority)
{
return (Capabilities.AllowedThreadPriosMask & (1L << Priority)) != 0;
}
@ -856,12 +869,12 @@ namespace Ryujinx.HLE.HOS.Kernel
bool ShallTerminate = false;
System.CriticalSection.Enter();
lock (ProcessLock)
{
if (State >= ProcessState.Started)
{
System.CriticalSection.Enter();
if (State == ProcessState.Started ||
State == ProcessState.Crashed ||
State == ProcessState.Attached ||
@ -872,8 +885,6 @@ namespace Ryujinx.HLE.HOS.Kernel
ShallTerminate = true;
}
System.CriticalSection.Leave();
Result = KernelResult.Success;
}
else
@ -882,6 +893,8 @@ namespace Ryujinx.HLE.HOS.Kernel
}
}
System.CriticalSection.Leave();
if (ShallTerminate)
{
UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread());
@ -919,6 +932,31 @@ namespace Ryujinx.HLE.HOS.Kernel
System.CriticalSection.Leave();
}
public KernelResult ClearIfNotExited()
{
KernelResult Result;
System.CriticalSection.Enter();
lock (ProcessLock)
{
if (State != ProcessState.Exited && Signaled)
{
Signaled = false;
Result = KernelResult.Success;
}
else
{
Result = KernelResult.InvalidState;
}
}
System.CriticalSection.Leave();
return Result;
}
private void CpuTraceHandler(object sender, EventArgs e)
{
System.Scheduler.GetCurrentThread().PrintGuestStackTrace();

View file

@ -82,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Kernel
}
//If the candidate was scheduled after the current thread, then it's not worth it.
if (SelectedThread == null || SelectedThread.LastScheduledTicks >= Thread.LastScheduledTicks)
if (SelectedThread == null || SelectedThread.LastScheduledTime >= Thread.LastScheduledTime)
{
yield return Thread;
}

View file

@ -16,7 +16,9 @@ namespace Ryujinx.HLE.HOS.Kernel
public long ThreadUid { get; private set; }
public KSynchronizationObject SignaledObj;
public long TotalTimeRunning { get; set; }
public KSynchronizationObject SignaledObj { get; set; }
public long CondVarAddress { get; set; }
@ -28,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Kernel
private long TlsAddress;
public long LastScheduledTicks { get; set; }
public long LastScheduledTime { get; set; }
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
@ -372,7 +374,7 @@ namespace Ryujinx.HLE.HOS.Kernel
//If the candidate was scheduled after the current thread, then it's not worth it,
//unless the priority is higher than the current one.
if (NextThreadOnCurrentQueue.LastScheduledTicks >= Thread.LastScheduledTicks ||
if (NextThreadOnCurrentQueue.LastScheduledTime >= Thread.LastScheduledTime ||
NextThreadOnCurrentQueue.DynamicPriority < Thread.DynamicPriority)
{
yield return Thread;
@ -538,13 +540,13 @@ namespace Ryujinx.HLE.HOS.Kernel
{
SyncCancelled = true;
}
else if (WithholderNode != null)
else if (Withholder != null)
{
System.Withholders.Remove(WithholderNode);
Withholder.Remove(WithholderNode);
SetNewSchedFlags(ThreadSchedState.Running);
WithholderNode = null;
Withholder = null;
SyncCancelled = true;
}
@ -561,7 +563,7 @@ namespace Ryujinx.HLE.HOS.Kernel
System.CriticalSection.Leave();
}
public long SetCoreAndAffinityMask(int NewCore, long NewAffinityMask)
public KernelResult SetCoreAndAffinityMask(int NewCore, long NewAffinityMask)
{
System.CriticalSection.Enter();
@ -576,7 +578,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{
System.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
return KernelResult.InvalidCombination;
}
}
@ -614,7 +616,7 @@ namespace Ryujinx.HLE.HOS.Kernel
System.CriticalSection.Leave();
return 0;
return KernelResult.Success;
}
private static int HighestSetCore(long Mask)
@ -662,13 +664,13 @@ namespace Ryujinx.HLE.HOS.Kernel
if ((SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
{
if (WithholderNode != null)
if (Withholder != null)
{
System.Withholders.Remove(WithholderNode);
Withholder.Remove(WithholderNode);
SetNewSchedFlags(ThreadSchedState.Running);
WithholderNode = null;
Withholder = null;
}
else
{

View file

@ -1,6 +1,6 @@
using Ryujinx.Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@ -25,18 +25,12 @@ namespace Ryujinx.HLE.HOS.Kernel
private AutoResetEvent WaitEvent;
private Stopwatch Counter;
private bool KeepRunning;
public KTimeManager()
{
WaitingObjects = new List<WaitingObject>();
Counter = new Stopwatch();
Counter.Start();
KeepRunning = true;
Thread Work = new Thread(WaitAndCheckScheduledObjects);
@ -46,31 +40,36 @@ namespace Ryujinx.HLE.HOS.Kernel
public void ScheduleFutureInvocation(IKFutureSchedulerObject Object, long Timeout)
{
long TimePoint = PerformanceCounter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(Timeout);
lock (WaitingObjects)
{
long TimePoint = Counter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(Timeout);
WaitingObjects.Add(new WaitingObject(Object, TimePoint));
}
WaitEvent.Set();
}
public static long ConvertNanosecondsToMilliseconds(long Timeout)
public static long ConvertNanosecondsToMilliseconds(long Time)
{
Timeout /= 1000000;
Time /= 1000000;
if ((ulong)Timeout > int.MaxValue)
if ((ulong)Time > int.MaxValue)
{
return int.MaxValue;
}
return Timeout;
return Time;
}
public static long ConvertMillisecondsToNanoseconds(long Timeout)
public static long ConvertMillisecondsToNanoseconds(long Time)
{
return Timeout * 1000000;
return Time * 1000000;
}
public static long ConvertMillisecondsToTicks(long Time)
{
return Time * 19200;
}
public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object)
@ -87,26 +86,31 @@ namespace Ryujinx.HLE.HOS.Kernel
{
while (KeepRunning)
{
Monitor.Enter(WaitingObjects);
WaitingObject Next;
WaitingObject Next = WaitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
Monitor.Exit(WaitingObjects);
lock (WaitingObjects)
{
Next = WaitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
}
if (Next != null)
{
long TimePoint = Counter.ElapsedMilliseconds;
long TimePoint = PerformanceCounter.ElapsedMilliseconds;
if (Next.TimePoint > TimePoint)
{
WaitEvent.WaitOne((int)(Next.TimePoint - TimePoint));
}
Monitor.Enter(WaitingObjects);
bool TimeUp = PerformanceCounter.ElapsedMilliseconds >= Next.TimePoint;
bool TimeUp = Counter.ElapsedMilliseconds >= Next.TimePoint && WaitingObjects.Remove(Next);
Monitor.Exit(WaitingObjects);
if (TimeUp)
{
lock (WaitingObjects)
{
TimeUp = WaitingObjects.Remove(Next);
}
}
if (TimeUp)
{

View file

@ -19,6 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel
TimedOut = 0xea01,
Cancelled = 0xec01,
MaximumExceeded = 0xee01,
InvalidEnumValue = 0xf001,
InvalidThread = 0xf401,
InvalidState = 0xfa01,
ReservedValue = 0xfc01,

View file

@ -58,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ 0x0c, SvcGetThreadPriority },
{ 0x0d, SvcSetThreadPriority },
{ 0x0e, SvcGetThreadCoreMask },
{ 0x0f, SvcSetThreadCoreMask },
{ 0x0f, SetThreadCoreMask64 },
{ 0x10, SvcGetCurrentProcessorNumber },
{ 0x11, SignalEvent64 },
{ 0x12, ClearEvent64 },
@ -80,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ 0x25, SvcGetThreadId },
{ 0x26, SvcBreak },
{ 0x27, SvcOutputDebugString },
{ 0x29, SvcGetInfo },
{ 0x29, GetInfo64 },
{ 0x2c, SvcMapPhysicalMemory },
{ 0x2d, SvcUnmapPhysicalMemory },
{ 0x32, SvcSetThreadActivity },

View file

@ -1,5 +1,6 @@
using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
@ -120,18 +121,28 @@ namespace Ryujinx.HLE.HOS.Kernel
private KernelResult ResetSignal(int Handle)
{
KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
KReadableEvent ReadableEvent = CurrentProcess.HandleTable.GetObject<KReadableEvent>(Handle);
KernelResult Result;
//TODO: KProcess support.
if (ReadableEvent != null)
{
Result = ReadableEvent.ClearIfSignaled();
}
else
{
Result = KernelResult.InvalidHandle;
KProcess Process = CurrentProcess.HandleTable.GetKProcess(Handle);
if (Process != null)
{
Result = Process.ClearIfNotExited();
}
else
{
Result = KernelResult.InvalidHandle;
}
}
if (Result == KernelResult.InvalidState)
@ -271,98 +282,240 @@ namespace Ryujinx.HLE.HOS.Kernel
ThreadState.X0 = 0;
}
private void SvcGetInfo(CpuThreadState ThreadState)
private void GetInfo64(CpuThreadState ThreadState)
{
long StackPtr = (long)ThreadState.X0;
int InfoType = (int)ThreadState.X1;
long Handle = (long)ThreadState.X2;
int InfoId = (int)ThreadState.X3;
int Id = (int)ThreadState.X1;
int Handle = (int)ThreadState.X2;
long SubId = (long)ThreadState.X3;
//Fail for info not available on older Kernel versions.
if (InfoType == 18 ||
InfoType == 19 ||
InfoType == 20 ||
InfoType == 21 ||
InfoType == 22)
{
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
KernelResult Result = GetInfo(Id, Handle, SubId, out long Value);
return;
}
ThreadState.X0 = (ulong)Result;
ThreadState.X1 = (ulong)Value;
}
switch (InfoType)
private KernelResult GetInfo(int Id, int Handle, long SubId, out long Value)
{
Value = 0;
switch (Id)
{
case 0:
ThreadState.X1 = AllowedCpuIdBitmask;
break;
case 1:
case 2:
ThreadState.X1 = (ulong)Process.MemoryManager.AliasRegionStart;
break;
case 3:
ThreadState.X1 = (ulong)Process.MemoryManager.AliasRegionEnd -
(ulong)Process.MemoryManager.AliasRegionStart;
break;
case 4:
ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart;
break;
case 5:
ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd -
(ulong)Process.MemoryManager.HeapRegionStart;
break;
case 6:
ThreadState.X1 = (ulong)Process.GetMemoryCapacity();
break;
case 7:
ThreadState.X1 = (ulong)Process.GetMemoryUsage();
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 20:
case 21:
case 22:
{
if (SubId != 0)
{
return KernelResult.InvalidCombination;
}
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
KProcess Process = CurrentProcess.HandleTable.GetKProcess(Handle);
if (Process == null)
{
return KernelResult.InvalidHandle;
}
switch (Id)
{
case 0: Value = Process.Capabilities.AllowedCpuCoresMask; break;
case 1: Value = Process.Capabilities.AllowedThreadPriosMask; break;
case 2: Value = Process.MemoryManager.AliasRegionStart; break;
case 3: Value = Process.MemoryManager.AliasRegionEnd -
Process.MemoryManager.AliasRegionStart; break;
case 4: Value = Process.MemoryManager.HeapRegionStart; break;
case 5: Value = Process.MemoryManager.HeapRegionEnd -
Process.MemoryManager.HeapRegionStart; break;
case 6: Value = Process.GetMemoryCapacity(); break;
case 7: Value = Process.GetMemoryUsage(); break;
case 12: Value = Process.MemoryManager.GetAddrSpaceBaseAddr(); break;
case 13: Value = Process.MemoryManager.GetAddrSpaceSize(); break;
case 14: Value = Process.MemoryManager.StackRegionStart; break;
case 15: Value = Process.MemoryManager.StackRegionEnd -
Process.MemoryManager.StackRegionStart; break;
case 16: Value = Process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break;
case 17:
if (Process.PersonalMmHeapPagesCount != 0)
{
Value = Process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize;
}
break;
case 18: Value = Process.TitleId; break;
case 20: Value = Process.UserExceptionContextAddress; break;
case 21: Value = Process.GetMemoryCapacityWithoutPersonalMmHeap(); break;
case 22: Value = Process.GetMemoryUsageWithoutPersonalMmHeap(); break;
}
break;
}
case 8:
ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
{
if (Handle != 0)
{
return KernelResult.InvalidHandle;
}
if (SubId != 0)
{
return KernelResult.InvalidCombination;
}
Value = System.Scheduler.GetCurrentProcess().Debug ? 1 : 0;
break;
}
case 9:
{
if (Handle != 0)
{
return KernelResult.InvalidHandle;
}
if (SubId != 0)
{
return KernelResult.InvalidCombination;
}
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
if (CurrentProcess.ResourceLimit != null)
{
KHandleTable HandleTable = CurrentProcess.HandleTable;
KResourceLimit ResourceLimit = CurrentProcess.ResourceLimit;
KernelResult Result = HandleTable.GenerateHandle(ResourceLimit, out int ResLimHandle);
if (Result != KernelResult.Success)
{
return Result;
}
Value = (uint)ResLimHandle;
}
break;
}
case 10:
{
if (Handle != 0)
{
return KernelResult.InvalidHandle;
}
int CurrentCore = System.Scheduler.GetCurrentThread().CurrentCore;
if (SubId != -1 && SubId != CurrentCore)
{
return KernelResult.InvalidCombination;
}
Value = System.Scheduler.CoreContexts[CurrentCore].TotalIdleTimeTicks;
break;
}
case 11:
ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
{
if (Handle != 0)
{
return KernelResult.InvalidHandle;
}
if ((ulong)SubId > 3)
{
return KernelResult.InvalidCombination;
}
Value = System.Scheduler.GetCurrentProcess().RandomEntropy[SubId];
break;
}
case unchecked((int)0xf0000002u):
{
if (SubId < -1 || SubId > 3)
{
return KernelResult.InvalidCombination;
}
KThread Thread = System.Scheduler.GetCurrentProcess().HandleTable.GetKThread(Handle);
if (Thread == null)
{
return KernelResult.InvalidHandle;
}
KThread CurrentThread = System.Scheduler.GetCurrentThread();
int CurrentCore = CurrentThread.CurrentCore;
if (SubId != -1 && SubId != CurrentCore)
{
return KernelResult.Success;
}
KCoreContext CoreContext = System.Scheduler.CoreContexts[CurrentCore];
long TimeDelta = PerformanceCounter.ElapsedMilliseconds - CoreContext.LastContextSwitchTime;
if (SubId != -1)
{
Value = KTimeManager.ConvertMillisecondsToTicks(TimeDelta);
}
else
{
long TotalTimeRunning = Thread.TotalTimeRunning;
if (Thread == CurrentThread)
{
TotalTimeRunning += TimeDelta;
}
Value = KTimeManager.ConvertMillisecondsToTicks(TotalTimeRunning);
}
case 12:
ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart;
break;
}
case 13:
ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd -
(ulong)Process.MemoryManager.AddrSpaceStart;
break;
case 14:
ThreadState.X1 = (ulong)Process.MemoryManager.StackRegionStart;
break;
case 15:
ThreadState.X1 = (ulong)Process.MemoryManager.StackRegionEnd -
(ulong)Process.MemoryManager.StackRegionStart;
break;
case 16:
//ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0);
break;
case 17:
ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage;
break;
default:
//Process.PrintStackTrace(ThreadState);
throw new NotImplementedException($"SvcGetInfo: {InfoType} 0x{Handle:x8} {InfoId}");
default: return KernelResult.InvalidEnumValue;
}
ThreadState.X0 = 0;
return KernelResult.Success;
}
private void CreateEvent64(CpuThreadState State)

View file

@ -38,12 +38,12 @@ namespace Ryujinx.HLE.HOS.Kernel
CpuCore = CurrentProcess.DefaultCpuCore;
}
if ((uint)CpuCore >= KScheduler.CpuCoresCount || !CurrentProcess.IsAllowedCpuCore(CpuCore))
if ((uint)CpuCore >= KScheduler.CpuCoresCount || !CurrentProcess.IsCpuCoreAllowed(CpuCore))
{
return KernelResult.InvalidCpuCore;
}
if ((uint)Priority >= KScheduler.PrioritiesCount || !CurrentProcess.IsAllowedPriority(Priority))
if ((uint)Priority >= KScheduler.PrioritiesCount || !CurrentProcess.IsPriorityAllowed(Priority))
{
return KernelResult.InvalidPriority;
}
@ -212,46 +212,60 @@ namespace Ryujinx.HLE.HOS.Kernel
}
}
private void SvcSetThreadCoreMask(CpuThreadState ThreadState)
private void SetThreadCoreMask64(CpuThreadState ThreadState)
{
int Handle = (int)ThreadState.X0;
int PrefferedCore = (int)ThreadState.X1;
int PreferredCore = (int)ThreadState.X1;
long AffinityMask = (long)ThreadState.X2;
Logger.PrintDebug(LogClass.KernelSvc,
"Handle = 0x" + Handle .ToString("x8") + ", " +
"PrefferedCore = 0x" + PrefferedCore.ToString("x8") + ", " +
"PreferredCore = 0x" + PreferredCore.ToString("x8") + ", " +
"AffinityMask = 0x" + AffinityMask .ToString("x16"));
if (PrefferedCore == -2)
{
//TODO: Get this value from the NPDM file.
PrefferedCore = 0;
KernelResult Result = SetThreadCoreMask(Handle, PreferredCore, AffinityMask);
AffinityMask = 1 << PrefferedCore;
if (Result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
}
ThreadState.X0 = (ulong)Result;
}
private KernelResult SetThreadCoreMask(int Handle, int PreferredCore, long AffinityMask)
{
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
if (PreferredCore == -2)
{
PreferredCore = CurrentProcess.DefaultCpuCore;
AffinityMask = 1 << PreferredCore;
}
else
{
//TODO: Check allowed cores from NPDM file.
if ((uint)PrefferedCore > 3)
if ((CurrentProcess.Capabilities.AllowedCpuCoresMask | AffinityMask) !=
CurrentProcess.Capabilities.AllowedCpuCoresMask)
{
if ((PrefferedCore | 2) != -1)
return KernelResult.InvalidCpuCore;
}
if (AffinityMask == 0)
{
return KernelResult.InvalidCombination;
}
if ((uint)PreferredCore > 3)
{
if ((PreferredCore | 2) != -1)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{PrefferedCore:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
return;
return KernelResult.InvalidCpuCore;
}
}
else if ((AffinityMask & (1 << PrefferedCore)) == 0)
else if ((AffinityMask & (1 << PreferredCore)) == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{AffinityMask:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
return;
return KernelResult.InvalidCombination;
}
}
@ -259,21 +273,10 @@ namespace Ryujinx.HLE.HOS.Kernel
if (Thread == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
return KernelResult.InvalidHandle;
}
long Result = Thread.SetCoreAndAffinityMask(PrefferedCore, AffinityMask);
if (Result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
}
ThreadState.X0 = (ulong)Result;
return Thread.SetCoreAndAffinityMask(PreferredCore, AffinityMask);
}
private void SvcGetCurrentProcessorNumber(CpuThreadState ThreadState)

View file

@ -63,13 +63,13 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
class NroInfo
{
public Nro Executable { get; private set; }
public NxRelocatableObject Executable { get; private set; }
public byte[] Hash { get; private set; }
public long NroAddress { get; private set; }
public long TotalSize { get; private set; }
public long NroMappedAddress { get; set; }
public NroInfo(Nro Executable, byte[] Hash, long TotalSize)
public NroInfo(NxRelocatableObject Executable, byte[] Hash, long TotalSize)
{
this.Executable = Executable;
this.Hash = Hash;
@ -226,19 +226,19 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
Stream.Position = 0;
Nro Executable = new Nro(Stream, "memory", NroHeapAddress, BssHeapAddress);
NxRelocatableObject Executable = new NxRelocatableObject(Stream, NroHeapAddress, BssHeapAddress);
// check if everything is page align.
if ((Executable.Text.Length & 0xFFF) != 0 || (Executable.RO.Length & 0xFFF) != 0
|| (Executable.Data.Length & 0xFFF) != 0 || (Executable.BssSize & 0xFFF) != 0)
if ((Executable.Text.Length & 0xFFF) != 0 || (Executable.RO.Length & 0xFFF) != 0 ||
(Executable.Data.Length & 0xFFF) != 0 || (Executable.BssSize & 0xFFF) != 0)
{
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
}
// check if everything is contiguous.
if (Executable.ROOffset != Executable.TextOffset + Executable.Text.Length
|| Executable.DataOffset != Executable.ROOffset + Executable.RO.Length
|| NroFileSize != Executable.DataOffset + Executable.Data.Length)
if (Executable.ROOffset != Executable.TextOffset + Executable.Text.Length ||
Executable.DataOffset != Executable.ROOffset + Executable.RO.Length ||
NroFileSize != Executable.DataOffset + Executable.Data.Length)
{
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
}

View file

@ -0,0 +1,15 @@
namespace Ryujinx.HLE.Loaders.Elf
{
struct ElfDynamic
{
public ElfDynamicTag Tag { get; private set; }
public long Value { get; private set; }
public ElfDynamic(ElfDynamicTag Tag, long Value)
{
this.Tag = Tag;
this.Value = Value;
}
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.Loaders
namespace Ryujinx.HLE.Loaders.Elf
{
enum ElfDynTag
enum ElfDynamicTag
{
DT_NULL = 0,
DT_NEEDED = 1,

View file

@ -0,0 +1,40 @@
namespace Ryujinx.HLE.Loaders.Elf
{
struct ElfSymbol
{
public string Name { get; private set; }
public ElfSymbolType Type { get; private set; }
public ElfSymbolBinding Binding { get; private set; }
public ElfSymbolVisibility Visibility { get; private set; }
public bool IsFuncOrObject =>
Type == ElfSymbolType.STT_FUNC ||
Type == ElfSymbolType.STT_OBJECT;
public bool IsGlobalOrWeak =>
Binding == ElfSymbolBinding.STB_GLOBAL ||
Binding == ElfSymbolBinding.STB_WEAK;
public int SHIdx { get; private set; }
public long Value { get; private set; }
public long Size { get; private set; }
public ElfSymbol(
string Name,
int Info,
int Other,
int SHIdx,
long Value,
long Size)
{
this.Name = Name;
this.Type = (ElfSymbolType)(Info & 0xf);
this.Binding = (ElfSymbolBinding)(Info >> 4);
this.Visibility = (ElfSymbolVisibility)Other;
this.SHIdx = SHIdx;
this.Value = Value;
this.Size = Size;
}
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.Loaders
namespace Ryujinx.HLE.Loaders.Elf
{
enum ElfSymBinding
enum ElfSymbolBinding
{
STB_LOCAL = 0,
STB_GLOBAL = 1,

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.Loaders
namespace Ryujinx.HLE.Loaders.Elf
{
enum ElfSymType
enum ElfSymbolType
{
STT_NOTYPE = 0,
STT_OBJECT = 1,

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.Loaders
namespace Ryujinx.HLE.Loaders.Elf
{
enum ElfSymVisibility
enum ElfSymbolVisibility
{
STV_DEFAULT = 0,
STV_INTERNAL = 1,

View file

@ -1,15 +0,0 @@
namespace Ryujinx.HLE.Loaders
{
struct ElfDyn
{
public ElfDynTag Tag { get; private set; }
public long Value { get; private set; }
public ElfDyn(ElfDynTag Tag, long Value)
{
this.Tag = Tag;
this.Value = Value;
}
}
}

View file

@ -1,40 +0,0 @@
namespace Ryujinx.HLE.Loaders
{
struct ElfSym
{
public string Name { get; private set; }
public ElfSymType Type { get; private set; }
public ElfSymBinding Binding { get; private set; }
public ElfSymVisibility Visibility { get; private set; }
public bool IsFuncOrObject =>
Type == ElfSymType.STT_FUNC ||
Type == ElfSymType.STT_OBJECT;
public bool IsGlobalOrWeak =>
Binding == ElfSymBinding.STB_GLOBAL ||
Binding == ElfSymBinding.STB_WEAK;
public int SHIdx { get; private set; }
public long Value { get; private set; }
public long Size { get; private set; }
public ElfSym(
string Name,
int Info,
int Other,
int SHIdx,
long Value,
long Size)
{
this.Name = Name;
this.Type = (ElfSymType)(Info & 0xf);
this.Binding = (ElfSymBinding)(Info >> 4);
this.Visibility = (ElfSymVisibility)Other;
this.SHIdx = SHIdx;
this.Value = Value;
this.Size = Size;
}
}
}

View file

@ -1,110 +0,0 @@
using ChocolArm64.Memory;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.Loaders.Executables;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Ryujinx.HLE.Loaders
{
class Executable
{
private MemoryManager Memory;
private List<ElfDyn> Dynamic;
public ReadOnlyCollection<ElfSym> SymbolTable;
public string Name { get; private set; }
public string FilePath { get; private set; }
public long ImageBase { get; private set; }
public long ImageEnd { get; private set; }
private KMemoryManager MemoryManager;
public Executable(IExecutable Exe, KMemoryManager MemoryManager, MemoryManager Memory, long ImageBase)
{
Dynamic = new List<ElfDyn>();
long Mod0Offset = ImageBase + Exe.Mod0Offset;
int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0);
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.Add(new ElfDyn(Tag, Value));
}
long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB);
long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB);
long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT);
List<ElfSym> Symbols = new List<ElfSym>();
while ((ulong)SymTblAddr < (ulong)StrTblAddr)
{
ElfSym Sym = GetSymbol(SymTblAddr, StrTblAddr);
Symbols.Add(Sym);
SymTblAddr += SymEntSize;
}
SymbolTable = Array.AsReadOnly(Symbols.OrderBy(x => x.Value).ToArray());
}
private ElfSym GetSymbol(long Position, long StrTblAddr)
{
int NameIndex = Memory.ReadInt32(Position + 0);
int Info = Memory.ReadByte(Position + 4);
int Other = Memory.ReadByte(Position + 5);
int SHIdx = Memory.ReadInt16(Position + 6);
long Value = Memory.ReadInt64(Position + 8);
long Size = Memory.ReadInt64(Position + 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);
}
private long GetFirstValue(ElfDynTag Tag)
{
foreach (ElfDyn Entry in Dynamic)
{
if (Entry.Tag == Tag)
{
return Entry.Value;
}
}
return 0;
}
}
}

View file

@ -2,8 +2,6 @@ namespace Ryujinx.HLE.Loaders.Executables
{
interface IExecutable
{
string FilePath { get; }
byte[] Text { get; }
byte[] RO { get; }
byte[] Data { get; }

View file

@ -2,10 +2,8 @@ using System.IO;
namespace Ryujinx.HLE.Loaders.Executables
{
class Nro : IExecutable
class NxRelocatableObject : IExecutable
{
public string FilePath { get; private set; }
public byte[] Text { get; private set; }
public byte[] RO { get; private set; }
public byte[] Data { get; private set; }
@ -19,9 +17,8 @@ namespace Ryujinx.HLE.Loaders.Executables
public long SourceAddress { get; private set; }
public long BssAddress { get; private set; }
public Nro(Stream Input, string FilePath, long SourceAddress = 0, long BssAddress = 0)
public NxRelocatableObject(Stream Input, long SourceAddress = 0, long BssAddress = 0)
{
this.FilePath = FilePath;
this.SourceAddress = SourceAddress;
this.BssAddress = BssAddress;

View file

@ -4,10 +4,8 @@ using System.IO;
namespace Ryujinx.HLE.Loaders.Executables
{
class Nso : IExecutable
class NxStaticObject : IExecutable
{
public string FilePath { get; private set; }
public byte[] Text { get; private set; }
public byte[] RO { get; private set; }
public byte[] Data { get; private set; }
@ -29,10 +27,8 @@ namespace Ryujinx.HLE.Loaders.Executables
HasDataHash = 1 << 5
}
public Nso(Stream Input, string FilePath)
public NxStaticObject(Stream Input)
{
this.FilePath = FilePath;
BinaryReader Reader = new BinaryReader(Input);
Input.Seek(0, SeekOrigin.Begin);
@ -83,7 +79,7 @@ namespace Ryujinx.HLE.Loaders.Executables
Text = Reader.ReadBytes(TextSize);
if (Flags.HasFlag(NsoFlags.IsTextCompressed) || true)
if (Flags.HasFlag(NsoFlags.IsTextCompressed))
{
Text = Lz4.Decompress(Text, TextDecSize);
}
@ -93,7 +89,7 @@ namespace Ryujinx.HLE.Loaders.Executables
RO = Reader.ReadBytes(ROSize);
if (Flags.HasFlag(NsoFlags.IsROCompressed) || true)
if (Flags.HasFlag(NsoFlags.IsROCompressed))
{
RO = Lz4.Decompress(RO, RODecSize);
}
@ -103,7 +99,7 @@ namespace Ryujinx.HLE.Loaders.Executables
Data = Reader.ReadBytes(DataSize);
if (Flags.HasFlag(NsoFlags.IsDataCompressed) || true)
if (Flags.HasFlag(NsoFlags.IsDataCompressed))
{
Data = Lz4.Decompress(Data, DataDecSize);
}