From b99e808791f0d1d39946b5fce0026592bfa4646c Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 6 Feb 2018 20:28:32 -0300 Subject: [PATCH] Support loading NSO/NRO without a MOD0 header, stub some functions, support more ids on SvcGetInfo --- Ryujinx/Cpu/Translation/AILEmitterCtx.cs | 2 +- Ryujinx/Loaders/Executable.cs | 27 ++++++---- .../Executables/{IElf.cs => IExecutable.cs} | 2 +- Ryujinx/Loaders/Executables/Nro.cs | 2 +- Ryujinx/Loaders/Executables/Nso.cs | 2 +- Ryujinx/OsHle/Ipc/IpcHandler.cs | 37 +++++++++---- .../OsHle/Objects/AmIApplicationFunctions.cs | 7 +++ Ryujinx/OsHle/Objects/AmISelfController.cs | 7 +++ .../Objects/ViIApplicationDisplayService.cs | 7 +++ Ryujinx/OsHle/Process.cs | 4 +- Ryujinx/OsHle/Services/ServiceFspSrv.cs | 7 +++ Ryujinx/OsHle/Services/ServiceNvDrv.cs | 9 ++++ Ryujinx/OsHle/Svc/SvcHandler.cs | 3 +- Ryujinx/OsHle/Svc/SvcSystem.cs | 53 +++++++++++++++++-- Ryujinx/VirtualFs.cs | 25 +++++---- 15 files changed, 153 insertions(+), 41 deletions(-) rename Ryujinx/Loaders/Executables/{IElf.cs => IExecutable.cs} (93%) diff --git a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs index bf56db212..410308ff8 100644 --- a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs +++ b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs @@ -147,7 +147,7 @@ namespace ChocolArm64.Translation int IntCond = (int)Cond; - if (LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond)) + if (LastCmpOp != null && LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond)) { Ldloc(Tmp3Index, AIoType.Int, GetIntType(LastCmpOp)); Ldloc(Tmp4Index, AIoType.Int, GetIntType(LastCmpOp)); diff --git a/Ryujinx/Loaders/Executable.cs b/Ryujinx/Loaders/Executable.cs index 31caf2946..4a3d36f57 100644 --- a/Ryujinx/Loaders/Executable.cs +++ b/Ryujinx/Loaders/Executable.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Loaders { class Executable { - private IElf NsoData; + private IExecutable NsoData; private AMemory Memory; private ElfDyn[] Dynamic; @@ -15,23 +15,25 @@ namespace Ryujinx.Loaders public long ImageBase { get; private set; } public long ImageEnd { get; private set; } - public Executable(IElf NsoData, AMemory Memory, long ImageBase) + public Executable(IExecutable Exe, AMemory Memory, long ImageBase) { - this.NsoData = NsoData; + this.NsoData = Exe; this.Memory = Memory; this.ImageBase = ImageBase; this.ImageEnd = ImageBase; - WriteData(ImageBase + NsoData.TextOffset, NsoData.Text, MemoryType.CodeStatic, AMemoryPerm.RX); - WriteData(ImageBase + NsoData.ROOffset, NsoData.RO, MemoryType.Normal, AMemoryPerm.Read); - WriteData(ImageBase + NsoData.DataOffset, NsoData.Data, MemoryType.Normal, AMemoryPerm.RW); + WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX); + WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.Normal, AMemoryPerm.Read); + WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.Normal, AMemoryPerm.RW); - if (NsoData.Text.Count == 0) + if (Exe.Mod0Offset == 0) { + MapBss(ImageBase + Exe.DataOffset + Exe.Data.Count, Exe.BssSize); + return; } - long Mod0Offset = ImageBase + NsoData.Mod0Offset; + long Mod0Offset = ImageBase + Exe.Mod0Offset; int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0); long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset; @@ -41,9 +43,7 @@ namespace Ryujinx.Loaders long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset; long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset; - long BssSize = BssEndOffset - BssStartOffset; - - Memory.Manager.MapPhys(BssStartOffset, BssSize, (int)MemoryType.Normal, AMemoryPerm.RW); + MapBss(BssStartOffset, BssEndOffset - BssStartOffset); ImageEnd = BssEndOffset; @@ -83,6 +83,11 @@ namespace Ryujinx.Loaders } } + private void MapBss(long Position, long Size) + { + Memory.Manager.MapPhys(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW); + } + private ElfRel GetRelocation(long Position) { long Offset = Memory.ReadInt64(Position + 0); diff --git a/Ryujinx/Loaders/Executables/IElf.cs b/Ryujinx/Loaders/Executables/IExecutable.cs similarity index 93% rename from Ryujinx/Loaders/Executables/IElf.cs rename to Ryujinx/Loaders/Executables/IExecutable.cs index bc8eb1bcf..3e42a834a 100644 --- a/Ryujinx/Loaders/Executables/IElf.cs +++ b/Ryujinx/Loaders/Executables/IExecutable.cs @@ -2,7 +2,7 @@ using System.Collections.ObjectModel; namespace Ryujinx.Loaders.Executables { - interface IElf + interface IExecutable { ReadOnlyCollection Text { get; } ReadOnlyCollection RO { get; } diff --git a/Ryujinx/Loaders/Executables/Nro.cs b/Ryujinx/Loaders/Executables/Nro.cs index 5067ba12e..2217f3310 100644 --- a/Ryujinx/Loaders/Executables/Nro.cs +++ b/Ryujinx/Loaders/Executables/Nro.cs @@ -4,7 +4,7 @@ using System.IO; namespace Ryujinx.Loaders.Executables { - class Nro : IElf + class Nro : IExecutable { private byte[] m_Text; private byte[] m_RO; diff --git a/Ryujinx/Loaders/Executables/Nso.cs b/Ryujinx/Loaders/Executables/Nso.cs index ae9a9af62..ead1baf15 100644 --- a/Ryujinx/Loaders/Executables/Nso.cs +++ b/Ryujinx/Loaders/Executables/Nso.cs @@ -5,7 +5,7 @@ using System.IO; namespace Ryujinx.Loaders.Executables { - class Nso : IElf + class Nso : IExecutable { private byte[] m_Text; private byte[] m_RO; diff --git a/Ryujinx/OsHle/Ipc/IpcHandler.cs b/Ryujinx/OsHle/Ipc/IpcHandler.cs index 444b1022b..509680149 100644 --- a/Ryujinx/OsHle/Ipc/IpcHandler.cs +++ b/Ryujinx/OsHle/Ipc/IpcHandler.cs @@ -20,6 +20,7 @@ namespace Ryujinx.OsHle.Ipc { ( "acc:u0", 100), Service.AccU0InitializeApplicationInfo }, { ( "acc:u0", 101), Service.AccU0GetBaasAccountManagerForApplication }, { ( "apm", 0), Service.ApmOpenSession }, + { ( "apm:p", 0), Service.ApmOpenSession }, { ( "appletOE", 0), Service.AppletOpenApplicationProxy }, { ( "audout:u", 0), Service.AudOutListAudioOuts }, { ( "audout:u", 1), Service.AudOutOpenAudioOut }, @@ -27,6 +28,7 @@ namespace Ryujinx.OsHle.Ipc { ( "audren:u", 1), Service.AudRenGetAudioRendererWorkBufferSize }, { ( "friend:a", 0), Service.FriendCreateFriendService }, { ( "fsp-srv", 1), Service.FspSrvInitialize }, + { ( "fsp-srv", 18), Service.FspSrvMountSdCard }, { ( "fsp-srv", 51), Service.FspSrvMountSaveData }, { ( "fsp-srv", 200), Service.FspSrvOpenDataStorageByCurrentProcess }, { ( "fsp-srv", 203), Service.FspSrvOpenRomStorage }, @@ -43,11 +45,13 @@ namespace Ryujinx.OsHle.Ipc { ( "nvdrv", 2), Service.NvDrvClose }, { ( "nvdrv", 3), Service.NvDrvInitialize }, { ( "nvdrv", 4), Service.NvDrvQueryEvent }, + { ( "nvdrv", 8), Service.NvDrvSetClientPid }, { ( "nvdrv:a", 0), Service.NvDrvOpen }, { ( "nvdrv:a", 1), Service.NvDrvIoctl }, { ( "nvdrv:a", 2), Service.NvDrvClose }, { ( "nvdrv:a", 3), Service.NvDrvInitialize }, { ( "nvdrv:a", 4), Service.NvDrvQueryEvent }, + { ( "nvdrv:a", 8), Service.NvDrvSetClientPid }, { ( "pctl:a", 0), Service.PctlCreateService }, { ( "pl:u", 1), Service.PlGetLoadState }, { ( "pl:u", 2), Service.PlGetFontSize }, @@ -81,6 +85,7 @@ namespace Ryujinx.OsHle.Ipc { (typeof(AmIApplicationFunctions), 1), AmIApplicationFunctions.PopLaunchParameter }, { (typeof(AmIApplicationFunctions), 20), AmIApplicationFunctions.EnsureSaveData }, { (typeof(AmIApplicationFunctions), 21), AmIApplicationFunctions.GetDesiredLanguage }, + { (typeof(AmIApplicationFunctions), 40), AmIApplicationFunctions.NotifyRunning }, //IApplicationProxy { (typeof(AmIApplicationProxy), 0), AmIApplicationProxy.GetCommonStateGetter }, @@ -103,6 +108,7 @@ namespace Ryujinx.OsHle.Ipc { (typeof(AmISelfController), 11), AmISelfController.SetOperationModeChangedNotification }, { (typeof(AmISelfController), 12), AmISelfController.SetPerformanceModeChangedNotification }, { (typeof(AmISelfController), 13), AmISelfController.SetFocusHandlingMode }, + { (typeof(AmISelfController), 16), AmISelfController.SetOutOfFocusSuspendingEnabled }, //IStorage { (typeof(AmIStorage), 0), AmIStorage.Open }, @@ -142,14 +148,15 @@ namespace Ryujinx.OsHle.Ipc { (typeof(TimeISystemClock), 0), TimeISystemClock.GetCurrentTime }, //IApplicationDisplayService - { (typeof(ViIApplicationDisplayService), 100), ViIApplicationDisplayService.GetRelayService }, - { (typeof(ViIApplicationDisplayService), 101), ViIApplicationDisplayService.GetSystemDisplayService }, - { (typeof(ViIApplicationDisplayService), 102), ViIApplicationDisplayService.GetManagerDisplayService }, - { (typeof(ViIApplicationDisplayService), 1010), ViIApplicationDisplayService.OpenDisplay }, - { (typeof(ViIApplicationDisplayService), 2020), ViIApplicationDisplayService.OpenLayer }, - { (typeof(ViIApplicationDisplayService), 2030), ViIApplicationDisplayService.CreateStrayLayer }, - { (typeof(ViIApplicationDisplayService), 2101), ViIApplicationDisplayService.SetLayerScalingMode }, - { (typeof(ViIApplicationDisplayService), 5202), ViIApplicationDisplayService.GetDisplayVSyncEvent }, + { (typeof(ViIApplicationDisplayService), 100), ViIApplicationDisplayService.GetRelayService }, + { (typeof(ViIApplicationDisplayService), 101), ViIApplicationDisplayService.GetSystemDisplayService }, + { (typeof(ViIApplicationDisplayService), 102), ViIApplicationDisplayService.GetManagerDisplayService }, + { (typeof(ViIApplicationDisplayService), 103), ViIApplicationDisplayService.GetIndirectDisplayTransactionService }, + { (typeof(ViIApplicationDisplayService), 1010), ViIApplicationDisplayService.OpenDisplay }, + { (typeof(ViIApplicationDisplayService), 2020), ViIApplicationDisplayService.OpenLayer }, + { (typeof(ViIApplicationDisplayService), 2030), ViIApplicationDisplayService.CreateStrayLayer }, + { (typeof(ViIApplicationDisplayService), 2101), ViIApplicationDisplayService.SetLayerScalingMode }, + { (typeof(ViIApplicationDisplayService), 5202), ViIApplicationDisplayService.GetDisplayVSyncEvent }, //IHOSBinderDriver { (typeof(ViIHOSBinderDriver), 0), ViIHOSBinderDriver.TransactParcel }, @@ -189,6 +196,8 @@ namespace Ryujinx.OsHle.Ipc bool IgnoreNullPR = false; + string DbgServiceName = string.Empty; + if (Session is HDomain Dom) { if (Request.DomCmd == IpcDomCmd.SendMsg) @@ -200,10 +209,14 @@ namespace Ryujinx.OsHle.Ipc if (Obj is HDomain) { + DbgServiceName = $"{ServiceName} {CmdId}"; + ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq); } else if (Obj != null) { + DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {CmdId}"; + ObjectCmds.TryGetValue((Obj.GetType(), CmdId), out ProcReq); } } @@ -225,12 +238,16 @@ namespace Ryujinx.OsHle.Ipc { object Obj = ((HSessionObj)Session).Obj; + DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {CmdId}"; + ObjectCmds.TryGetValue((Obj.GetType(), CmdId), out ProcReq); } else { + DbgServiceName = $"{ServiceName} {CmdId}"; + ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq); - } + } } if (ProcReq != null) @@ -255,7 +272,7 @@ namespace Ryujinx.OsHle.Ipc } else if (!IgnoreNullPR) { - throw new NotImplementedException(ServiceName); + throw new NotImplementedException(DbgServiceName); } } else if (Request.Type == IpcMessageType.Control) diff --git a/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs b/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs index e174f9433..b5712484e 100644 --- a/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs +++ b/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs @@ -35,6 +35,13 @@ namespace Ryujinx.OsHle.Objects return 0; } + public static long NotifyRunning(ServiceCtx Context) + { + Context.ResponseData.Write(1); + + return 0; + } + private static byte[] MakeLaunchParams() { //Size needs to be at least 0x88 bytes otherwise application errors. diff --git a/Ryujinx/OsHle/Objects/AmISelfController.cs b/Ryujinx/OsHle/Objects/AmISelfController.cs index 33cde0958..8affb92b6 100644 --- a/Ryujinx/OsHle/Objects/AmISelfController.cs +++ b/Ryujinx/OsHle/Objects/AmISelfController.cs @@ -24,5 +24,12 @@ namespace Ryujinx.OsHle.Objects return 0; } + + public static long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } } } \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs b/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs index 81616ae11..174c97b4f 100644 --- a/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs +++ b/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs @@ -31,6 +31,13 @@ namespace Ryujinx.OsHle.Objects return 0; } + public static long GetIndirectDisplayTransactionService(ServiceCtx Context) + { + MakeObject(Context, new ViIHOSBinderDriver()); + + return 0; + } + public static long OpenDisplay(ServiceCtx Context) { string Name = GetDisplayName(Context); diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs index 3f72527e6..b723b165c 100644 --- a/Ryujinx/OsHle/Process.cs +++ b/Ryujinx/OsHle/Process.cs @@ -54,7 +54,7 @@ namespace Ryujinx.OsHle AMemoryPerm.RW); } - public void LoadProgram(IElf Program) + public void LoadProgram(IExecutable Program) { Executable Executable = new Executable(Program, Memory, ImageBase); @@ -138,7 +138,7 @@ namespace Ryujinx.OsHle Thread.Registers.SvcCall += SvcHandler.SvcCall; Thread.Registers.ProcessId = ProcessId; Thread.Registers.ThreadId = Ns.Os.IdGen.GenerateId(); - Thread.Registers.Tpidr = TlsPageAddr + TlsSlot * TlsSize; + Thread.Registers.Tpidr = TlsPageAddr + TlsSlot * TlsSize; Thread.Registers.X0 = (ulong)ArgsPtr; Thread.Registers.X1 = (ulong)Handle; Thread.Registers.X31 = (ulong)StackTop; diff --git a/Ryujinx/OsHle/Services/ServiceFspSrv.cs b/Ryujinx/OsHle/Services/ServiceFspSrv.cs index e2ceb0aed..7f431f267 100644 --- a/Ryujinx/OsHle/Services/ServiceFspSrv.cs +++ b/Ryujinx/OsHle/Services/ServiceFspSrv.cs @@ -11,6 +11,13 @@ namespace Ryujinx.OsHle.Services return 0; } + public static long FspSrvMountSdCard(ServiceCtx Context) + { + MakeObject(Context, new FspSrvIFileSystem(Context.Ns.VFs.GetSdCardPath())); + + return 0; + } + public static long FspSrvMountSaveData(ServiceCtx Context) { MakeObject(Context, new FspSrvIFileSystem(Context.Ns.VFs.GetGameSavesPath())); diff --git a/Ryujinx/OsHle/Services/ServiceNvDrv.cs b/Ryujinx/OsHle/Services/ServiceNvDrv.cs index f7c0d3022..f410e1ab0 100644 --- a/Ryujinx/OsHle/Services/ServiceNvDrv.cs +++ b/Ryujinx/OsHle/Services/ServiceNvDrv.cs @@ -110,6 +110,15 @@ namespace Ryujinx.OsHle.Services return 0; } + public static long NvDrvSetClientPid(ServiceCtx Context) + { + long Pid = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(0); + + return 0; + } + private static long NvGpuAsIoctlBindChannel(ServiceCtx Context) { long Position = Context.Request.PtrBuff[0].Position; diff --git a/Ryujinx/OsHle/Svc/SvcHandler.cs b/Ryujinx/OsHle/Svc/SvcHandler.cs index 245d24389..937c341e5 100644 --- a/Ryujinx/OsHle/Svc/SvcHandler.cs +++ b/Ryujinx/OsHle/Svc/SvcHandler.cs @@ -43,7 +43,8 @@ namespace Ryujinx.OsHle.Svc Success = 0, ErrBadHandle = 0xe401, ErrTimeout = 0xea01, - ErrBadIpcReq = 0xf601, + ErrBadInfo = 0xf001, + ErrBadIpcReq = 0xf601 } private Switch Ns; diff --git a/Ryujinx/OsHle/Svc/SvcSystem.cs b/Ryujinx/OsHle/Svc/SvcSystem.cs index 75d04830a..fa39f5181 100644 --- a/Ryujinx/OsHle/Svc/SvcSystem.cs +++ b/Ryujinx/OsHle/Svc/SvcSystem.cs @@ -133,11 +133,28 @@ namespace Ryujinx.OsHle.Svc long Handle = (long)Registers.X2; int InfoId = (int)Registers.X3; + //Fail for info not available on older Kernel versions. + if (InfoType == 18 || + InfoType == 19) + { + Registers.X0 = (int)SvcResult.ErrBadInfo; + + return; + } + switch (InfoType) { - case 6: Registers.X1 = GetTotalMem(Memory); break; - case 7: Registers.X1 = GetUsedMem(Memory); break; - case 11: Registers.X1 = GetRnd64(); break; + case 2: Registers.X1 = GetMapRegionBaseAddr(); break; + case 3: Registers.X1 = GetMapRegionSize(); break; + case 4: Registers.X1 = GetHeapRegionBaseAddr(); break; + case 5: Registers.X1 = GetHeapRegionSize(); break; + case 6: Registers.X1 = GetTotalMem(Memory); break; + case 7: Registers.X1 = GetUsedMem(Memory); break; + case 11: Registers.X1 = GetRnd64(); break; + case 12: Registers.X1 = GetAddrSpaceBaseAddr(); break; + case 13: Registers.X1 = GetAddrSpaceSize(); break; + case 14: Registers.X1 = GetMapRegionBaseAddr(); break; + case 15: Registers.X1 = GetMapRegionSize(); break; default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}"); } @@ -159,5 +176,35 @@ namespace Ryujinx.OsHle.Svc { return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); } + + private static ulong GetAddrSpaceBaseAddr() + { + return 0x08000000; + } + + private static ulong GetAddrSpaceSize() + { + return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr(); + } + + private static ulong GetMapRegionBaseAddr() + { + return 0x80000000; + } + + private static ulong GetMapRegionSize() + { + return 0x40000000; + } + + private static ulong GetHeapRegionBaseAddr() + { + return GetMapRegionBaseAddr() + GetMapRegionSize(); + } + + private static ulong GetHeapRegionSize() + { + return 0x40000000; + } } } \ No newline at end of file diff --git a/Ryujinx/VirtualFs.cs b/Ryujinx/VirtualFs.cs index 03317f4a1..e5579bcf1 100644 --- a/Ryujinx/VirtualFs.cs +++ b/Ryujinx/VirtualFs.cs @@ -5,8 +5,9 @@ namespace Ryujinx { class VirtualFs : IDisposable { - private const string BasePath = "Fs"; - private const string SavesPath = "Saves"; + private const string BasePath = "Fs"; + private const string SavesPath = "Saves"; + private const string SdCardPath = "SdCard"; public Stream RomFs { get; private set; } @@ -15,7 +16,7 @@ namespace Ryujinx RomFs = new FileStream(FileName, FileMode.Open, FileAccess.Read); } - internal string GetFullPath(string BasePath, string FileName) + public string GetFullPath(string BasePath, string FileName) { if (FileName.StartsWith('/')) { @@ -32,19 +33,23 @@ namespace Ryujinx return FullPath; } - internal string GetGameSavesPath() - { - string SavesDir = Path.Combine(GetBasePath(), SavesPath); + public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath); - if (!Directory.Exists(SavesDir)) + public string GetGameSavesPath() => MakeDirAndGetFullPath(SavesPath); + + private string MakeDirAndGetFullPath(string Dir) + { + string FullPath = Path.Combine(GetBasePath(), Dir); + + if (!Directory.Exists(FullPath)) { - Directory.CreateDirectory(SavesDir); + Directory.CreateDirectory(FullPath); } - return SavesDir; + return FullPath; } - internal string GetBasePath() + public string GetBasePath() { return Path.Combine(Directory.GetCurrentDirectory(), BasePath); }