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)
|
||||
{
|
||||
using (FileStream fs = new FileStream(kipFile, FileMode.Open))
|
||||
using (IStorage fs = new LocalStorage(kipFile, FileAccess.Read))
|
||||
{
|
||||
ProgramLoader.LoadKernelInitalProcess(this, new KernelInitialProcess(fs));
|
||||
}
|
||||
|
@ -544,8 +544,8 @@ namespace Ryujinx.HLE.HOS
|
|||
Logger.PrintInfo(LogClass.Loader, $"Loading {file.Name}...");
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -569,12 +569,12 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
|
||||
|
||||
FileStream input = new FileStream(filePath, FileMode.Open);
|
||||
|
||||
IExecutable staticObject;
|
||||
|
||||
if (isNro)
|
||||
{
|
||||
FileStream input = new FileStream(filePath, FileMode.Open);
|
||||
NxRelocatableObject obj = new NxRelocatableObject(input);
|
||||
staticObject = obj;
|
||||
|
||||
|
@ -648,7 +648,7 @@ namespace Ryujinx.HLE.HOS
|
|||
}
|
||||
else
|
||||
{
|
||||
staticObject = new NxStaticObject(input);
|
||||
staticObject = new NxStaticObject(new LocalStorage(filePath, FileAccess.Read));
|
||||
}
|
||||
|
||||
ContentManager.LoadEntries(Device);
|
||||
|
|
|
@ -6,6 +6,7 @@ using Ryujinx.HLE.HOS.Kernel.Memory;
|
|||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Loaders.Npdm;
|
||||
using LibHac;
|
||||
|
||||
namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
|
@ -288,7 +289,6 @@ namespace Ryujinx.HLE.HOS
|
|||
}
|
||||
|
||||
size = BitUtils.AlignUp(size, KMemoryManager.PageSize);
|
||||
|
||||
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
|
||||
}
|
||||
|
||||
|
@ -306,6 +306,7 @@ namespace Ryujinx.HLE.HOS
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
return SetProcessMemoryPermission(dataStart, end - dataStart, MemoryPermission.ReadAndWrite);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +1,46 @@
|
|||
using Ryujinx.HLE.Loaders.Compression;
|
||||
using System.IO;
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
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 DefaultProcessorId { get; private set; }
|
||||
public byte MainThreadPriority => kip.Header.MainThreadPriority;
|
||||
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[] Ro { get; private set; }
|
||||
public byte[] Ro { get; private set; }
|
||||
public byte[] Data { get; private set; }
|
||||
|
||||
public int TextOffset { get; private set; }
|
||||
public int RoOffset { get; private set; }
|
||||
public int DataOffset { get; private set; }
|
||||
public int BssOffset { get; private set; }
|
||||
public int BssSize { get; private set; }
|
||||
public int TextOffset => kip.Header.Sections[0].OutOffset;
|
||||
public int RoOffset => kip.Header.Sections[1].OutOffset;
|
||||
public int DataOffset => kip.Header.Sections[2].OutOffset;
|
||||
public int BssOffset => kip.Header.Sections[3].OutOffset;
|
||||
public int BssSize => kip.Header.Sections[3].DecompressedSize;
|
||||
|
||||
public int MainThreadStackSize { get; private set; }
|
||||
|
||||
public int[] Capabilities { get; private set; }
|
||||
public int MainThreadStackSize => kip.Header.Sections[1].Attribute;
|
||||
public int[] Capabilities { get; set; }
|
||||
|
||||
private struct SegmentHeader
|
||||
{
|
||||
public int Offset { get; private set; }
|
||||
public int Offset { get; private set; }
|
||||
public int DecompressedSize { get; private set; }
|
||||
public int CompressedSize { get; private set; }
|
||||
public int Attribute { get; private set; }
|
||||
public int CompressedSize { get; private set; }
|
||||
public int Attribute { get; private set; }
|
||||
|
||||
public SegmentHeader(
|
||||
int offset,
|
||||
|
@ -45,103 +48,28 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
int compressedSize,
|
||||
int attribute)
|
||||
{
|
||||
Offset = offset;
|
||||
Offset = offset;
|
||||
DecompressedSize = decompressedSize;
|
||||
CompressedSize = compressedSize;
|
||||
Attribute = attribute;
|
||||
CompressedSize = compressedSize;
|
||||
Attribute = attribute;
|
||||
}
|
||||
}
|
||||
|
||||
public KernelInitialProcess(Stream input)
|
||||
public KernelInitialProcess(IStorage inStorage)
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(input);
|
||||
|
||||
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;
|
||||
|
||||
kip = new Kip(inStorage);
|
||||
Capabilities = new int[32];
|
||||
|
||||
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);
|
||||
Ro = ReadSegment(segments[1], input);
|
||||
Data = ReadSegment(segments[2], input);
|
||||
Text = kip.DecompressSection(0);
|
||||
Ro = kip.DecompressSection(1);
|
||||
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 System;
|
||||
using System.IO;
|
||||
using LibHac.Fs;
|
||||
using LibHac;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class NxStaticObject : IExecutable
|
||||
{
|
||||
Nso nso;
|
||||
|
||||
public byte[] Text { get; private set; }
|
||||
public byte[] Ro { get; private set; }
|
||||
public byte[] Data { 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 TextOffset => (int)nso.Sections[0].MemoryOffset;
|
||||
public int RoOffset => (int)nso.Sections[1].MemoryOffset;
|
||||
public int DataOffset => (int)nso.Sections[2].MemoryOffset;
|
||||
public int BssOffset => DataOffset + Data.Length;
|
||||
public int BssSize => (int)nso.BssSize;
|
||||
|
||||
[Flags]
|
||||
private enum NsoFlags
|
||||
|
@ -28,82 +31,13 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
HasDataHash = 1 << 5
|
||||
}
|
||||
|
||||
public NxStaticObject(Stream input)
|
||||
public NxStaticObject(IStorage inStorage)
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(input);
|
||||
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
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);
|
||||
}
|
||||
nso = new Nso(inStorage);
|
||||
Text = nso.Sections[0].DecompressSection();
|
||||
Ro = nso.Sections[1].DecompressSection();
|
||||
Data = nso.Sections[2].DecompressSection();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue