aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/Loaders/Executables
diff options
context:
space:
mode:
authormageven <62494521+mageven@users.noreply.github.com>2020-07-09 10:01:15 +0530
committerGitHub <noreply@github.com>2020-07-09 14:31:15 +1000
commit189c0c9c726b3a700272831cd5cf10b2fc817cc2 (patch)
tree724e5d808c061917ae686e1e557c504fff3cd24f /Ryujinx.HLE/Loaders/Executables
parentc050994995268494d46a6cac1d4ffa931effa0f6 (diff)
Implement modding support (#1249)
* Implement Modding Support * Executables: Rewrite to use contiguous mem and Spans * Reorder ExeFs, Npdm, ControlData and SaveData calls After discussion with gdkchan, it was decided it's best to call LoadExeFs after all other loads are done as it starts the guest process. * Build RomFs manually instead of Layering FS Layered FS approach has considerable latency when building the final romfs. So, we manually replace files in a single romfs instance. * Add RomFs modding via storage file * Fix and cleanup MemPatch * Add dynamically loaded NRO patching * Support exefs file replacement * Rewrite ModLoader to use mods-search architecture * Disable PPTC when exefs patches are detected Disable PPTC on exefs replacements too * Rewrite ModLoader, again * Increased maintainability and matches Atmosphere closely * Creates base mods structure if it doesn't exist * Add Exefs partition replacement * IPSwitch: Fix nsobid parsing * Move mod logs to new LogClass * Allow custom suffixes to title dirs again * Address nits * Add a per-App "Open Mods Directory" context menu item Creates the path if not present. * Normalize tooltips verbiage * Use LocalStorage and remove unused namespaces
Diffstat (limited to 'Ryujinx.HLE/Loaders/Executables')
-rw-r--r--Ryujinx.HLE/Loaders/Executables/IExecutable.cs9
-rw-r--r--Ryujinx.HLE/Loaders/Executables/KipExecutable.cs30
-rw-r--r--Ryujinx.HLE/Loaders/Executables/NroExecutable.cs71
-rw-r--r--Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs37
4 files changed, 72 insertions, 75 deletions
diff --git a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs
index 440e8f5f..76a550df 100644
--- a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs
+++ b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs
@@ -1,10 +1,13 @@
+using System;
+
namespace Ryujinx.HLE.Loaders.Executables
{
interface IExecutable
{
- byte[] Text { get; }
- byte[] Ro { get; }
- byte[] Data { get; }
+ byte[] Program { get; }
+ Span<byte> Text { get; }
+ Span<byte> Ro { get; }
+ Span<byte> Data { get; }
int TextOffset { get; }
int RoOffset { get; }
diff --git a/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs b/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs
index 0f1309c0..a44b7c48 100644
--- a/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs
+++ b/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs
@@ -1,18 +1,24 @@
using LibHac.Fs;
using LibHac.Loader;
+using System;
namespace Ryujinx.HLE.Loaders.Executables
{
class KipExecutable : IExecutable
{
- public byte[] Text { get; }
- public byte[] Ro { get; }
- public byte[] Data { get; }
+ public byte[] Program { get; }
+ public Span<byte> Text => Program.AsSpan().Slice(TextOffset, TextSize);
+ public Span<byte> Ro => Program.AsSpan().Slice(RoOffset, RoSize);
+ public Span<byte> Data => Program.AsSpan().Slice(DataOffset, DataSize);
public int TextOffset { get; }
public int RoOffset { get; }
public int DataOffset { get; }
public int BssOffset { get; }
+
+ public int TextSize { get; }
+ public int RoSize { get; }
+ public int DataSize { get; }
public int BssSize { get; }
public int[] Capabilities { get; }
@@ -25,7 +31,6 @@ namespace Ryujinx.HLE.Loaders.Executables
public byte IdealCoreId { get; }
public int Version { get; }
public string Name { get; }
-
public KipExecutable(IStorage inStorage)
{
KipReader reader = new KipReader();
@@ -57,20 +62,23 @@ namespace Ryujinx.HLE.Loaders.Executables
Capabilities[index] = (int)reader.Capabilities[index];
}
- Text = DecompressSection(reader, KipReader.SegmentType.Text);
- Ro = DecompressSection(reader, KipReader.SegmentType.Ro);
- Data = DecompressSection(reader, KipReader.SegmentType.Data);
+ reader.GetSegmentSize(KipReader.SegmentType.Data, out int uncompressedSize).ThrowIfFailure();
+ Program = new byte[DataOffset + uncompressedSize];
+
+ TextSize = DecompressSection(reader, KipReader.SegmentType.Text, TextOffset, Program);
+ RoSize = DecompressSection(reader, KipReader.SegmentType.Ro, RoOffset, Program);
+ DataSize = DecompressSection(reader, KipReader.SegmentType.Data, DataOffset, Program);
}
- private static byte[] DecompressSection(KipReader reader, KipReader.SegmentType segmentType)
+ private static int DecompressSection(KipReader reader, KipReader.SegmentType segmentType, int offset, byte[] Program)
{
reader.GetSegmentSize(segmentType, out int uncompressedSize).ThrowIfFailure();
- byte[] result = new byte[uncompressedSize];
+ var span = Program.AsSpan().Slice(offset, uncompressedSize);
- reader.ReadSegment(segmentType, result).ThrowIfFailure();
+ reader.ReadSegment(segmentType, span).ThrowIfFailure();
- return result;
+ return uncompressedSize;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs b/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs
index 4a7f2116..b7a887b7 100644
--- a/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs
+++ b/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs
@@ -1,67 +1,38 @@
-using System.IO;
+using LibHac;
+using LibHac.Fs;
+using System;
namespace Ryujinx.HLE.Loaders.Executables
{
- class NroExecutable : IExecutable
+ class NroExecutable : Nro, IExecutable
{
- public byte[] Text { get; private set; }
- public byte[] Ro { get; private set; }
- public byte[] Data { get; private set; }
+ public byte[] Program { get; }
+ public Span<byte> Text => Program.AsSpan().Slice(TextOffset, (int)Header.NroSegments[0].Size);
+ public Span<byte> Ro => Program.AsSpan().Slice(RoOffset, (int)Header.NroSegments[1].Size);
+ public Span<byte> Data => Program.AsSpan().Slice(DataOffset, (int)Header.NroSegments[2].Size);
- public int Mod0Offset { get; private set; }
- public int TextOffset { get; private set; }
- public int RoOffset { get; private set; }
- public int DataOffset { get; private set; }
- public int BssSize { get; private set; }
- public int FileSize { get; private set; }
+ public int TextOffset => (int)Header.NroSegments[0].FileOffset;
+ public int RoOffset => (int)Header.NroSegments[1].FileOffset;
+ public int DataOffset => (int)Header.NroSegments[2].FileOffset;
+ public int BssOffset => DataOffset + Data.Length;
+ public int BssSize => (int)Header.BssSize;
- public int BssOffset => DataOffset + Data.Length;
+ public int Mod0Offset => Start.Mod0Offset;
+ public int FileSize => (int)Header.Size;
public ulong SourceAddress { get; private set; }
public ulong BssAddress { get; private set; }
- public NroExecutable(Stream input, ulong sourceAddress = 0, ulong bssAddress = 0)
+ public NroExecutable(IStorage inStorage, ulong sourceAddress = 0, ulong bssAddress = 0) : base(inStorage)
{
+ Program = new byte[FileSize];
+
SourceAddress = sourceAddress;
BssAddress = bssAddress;
- BinaryReader reader = new BinaryReader(input);
-
- input.Seek(4, SeekOrigin.Begin);
-
- int mod0Offset = reader.ReadInt32();
- int padding8 = reader.ReadInt32();
- int paddingC = reader.ReadInt32();
- int nroMagic = reader.ReadInt32();
- int unknown14 = reader.ReadInt32();
- int fileSize = reader.ReadInt32();
- int unknown1C = reader.ReadInt32();
- int textOffset = reader.ReadInt32();
- int textSize = reader.ReadInt32();
- int roOffset = reader.ReadInt32();
- int roSize = reader.ReadInt32();
- int dataOffset = reader.ReadInt32();
- int dataSize = reader.ReadInt32();
- int bssSize = reader.ReadInt32();
-
- Mod0Offset = mod0Offset;
- TextOffset = textOffset;
- RoOffset = roOffset;
- DataOffset = dataOffset;
- BssSize = bssSize;
-
- byte[] Read(long position, int size)
- {
- input.Seek(position, SeekOrigin.Begin);
-
- return reader.ReadBytes(size);
- }
-
- Text = Read(textOffset, textSize);
- Ro = Read(roOffset, roSize);
- Data = Read(dataOffset, dataSize);
-
- FileSize = fileSize;
+ OpenNroSegment(NroSegmentType.Text, false).Read(0, Text);
+ OpenNroSegment(NroSegmentType.Ro , false).Read(0, Ro);
+ OpenNroSegment(NroSegmentType.Data, false).Read(0, Data);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs b/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs
index bbe2c87f..96f1df4e 100644
--- a/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs
+++ b/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs
@@ -1,23 +1,32 @@
+using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Loader;
+using System;
namespace Ryujinx.HLE.Loaders.Executables
{
class NsoExecutable : IExecutable
{
- public byte[] Text { get; }
- public byte[] Ro { get; }
- public byte[] Data { get; }
+ public byte[] Program { get; }
+ public Span<byte> Text => Program.AsSpan().Slice(TextOffset, TextSize);
+ public Span<byte> Ro => Program.AsSpan().Slice(RoOffset, RoSize);
+ public Span<byte> Data => Program.AsSpan().Slice(DataOffset, DataSize);
public int TextOffset { get; }
public int RoOffset { get; }
public int DataOffset { get; }
public int BssOffset => DataOffset + Data.Length;
+ public int TextSize { get; }
+ public int RoSize { get; }
+ public int DataSize { get; }
public int BssSize { get; }
- public NsoExecutable(IStorage inStorage)
+ public string Name;
+ public Buffer32 BuildId;
+
+ public NsoExecutable(IStorage inStorage, string name = null)
{
NsoReader reader = new NsoReader();
@@ -28,20 +37,26 @@ namespace Ryujinx.HLE.Loaders.Executables
DataOffset = (int)reader.Header.Segments[2].MemoryOffset;
BssSize = (int)reader.Header.BssSize;
- Text = DecompressSection(reader, NsoReader.SegmentType.Text);
- Ro = DecompressSection(reader, NsoReader.SegmentType.Ro);
- Data = DecompressSection(reader, NsoReader.SegmentType.Data);
+ reader.GetSegmentSize(NsoReader.SegmentType.Data, out uint uncompressedSize).ThrowIfFailure();
+ Program = new byte[DataOffset + uncompressedSize];
+
+ TextSize = DecompressSection(reader, NsoReader.SegmentType.Text, TextOffset, Program);
+ RoSize = DecompressSection(reader, NsoReader.SegmentType.Ro, RoOffset, Program);
+ DataSize = DecompressSection(reader, NsoReader.SegmentType.Data, DataOffset, Program);
+
+ Name = name;
+ BuildId = reader.Header.ModuleId;
}
- private static byte[] DecompressSection(NsoReader reader, NsoReader.SegmentType segmentType)
+ private static int DecompressSection(NsoReader reader, NsoReader.SegmentType segmentType, int offset, byte[] Program)
{
reader.GetSegmentSize(segmentType, out uint uncompressedSize).ThrowIfFailure();
- byte[] result = new byte[uncompressedSize];
+ var span = Program.AsSpan().Slice(offset, (int)uncompressedSize);
- reader.ReadSegment(segmentType, result).ThrowIfFailure();
+ reader.ReadSegment(segmentType, span).ThrowIfFailure();
- return result;
+ return (int)uncompressedSize;
}
}
} \ No newline at end of file