Better process implementation (#491)
* Initial implementation of KProcess * Some improvements to the memory manager, implement back guest stack trace printing * Better GetInfo implementation, improve checking in some places with information from process capabilities * Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary * Change long -> ulong for address/size on memory related methods to avoid unnecessary casts * Attempt at implementing ldr:ro with new KProcess * Allow BSS with size 0 on ldr:ro * Add checking for memory block slab heap usage, return errors if full, exit gracefully * Use KMemoryBlockSize const from KMemoryManager * Allow all methods to read from non-contiguous locations * Fix for TransactParcelAuto * Address PR feedback, additionally fix some small issues related to the KIP loader and implement SVCs GetProcessId, GetProcessList, GetSystemInfo, CreatePort and ManageNamedPort * Fix wrong check for source pages count from page list on MapPhysicalMemory * Fix some issues with UnloadNro on ldr:ro
This commit is contained in:
parent
e7fe7d7247
commit
00579927e4
119 changed files with 7998 additions and 3232 deletions
105
Ryujinx.HLE/Loaders/Compression/BackwardsLz.cs
Normal file
105
Ryujinx.HLE/Loaders/Compression/BackwardsLz.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Compression
|
||||
{
|
||||
static class BackwardsLz
|
||||
{
|
||||
private class BackwardsReader
|
||||
{
|
||||
private Stream BaseStream;
|
||||
|
||||
public BackwardsReader(Stream BaseStream)
|
||||
{
|
||||
this.BaseStream = BaseStream;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
BaseStream.Seek(-1, SeekOrigin.Current);
|
||||
|
||||
byte Value = (byte)BaseStream.ReadByte();
|
||||
|
||||
BaseStream.Seek(-1, SeekOrigin.Current);
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
public short ReadInt16()
|
||||
{
|
||||
return (short)((ReadByte() << 8) | (ReadByte() << 0));
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
return ((ReadByte() << 24) |
|
||||
(ReadByte() << 16) |
|
||||
(ReadByte() << 8) |
|
||||
(ReadByte() << 0));
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Decompress(Stream Input, int DecompressedLength)
|
||||
{
|
||||
long End = Input.Position;
|
||||
|
||||
BackwardsReader Reader = new BackwardsReader(Input);
|
||||
|
||||
int AdditionalDecLength = Reader.ReadInt32();
|
||||
int StartOffset = Reader.ReadInt32();
|
||||
int CompressedLength = Reader.ReadInt32();
|
||||
|
||||
Input.Seek(12 - StartOffset, SeekOrigin.Current);
|
||||
|
||||
byte[] Dec = new byte[DecompressedLength];
|
||||
|
||||
int DecompressedLengthUnpadded = CompressedLength + AdditionalDecLength;
|
||||
|
||||
int DecompressionStart = DecompressedLength - DecompressedLengthUnpadded;
|
||||
|
||||
int DecPos = Dec.Length;
|
||||
|
||||
byte Mask = 0;
|
||||
byte Header = 0;
|
||||
|
||||
while (DecPos > DecompressionStart)
|
||||
{
|
||||
if ((Mask >>= 1) == 0)
|
||||
{
|
||||
Header = Reader.ReadByte();
|
||||
Mask = 0x80;
|
||||
}
|
||||
|
||||
if ((Header & Mask) == 0)
|
||||
{
|
||||
Dec[--DecPos] = Reader.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort Pair = (ushort)Reader.ReadInt16();
|
||||
|
||||
int Length = (Pair >> 12) + 3;
|
||||
int Position = (Pair & 0xfff) + 3;
|
||||
|
||||
DecPos -= Length;
|
||||
|
||||
if (Length <= Position)
|
||||
{
|
||||
int SrcPos = DecPos + Position;
|
||||
|
||||
Buffer.BlockCopy(Dec, SrcPos, Dec, DecPos, Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int Offset = 0; Offset < Length; Offset++)
|
||||
{
|
||||
Dec[DecPos + Offset] = Dec[DecPos + Position + Offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Dec;
|
||||
}
|
||||
}
|
||||
}
|
15
Ryujinx.HLE/Loaders/Elf/ElfDynamic.cs
Normal file
15
Ryujinx.HLE/Loaders/Elf/ElfDynamic.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.Loaders
|
||||
namespace Ryujinx.HLE.Loaders.Elf
|
||||
{
|
||||
enum ElfDynTag
|
||||
enum ElfDynamicTag
|
||||
{
|
||||
DT_NULL = 0,
|
||||
DT_NEEDED = 1,
|
40
Ryujinx.HLE/Loaders/Elf/ElfSymbol.cs
Normal file
40
Ryujinx.HLE/Loaders/Elf/ElfSymbol.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.Loaders
|
||||
namespace Ryujinx.HLE.Loaders.Elf
|
||||
{
|
||||
enum ElfSymBinding
|
||||
enum ElfSymbolBinding
|
||||
{
|
||||
STB_LOCAL = 0,
|
||||
STB_GLOBAL = 1,
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.Loaders
|
||||
namespace Ryujinx.HLE.Loaders.Elf
|
||||
{
|
||||
enum ElfSymType
|
||||
enum ElfSymbolType
|
||||
{
|
||||
STT_NOTYPE = 0,
|
||||
STT_OBJECT = 1,
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.Loaders
|
||||
namespace Ryujinx.HLE.Loaders.Elf
|
||||
{
|
||||
enum ElfSymVisibility
|
||||
enum ElfSymbolVisibility
|
||||
{
|
||||
STV_DEFAULT = 0,
|
||||
STV_INTERNAL = 1,
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders
|
||||
{
|
||||
struct ElfRel
|
||||
{
|
||||
public long Offset { get; private set; }
|
||||
public long Addend { get; private set; }
|
||||
|
||||
public ElfSym Symbol { get; private set; }
|
||||
public ElfRelType Type { get; private set; }
|
||||
|
||||
public ElfRel(long Offset, long Addend, ElfSym Symbol, ElfRelType Type)
|
||||
{
|
||||
this.Offset = Offset;
|
||||
this.Addend = Addend;
|
||||
this.Symbol = Symbol;
|
||||
this.Type = Type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders
|
||||
{
|
||||
enum ElfRelType
|
||||
{
|
||||
R_AARCH64_NONE = 0,
|
||||
R_AARCH64_ABS64 = 257,
|
||||
R_AARCH64_ABS32 = 258,
|
||||
R_AARCH64_ABS16 = 259,
|
||||
R_AARCH64_PREL64 = 260,
|
||||
R_AARCH64_PREL32 = 261,
|
||||
R_AARCH64_PREL16 = 262,
|
||||
R_AARCH64_MOVW_UABS_G0 = 263,
|
||||
R_AARCH64_MOVW_UABS_G0_NC = 264,
|
||||
R_AARCH64_MOVW_UABS_G1 = 265,
|
||||
R_AARCH64_MOVW_UABS_G1_NC = 266,
|
||||
R_AARCH64_MOVW_UABS_G2 = 267,
|
||||
R_AARCH64_MOVW_UABS_G2_NC = 268,
|
||||
R_AARCH64_MOVW_UABS_G3 = 269,
|
||||
R_AARCH64_MOVW_SABS_G0 = 270,
|
||||
R_AARCH64_MOVW_SABS_G1 = 271,
|
||||
R_AARCH64_MOVW_SABS_G2 = 272,
|
||||
R_AARCH64_LD_PREL_LO19 = 273,
|
||||
R_AARCH64_ADR_PREL_LO21 = 274,
|
||||
R_AARCH64_ADR_PREL_PG_HI21 = 275,
|
||||
R_AARCH64_ADR_PREL_PG_HI21_NC = 276,
|
||||
R_AARCH64_ADD_ABS_LO12_NC = 277,
|
||||
R_AARCH64_LDST8_ABS_LO12_NC = 278,
|
||||
R_AARCH64_TSTBR14 = 279,
|
||||
R_AARCH64_CONDBR19 = 280,
|
||||
R_AARCH64_JUMP26 = 282,
|
||||
R_AARCH64_CALL26 = 283,
|
||||
R_AARCH64_LDST16_ABS_LO12_NC = 284,
|
||||
R_AARCH64_LDST32_ABS_LO12_NC = 285,
|
||||
R_AARCH64_LDST64_ABS_LO12_NC = 286,
|
||||
R_AARCH64_MOVW_PREL_G0 = 287,
|
||||
R_AARCH64_MOVW_PREL_G0_NC = 288,
|
||||
R_AARCH64_MOVW_PREL_G1 = 289,
|
||||
R_AARCH64_MOVW_PREL_G1_NC = 290,
|
||||
R_AARCH64_MOVW_PREL_G2 = 291,
|
||||
R_AARCH64_MOVW_PREL_G2_NC = 292,
|
||||
R_AARCH64_MOVW_PREL_G3 = 293,
|
||||
R_AARCH64_LDST128_ABS_LO12_NC = 299,
|
||||
R_AARCH64_MOVW_GOTOFF_G0 = 300,
|
||||
R_AARCH64_MOVW_GOTOFF_G0_NC = 301,
|
||||
R_AARCH64_MOVW_GOTOFF_G1 = 302,
|
||||
R_AARCH64_MOVW_GOTOFF_G1_NC = 303,
|
||||
R_AARCH64_MOVW_GOTOFF_G2 = 304,
|
||||
R_AARCH64_MOVW_GOTOFF_G2_NC = 305,
|
||||
R_AARCH64_MOVW_GOTOFF_G3 = 306,
|
||||
R_AARCH64_GOTREL64 = 307,
|
||||
R_AARCH64_GOTREL32 = 308,
|
||||
R_AARCH64_GOT_LD_PREL19 = 309,
|
||||
R_AARCH64_LD64_GOTOFF_LO15 = 310,
|
||||
R_AARCH64_ADR_GOT_PAGE = 311,
|
||||
R_AARCH64_LD64_GOT_LO12_NC = 312,
|
||||
R_AARCH64_LD64_GOTPAGE_LO15 = 313,
|
||||
R_AARCH64_TLSGD_ADR_PREL21 = 512,
|
||||
R_AARCH64_TLSGD_ADR_PAGE21 = 513,
|
||||
R_AARCH64_TLSGD_ADD_LO12_NC = 514,
|
||||
R_AARCH64_TLSGD_MOVW_G1 = 515,
|
||||
R_AARCH64_TLSGD_MOVW_G0_NC = 516,
|
||||
R_AARCH64_TLSLD_ADR_PREL21 = 517,
|
||||
R_AARCH64_TLSLD_ADR_PAGE21 = 518,
|
||||
R_AARCH64_TLSLD_ADD_LO12_NC = 519,
|
||||
R_AARCH64_TLSLD_MOVW_G1 = 520,
|
||||
R_AARCH64_TLSLD_MOVW_G0_NC = 521,
|
||||
R_AARCH64_TLSLD_LD_PREL19 = 522,
|
||||
R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523,
|
||||
R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524,
|
||||
R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525,
|
||||
R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526,
|
||||
R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527,
|
||||
R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528,
|
||||
R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529,
|
||||
R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530,
|
||||
R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531,
|
||||
R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532,
|
||||
R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533,
|
||||
R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534,
|
||||
R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535,
|
||||
R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536,
|
||||
R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537,
|
||||
R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538,
|
||||
R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539,
|
||||
R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540,
|
||||
R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541,
|
||||
R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542,
|
||||
R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543,
|
||||
R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544,
|
||||
R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545,
|
||||
R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546,
|
||||
R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547,
|
||||
R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551,
|
||||
R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552,
|
||||
R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553,
|
||||
R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554,
|
||||
R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555,
|
||||
R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556,
|
||||
R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557,
|
||||
R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558,
|
||||
R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559,
|
||||
R_AARCH64_TLSDESC_LD_PREL19 = 560,
|
||||
R_AARCH64_TLSDESC_ADR_PREL21 = 561,
|
||||
R_AARCH64_TLSDESC_ADR_PAGE21 = 562,
|
||||
R_AARCH64_TLSDESC_LD64_LO12 = 563,
|
||||
R_AARCH64_TLSDESC_ADD_LO12 = 564,
|
||||
R_AARCH64_TLSDESC_OFF_G1 = 565,
|
||||
R_AARCH64_TLSDESC_OFF_G0_NC = 566,
|
||||
R_AARCH64_TLSDESC_LDR = 567,
|
||||
R_AARCH64_TLSDESC_ADD = 568,
|
||||
R_AARCH64_TLSDESC_CALL = 569,
|
||||
R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570,
|
||||
R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571,
|
||||
R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572,
|
||||
R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573,
|
||||
R_AARCH64_COPY = 1024,
|
||||
R_AARCH64_GLOB_DAT = 1025,
|
||||
R_AARCH64_JUMP_SLOT = 1026,
|
||||
R_AARCH64_RELATIVE = 1027,
|
||||
R_AARCH64_TLS_DTPMOD64 = 1028,
|
||||
R_AARCH64_TLS_DTPREL64 = 1029,
|
||||
R_AARCH64_TLS_TPREL64 = 1030,
|
||||
R_AARCH64_TLSDESC = 1031
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders
|
||||
{
|
||||
class Executable
|
||||
{
|
||||
private MemoryManager Memory;
|
||||
|
||||
private List<ElfDyn> Dynamic;
|
||||
|
||||
public ReadOnlyCollection<ElfSym> 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<ElfDyn>();
|
||||
|
||||
FilePath = Exe.FilePath;
|
||||
|
||||
if (FilePath != null)
|
||||
{
|
||||
Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, ""));
|
||||
}
|
||||
|
||||
this.Memory = Memory;
|
||||
this.MemoryManager = MemoryManager;
|
||||
this.ImageBase = ImageBase;
|
||||
this.ImageEnd = ImageBase;
|
||||
|
||||
long TextPosition = ImageBase + (uint)Exe.TextOffset;
|
||||
long ROPosition = ImageBase + (uint)Exe.ROOffset;
|
||||
long DataPosition = ImageBase + (uint)Exe.DataOffset;
|
||||
|
||||
long TextSize = (uint)IntUtils.AlignUp(Exe.Text.Length, KMemoryManager.PageSize);
|
||||
long ROSize = (uint)IntUtils.AlignUp(Exe.RO.Length, KMemoryManager.PageSize);
|
||||
long DataSize = (uint)IntUtils.AlignUp(Exe.Data.Length, KMemoryManager.PageSize);
|
||||
long BssSize = (uint)IntUtils.AlignUp(Exe.BssSize, KMemoryManager.PageSize);
|
||||
|
||||
long DataAndBssSize = BssSize + DataSize;
|
||||
|
||||
ImageEnd = DataPosition + DataAndBssSize;
|
||||
|
||||
if (Exe.SourceAddress == 0)
|
||||
{
|
||||
MemoryManager.HleMapProcessCode(TextPosition, TextSize + ROSize + DataAndBssSize);
|
||||
|
||||
MemoryManager.SetProcessMemoryPermission(ROPosition, ROSize, MemoryPermission.Read);
|
||||
MemoryManager.SetProcessMemoryPermission(DataPosition, DataAndBssSize, MemoryPermission.ReadAndWrite);
|
||||
|
||||
Memory.WriteBytes(TextPosition, Exe.Text);
|
||||
Memory.WriteBytes(ROPosition, Exe.RO);
|
||||
Memory.WriteBytes(DataPosition, Exe.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
long Result = MemoryManager.MapProcessCodeMemory(TextPosition, Exe.SourceAddress, TextSize + ROSize + DataSize);
|
||||
|
||||
if (Result != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
MemoryManager.SetProcessMemoryPermission(ROPosition, ROSize, MemoryPermission.Read);
|
||||
MemoryManager.SetProcessMemoryPermission(DataPosition, DataSize, MemoryPermission.ReadAndWrite);
|
||||
|
||||
if (Exe.BssAddress != 0 && Exe.BssSize != 0)
|
||||
{
|
||||
Result = MemoryManager.MapProcessCodeMemory(DataPosition + DataSize, Exe.BssAddress, BssSize);
|
||||
|
||||
if (Result != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
MemoryManager.SetProcessMemoryPermission(DataPosition + DataSize, BssSize, MemoryPermission.ReadAndWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if (Exe.Mod0Offset == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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<ElfSym> Symbols = new List<ElfSym>();
|
||||
|
||||
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 ElfRel GetRelocation(long Position)
|
||||
{
|
||||
long Offset = Memory.ReadInt64(Position + 0);
|
||||
long Info = Memory.ReadInt64(Position + 8);
|
||||
long Addend = Memory.ReadInt64(Position + 16);
|
||||
|
||||
int RelType = (int)(Info >> 0);
|
||||
int SymIdx = (int)(Info >> 32);
|
||||
|
||||
ElfSym Symbol = GetSymbol(SymIdx);
|
||||
|
||||
return new ElfRel(Offset, Addend, Symbol, (ElfRelType)RelType);
|
||||
}
|
||||
|
||||
private ElfSym GetSymbol(int Index)
|
||||
{
|
||||
long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB);
|
||||
long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB);
|
||||
|
||||
long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT);
|
||||
|
||||
long Position = SymTblAddr + Index * SymEntSize;
|
||||
|
||||
return GetSymbol(Position, StrTblAddr);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,15 @@
|
|||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
public interface IExecutable
|
||||
interface IExecutable
|
||||
{
|
||||
string FilePath { get; }
|
||||
|
||||
byte[] Text { get; }
|
||||
byte[] RO { get; }
|
||||
byte[] Data { get; }
|
||||
|
||||
long SourceAddress { get; }
|
||||
long BssAddress { get; }
|
||||
|
||||
int Mod0Offset { get; }
|
||||
int TextOffset { get; }
|
||||
int ROOffset { get; }
|
||||
int DataOffset { get; }
|
||||
int BssOffset { get; }
|
||||
int BssSize { get; }
|
||||
}
|
||||
}
|
149
Ryujinx.HLE/Loaders/Executables/KernelInitialProcess.cs
Normal file
149
Ryujinx.HLE/Loaders/Executables/KernelInitialProcess.cs
Normal file
|
@ -0,0 +1,149 @@
|
|||
using Ryujinx.HLE.Loaders.Compression;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class KernelInitialProcess : IExecutable
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public long TitleId { get; private set; }
|
||||
|
||||
public int ProcessCategory { get; private set; }
|
||||
|
||||
public byte MainThreadPriority { get; private set; }
|
||||
public byte DefaultProcessorId { get; private set; }
|
||||
|
||||
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[] 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 MainThreadStackSize { get; private set; }
|
||||
|
||||
public int[] Capabilities { get; private set; }
|
||||
|
||||
private struct SegmentHeader
|
||||
{
|
||||
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 SegmentHeader(
|
||||
int Offset,
|
||||
int DecompressedSize,
|
||||
int CompressedSize,
|
||||
int Attribute)
|
||||
{
|
||||
this.Offset = Offset;
|
||||
this.DecompressedSize = DecompressedSize;
|
||||
this.CompressedSize = CompressedSize;
|
||||
this.Attribute = Attribute;
|
||||
}
|
||||
}
|
||||
|
||||
public KernelInitialProcess(Stream Input)
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(Input);
|
||||
|
||||
string Magic = ReadString(Reader, 4);
|
||||
|
||||
if (Magic != "KIP1")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Name = ReadString(Reader, 12);
|
||||
|
||||
TitleId = Reader.ReadInt64();
|
||||
|
||||
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[8];
|
||||
|
||||
for (int Index = 0; Index < Capabilities.Length; Index++)
|
||||
{
|
||||
Capabilities[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
Input.Seek(0x100, SeekOrigin.Begin);
|
||||
|
||||
Text = ReadSegment(Segments[0], Input);
|
||||
RO = ReadSegment(Segments[1], Input);
|
||||
Data = ReadSegment(Segments[2], Input);
|
||||
}
|
||||
|
||||
private byte[] ReadSegment(SegmentHeader Header, Stream Input)
|
||||
{
|
||||
long End = Input.Position + Header.CompressedSize;
|
||||
|
||||
Input.Seek(End, SeekOrigin.Begin);
|
||||
|
||||
byte[] Data = BackwardsLz.Decompress(Input, Header.DecompressedSize);
|
||||
|
||||
Input.Seek(End, SeekOrigin.Begin);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
|
@ -16,12 +14,13 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
public int DataOffset { get; private set; }
|
||||
public int BssSize { get; private set; }
|
||||
|
||||
public long SourceAddress { get; private set; }
|
||||
public long BssAddress { get; private set; }
|
||||
public int BssOffset => DataOffset + Data.Length;
|
||||
|
||||
public Nro(Stream Input, string FilePath, long SourceAddress = 0, long BssAddress = 0)
|
||||
public ulong SourceAddress { get; private set; }
|
||||
public ulong BssAddress { get; private set; }
|
||||
|
||||
public NxRelocatableObject(Stream Input, ulong SourceAddress = 0, ulong BssAddress = 0)
|
||||
{
|
||||
this.FilePath = FilePath;
|
||||
this.SourceAddress = SourceAddress;
|
||||
this.BssAddress = BssAddress;
|
||||
|
|
@ -4,22 +4,18 @@ 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; }
|
||||
|
||||
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 long SourceAddress { get; private set; }
|
||||
public long BssAddress { get; private set; }
|
||||
public int BssOffset => DataOffset + Data.Length;
|
||||
|
||||
[Flags]
|
||||
private enum NsoFlags
|
||||
|
@ -32,13 +28,8 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
HasDataHash = 1 << 5
|
||||
}
|
||||
|
||||
public Nso(Stream Input, string FilePath)
|
||||
public NxStaticObject(Stream Input)
|
||||
{
|
||||
this.FilePath = FilePath;
|
||||
|
||||
SourceAddress = 0;
|
||||
BssAddress = 0;
|
||||
|
||||
BinaryReader Reader = new BinaryReader(Input);
|
||||
|
||||
Input.Seek(0, SeekOrigin.Begin);
|
||||
|
@ -89,7 +80,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);
|
||||
}
|
||||
|
@ -99,7 +90,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);
|
||||
}
|
||||
|
@ -109,19 +100,10 @@ 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);
|
||||
}
|
||||
|
||||
using (MemoryStream TextMS = new MemoryStream(Text))
|
||||
{
|
||||
BinaryReader TextReader = new BinaryReader(TextMS);
|
||||
|
||||
TextMS.Seek(4, SeekOrigin.Begin);
|
||||
|
||||
Mod0Offset = TextReader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
enum ApplicationType
|
||||
{
|
||||
SystemModule,
|
||||
Application,
|
||||
Applet
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
enum FsPermissionBool : ulong
|
||||
{
|
||||
BisCache = 0x8000000000000080,
|
||||
EraseMmc = 0x8000000000000080,
|
||||
GameCardCertificate = 0x8000000000000010,
|
||||
GameCardIdSet = 0x8000000000000010,
|
||||
GameCardDriver = 0x8000000000000200,
|
||||
GameCardAsic = 0x8000000000000200,
|
||||
SaveDataCreate = 0x8000000000002020,
|
||||
SaveDataDelete0 = 0x8000000000000060,
|
||||
SystemSaveDataCreate0 = 0x8000000000000028,
|
||||
SystemSaveDataCreate1 = 0x8000000000000020,
|
||||
SaveDataDelete1 = 0x8000000000004028,
|
||||
SaveDataIterators0 = 0x8000000000000060,
|
||||
SaveDataIterators1 = 0x8000000000004020,
|
||||
SaveThumbnails = 0x8000000000020000,
|
||||
PosixTime = 0x8000000000000400,
|
||||
SaveDataExtraData = 0x8000000000004060,
|
||||
GlobalMode = 0x8000000000080000,
|
||||
SpeedEmulation = 0x8000000000080000,
|
||||
NULL = 0,
|
||||
PaddingFiles = 0xC000000000800000,
|
||||
SaveData_Debug = 0xC000000001000000,
|
||||
SaveData_SystemManagement = 0xC000000002000000,
|
||||
Unknown0x16 = 0x8000000004000000,
|
||||
Unknown0x17 = 0x8000000008000000,
|
||||
Unknown0x18 = 0x8000000010000000,
|
||||
Unknown0x19 = 0x8000000000000800,
|
||||
Unknown0x1A = 0x8000000000004020
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
enum FsPermissionRw : ulong
|
||||
{
|
||||
MountContentType2 = 0x8000000000000801,
|
||||
MountContentType5 = 0x8000000000000801,
|
||||
MountContentType3 = 0x8000000000000801,
|
||||
MountContentType4 = 0x8000000000000801,
|
||||
MountContentType6 = 0x8000000000000801,
|
||||
MountContentType7 = 0x8000000000000801,
|
||||
Unknown0x6 = 0x8000000000000000,
|
||||
ContentStorageAccess = 0x8000000000000800,
|
||||
ImageDirectoryAccess = 0x8000000000001000,
|
||||
MountBisType28 = 0x8000000000000084,
|
||||
MountBisType29 = 0x8000000000000080,
|
||||
MountBisType30 = 0x8000000000008080,
|
||||
MountBisType31 = 0x8000000000008080,
|
||||
Unknown0xD = 0x8000000000000080,
|
||||
SdCardAccess = 0xC000000000200000,
|
||||
GameCardUser = 0x8000000000000010,
|
||||
SaveDataAccess0 = 0x8000000000040020,
|
||||
SystemSaveDataAccess0 = 0x8000000000000028,
|
||||
SaveDataAccess1 = 0x8000000000000020,
|
||||
SystemSaveDataAccess1 = 0x8000000000000020,
|
||||
BisPartition0 = 0x8000000000010082,
|
||||
BisPartition10 = 0x8000000000010080,
|
||||
BisPartition20 = 0x8000000000010080,
|
||||
BisPartition21 = 0x8000000000010080,
|
||||
BisPartition22 = 0x8000000000010080,
|
||||
BisPartition23 = 0x8000000000010080,
|
||||
BisPartition24 = 0x8000000000010080,
|
||||
BisPartition25 = 0x8000000000010080,
|
||||
BisPartition26 = 0x8000000000000080,
|
||||
BisPartition27 = 0x8000000000000084,
|
||||
BisPartition28 = 0x8000000000000084,
|
||||
BisPartition29 = 0x8000000000000080,
|
||||
BisPartition30 = 0x8000000000000080,
|
||||
BisPartition31 = 0x8000000000000080,
|
||||
BisPartition32 = 0x8000000000000080,
|
||||
Unknown0x23 = 0xC000000000200000,
|
||||
GameCard_System = 0x8000000000000100,
|
||||
MountContent_System = 0x8000000000100008,
|
||||
HostAccess = 0xC000000000400000
|
||||
}
|
||||
}
|
|
@ -1,173 +1,23 @@
|
|||
using Ryujinx.HLE.Exceptions;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
class KernelAccessControl
|
||||
{
|
||||
public ReadOnlyCollection<KernelAccessControlItem> Items;
|
||||
public int[] Capabilities { get; private set; }
|
||||
|
||||
public KernelAccessControl(Stream Stream, int Offset, int Size)
|
||||
{
|
||||
Stream.Seek(Offset, SeekOrigin.Begin);
|
||||
|
||||
Capabilities = new int[Size / 4];
|
||||
|
||||
BinaryReader Reader = new BinaryReader(Stream);
|
||||
|
||||
KernelAccessControlItem[] Items = new KernelAccessControlItem[Size / 4];
|
||||
|
||||
for (int Index = 0; Index < Size / 4; Index++)
|
||||
for (int Index = 0; Index < Capabilities.Length; Index++)
|
||||
{
|
||||
uint Descriptor = Reader.ReadUInt32();
|
||||
|
||||
//Ignore the descriptor.
|
||||
if (Descriptor == 0xffffffff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Items[Index] = new KernelAccessControlItem();
|
||||
|
||||
int LowBits = 0;
|
||||
|
||||
while ((Descriptor & 1) != 0)
|
||||
{
|
||||
Descriptor >>= 1;
|
||||
|
||||
LowBits++;
|
||||
}
|
||||
|
||||
Descriptor >>= 1;
|
||||
|
||||
switch (LowBits)
|
||||
{
|
||||
//Kernel flags.
|
||||
case 3:
|
||||
{
|
||||
Items[Index].HasKernelFlags = true;
|
||||
|
||||
Items[Index].HighestThreadPriority = (Descriptor >> 0) & 0x3f;
|
||||
Items[Index].LowestThreadPriority = (Descriptor >> 6) & 0x3f;
|
||||
Items[Index].LowestCpuId = (Descriptor >> 12) & 0xff;
|
||||
Items[Index].HighestCpuId = (Descriptor >> 20) & 0xff;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Syscall mask.
|
||||
case 4:
|
||||
{
|
||||
Items[Index].HasSvcFlags = true;
|
||||
|
||||
Items[Index].AllowedSvcs = new bool[0x80];
|
||||
|
||||
int SysCallBase = (int)(Descriptor >> 24) * 0x18;
|
||||
|
||||
for (int SysCall = 0; SysCall < 0x18 && SysCallBase + SysCall < 0x80; SysCall++)
|
||||
{
|
||||
Items[Index].AllowedSvcs[SysCallBase + SysCall] = (Descriptor & 1) != 0;
|
||||
|
||||
Descriptor >>= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Map IO/Normal.
|
||||
case 6:
|
||||
{
|
||||
ulong Address = (Descriptor & 0xffffff) << 12;
|
||||
bool IsRo = (Descriptor >> 24) != 0;
|
||||
|
||||
if (Index == Size / 4 - 1)
|
||||
{
|
||||
throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!");
|
||||
}
|
||||
|
||||
Descriptor = Reader.ReadUInt32();
|
||||
|
||||
if ((Descriptor & 0x7f) != 0x3f)
|
||||
{
|
||||
throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!");
|
||||
}
|
||||
|
||||
Descriptor >>= 7;
|
||||
|
||||
ulong MmioSize = (Descriptor & 0xffffff) << 12;
|
||||
bool IsNormal = (Descriptor >> 24) != 0;
|
||||
|
||||
Items[Index].NormalMmio.Add(new KernelAccessControlMmio(Address, MmioSize, IsRo, IsNormal));
|
||||
|
||||
Index++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Map Normal Page.
|
||||
case 7:
|
||||
{
|
||||
ulong Address = Descriptor << 12;
|
||||
|
||||
Items[Index].PageMmio.Add(new KernelAccessControlMmio(Address, 0x1000, false, false));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//IRQ Pair.
|
||||
case 11:
|
||||
{
|
||||
Items[Index].Irq.Add(new KernelAccessControlIrq(
|
||||
(Descriptor >> 0) & 0x3ff,
|
||||
(Descriptor >> 10) & 0x3ff));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Application Type.
|
||||
case 13:
|
||||
{
|
||||
Items[Index].HasApplicationType = true;
|
||||
|
||||
Items[Index].ApplicationType = (int)Descriptor & 7;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Kernel Release Version.
|
||||
case 14:
|
||||
{
|
||||
Items[Index].HasKernelVersion = true;
|
||||
|
||||
Items[Index].KernelVersionRelease = (int)Descriptor;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Handle Table Size.
|
||||
case 15:
|
||||
{
|
||||
Items[Index].HasHandleTableSize = true;
|
||||
|
||||
Items[Index].HandleTableSize = (int)Descriptor;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Debug Flags.
|
||||
case 16:
|
||||
{
|
||||
Items[Index].HasDebugFlags = true;
|
||||
|
||||
Items[Index].AllowDebug = ((Descriptor >> 0) & 1) != 0;
|
||||
Items[Index].ForceDebug = ((Descriptor >> 1) & 1) != 0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Capabilities[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
this.Items = Array.AsReadOnly(Items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
struct KernelAccessControlIrq
|
||||
{
|
||||
public uint Irq0 { get; private set; }
|
||||
public uint Irq1 { get; private set; }
|
||||
|
||||
public KernelAccessControlIrq(uint Irq0, uint Irq1)
|
||||
{
|
||||
this.Irq0 = Irq0;
|
||||
this.Irq1 = Irq1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
struct KernelAccessControlMmio
|
||||
{
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
public bool IsRo { get; private set; }
|
||||
public bool IsNormal { get; private set; }
|
||||
|
||||
public KernelAccessControlMmio(
|
||||
ulong Address,
|
||||
ulong Size,
|
||||
bool IsRo,
|
||||
bool IsNormal)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
this.IsRo = IsRo;
|
||||
this.IsNormal = IsNormal;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
struct KernelAccessControlItem
|
||||
{
|
||||
public bool HasKernelFlags { get; set; }
|
||||
public uint LowestThreadPriority { get; set; }
|
||||
public uint HighestThreadPriority { get; set; }
|
||||
public uint LowestCpuId { get; set; }
|
||||
public uint HighestCpuId { get; set; }
|
||||
|
||||
public bool HasSvcFlags { get; set; }
|
||||
public bool[] AllowedSvcs { get; set; }
|
||||
|
||||
public List<KernelAccessControlMmio> NormalMmio { get; set; }
|
||||
public List<KernelAccessControlMmio> PageMmio { get; set; }
|
||||
public List<KernelAccessControlIrq> Irq { get; set; }
|
||||
|
||||
public bool HasApplicationType { get; set; }
|
||||
public int ApplicationType { get; set; }
|
||||
|
||||
public bool HasKernelVersion { get; set; }
|
||||
public int KernelVersionRelease { get; set; }
|
||||
|
||||
public bool HasHandleTableSize { get; set; }
|
||||
public int HandleTableSize { get; set; }
|
||||
|
||||
public bool HasDebugFlags { get; set; }
|
||||
public bool AllowDebug { get; set; }
|
||||
public bool ForceDebug { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
|
@ -12,15 +11,15 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
|||
{
|
||||
private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;
|
||||
|
||||
public bool Is64Bits { get; private set; }
|
||||
public int AddressSpaceWidth { get; private set; }
|
||||
public byte MainThreadPriority { get; private set; }
|
||||
public byte DefaultCpuId { get; private set; }
|
||||
public int SystemResourceSize { get; private set; }
|
||||
public int ProcessCategory { get; private set; }
|
||||
public int MainEntrypointStackSize { get; private set; }
|
||||
public string TitleName { get; private set; }
|
||||
public byte[] ProductCode { get; private set; }
|
||||
public byte MmuFlags { get; private set; }
|
||||
public bool Is64Bits { get; private set; }
|
||||
public byte MainThreadPriority { get; private set; }
|
||||
public byte DefaultCpuId { get; private set; }
|
||||
public int PersonalMmHeapSize { get; private set; }
|
||||
public int ProcessCategory { get; private set; }
|
||||
public int MainThreadStackSize { get; private set; }
|
||||
public string TitleName { get; private set; }
|
||||
public byte[] ProductCode { get; private set; }
|
||||
|
||||
public ACI0 ACI0 { get; private set; }
|
||||
public ACID ACID { get; private set; }
|
||||
|
@ -36,27 +35,22 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
|||
|
||||
Reader.ReadInt64();
|
||||
|
||||
//MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF.
|
||||
byte MmuFlags = Reader.ReadByte();
|
||||
MmuFlags = Reader.ReadByte();
|
||||
|
||||
Is64Bits = (MmuFlags & 1) != 0;
|
||||
AddressSpaceWidth = (MmuFlags >> 1) & 7;
|
||||
Is64Bits = (MmuFlags & 1) != 0;
|
||||
|
||||
Reader.ReadByte();
|
||||
|
||||
MainThreadPriority = Reader.ReadByte(); //(0-63).
|
||||
MainThreadPriority = Reader.ReadByte();
|
||||
DefaultCpuId = Reader.ReadByte();
|
||||
|
||||
Reader.ReadInt32();
|
||||
|
||||
//System resource size (max size as of 5.x: 534773760).
|
||||
SystemResourceSize = EndianSwap.Swap32(Reader.ReadInt32());
|
||||
PersonalMmHeapSize = Reader.ReadInt32();
|
||||
|
||||
//ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here.
|
||||
ProcessCategory = EndianSwap.Swap32(Reader.ReadInt32());
|
||||
ProcessCategory = Reader.ReadInt32();
|
||||
|
||||
//Main entrypoint stack size.
|
||||
MainEntrypointStackSize = Reader.ReadInt32();
|
||||
MainThreadStackSize = Reader.ReadInt32();
|
||||
|
||||
byte[] TempTitleName = Reader.ReadBytes(0x10);
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
|||
break;
|
||||
}
|
||||
|
||||
int Length = ((ControlByte & 0x07)) + 1;
|
||||
bool RegisterAllowed = ((ControlByte & 0x80) != 0);
|
||||
int Length = (ControlByte & 0x07) + 1;
|
||||
bool RegisterAllowed = (ControlByte & 0x80) != 0;
|
||||
|
||||
Services.Add(Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed);
|
||||
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
namespace Ryujinx.HLE.Loaders.Npdm
|
||||
{
|
||||
enum SvcName
|
||||
{
|
||||
Reserved0,
|
||||
SetHeapSize,
|
||||
SetMemoryPermission,
|
||||
SetMemoryAttribute,
|
||||
MapMemory,
|
||||
UnmapMemory,
|
||||
QueryMemory,
|
||||
ExitProcess,
|
||||
CreateThread,
|
||||
StartThread,
|
||||
ExitThread,
|
||||
SleepThread,
|
||||
GetThreadPriority,
|
||||
SetThreadPriority,
|
||||
GetThreadCoreMask,
|
||||
SetThreadCoreMask,
|
||||
GetCurrentProcessorNumber,
|
||||
SignalEvent,
|
||||
ClearEvent,
|
||||
MapSharedMemory,
|
||||
UnmapSharedMemory,
|
||||
CreateTransferMemory,
|
||||
CloseHandle,
|
||||
ResetSignal,
|
||||
WaitSynchronization,
|
||||
CancelSynchronization,
|
||||
ArbitrateLock,
|
||||
ArbitrateUnlock,
|
||||
WaitProcessWideKeyAtomic,
|
||||
SignalProcessWideKey,
|
||||
GetSystemTick,
|
||||
ConnectToNamedPort,
|
||||
SendSyncRequestLight,
|
||||
SendSyncRequest,
|
||||
SendSyncRequestWithUserBuffer,
|
||||
SendAsyncRequestWithUserBuffer,
|
||||
GetProcessId,
|
||||
GetThreadId,
|
||||
Break,
|
||||
OutputDebugString,
|
||||
ReturnFromException,
|
||||
GetInfo,
|
||||
FlushEntireDataCache,
|
||||
FlushDataCache,
|
||||
MapPhysicalMemory,
|
||||
UnmapPhysicalMemory,
|
||||
GetFutureThreadInfo,
|
||||
GetLastThreadInfo,
|
||||
GetResourceLimitLimitValue,
|
||||
GetResourceLimitCurrentValue,
|
||||
SetThreadActivity,
|
||||
GetThreadContext3,
|
||||
WaitForAddress,
|
||||
SignalToAddress,
|
||||
Reserved1,
|
||||
Reserved2,
|
||||
Reserved3,
|
||||
Reserved4,
|
||||
Reserved5,
|
||||
Reserved6,
|
||||
DumpInfo,
|
||||
DumpInfoNew,
|
||||
Reserved7,
|
||||
Reserved8,
|
||||
CreateSession,
|
||||
AcceptSession,
|
||||
ReplyAndReceiveLight,
|
||||
ReplyAndReceive,
|
||||
ReplyAndReceiveWithUserBuffer,
|
||||
CreateEvent,
|
||||
Reserved9,
|
||||
Reserved10,
|
||||
MapPhysicalMemoryUnsafe,
|
||||
UnmapPhysicalMemoryUnsafe,
|
||||
SetUnsafeLimit,
|
||||
CreateCodeMemory,
|
||||
ControlCodeMemory,
|
||||
SleepSystem,
|
||||
ReadWriteRegister,
|
||||
SetProcessActivity,
|
||||
CreateSharedMemory,
|
||||
MapTransferMemory,
|
||||
UnmapTransferMemory,
|
||||
CreateInterruptEvent,
|
||||
QueryPhysicalAddress,
|
||||
QueryIoMapping,
|
||||
CreateDeviceAddressSpace,
|
||||
AttachDeviceAddressSpace,
|
||||
DetachDeviceAddressSpace,
|
||||
MapDeviceAddressSpaceByForce,
|
||||
MapDeviceAddressSpaceAligned,
|
||||
MapDeviceAddressSpace,
|
||||
UnmapDeviceAddressSpace,
|
||||
InvalidateProcessDataCache,
|
||||
StoreProcessDataCache,
|
||||
FlushProcessDataCache,
|
||||
DebugActiveProcess,
|
||||
BreakDebugProcess,
|
||||
TerminateDebugProcess,
|
||||
GetDebugEvent,
|
||||
ContinueDebugEvent,
|
||||
GetProcessList,
|
||||
GetThreadList,
|
||||
GetDebugThreadContext,
|
||||
SetDebugThreadContext,
|
||||
QueryDebugProcessMemory,
|
||||
ReadDebugProcessMemory,
|
||||
WriteDebugProcessMemory,
|
||||
SetHardwareBreakPoint,
|
||||
GetDebugThreadParam,
|
||||
Reserved11,
|
||||
GetSystemInfo,
|
||||
CreatePort,
|
||||
ManageNamedPort,
|
||||
ConnectToPort,
|
||||
SetProcessMemoryPermission,
|
||||
MapProcessMemory,
|
||||
UnmapProcessMemory,
|
||||
QueryProcessMemory,
|
||||
MapProcessCodeMemory,
|
||||
UnmapProcessCodeMemory,
|
||||
CreateProcess,
|
||||
StartProcess,
|
||||
TerminateProcess,
|
||||
GetProcessInfo,
|
||||
CreateResourceLimit,
|
||||
SetResourceLimitLimitValue,
|
||||
CallSecureMonitor
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue