Use libhac for loading NSOs and KIPs
This commit is contained in:
parent
0dd38028cb
commit
0c762455cc
4 changed files with 53 additions and 190 deletions
|
@ -271,7 +271,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
public void LoadKip(string kipFile)
|
public void LoadKip(string kipFile)
|
||||||
{
|
{
|
||||||
using (FileStream fs = new FileStream(kipFile, FileMode.Open))
|
using (IStorage fs = new LocalStorage(kipFile, FileAccess.Read))
|
||||||
{
|
{
|
||||||
ProgramLoader.LoadKernelInitalProcess(this, new KernelInitialProcess(fs));
|
ProgramLoader.LoadKernelInitalProcess(this, new KernelInitialProcess(fs));
|
||||||
}
|
}
|
||||||
|
@ -545,7 +545,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
codeFs.OpenFile(out IFile nsoFile, file.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
codeFs.OpenFile(out IFile nsoFile, file.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
NxStaticObject staticObject = new NxStaticObject(nsoFile.AsStream());
|
NxStaticObject staticObject = new NxStaticObject(nsoFile.AsStorage());
|
||||||
|
|
||||||
staticObjects.Add(staticObject);
|
staticObjects.Add(staticObject);
|
||||||
}
|
}
|
||||||
|
@ -569,12 +569,12 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
|
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
|
||||||
|
|
||||||
FileStream input = new FileStream(filePath, FileMode.Open);
|
|
||||||
|
|
||||||
IExecutable staticObject;
|
IExecutable staticObject;
|
||||||
|
|
||||||
if (isNro)
|
if (isNro)
|
||||||
{
|
{
|
||||||
|
FileStream input = new FileStream(filePath, FileMode.Open);
|
||||||
NxRelocatableObject obj = new NxRelocatableObject(input);
|
NxRelocatableObject obj = new NxRelocatableObject(input);
|
||||||
staticObject = obj;
|
staticObject = obj;
|
||||||
|
|
||||||
|
@ -648,7 +648,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
staticObject = new NxStaticObject(input);
|
staticObject = new NxStaticObject(new LocalStorage(filePath, FileAccess.Read));
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentManager.LoadEntries(Device);
|
ContentManager.LoadEntries(Device);
|
||||||
|
|
|
@ -6,6 +6,7 @@ using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Loaders.Npdm;
|
using Ryujinx.HLE.Loaders.Npdm;
|
||||||
|
using LibHac;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS
|
namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
|
@ -288,7 +289,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
}
|
}
|
||||||
|
|
||||||
size = BitUtils.AlignUp(size, KMemoryManager.PageSize);
|
size = BitUtils.AlignUp(size, KMemoryManager.PageSize);
|
||||||
|
|
||||||
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
|
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +306,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return SetProcessMemoryPermission(dataStart, end - dataStart, MemoryPermission.ReadAndWrite);
|
return SetProcessMemoryPermission(dataStart, end - dataStart, MemoryPermission.ReadAndWrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,39 @@
|
||||||
using Ryujinx.HLE.Loaders.Compression;
|
using Ryujinx.HLE.Loaders.Compression;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LibHac;
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Loaders.Executables
|
namespace Ryujinx.HLE.Loaders.Executables
|
||||||
{
|
{
|
||||||
class KernelInitialProcess : IExecutable
|
class KernelInitialProcess : IExecutable
|
||||||
{
|
{
|
||||||
public string Name { get; private set; }
|
Kip kip;
|
||||||
|
public string Name => kip.Header.Name;
|
||||||
|
|
||||||
public ulong TitleId { get; private set; }
|
public ulong TitleId => kip.Header.TitleId;
|
||||||
|
|
||||||
public int ProcessCategory { get; private set; }
|
public int ProcessCategory => kip.Header.ProcessCategory;
|
||||||
|
|
||||||
public byte MainThreadPriority { get; private set; }
|
public byte MainThreadPriority => kip.Header.MainThreadPriority;
|
||||||
public byte DefaultProcessorId { get; private set; }
|
public byte DefaultProcessorId => kip.Header.DefaultCore;
|
||||||
|
|
||||||
|
public bool Is64Bits => (kip.Header.Flags & 0x08) != 0;
|
||||||
|
public bool Addr39Bits => (kip.Header.Flags & 0x10) != 0;
|
||||||
|
public bool IsService => (kip.Header.Flags & 0x20) != 0;
|
||||||
|
|
||||||
public bool Is64Bits { get; private set; }
|
|
||||||
public bool Addr39Bits { get; private set; }
|
|
||||||
public bool IsService { get; private set; }
|
|
||||||
|
|
||||||
public byte[] Text { get; private set; }
|
public byte[] Text { get; private set; }
|
||||||
public byte[] Ro { get; private set; }
|
public byte[] Ro { get; private set; }
|
||||||
public byte[] Data { get; private set; }
|
public byte[] Data { get; private set; }
|
||||||
|
|
||||||
public int TextOffset { get; private set; }
|
public int TextOffset => kip.Header.Sections[0].OutOffset;
|
||||||
public int RoOffset { get; private set; }
|
public int RoOffset => kip.Header.Sections[1].OutOffset;
|
||||||
public int DataOffset { get; private set; }
|
public int DataOffset => kip.Header.Sections[2].OutOffset;
|
||||||
public int BssOffset { get; private set; }
|
public int BssOffset => kip.Header.Sections[3].OutOffset;
|
||||||
public int BssSize { get; private set; }
|
public int BssSize => kip.Header.Sections[3].DecompressedSize;
|
||||||
|
|
||||||
public int MainThreadStackSize { get; private set; }
|
public int MainThreadStackSize => kip.Header.Sections[1].Attribute;
|
||||||
|
public int[] Capabilities { get; set; }
|
||||||
public int[] Capabilities { get; private set; }
|
|
||||||
|
|
||||||
private struct SegmentHeader
|
private struct SegmentHeader
|
||||||
{
|
{
|
||||||
|
@ -52,96 +55,21 @@ namespace Ryujinx.HLE.Loaders.Executables
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelInitialProcess(Stream input)
|
public KernelInitialProcess(IStorage inStorage)
|
||||||
{
|
{
|
||||||
BinaryReader reader = new BinaryReader(input);
|
kip = new Kip(inStorage);
|
||||||
|
|
||||||
string magic = ReadString(reader, 4);
|
|
||||||
|
|
||||||
if (magic != "KIP1")
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Name = ReadString(reader, 12);
|
|
||||||
|
|
||||||
TitleId = reader.ReadUInt64();
|
|
||||||
|
|
||||||
ProcessCategory = reader.ReadInt32();
|
|
||||||
|
|
||||||
MainThreadPriority = reader.ReadByte();
|
|
||||||
DefaultProcessorId = reader.ReadByte();
|
|
||||||
|
|
||||||
byte reserved = reader.ReadByte();
|
|
||||||
byte flags = reader.ReadByte();
|
|
||||||
|
|
||||||
Is64Bits = (flags & 0x08) != 0;
|
|
||||||
Addr39Bits = (flags & 0x10) != 0;
|
|
||||||
IsService = (flags & 0x20) != 0;
|
|
||||||
|
|
||||||
SegmentHeader[] segments = new SegmentHeader[6];
|
|
||||||
|
|
||||||
for (int index = 0; index < segments.Length; index++)
|
|
||||||
{
|
|
||||||
segments[index] = new SegmentHeader(
|
|
||||||
reader.ReadInt32(),
|
|
||||||
reader.ReadInt32(),
|
|
||||||
reader.ReadInt32(),
|
|
||||||
reader.ReadInt32());
|
|
||||||
}
|
|
||||||
|
|
||||||
TextOffset = segments[0].Offset;
|
|
||||||
RoOffset = segments[1].Offset;
|
|
||||||
DataOffset = segments[2].Offset;
|
|
||||||
BssOffset = segments[3].Offset;
|
|
||||||
BssSize = segments[3].DecompressedSize;
|
|
||||||
|
|
||||||
MainThreadStackSize = segments[1].Attribute;
|
|
||||||
|
|
||||||
Capabilities = new int[32];
|
Capabilities = new int[32];
|
||||||
|
|
||||||
for (int index = 0; index < Capabilities.Length; index++)
|
for (int index = 0; index < Capabilities.Length; index++)
|
||||||
{
|
{
|
||||||
Capabilities[index] = reader.ReadInt32();
|
Capabilities[index] = System.BitConverter.ToInt32(kip.Header.Capabilities, index * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
input.Seek(0x100, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
Text = ReadSegment(segments[0], input);
|
Text = kip.DecompressSection(0);
|
||||||
Ro = ReadSegment(segments[1], input);
|
Ro = kip.DecompressSection(1);
|
||||||
Data = ReadSegment(segments[2], input);
|
Data = kip.DecompressSection(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] ReadSegment(SegmentHeader header, Stream input)
|
|
||||||
{
|
|
||||||
byte[] data = new byte[header.DecompressedSize];
|
|
||||||
|
|
||||||
input.Read(data, 0, header.CompressedSize);
|
|
||||||
|
|
||||||
BackwardsLz.DecompressInPlace(data, header.CompressedSize);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadString(BinaryReader reader, int maxSize)
|
|
||||||
{
|
|
||||||
string value = string.Empty;
|
|
||||||
|
|
||||||
for (int index = 0; index < maxSize; index++)
|
|
||||||
{
|
|
||||||
char chr = (char)reader.ReadByte();
|
|
||||||
|
|
||||||
if (chr == '\0')
|
|
||||||
{
|
|
||||||
reader.BaseStream.Seek(maxSize - index - 1, SeekOrigin.Current);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
value += chr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,21 +1,24 @@
|
||||||
using Ryujinx.HLE.Loaders.Compression;
|
using Ryujinx.HLE.Loaders.Compression;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Loaders.Executables
|
namespace Ryujinx.HLE.Loaders.Executables
|
||||||
{
|
{
|
||||||
class NxStaticObject : IExecutable
|
class NxStaticObject : IExecutable
|
||||||
{
|
{
|
||||||
|
Nso nso;
|
||||||
|
|
||||||
public byte[] Text { get; private set; }
|
public byte[] Text { get; private set; }
|
||||||
public byte[] Ro { get; private set; }
|
public byte[] Ro { get; private set; }
|
||||||
public byte[] Data { get; private set; }
|
public byte[] Data { get; private set; }
|
||||||
|
|
||||||
public int TextOffset { get; private set; }
|
public int TextOffset => (int)nso.Sections[0].MemoryOffset;
|
||||||
public int RoOffset { get; private set; }
|
public int RoOffset => (int)nso.Sections[1].MemoryOffset;
|
||||||
public int DataOffset { get; private set; }
|
public int DataOffset => (int)nso.Sections[2].MemoryOffset;
|
||||||
public int BssSize { get; private set; }
|
|
||||||
|
|
||||||
public int BssOffset => DataOffset + Data.Length;
|
public int BssOffset => DataOffset + Data.Length;
|
||||||
|
public int BssSize => (int)nso.BssSize;
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
private enum NsoFlags
|
private enum NsoFlags
|
||||||
|
@ -28,82 +31,13 @@ namespace Ryujinx.HLE.Loaders.Executables
|
||||||
HasDataHash = 1 << 5
|
HasDataHash = 1 << 5
|
||||||
}
|
}
|
||||||
|
|
||||||
public NxStaticObject(Stream input)
|
public NxStaticObject(IStorage inStorage)
|
||||||
{
|
{
|
||||||
BinaryReader reader = new BinaryReader(input);
|
nso = new Nso(inStorage);
|
||||||
|
Text = nso.Sections[0].DecompressSection();
|
||||||
input.Seek(0, SeekOrigin.Begin);
|
Ro = nso.Sections[1].DecompressSection();
|
||||||
|
Data = nso.Sections[2].DecompressSection();
|
||||||
int nsoMagic = reader.ReadInt32();
|
|
||||||
int version = reader.ReadInt32();
|
|
||||||
int reserved = reader.ReadInt32();
|
|
||||||
int flagsMsk = reader.ReadInt32();
|
|
||||||
int textOffset = reader.ReadInt32();
|
|
||||||
int textMemOffset = reader.ReadInt32();
|
|
||||||
int textDecSize = reader.ReadInt32();
|
|
||||||
int modNameOffset = reader.ReadInt32();
|
|
||||||
int roOffset = reader.ReadInt32();
|
|
||||||
int roMemOffset = reader.ReadInt32();
|
|
||||||
int roDecSize = reader.ReadInt32();
|
|
||||||
int modNameSize = reader.ReadInt32();
|
|
||||||
int dataOffset = reader.ReadInt32();
|
|
||||||
int dataMemOffset = reader.ReadInt32();
|
|
||||||
int dataDecSize = reader.ReadInt32();
|
|
||||||
int bssSize = reader.ReadInt32();
|
|
||||||
|
|
||||||
byte[] buildId = reader.ReadBytes(0x20);
|
|
||||||
|
|
||||||
int textSize = reader.ReadInt32();
|
|
||||||
int roSize = reader.ReadInt32();
|
|
||||||
int dataSize = reader.ReadInt32();
|
|
||||||
|
|
||||||
input.Seek(0x24, SeekOrigin.Current);
|
|
||||||
|
|
||||||
int dynStrOffset = reader.ReadInt32();
|
|
||||||
int dynStrSize = reader.ReadInt32();
|
|
||||||
int dynSymOffset = reader.ReadInt32();
|
|
||||||
int dynSymSize = reader.ReadInt32();
|
|
||||||
|
|
||||||
byte[] textHash = reader.ReadBytes(0x20);
|
|
||||||
byte[] roHash = reader.ReadBytes(0x20);
|
|
||||||
byte[] dataHash = reader.ReadBytes(0x20);
|
|
||||||
|
|
||||||
NsoFlags flags = (NsoFlags)flagsMsk;
|
|
||||||
|
|
||||||
TextOffset = textMemOffset;
|
|
||||||
RoOffset = roMemOffset;
|
|
||||||
DataOffset = dataMemOffset;
|
|
||||||
BssSize = bssSize;
|
|
||||||
|
|
||||||
// Text segment
|
|
||||||
input.Seek(textOffset, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
Text = reader.ReadBytes(textSize);
|
|
||||||
|
|
||||||
if (flags.HasFlag(NsoFlags.IsTextCompressed) && textSize != 0)
|
|
||||||
{
|
|
||||||
Text = Lz4.Decompress(Text, textDecSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read-only data segment
|
|
||||||
input.Seek(roOffset, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
Ro = reader.ReadBytes(roSize);
|
|
||||||
|
|
||||||
if (flags.HasFlag(NsoFlags.IsRoCompressed) && roSize != 0)
|
|
||||||
{
|
|
||||||
Ro = Lz4.Decompress(Ro, roDecSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data segment
|
|
||||||
input.Seek(dataOffset, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
Data = reader.ReadBytes(dataSize);
|
|
||||||
|
|
||||||
if (flags.HasFlag(NsoFlags.IsDataCompressed) && dataSize != 0)
|
|
||||||
{
|
|
||||||
Data = Lz4.Decompress(Data, dataDecSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue