diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 0b94a11abe..800ac2e823 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -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 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(); - 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; diff --git a/Ryujinx.HLE/HOS/Kernel/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/HleProcessDebugger.cs index 5207950c36..11360b617f 100644 --- a/Ryujinx.HLE/HOS/Kernel/HleProcessDebugger.cs +++ b/Ryujinx.HLE/HOS/Kernel/HleProcessDebugger.cs @@ -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 Dynamic = new Dictionary(); + Dictionary Dynamic = new Dictionary(); 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 Symbols = new List(); + List Symbols = new List(); 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); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KCoreContext.cs b/Ryujinx.HLE/HOS/Kernel/KCoreContext.cs index 39f9625b28..638dde9eeb 100644 --- a/Ryujinx.HLE/HOS/Kernel/KCoreContext.cs +++ b/Ryujinx.HLE/HOS/Kernel/KCoreContext.cs @@ -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); diff --git a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/KHandleTable.cs similarity index 87% rename from Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs rename to Ryujinx.HLE/HOS/Kernel/KHandleTable.cs index c88b9c9230..e39dfb671d 100644 --- a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/KHandleTable.cs @@ -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(Handle); + } + } + public void Destroy() { lock (Table) diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs index 13552cf934..2589203fdc 100644 --- a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs @@ -12,6 +12,8 @@ namespace Ryujinx.HLE.HOS.Kernel { public const int PageSize = 0x1000; + private const int KMemoryBlockSize = 0x40; + private LinkedList 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; diff --git a/Ryujinx.HLE/HOS/Kernel/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/KProcess.cs index 2c349d9136..0044cd8d35 100644 --- a/Ryujinx.HLE/HOS/Kernel/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/KProcess.cs @@ -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 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(); diff --git a/Ryujinx.HLE/HOS/Kernel/KScheduler.cs b/Ryujinx.HLE/HOS/Kernel/KScheduler.cs index fb83867958..3342f4a613 100644 --- a/Ryujinx.HLE/HOS/Kernel/KScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/KScheduler.cs @@ -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; } diff --git a/Ryujinx.HLE/HOS/Kernel/KThread.cs b/Ryujinx.HLE/HOS/Kernel/KThread.cs index f52c20d5c8..6b908f2b20 100644 --- a/Ryujinx.HLE/HOS/Kernel/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/KThread.cs @@ -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[] 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 { diff --git a/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs b/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs index febd985419..375789f057 100644 --- a/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs @@ -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(); - 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) { diff --git a/Ryujinx.HLE/HOS/Kernel/KernelResult.cs b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs index 060fe5ccb5..ad0be5a20c 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelResult.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs @@ -19,6 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel TimedOut = 0xea01, Cancelled = 0xec01, MaximumExceeded = 0xee01, + InvalidEnumValue = 0xf001, InvalidThread = 0xf401, InvalidState = 0xfa01, ReservedValue = 0xfc01, diff --git a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs index 27fc377b43..005c051972 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs @@ -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 }, diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs index bd6715a7f3..e79fe0f55b 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs @@ -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(Handle); + KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); + + KReadableEvent ReadableEvent = CurrentProcess.HandleTable.GetObject(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) diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs index 65bb908139..ac0cf86a7a 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs @@ -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) diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs index e571006436..442f01bfd7 100644 --- a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs @@ -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); } diff --git a/Ryujinx.HLE/Loaders/Elf/ElfDynamic.cs b/Ryujinx.HLE/Loaders/Elf/ElfDynamic.cs new file mode 100644 index 0000000000..fb0ea53e09 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Elf/ElfDynamic.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/ElfDynTag.cs b/Ryujinx.HLE/Loaders/Elf/ElfDynamicTag.cs similarity index 97% rename from Ryujinx.HLE/Loaders/ElfDynTag.cs rename to Ryujinx.HLE/Loaders/Elf/ElfDynamicTag.cs index 5915d4d123..9d7ad72e09 100644 --- a/Ryujinx.HLE/Loaders/ElfDynTag.cs +++ b/Ryujinx.HLE/Loaders/Elf/ElfDynamicTag.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.HLE.Loaders +namespace Ryujinx.HLE.Loaders.Elf { - enum ElfDynTag + enum ElfDynamicTag { DT_NULL = 0, DT_NEEDED = 1, diff --git a/Ryujinx.HLE/Loaders/Elf/ElfSymbol.cs b/Ryujinx.HLE/Loaders/Elf/ElfSymbol.cs new file mode 100644 index 0000000000..3f3a2a7909 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Elf/ElfSymbol.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/ElfSymBinding.cs b/Ryujinx.HLE/Loaders/Elf/ElfSymbolBinding.cs similarity index 58% rename from Ryujinx.HLE/Loaders/ElfSymBinding.cs rename to Ryujinx.HLE/Loaders/Elf/ElfSymbolBinding.cs index f1d249ec24..3c915311eb 100644 --- a/Ryujinx.HLE/Loaders/ElfSymBinding.cs +++ b/Ryujinx.HLE/Loaders/Elf/ElfSymbolBinding.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.HLE.Loaders +namespace Ryujinx.HLE.Loaders.Elf { - enum ElfSymBinding + enum ElfSymbolBinding { STB_LOCAL = 0, STB_GLOBAL = 1, diff --git a/Ryujinx.HLE/Loaders/ElfSymType.cs b/Ryujinx.HLE/Loaders/Elf/ElfSymbolType.cs similarity index 76% rename from Ryujinx.HLE/Loaders/ElfSymType.cs rename to Ryujinx.HLE/Loaders/Elf/ElfSymbolType.cs index 478064bc4b..f22e6c45fc 100644 --- a/Ryujinx.HLE/Loaders/ElfSymType.cs +++ b/Ryujinx.HLE/Loaders/Elf/ElfSymbolType.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.HLE.Loaders +namespace Ryujinx.HLE.Loaders.Elf { - enum ElfSymType + enum ElfSymbolType { STT_NOTYPE = 0, STT_OBJECT = 1, diff --git a/Ryujinx.HLE/Loaders/ElfSymVisibility.cs b/Ryujinx.HLE/Loaders/Elf/ElfSymbolVisibility.cs similarity index 65% rename from Ryujinx.HLE/Loaders/ElfSymVisibility.cs rename to Ryujinx.HLE/Loaders/Elf/ElfSymbolVisibility.cs index fe7243a7ae..4bec50a37f 100644 --- a/Ryujinx.HLE/Loaders/ElfSymVisibility.cs +++ b/Ryujinx.HLE/Loaders/Elf/ElfSymbolVisibility.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.HLE.Loaders +namespace Ryujinx.HLE.Loaders.Elf { - enum ElfSymVisibility + enum ElfSymbolVisibility { STV_DEFAULT = 0, STV_INTERNAL = 1, diff --git a/Ryujinx.HLE/Loaders/ElfDyn.cs b/Ryujinx.HLE/Loaders/ElfDyn.cs deleted file mode 100644 index 3508e6e4e0..0000000000 --- a/Ryujinx.HLE/Loaders/ElfDyn.cs +++ /dev/null @@ -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; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/ElfSym.cs b/Ryujinx.HLE/Loaders/ElfSym.cs deleted file mode 100644 index 869938d357..0000000000 --- a/Ryujinx.HLE/Loaders/ElfSym.cs +++ /dev/null @@ -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; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs deleted file mode 100644 index ed2e066be9..0000000000 --- a/Ryujinx.HLE/Loaders/Executable.cs +++ /dev/null @@ -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 Dynamic; - - public ReadOnlyCollection 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(); - - 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 Symbols = new List(); - - 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; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs index 82b284534c..f9059c96aa 100644 --- a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs +++ b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs @@ -2,8 +2,6 @@ namespace Ryujinx.HLE.Loaders.Executables { interface IExecutable { - string FilePath { get; } - byte[] Text { get; } byte[] RO { get; } byte[] Data { get; } diff --git a/Ryujinx.HLE/Loaders/Executables/Nro.cs b/Ryujinx.HLE/Loaders/Executables/NxRelocatableObject.cs similarity index 90% rename from Ryujinx.HLE/Loaders/Executables/Nro.cs rename to Ryujinx.HLE/Loaders/Executables/NxRelocatableObject.cs index 6015da2132..8feb7e6684 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nro.cs +++ b/Ryujinx.HLE/Loaders/Executables/NxRelocatableObject.cs @@ -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; diff --git a/Ryujinx.HLE/Loaders/Executables/Nso.cs b/Ryujinx.HLE/Loaders/Executables/NxStaticObject.cs similarity index 90% rename from Ryujinx.HLE/Loaders/Executables/Nso.cs rename to Ryujinx.HLE/Loaders/Executables/NxStaticObject.cs index fef9c4b853..7473197622 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nso.cs +++ b/Ryujinx.HLE/Loaders/Executables/NxStaticObject.cs @@ -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); }