Merge branch 'master' into MoreDynamicStatesPartOne
This commit is contained in:
commit
34ac6f33ad
30 changed files with 347 additions and 354 deletions
|
@ -473,7 +473,7 @@ namespace Ryujinx.UI.Widgets
|
||||||
|
|
||||||
private void ManageDlc_Clicked(object sender, EventArgs args)
|
private void ManageDlc_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
new DlcWindow(_virtualFileSystem, _applicationData.IdString, _applicationData).Show();
|
new DlcWindow(_virtualFileSystem, _applicationData.IdBaseString, _applicationData).Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ManageCheats_Clicked(object sender, EventArgs args)
|
private void ManageCheats_Clicked(object sender, EventArgs args)
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.UI.Windows
|
||||||
public class DlcWindow : Window
|
public class DlcWindow : Window
|
||||||
{
|
{
|
||||||
private readonly VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private readonly string _applicationId;
|
private readonly string _applicationIdBase;
|
||||||
private readonly string _dlcJsonPath;
|
private readonly string _dlcJsonPath;
|
||||||
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
||||||
|
|
||||||
|
@ -36,16 +36,16 @@ namespace Ryujinx.UI.Windows
|
||||||
[GUI] TreeSelection _dlcTreeSelection;
|
[GUI] TreeSelection _dlcTreeSelection;
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
||||||
public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, ApplicationData applicationData) : this(new Builder("Ryujinx.Gtk3.UI.Windows.DlcWindow.glade"), virtualFileSystem, titleId, applicationData) { }
|
public DlcWindow(VirtualFileSystem virtualFileSystem, string applicationIdBase, ApplicationData applicationData) : this(new Builder("Ryujinx.Gtk3.UI.Windows.DlcWindow.glade"), virtualFileSystem, applicationIdBase, applicationData) { }
|
||||||
|
|
||||||
private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string applicationId, ApplicationData applicationData) : base(builder.GetRawOwnedObject("_dlcWindow"))
|
private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string applicationIdBase, ApplicationData applicationData) : base(builder.GetRawOwnedObject("_dlcWindow"))
|
||||||
{
|
{
|
||||||
builder.Autoconnect(this);
|
builder.Autoconnect(this);
|
||||||
|
|
||||||
_applicationId = applicationId;
|
_applicationIdBase = applicationIdBase;
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationId, "dlc.json");
|
_dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationIdBase, "dlc.json");
|
||||||
_baseTitleInfoLabel.Text = $"DLC Available for {applicationData.Name} [{applicationId.ToUpper()}]";
|
_baseTitleInfoLabel.Text = $"DLC Available for {applicationData.Name} [{applicationIdBase.ToUpper()}]";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -163,7 +163,7 @@ namespace Ryujinx.UI.Windows
|
||||||
|
|
||||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||||
{
|
{
|
||||||
if (nca.GetProgramIdBase() != (ulong.Parse(_applicationId, NumberStyles.HexNumber) & ~0x1FFFUL))
|
if (nca.GetProgramIdBase() != ulong.Parse(_applicationIdBase, NumberStyles.HexNumber))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.UI.Windows
|
||||||
|
|
||||||
_applicationData = applicationData;
|
_applicationData = applicationData;
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, applicationData.IdString, "updates.json");
|
_updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, applicationData.IdBaseString, "updates.json");
|
||||||
_radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
|
_radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -67,7 +67,7 @@ namespace Ryujinx.UI.Windows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_baseTitleInfoLabel.Text = $"Updates Available for {applicationData.Name} [{applicationData.IdString}]";
|
_baseTitleInfoLabel.Text = $"Updates Available for {applicationData.Name} [{applicationData.IdBaseString}]";
|
||||||
|
|
||||||
// Try to get updates from PFS first
|
// Try to get updates from PFS first
|
||||||
AddUpdate(_applicationData.Path, true);
|
AddUpdate(_applicationData.Path, true);
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|
||||||
{
|
|
||||||
enum AddressSpaceType
|
|
||||||
{
|
|
||||||
Addr32Bits = 0,
|
|
||||||
Addr36Bits = 1,
|
|
||||||
Addr32BitsNoMap = 2,
|
|
||||||
Addr39Bits = 3,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -58,11 +58,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
public ulong AslrRegionStart { get; private set; }
|
public ulong AslrRegionStart { get; private set; }
|
||||||
public ulong AslrRegionEnd { get; private set; }
|
public ulong AslrRegionEnd { get; private set; }
|
||||||
|
|
||||||
#pragma warning disable IDE0052 // Remove unread private member
|
|
||||||
private ulong _heapCapacity;
|
private ulong _heapCapacity;
|
||||||
#pragma warning restore IDE0052
|
|
||||||
|
|
||||||
public ulong PhysicalMemoryUsage { get; private set; }
|
public ulong PhysicalMemoryUsage { get; private set; }
|
||||||
|
public ulong AliasRegionExtraSize { get; private set; }
|
||||||
|
|
||||||
private readonly KMemoryBlockManager _blockManager;
|
private readonly KMemoryBlockManager _blockManager;
|
||||||
|
|
||||||
|
@ -98,30 +97,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
_reservedAddressSpaceSize = reservedAddressSpaceSize;
|
_reservedAddressSpaceSize = reservedAddressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly int[] _addrSpaceSizes = { 32, 36, 32, 39 };
|
|
||||||
|
|
||||||
public Result InitializeForProcess(
|
public Result InitializeForProcess(
|
||||||
AddressSpaceType addrSpaceType,
|
ProcessCreationFlags flags,
|
||||||
bool aslrEnabled,
|
|
||||||
bool fromBack,
|
bool fromBack,
|
||||||
MemoryRegion memRegion,
|
MemoryRegion memRegion,
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong size,
|
ulong size,
|
||||||
KMemoryBlockSlabManager slabManager)
|
KMemoryBlockSlabManager slabManager)
|
||||||
{
|
{
|
||||||
if ((uint)addrSpaceType > (uint)AddressSpaceType.Addr39Bits)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"AddressSpaceType bigger than {(uint)AddressSpaceType.Addr39Bits}: {(uint)addrSpaceType}", nameof(addrSpaceType));
|
|
||||||
}
|
|
||||||
|
|
||||||
_contextId = Context.ContextIdManager.GetId();
|
_contextId = Context.ContextIdManager.GetId();
|
||||||
|
|
||||||
ulong addrSpaceBase = 0;
|
ulong addrSpaceBase = 0;
|
||||||
ulong addrSpaceSize = 1UL << _addrSpaceSizes[(int)addrSpaceType];
|
ulong addrSpaceSize = 1UL << GetAddressSpaceWidth(flags);
|
||||||
|
|
||||||
Result result = CreateUserAddressSpace(
|
Result result = CreateUserAddressSpace(
|
||||||
addrSpaceType,
|
flags,
|
||||||
aslrEnabled,
|
|
||||||
fromBack,
|
fromBack,
|
||||||
addrSpaceBase,
|
addrSpaceBase,
|
||||||
addrSpaceSize,
|
addrSpaceSize,
|
||||||
|
@ -138,6 +128,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetAddressSpaceWidth(ProcessCreationFlags flags)
|
||||||
|
{
|
||||||
|
switch (flags & ProcessCreationFlags.AddressSpaceMask)
|
||||||
|
{
|
||||||
|
case ProcessCreationFlags.AddressSpace32Bit:
|
||||||
|
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
|
||||||
|
return 32;
|
||||||
|
case ProcessCreationFlags.AddressSpace64BitDeprecated:
|
||||||
|
return 36;
|
||||||
|
case ProcessCreationFlags.AddressSpace64Bit:
|
||||||
|
return 39;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"Invalid process flags {flags}", nameof(flags));
|
||||||
|
}
|
||||||
|
|
||||||
private struct Region
|
private struct Region
|
||||||
{
|
{
|
||||||
public ulong Start;
|
public ulong Start;
|
||||||
|
@ -147,8 +153,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result CreateUserAddressSpace(
|
private Result CreateUserAddressSpace(
|
||||||
AddressSpaceType addrSpaceType,
|
ProcessCreationFlags flags,
|
||||||
bool aslrEnabled,
|
|
||||||
bool fromBack,
|
bool fromBack,
|
||||||
ulong addrSpaceStart,
|
ulong addrSpaceStart,
|
||||||
ulong addrSpaceEnd,
|
ulong addrSpaceEnd,
|
||||||
|
@ -168,9 +173,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong stackAndTlsIoStart;
|
ulong stackAndTlsIoStart;
|
||||||
ulong stackAndTlsIoEnd;
|
ulong stackAndTlsIoEnd;
|
||||||
|
|
||||||
switch (addrSpaceType)
|
AliasRegionExtraSize = 0;
|
||||||
|
|
||||||
|
switch (flags & ProcessCreationFlags.AddressSpaceMask)
|
||||||
{
|
{
|
||||||
case AddressSpaceType.Addr32Bits:
|
case ProcessCreationFlags.AddressSpace32Bit:
|
||||||
aliasRegion.Size = 0x40000000;
|
aliasRegion.Size = 0x40000000;
|
||||||
heapRegion.Size = 0x40000000;
|
heapRegion.Size = 0x40000000;
|
||||||
stackRegion.Size = 0;
|
stackRegion.Size = 0;
|
||||||
|
@ -183,7 +190,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
stackAndTlsIoEnd = 0x40000000;
|
stackAndTlsIoEnd = 0x40000000;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr36Bits:
|
case ProcessCreationFlags.AddressSpace64BitDeprecated:
|
||||||
aliasRegion.Size = 0x180000000;
|
aliasRegion.Size = 0x180000000;
|
||||||
heapRegion.Size = 0x180000000;
|
heapRegion.Size = 0x180000000;
|
||||||
stackRegion.Size = 0;
|
stackRegion.Size = 0;
|
||||||
|
@ -196,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
stackAndTlsIoEnd = 0x80000000;
|
stackAndTlsIoEnd = 0x80000000;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr32BitsNoMap:
|
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
|
||||||
aliasRegion.Size = 0;
|
aliasRegion.Size = 0;
|
||||||
heapRegion.Size = 0x80000000;
|
heapRegion.Size = 0x80000000;
|
||||||
stackRegion.Size = 0;
|
stackRegion.Size = 0;
|
||||||
|
@ -209,7 +216,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
stackAndTlsIoEnd = 0x40000000;
|
stackAndTlsIoEnd = 0x40000000;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr39Bits:
|
case ProcessCreationFlags.AddressSpace64Bit:
|
||||||
if (_reservedAddressSpaceSize < addrSpaceEnd)
|
if (_reservedAddressSpaceSize < addrSpaceEnd)
|
||||||
{
|
{
|
||||||
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
|
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
|
||||||
|
@ -218,8 +225,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
heapRegion.Size = 0x180000000;
|
heapRegion.Size = 0x180000000;
|
||||||
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
||||||
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
|
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
|
||||||
CodeRegionStart = BitUtils.AlignDown<ulong>(address, RegionAlignment);
|
CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment);
|
||||||
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, RegionAlignment) - CodeRegionStart;
|
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
|
||||||
stackAndTlsIoStart = 0;
|
stackAndTlsIoStart = 0;
|
||||||
stackAndTlsIoEnd = 0;
|
stackAndTlsIoEnd = 0;
|
||||||
AslrRegionStart = 0x8000000;
|
AslrRegionStart = 0x8000000;
|
||||||
|
@ -239,9 +246,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
stackAndTlsIoStart = 0;
|
stackAndTlsIoStart = 0;
|
||||||
stackAndTlsIoEnd = 0;
|
stackAndTlsIoEnd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize))
|
||||||
|
{
|
||||||
|
AliasRegionExtraSize = addrSpaceEnd / 8;
|
||||||
|
aliasRegion.Size += AliasRegionExtraSize;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"AddressSpaceType bigger than {(uint)AddressSpaceType.Addr39Bits}: {(uint)addrSpaceType}", nameof(addrSpaceType));
|
throw new ArgumentException($"Invalid process flags {flags}", nameof(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeRegionEnd = CodeRegionStart + codeRegionSize;
|
CodeRegionEnd = CodeRegionStart + codeRegionSize;
|
||||||
|
@ -266,6 +280,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
ulong aslrMaxOffset = mapAvailableSize - mapTotalSize;
|
ulong aslrMaxOffset = mapAvailableSize - mapTotalSize;
|
||||||
|
|
||||||
|
bool aslrEnabled = flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||||
|
|
||||||
_aslrEnabled = aslrEnabled;
|
_aslrEnabled = aslrEnabled;
|
||||||
|
|
||||||
AddrSpaceStart = addrSpaceStart;
|
AddrSpaceStart = addrSpaceStart;
|
||||||
|
@ -725,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
address = 0;
|
address = 0;
|
||||||
|
|
||||||
if (size > HeapRegionEnd - HeapRegionStart)
|
if (size > HeapRegionEnd - HeapRegionStart || size > _heapCapacity)
|
||||||
{
|
{
|
||||||
return KernelResult.OutOfMemory;
|
return KernelResult.OutOfMemory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,8 +126,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
_contextFactory = contextFactory ?? new ProcessContextFactory();
|
_contextFactory = contextFactory ?? new ProcessContextFactory();
|
||||||
_customThreadStart = customThreadStart;
|
_customThreadStart = customThreadStart;
|
||||||
|
|
||||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
|
||||||
|
|
||||||
Pid = KernelContext.NewKipId();
|
Pid = KernelContext.NewKipId();
|
||||||
|
|
||||||
if (Pid == 0 || Pid >= KernelConstants.InitialProcessId)
|
if (Pid == 0 || Pid >= KernelConstants.InitialProcessId)
|
||||||
|
@ -137,8 +135,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
InitializeMemoryManager(creationInfo.Flags);
|
InitializeMemoryManager(creationInfo.Flags);
|
||||||
|
|
||||||
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
|
||||||
|
|
||||||
ulong codeAddress = creationInfo.CodeAddress;
|
ulong codeAddress = creationInfo.CodeAddress;
|
||||||
|
|
||||||
ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
|
ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
|
||||||
|
@ -148,9 +144,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
: KernelContext.SmallMemoryBlockSlabManager;
|
: KernelContext.SmallMemoryBlockSlabManager;
|
||||||
|
|
||||||
Result result = MemoryManager.InitializeForProcess(
|
Result result = MemoryManager.InitializeForProcess(
|
||||||
addrSpaceType,
|
creationInfo.Flags,
|
||||||
aslrEnabled,
|
!creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr),
|
||||||
!aslrEnabled,
|
|
||||||
memRegion,
|
memRegion,
|
||||||
codeAddress,
|
codeAddress,
|
||||||
codeSize,
|
codeSize,
|
||||||
|
@ -234,8 +229,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
: KernelContext.SmallMemoryBlockSlabManager;
|
: KernelContext.SmallMemoryBlockSlabManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
|
||||||
|
|
||||||
Pid = KernelContext.NewProcessId();
|
Pid = KernelContext.NewProcessId();
|
||||||
|
|
||||||
if (Pid == ulong.MaxValue || Pid < KernelConstants.InitialProcessId)
|
if (Pid == ulong.MaxValue || Pid < KernelConstants.InitialProcessId)
|
||||||
|
@ -245,16 +238,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
InitializeMemoryManager(creationInfo.Flags);
|
InitializeMemoryManager(creationInfo.Flags);
|
||||||
|
|
||||||
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
|
||||||
|
|
||||||
ulong codeAddress = creationInfo.CodeAddress;
|
ulong codeAddress = creationInfo.CodeAddress;
|
||||||
|
|
||||||
ulong codeSize = codePagesCount * KPageTableBase.PageSize;
|
ulong codeSize = codePagesCount * KPageTableBase.PageSize;
|
||||||
|
|
||||||
Result result = MemoryManager.InitializeForProcess(
|
Result result = MemoryManager.InitializeForProcess(
|
||||||
addrSpaceType,
|
creationInfo.Flags,
|
||||||
aslrEnabled,
|
!creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr),
|
||||||
!aslrEnabled,
|
|
||||||
memRegion,
|
memRegion,
|
||||||
codeAddress,
|
codeAddress,
|
||||||
codeSize,
|
codeSize,
|
||||||
|
@ -309,8 +299,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
private Result ParseProcessInfo(ProcessCreationInfo creationInfo)
|
private Result ParseProcessInfo(ProcessCreationInfo creationInfo)
|
||||||
{
|
{
|
||||||
// Ensure that the current kernel version is equal or above to the minimum required.
|
// Ensure that the current kernel version is equal or above to the minimum required.
|
||||||
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
|
uint requiredKernelVersionMajor = Capabilities.KernelReleaseVersion >> 19;
|
||||||
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
|
uint requiredKernelVersionMinor = (Capabilities.KernelReleaseVersion >> 15) & 0xf;
|
||||||
|
|
||||||
if (KernelContext.EnableVersionChecks)
|
if (KernelContext.EnableVersionChecks)
|
||||||
{
|
{
|
||||||
|
@ -519,12 +509,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
private void GenerateRandomEntropy()
|
private void GenerateRandomEntropy()
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO.
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
public Result Start(int mainThreadPriority, ulong stackSize)
|
public Result Start(int mainThreadPriority, ulong stackSize)
|
||||||
{
|
{
|
||||||
|
@ -1182,5 +1170,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
// TODO
|
// TODO
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSvcPermitted(int svcId)
|
||||||
|
{
|
||||||
|
return Capabilities.IsSvcPermitted(svcId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
class KProcessCapabilities
|
class KProcessCapabilities
|
||||||
{
|
{
|
||||||
|
private const int SvcMaskElementBits = 8;
|
||||||
|
|
||||||
public byte[] SvcAccessMask { get; }
|
public byte[] SvcAccessMask { get; }
|
||||||
public byte[] IrqAccessMask { get; }
|
public byte[] IrqAccessMask { get; }
|
||||||
|
|
||||||
|
@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
public KProcessCapabilities()
|
public KProcessCapabilities()
|
||||||
{
|
{
|
||||||
// length / number of bits of the underlying type
|
// length / number of bits of the underlying type
|
||||||
SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / 8];
|
SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / SvcMaskElementBits];
|
||||||
IrqAccessMask = new byte[0x80];
|
IrqAccessMask = new byte[0x80];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +210,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return KernelResult.MaximumExceeded;
|
return KernelResult.MaximumExceeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7));
|
SvcAccessMask[svcId / SvcMaskElementBits] |= (byte)(1 << (svcId % SvcMaskElementBits));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -324,5 +326,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
return mask << (int)min;
|
return mask << (int)min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSvcPermitted(int svcId)
|
||||||
|
{
|
||||||
|
int index = svcId / SvcMaskElementBits;
|
||||||
|
int mask = 1 << (svcId % SvcMaskElementBits);
|
||||||
|
|
||||||
|
return (uint)svcId < KernelConstants.SupervisorCallCount && (SvcAccessMask[index] & mask) != 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
PoolPartitionMask = 0xf << PoolPartitionShift,
|
PoolPartitionMask = 0xf << PoolPartitionShift,
|
||||||
|
|
||||||
OptimizeMemoryAllocation = 1 << 11,
|
OptimizeMemoryAllocation = 1 << 11,
|
||||||
|
DisableDeviceAddressSpaceMerge = 1 << 12,
|
||||||
|
EnableAliasRegionExtraSize = 1 << 13,
|
||||||
|
|
||||||
All =
|
All =
|
||||||
Is64Bit |
|
Is64Bit |
|
||||||
|
@ -38,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
IsApplication |
|
IsApplication |
|
||||||
DeprecatedUseSecureMemory |
|
DeprecatedUseSecureMemory |
|
||||||
PoolPartitionMask |
|
PoolPartitionMask |
|
||||||
OptimizeMemoryAllocation,
|
OptimizeMemoryAllocation |
|
||||||
|
DisableDeviceAddressSpaceMerge |
|
||||||
|
EnableAliasRegionExtraSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
SystemResourceSizeTotal,
|
SystemResourceSizeTotal,
|
||||||
SystemResourceSizeUsed,
|
SystemResourceSizeUsed,
|
||||||
ProgramId,
|
ProgramId,
|
||||||
// NOTE: Added in 4.0.0, removed in 5.0.0.
|
InitialProcessIdRange, // NOTE: Added in 4.0.0, removed in 5.0.0.
|
||||||
InitialProcessIdRange,
|
|
||||||
UserExceptionContextAddress,
|
UserExceptionContextAddress,
|
||||||
TotalNonSystemMemorySize,
|
TotalNonSystemMemorySize,
|
||||||
UsedNonSystemMemorySize,
|
UsedNonSystemMemorySize,
|
||||||
IsApplication,
|
IsApplication,
|
||||||
FreeThreadCount,
|
FreeThreadCount,
|
||||||
ThreadTickCount,
|
ThreadTickCount,
|
||||||
|
IsSvcPermitted,
|
||||||
|
IoRegionHint,
|
||||||
|
AliasRegionExtraSize,
|
||||||
|
|
||||||
MesosphereCurrentProcess = 65001,
|
MesosphereCurrentProcess = 65001,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidSize;
|
return KernelResult.InvalidSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.Flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize))
|
||||||
|
{
|
||||||
|
if ((info.Flags & ProcessCreationFlags.AddressSpaceMask) != ProcessCreationFlags.AddressSpace64Bit ||
|
||||||
|
info.SystemResourcePagesCount <= 0)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check that we are in debug mode.
|
||||||
|
}
|
||||||
|
|
||||||
if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
|
if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
|
||||||
!info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
|
!info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
|
||||||
{
|
{
|
||||||
|
@ -139,7 +150,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return handleTable.GenerateHandle(process, out handle);
|
return handleTable.GenerateHandle(process, out handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
|
public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
|
KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
|
||||||
|
@ -172,17 +182,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x5f)]
|
[Svc(0x5f)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result FlushProcessDataCache(int processHandle, ulong address, ulong size)
|
public Result FlushProcessDataCache(int processHandle, ulong address, ulong size)
|
||||||
{
|
{
|
||||||
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
|
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
|
||||||
// As we don't support (and don't actually need) to flush the cache, this is stubbed.
|
// As we don't support (and don't actually need) to flush the cache, this is stubbed.
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
// IPC
|
// IPC
|
||||||
|
|
||||||
|
@ -256,7 +263,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x22)]
|
[Svc(0x22)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SendSyncRequestWithUserBuffer(
|
public Result SendSyncRequestWithUserBuffer(
|
||||||
[PointerSized] ulong messagePtr,
|
[PointerSized] ulong messagePtr,
|
||||||
[PointerSized] ulong messageSize,
|
[PointerSized] ulong messageSize,
|
||||||
|
@ -306,7 +312,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x23)]
|
[Svc(0x23)]
|
||||||
public Result SendAsyncRequestWithUserBuffer(
|
public Result SendAsyncRequestWithUserBuffer(
|
||||||
|
@ -896,7 +901,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(2)]
|
[Svc(2)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -928,10 +932,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission);
|
return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(3)]
|
[Svc(3)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetMemoryAttribute(
|
public Result SetMemoryAttribute(
|
||||||
[PointerSized] ulong address,
|
[PointerSized] ulong address,
|
||||||
[PointerSized] ulong size,
|
[PointerSized] ulong size,
|
||||||
|
@ -979,10 +981,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(4)]
|
[Svc(4)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
|
public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(src | dst))
|
if (!PageAligned(src | dst))
|
||||||
|
@ -1018,10 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return process.MemoryManager.Map(dst, src, size);
|
return process.MemoryManager.Map(dst, src, size);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(5)]
|
[Svc(5)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
|
public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(src | dst))
|
if (!PageAligned(src | dst))
|
||||||
|
@ -1057,7 +1055,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return process.MemoryManager.Unmap(dst, src, size);
|
return process.MemoryManager.Unmap(dst, src, size);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(6)]
|
[Svc(6)]
|
||||||
public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
|
public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
|
||||||
|
@ -1074,7 +1071,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
|
public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -1094,10 +1090,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x13)]
|
[Svc(0x13)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -1143,10 +1137,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
currentProcess,
|
currentProcess,
|
||||||
permission);
|
permission);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x14)]
|
[Svc(0x14)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
|
public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -1186,7 +1178,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
size,
|
size,
|
||||||
currentProcess);
|
currentProcess);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x15)]
|
[Svc(0x15)]
|
||||||
public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
||||||
|
@ -1253,7 +1244,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x51)]
|
[Svc(0x51)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -1299,10 +1289,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
currentProcess,
|
currentProcess,
|
||||||
permission);
|
permission);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x52)]
|
[Svc(0x52)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
|
public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -1342,10 +1330,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
size,
|
size,
|
||||||
currentProcess);
|
currentProcess);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x2c)]
|
[Svc(0x2c)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
|
public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -1380,10 +1366,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return process.MemoryManager.MapPhysicalMemory(address, size);
|
return process.MemoryManager.MapPhysicalMemory(address, size);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x2d)]
|
[Svc(0x2d)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
|
public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
|
@ -1418,7 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return process.MemoryManager.UnmapPhysicalMemory(address, size);
|
return process.MemoryManager.UnmapPhysicalMemory(address, size);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x4b)]
|
[Svc(0x4b)]
|
||||||
public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
|
public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
|
||||||
|
@ -1462,7 +1445,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x4c)]
|
[Svc(0x4c)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result ControlCodeMemory(
|
public Result ControlCodeMemory(
|
||||||
int handle,
|
int handle,
|
||||||
CodeMemoryOperation op,
|
CodeMemoryOperation op,
|
||||||
|
@ -1540,10 +1522,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidEnumValue;
|
return KernelResult.InvalidEnumValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x73)]
|
[Svc(0x73)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetProcessMemoryPermission(
|
public Result SetProcessMemoryPermission(
|
||||||
int handle,
|
int handle,
|
||||||
ulong src,
|
ulong src,
|
||||||
|
@ -1584,10 +1564,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
|
return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x74)]
|
[Svc(0x74)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result MapProcessMemory(
|
public Result MapProcessMemory(
|
||||||
[PointerSized] ulong dst,
|
[PointerSized] ulong dst,
|
||||||
int handle,
|
int handle,
|
||||||
|
@ -1643,10 +1621,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite);
|
return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x75)]
|
[Svc(0x75)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result UnmapProcessMemory(
|
public Result UnmapProcessMemory(
|
||||||
[PointerSized] ulong dst,
|
[PointerSized] ulong dst,
|
||||||
int handle,
|
int handle,
|
||||||
|
@ -1691,10 +1667,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x77)]
|
[Svc(0x77)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
|
public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(dst) || !PageAligned(src))
|
if (!PageAligned(dst) || !PageAligned(src))
|
||||||
|
@ -1731,10 +1705,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
|
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x78)]
|
[Svc(0x78)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
|
public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
|
||||||
{
|
{
|
||||||
if (!PageAligned(dst) || !PageAligned(src))
|
if (!PageAligned(dst) || !PageAligned(src))
|
||||||
|
@ -1771,7 +1743,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
private static bool PageAligned(ulong address)
|
private static bool PageAligned(ulong address)
|
||||||
{
|
{
|
||||||
|
@ -1781,7 +1752,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
// System
|
// System
|
||||||
|
|
||||||
[Svc(0x7b)]
|
[Svc(0x7b)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result TerminateProcess(int handle)
|
public Result TerminateProcess(int handle)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -1810,15 +1780,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(7)]
|
[Svc(7)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void ExitProcess()
|
public void ExitProcess()
|
||||||
{
|
{
|
||||||
KernelStatic.GetCurrentProcess().TerminateCurrentProcess();
|
KernelStatic.GetCurrentProcess().TerminateCurrentProcess();
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x11)]
|
[Svc(0x11)]
|
||||||
public Result SignalEvent(int handle)
|
public Result SignalEvent(int handle)
|
||||||
|
@ -1911,7 +1878,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x26)]
|
[Svc(0x26)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void Break(ulong reason)
|
public void Break(ulong reason)
|
||||||
{
|
{
|
||||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||||
|
@ -1937,10 +1903,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
Logger.Debug?.Print(LogClass.KernelSvc, "Debugger triggered.");
|
Logger.Debug?.Print(LogClass.KernelSvc, "Debugger triggered.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x27)]
|
[Svc(0x27)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size)
|
public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -1949,7 +1913,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.KernelSvc, str);
|
Logger.Warning?.Print(LogClass.KernelSvc, str);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x29)]
|
[Svc(0x29)]
|
||||||
public Result GetInfo(out ulong value, InfoType id, int handle, long subId)
|
public Result GetInfo(out ulong value, InfoType id, int handle, long subId)
|
||||||
|
@ -1978,6 +1941,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
case InfoType.UsedNonSystemMemorySize:
|
case InfoType.UsedNonSystemMemorySize:
|
||||||
case InfoType.IsApplication:
|
case InfoType.IsApplication:
|
||||||
case InfoType.FreeThreadCount:
|
case InfoType.FreeThreadCount:
|
||||||
|
case InfoType.AliasRegionExtraSize:
|
||||||
{
|
{
|
||||||
if (subId != 0)
|
if (subId != 0)
|
||||||
{
|
{
|
||||||
|
@ -2006,22 +1970,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
value = process.MemoryManager.AliasRegionStart;
|
value = process.MemoryManager.AliasRegionStart;
|
||||||
break;
|
break;
|
||||||
case InfoType.AliasRegionSize:
|
case InfoType.AliasRegionSize:
|
||||||
value = (process.MemoryManager.AliasRegionEnd -
|
value = process.MemoryManager.AliasRegionEnd - process.MemoryManager.AliasRegionStart;
|
||||||
process.MemoryManager.AliasRegionStart);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.HeapRegionAddress:
|
case InfoType.HeapRegionAddress:
|
||||||
value = process.MemoryManager.HeapRegionStart;
|
value = process.MemoryManager.HeapRegionStart;
|
||||||
break;
|
break;
|
||||||
case InfoType.HeapRegionSize:
|
case InfoType.HeapRegionSize:
|
||||||
value = (process.MemoryManager.HeapRegionEnd -
|
value = process.MemoryManager.HeapRegionEnd - process.MemoryManager.HeapRegionStart;
|
||||||
process.MemoryManager.HeapRegionStart);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.TotalMemorySize:
|
case InfoType.TotalMemorySize:
|
||||||
value = process.GetMemoryCapacity();
|
value = process.GetMemoryCapacity();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.UsedMemorySize:
|
case InfoType.UsedMemorySize:
|
||||||
value = process.GetMemoryUsage();
|
value = process.GetMemoryUsage();
|
||||||
break;
|
break;
|
||||||
|
@ -2029,7 +1990,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
case InfoType.AslrRegionAddress:
|
case InfoType.AslrRegionAddress:
|
||||||
value = process.MemoryManager.GetAddrSpaceBaseAddr();
|
value = process.MemoryManager.GetAddrSpaceBaseAddr();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.AslrRegionSize:
|
case InfoType.AslrRegionSize:
|
||||||
value = process.MemoryManager.GetAddrSpaceSize();
|
value = process.MemoryManager.GetAddrSpaceSize();
|
||||||
break;
|
break;
|
||||||
|
@ -2038,20 +1998,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
value = process.MemoryManager.StackRegionStart;
|
value = process.MemoryManager.StackRegionStart;
|
||||||
break;
|
break;
|
||||||
case InfoType.StackRegionSize:
|
case InfoType.StackRegionSize:
|
||||||
value = (process.MemoryManager.StackRegionEnd -
|
value = process.MemoryManager.StackRegionEnd - process.MemoryManager.StackRegionStart;
|
||||||
process.MemoryManager.StackRegionStart);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.SystemResourceSizeTotal:
|
case InfoType.SystemResourceSizeTotal:
|
||||||
value = process.PersonalMmHeapPagesCount * KPageTableBase.PageSize;
|
value = process.PersonalMmHeapPagesCount * KPageTableBase.PageSize;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.SystemResourceSizeUsed:
|
case InfoType.SystemResourceSizeUsed:
|
||||||
if (process.PersonalMmHeapPagesCount != 0)
|
if (process.PersonalMmHeapPagesCount != 0)
|
||||||
{
|
{
|
||||||
value = process.MemoryManager.GetMmUsedPages() * KPageTableBase.PageSize;
|
value = process.MemoryManager.GetMmUsedPages() * KPageTableBase.PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.ProgramId:
|
case InfoType.ProgramId:
|
||||||
|
@ -2065,7 +2022,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
case InfoType.TotalNonSystemMemorySize:
|
case InfoType.TotalNonSystemMemorySize:
|
||||||
value = process.GetMemoryCapacityWithoutPersonalMmHeap();
|
value = process.GetMemoryCapacityWithoutPersonalMmHeap();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InfoType.UsedNonSystemMemorySize:
|
case InfoType.UsedNonSystemMemorySize:
|
||||||
value = process.GetMemoryUsageWithoutPersonalMmHeap();
|
value = process.GetMemoryUsageWithoutPersonalMmHeap();
|
||||||
break;
|
break;
|
||||||
|
@ -2084,10 +2040,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
{
|
{
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InfoType.AliasRegionExtraSize:
|
||||||
|
value = process.MemoryManager.AliasRegionExtraSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2104,7 +2062,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
value = KernelStatic.GetCurrentProcess().Debug ? 1UL : 0UL;
|
value = KernelStatic.GetCurrentProcess().Debug ? 1UL : 0UL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2136,7 +2093,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
value = (uint)resLimHandle;
|
value = (uint)resLimHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2155,7 +2111,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
value = (ulong)KTimeManager.ConvertHostTicksToTicks(_context.Schedulers[currentCore].TotalIdleTimeTicks);
|
value = (ulong)KTimeManager.ConvertHostTicksToTicks(_context.Schedulers[currentCore].TotalIdleTimeTicks);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2174,7 +2129,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
||||||
|
|
||||||
value = currentProcess.RandomEntropy[subId];
|
value = currentProcess.RandomEntropy[subId];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2220,7 +2174,22 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
value = (ulong)KTimeManager.ConvertHostTicksToTicks(totalTimeRunning);
|
value = (ulong)KTimeManager.ConvertHostTicksToTicks(totalTimeRunning);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case InfoType.IsSvcPermitted:
|
||||||
|
{
|
||||||
|
if (handle != 0)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subId != 0x36)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidCombination;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = KernelStatic.GetCurrentProcess().IsSvcPermitted((int)subId) ? 1UL : 0UL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2231,7 +2200,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidHandle;
|
return KernelResult.InvalidHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ulong)subId != 0)
|
if (subId != 0)
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidCombination;
|
return KernelResult.InvalidCombination;
|
||||||
}
|
}
|
||||||
|
@ -2246,8 +2215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = (ulong)outHandle;
|
value = (uint)outHandle;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2398,7 +2366,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x30)]
|
[Svc(0x30)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
|
public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
|
||||||
{
|
{
|
||||||
limitValue = 0;
|
limitValue = 0;
|
||||||
|
@ -2419,10 +2386,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x31)]
|
[Svc(0x31)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
|
public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
|
||||||
{
|
{
|
||||||
limitValue = 0;
|
limitValue = 0;
|
||||||
|
@ -2443,10 +2408,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x37)]
|
[Svc(0x37)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
|
public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
|
||||||
{
|
{
|
||||||
peak = 0;
|
peak = 0;
|
||||||
|
@ -2467,7 +2430,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x7d)]
|
[Svc(0x7d)]
|
||||||
public Result CreateResourceLimit(out int handle)
|
public Result CreateResourceLimit(out int handle)
|
||||||
|
@ -2480,7 +2442,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x7e)]
|
[Svc(0x7e)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
|
public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
|
||||||
{
|
{
|
||||||
if (resource >= LimitableResource.Count)
|
if (resource >= LimitableResource.Count)
|
||||||
|
@ -2497,7 +2458,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return resourceLimit.SetLimitValue(resource, limitValue);
|
return resourceLimit.SetLimitValue(resource, limitValue);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
// Thread
|
// Thread
|
||||||
|
|
||||||
|
@ -2577,7 +2537,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(9)]
|
[Svc(9)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result StartThread(int handle)
|
public Result StartThread(int handle)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2604,17 +2563,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidHandle;
|
return KernelResult.InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0xa)]
|
[Svc(0xa)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void ExitThread()
|
public void ExitThread()
|
||||||
{
|
{
|
||||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||||
|
|
||||||
currentThread.Exit();
|
currentThread.Exit();
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0xb)]
|
[Svc(0xb)]
|
||||||
public void SleepThread(long timeout)
|
public void SleepThread(long timeout)
|
||||||
|
@ -2641,7 +2597,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0xc)]
|
[Svc(0xc)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetThreadPriority(out int priority, int handle)
|
public Result GetThreadPriority(out int priority, int handle)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2661,10 +2616,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidHandle;
|
return KernelResult.InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0xd)]
|
[Svc(0xd)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetThreadPriority(int handle, int priority)
|
public Result SetThreadPriority(int handle, int priority)
|
||||||
{
|
{
|
||||||
// TODO: NPDM check.
|
// TODO: NPDM check.
|
||||||
|
@ -2682,10 +2635,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0xe)]
|
[Svc(0xe)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
|
public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2707,10 +2658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidHandle;
|
return KernelResult.InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0xf)]
|
[Svc(0xf)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
|
public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
|
||||||
{
|
{
|
||||||
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2758,18 +2707,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
|
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x10)]
|
[Svc(0x10)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public int GetCurrentProcessorNumber()
|
public int GetCurrentProcessorNumber()
|
||||||
{
|
{
|
||||||
return KernelStatic.GetCurrentThread().CurrentCore;
|
return KernelStatic.GetCurrentThread().CurrentCore;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x25)]
|
[Svc(0x25)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetThreadId(out ulong threadUid, int handle)
|
public Result GetThreadId(out ulong threadUid, int handle)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2789,10 +2734,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidHandle;
|
return KernelResult.InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x32)]
|
[Svc(0x32)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SetThreadActivity(int handle, bool pause)
|
public Result SetThreadActivity(int handle, bool pause)
|
||||||
{
|
{
|
||||||
KProcess process = KernelStatic.GetCurrentProcess();
|
KProcess process = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2816,10 +2759,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return thread.SetActivity(pause);
|
return thread.SetActivity(pause);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x33)]
|
[Svc(0x33)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result GetThreadContext3([PointerSized] ulong address, int handle)
|
public Result GetThreadContext3([PointerSized] ulong address, int handle)
|
||||||
{
|
{
|
||||||
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -2853,7 +2794,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
// Thread synchronization
|
// Thread synchronization
|
||||||
|
|
||||||
|
@ -2986,7 +2926,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
[Svc(0x1a)]
|
[Svc(0x1a)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
|
public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
|
||||||
{
|
{
|
||||||
if (IsPointingInsideKernel(mutexAddress))
|
if (IsPointingInsideKernel(mutexAddress))
|
||||||
|
@ -3003,10 +2942,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x1b)]
|
[Svc(0x1b)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result ArbitrateUnlock([PointerSized] ulong mutexAddress)
|
public Result ArbitrateUnlock([PointerSized] ulong mutexAddress)
|
||||||
{
|
{
|
||||||
if (IsPointingInsideKernel(mutexAddress))
|
if (IsPointingInsideKernel(mutexAddress))
|
||||||
|
@ -3023,10 +2960,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
|
return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x1c)]
|
[Svc(0x1c)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result WaitProcessWideKeyAtomic(
|
public Result WaitProcessWideKeyAtomic(
|
||||||
[PointerSized] ulong mutexAddress,
|
[PointerSized] ulong mutexAddress,
|
||||||
[PointerSized] ulong condVarAddress,
|
[PointerSized] ulong condVarAddress,
|
||||||
|
@ -3056,10 +2991,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
handle,
|
handle,
|
||||||
timeout);
|
timeout);
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x1d)]
|
[Svc(0x1d)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SignalProcessWideKey([PointerSized] ulong address, int count)
|
public Result SignalProcessWideKey([PointerSized] ulong address, int count)
|
||||||
{
|
{
|
||||||
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
||||||
|
@ -3068,10 +3001,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x34)]
|
[Svc(0x34)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
|
public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
|
||||||
{
|
{
|
||||||
if (IsPointingInsideKernel(address))
|
if (IsPointingInsideKernel(address))
|
||||||
|
@ -3102,10 +3033,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
_ => KernelResult.InvalidEnumValue,
|
_ => KernelResult.InvalidEnumValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x35)]
|
[Svc(0x35)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
|
public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
|
||||||
{
|
{
|
||||||
if (IsPointingInsideKernel(address))
|
if (IsPointingInsideKernel(address))
|
||||||
|
@ -3131,17 +3060,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
_ => KernelResult.InvalidEnumValue,
|
_ => KernelResult.InvalidEnumValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
[Svc(0x36)]
|
[Svc(0x36)]
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public Result SynchronizePreemptionState()
|
public Result SynchronizePreemptionState()
|
||||||
{
|
{
|
||||||
KernelStatic.GetCurrentThread().SynchronizePreemptionState();
|
KernelStatic.GetCurrentThread().SynchronizePreemptionState();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
// Not actual syscalls, used by HLE services and such.
|
// Not actual syscalls, used by HLE services and such.
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,12 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public ServiceAccessControl ServiceAccessControl { get; private set; }
|
public ServiceAccessControl ServiceAccessControl { get; private set; }
|
||||||
public KernelAccessControl KernelAccessControl { get; private set; }
|
public KernelAccessControl KernelAccessControl { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="InvalidNpdmException">The stream doesn't contain valid ACI0 data.</exception>
|
||||||
|
/// <exception cref="System.ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="System.ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
|
/// <exception cref="System.NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
|
||||||
public Aci0(Stream stream, int offset)
|
public Aci0(Stream stream, int offset)
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
stream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -19,6 +19,11 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public ServiceAccessControl ServiceAccessControl { get; private set; }
|
public ServiceAccessControl ServiceAccessControl { get; private set; }
|
||||||
public KernelAccessControl KernelAccessControl { get; private set; }
|
public KernelAccessControl KernelAccessControl { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="InvalidNpdmException">The stream doesn't contain valid ACID data.</exception>
|
||||||
|
/// <exception cref="System.ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="System.ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
public Acid(Stream stream, int offset)
|
public Acid(Stream stream, int offset)
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
stream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -11,6 +11,10 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public int Unknown3 { get; private set; }
|
public int Unknown3 { get; private set; }
|
||||||
public int Unknown4 { get; private set; }
|
public int Unknown4 { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="System.ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="System.ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
public FsAccessControl(Stream stream, int offset, int size)
|
public FsAccessControl(Stream stream, int offset, int size)
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
stream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -9,6 +9,12 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public int Version { get; private set; }
|
public int Version { get; private set; }
|
||||||
public ulong PermissionsBitmask { get; private set; }
|
public ulong PermissionsBitmask { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="InvalidNpdmException">The stream contains invalid data.</exception>
|
||||||
|
/// <exception cref="NotImplementedException">The ContentOwnerId section is not implemented.</exception>
|
||||||
|
/// <exception cref="ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
public FsAccessHeader(Stream stream, int offset, int size)
|
public FsAccessHeader(Stream stream, int offset, int size)
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
stream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -6,6 +6,10 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
{
|
{
|
||||||
public int[] Capabilities { get; private set; }
|
public int[] Capabilities { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="System.ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="System.ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
public KernelAccessControl(Stream stream, int offset, int size)
|
public KernelAccessControl(Stream stream, int offset, int size)
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
stream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -24,6 +24,13 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public Aci0 Aci0 { get; private set; }
|
public Aci0 Aci0 { get; private set; }
|
||||||
public Acid Acid { get; private set; }
|
public Acid Acid { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="InvalidNpdmException">The stream doesn't contain valid NPDM data.</exception>
|
||||||
|
/// <exception cref="System.NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
|
||||||
|
/// <exception cref="System.ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="System.ArgumentException">An error occured while reading bytes from the stream.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="System.ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
public Npdm(Stream stream)
|
public Npdm(Stream stream)
|
||||||
{
|
{
|
||||||
BinaryReader reader = new(stream);
|
BinaryReader reader = new(stream);
|
||||||
|
|
|
@ -9,6 +9,11 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
{
|
{
|
||||||
public IReadOnlyDictionary<string, bool> Services { get; private set; }
|
public IReadOnlyDictionary<string, bool> Services { get; private set; }
|
||||||
|
|
||||||
|
/// <exception cref="System.ArgumentException">The stream does not support reading, is <see langword="null"/>, or is already closed.</exception>
|
||||||
|
/// <exception cref="System.ArgumentException">An error occured while reading bytes from the stream.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="System.ObjectDisposedException">The stream is closed.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
public ServiceAccessControl(Stream stream, int offset, int size)
|
public ServiceAccessControl(Stream stream, int offset, int size)
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
stream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -139,7 +139,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||||
ulong titleIdBase = mainNca.GetProgramIdBase();
|
ulong titleIdBase = mainNca.GetProgramIdBase();
|
||||||
|
|
||||||
// Load update information if exists.
|
// Load update information if exists.
|
||||||
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "updates.json");
|
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
|
||||||
if (File.Exists(titleUpdateMetadataPath))
|
if (File.Exists(titleUpdateMetadataPath))
|
||||||
{
|
{
|
||||||
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected;
|
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected;
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||||
device.Configuration.ContentManager.ClearAocData();
|
device.Configuration.ContentManager.ClearAocData();
|
||||||
|
|
||||||
// Load DownloadableContents.
|
// Load DownloadableContents.
|
||||||
string addOnContentMetadataPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json");
|
string addOnContentMetadataPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, mainNca.GetProgramIdBase().ToString("x16"), "dlc.json");
|
||||||
if (File.Exists(addOnContentMetadataPath))
|
if (File.Exists(addOnContentMetadataPath))
|
||||||
{
|
{
|
||||||
List<DownloadableContentContainer> dlcContainerList = JsonHelper.DeserializeFromFile(addOnContentMetadataPath, _contentSerializerContext.ListDownloadableContentContainer);
|
List<DownloadableContentContainer> dlcContainerList = JsonHelper.DeserializeFromFile(addOnContentMetadataPath, _contentSerializerContext.ListDownloadableContentContainer);
|
||||||
|
|
|
@ -26,7 +26,11 @@ namespace Ryujinx.Horizon.Ngc.Ipc
|
||||||
}
|
}
|
||||||
|
|
||||||
[CmifCommand(1)]
|
[CmifCommand(1)]
|
||||||
public Result Check(out uint checkMask, ReadOnlySpan<byte> text, uint regionMask, ProfanityFilterOption option)
|
public Result Check(
|
||||||
|
out uint checkMask,
|
||||||
|
[Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> text,
|
||||||
|
uint regionMask,
|
||||||
|
ProfanityFilterOption option)
|
||||||
{
|
{
|
||||||
lock (_profanityFilter)
|
lock (_profanityFilter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
|
||||||
|
|
||||||
public long CurrentTime { get; private set; }
|
public long CurrentTime { get; private set; }
|
||||||
|
|
||||||
|
public IEnumerable<MultiWaitHolderBase> MultiWaits => _multiWaits;
|
||||||
|
|
||||||
public MultiWaitImpl()
|
public MultiWaitImpl()
|
||||||
{
|
{
|
||||||
_multiWaits = new List<MultiWaitHolderBase>();
|
_multiWaits = new List<MultiWaitHolderBase>();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Horizon.Sdk.OsTypes.Impl;
|
using Ryujinx.Horizon.Sdk.OsTypes.Impl;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.Sdk.OsTypes
|
namespace Ryujinx.Horizon.Sdk.OsTypes
|
||||||
{
|
{
|
||||||
|
@ -6,6 +7,8 @@ namespace Ryujinx.Horizon.Sdk.OsTypes
|
||||||
{
|
{
|
||||||
private readonly MultiWaitImpl _impl;
|
private readonly MultiWaitImpl _impl;
|
||||||
|
|
||||||
|
public IEnumerable<MultiWaitHolderBase> MultiWaits => _impl.MultiWaits;
|
||||||
|
|
||||||
public MultiWait()
|
public MultiWait()
|
||||||
{
|
{
|
||||||
_impl = new MultiWaitImpl();
|
_impl = new MultiWaitImpl();
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Horizon.Sdk.OsTypes;
|
||||||
using Ryujinx.Horizon.Sdk.Sf.Cmif;
|
using Ryujinx.Horizon.Sdk.Sf.Cmif;
|
||||||
using Ryujinx.Horizon.Sdk.Sm;
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
||||||
{
|
{
|
||||||
|
@ -116,6 +117,18 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
||||||
while (WaitAndProcessRequestsImpl())
|
while (WaitAndProcessRequestsImpl())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unlink pending sessions, dispose expects them to be already unlinked.
|
||||||
|
|
||||||
|
ServerSession[] serverSessions = Enumerable.OfType<ServerSession>(_multiWait.MultiWaits).ToArray();
|
||||||
|
|
||||||
|
foreach (ServerSession serverSession in serverSessions)
|
||||||
|
{
|
||||||
|
if (serverSession.IsLinked)
|
||||||
|
{
|
||||||
|
serverSession.UnlinkFromMultiWaitHolder();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitAndProcessRequests()
|
public void WaitAndProcessRequests()
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace Ryujinx.UI.App.Common
|
||||||
|
|
||||||
[JsonIgnore] public ulong IdBase => Id & ~0x1FFFUL;
|
[JsonIgnore] public ulong IdBase => Id & ~0x1FFFUL;
|
||||||
|
|
||||||
|
[JsonIgnore] public string IdBaseString => IdBase.ToString("x16");
|
||||||
|
|
||||||
public static string GetBuildId(VirtualFileSystem virtualFileSystem, IntegrityCheckLevel checkLevel, string titleFilePath)
|
public static string GetBuildId(VirtualFileSystem virtualFileSystem, IntegrityCheckLevel checkLevel, string titleFilePath)
|
||||||
{
|
{
|
||||||
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
|
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
|
||||||
|
|
|
@ -72,37 +72,43 @@ namespace Ryujinx.UI.App.Common
|
||||||
return resourceByteArray;
|
return resourceByteArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception>
|
||||||
|
/// <exception cref="NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
|
||||||
|
/// <exception cref="ArgumentException">An error occured while reading bytes from the stream.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
private ApplicationData GetApplicationFromExeFs(PartitionFileSystem pfs, string filePath)
|
private ApplicationData GetApplicationFromExeFs(PartitionFileSystem pfs, string filePath)
|
||||||
{
|
{
|
||||||
ApplicationData data = new()
|
ApplicationData data = new()
|
||||||
{
|
{
|
||||||
Icon = _nspIcon,
|
Icon = _nspIcon,
|
||||||
|
Path = filePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
using UniqueRef<IFile> npdmFile = new();
|
using UniqueRef<IFile> npdmFile = new();
|
||||||
|
|
||||||
try
|
Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
|
||||||
|
|
||||||
|
if (ResultFs.PathNotFound.Includes(result))
|
||||||
{
|
{
|
||||||
Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
|
Npdm npdm = new(npdmFile.Get.AsStream());
|
||||||
|
|
||||||
if (ResultFs.PathNotFound.Includes(result))
|
data.Name = npdm.TitleName;
|
||||||
{
|
data.Id = npdm.Aci0.TitleId;
|
||||||
Npdm npdm = new(npdmFile.Get.AsStream());
|
|
||||||
|
|
||||||
data.Name = npdm.TitleName;
|
|
||||||
data.Id = npdm.Aci0.TitleId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{filePath}' Error: {exception.Message}");
|
|
||||||
|
|
||||||
return null;
|
return data;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <exception cref="MissingKeyException">The configured key set is missing a key.</exception>
|
||||||
|
/// <exception cref="InvalidDataException">The NCA header could not be decrypted.</exception>
|
||||||
|
/// <exception cref="NotSupportedException">The NCA version is not supported.</exception>
|
||||||
|
/// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception>
|
||||||
|
/// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception>
|
||||||
|
/// <exception cref="NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
|
||||||
|
/// <exception cref="ArgumentException">An error occured while reading bytes from the stream.</exception>
|
||||||
|
/// <exception cref="EndOfStreamException">The end of the stream is reached.</exception>
|
||||||
|
/// <exception cref="IOException">An I/O error occurred.</exception>
|
||||||
private ApplicationData GetApplicationFromNsp(PartitionFileSystem pfs, string filePath)
|
private ApplicationData GetApplicationFromNsp(PartitionFileSystem pfs, string filePath)
|
||||||
{
|
{
|
||||||
bool isExeFs = false;
|
bool isExeFs = false;
|
||||||
|
@ -170,99 +176,88 @@ namespace Ryujinx.UI.App.Common
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <exception cref="MissingKeyException">The configured key set is missing a key.</exception>
|
||||||
|
/// <exception cref="InvalidDataException">The NCA header could not be decrypted.</exception>
|
||||||
|
/// <exception cref="NotSupportedException">The NCA version is not supported.</exception>
|
||||||
|
/// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception>
|
||||||
private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath)
|
private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath)
|
||||||
{
|
{
|
||||||
var applications = new List<ApplicationData>();
|
var applications = new List<ApplicationData>();
|
||||||
string extension = Path.GetExtension(filePath).ToLower();
|
string extension = Path.GetExtension(filePath).ToLower();
|
||||||
|
|
||||||
try
|
foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel))
|
||||||
{
|
{
|
||||||
foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel))
|
ApplicationData applicationData = new()
|
||||||
{
|
{
|
||||||
ApplicationData applicationData = new()
|
Id = titleId,
|
||||||
|
Path = filePath,
|
||||||
|
};
|
||||||
|
|
||||||
|
Nca mainNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program);
|
||||||
|
Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control);
|
||||||
|
|
||||||
|
BlitStruct<ApplicationControlProperty> controlHolder = new(1);
|
||||||
|
|
||||||
|
IFileSystem controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, _checkLevel);
|
||||||
|
|
||||||
|
// Check if there is an update available.
|
||||||
|
if (IsUpdateApplied(mainNca, out IFileSystem updatedControlFs))
|
||||||
|
{
|
||||||
|
// Replace the original ControlFs by the updated one.
|
||||||
|
controlFs = updatedControlFs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controlFs == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadControlData(controlFs, controlHolder.ByteSpan);
|
||||||
|
|
||||||
|
GetApplicationInformation(ref controlHolder.Value, ref applicationData);
|
||||||
|
|
||||||
|
// Read the icon from the ControlFS and store it as a byte array
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using UniqueRef<IFile> icon = new();
|
||||||
|
|
||||||
|
controlFs.OpenFile(ref icon.Ref, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
|
using MemoryStream stream = new();
|
||||||
|
|
||||||
|
icon.Get.AsStream().CopyTo(stream);
|
||||||
|
applicationData.Icon = stream.ToArray();
|
||||||
|
}
|
||||||
|
catch (HorizonResultException)
|
||||||
|
{
|
||||||
|
foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
|
||||||
{
|
{
|
||||||
Id = titleId,
|
if (entry.Name == "control.nacp")
|
||||||
Path = filePath,
|
{
|
||||||
};
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Nca mainNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program);
|
using var icon = new UniqueRef<IFile>();
|
||||||
Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control);
|
|
||||||
|
|
||||||
BlitStruct<ApplicationControlProperty> controlHolder = new(1);
|
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
IFileSystem controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, _checkLevel);
|
|
||||||
|
|
||||||
// Check if there is an update available.
|
|
||||||
if (IsUpdateApplied(mainNca, out IFileSystem updatedControlFs))
|
|
||||||
{
|
|
||||||
// Replace the original ControlFs by the updated one.
|
|
||||||
controlFs = updatedControlFs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controlFs == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadControlData(controlFs, controlHolder.ByteSpan);
|
|
||||||
|
|
||||||
GetApplicationInformation(ref controlHolder.Value, ref applicationData);
|
|
||||||
|
|
||||||
// Read the icon from the ControlFS and store it as a byte array
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using UniqueRef<IFile> icon = new();
|
|
||||||
|
|
||||||
controlFs.OpenFile(ref icon.Ref, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
|
||||||
|
|
||||||
using MemoryStream stream = new();
|
using MemoryStream stream = new();
|
||||||
|
|
||||||
icon.Get.AsStream().CopyTo(stream);
|
icon.Get.AsStream().CopyTo(stream);
|
||||||
applicationData.Icon = stream.ToArray();
|
applicationData.Icon = stream.ToArray();
|
||||||
}
|
|
||||||
catch (HorizonResultException)
|
if (applicationData.Icon != null)
|
||||||
{
|
|
||||||
foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
|
|
||||||
{
|
{
|
||||||
if (entry.Name == "control.nacp")
|
break;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var icon = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
|
||||||
|
|
||||||
using MemoryStream stream = new();
|
|
||||||
|
|
||||||
icon.Get.AsStream().CopyTo(stream);
|
|
||||||
applicationData.Icon = stream.ToArray();
|
|
||||||
|
|
||||||
if (applicationData.Icon != null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationData.ControlHolder = controlHolder;
|
applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon;
|
||||||
|
|
||||||
applications.Add(applicationData);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (MissingKeyException exception)
|
applicationData.ControlHolder = controlHolder;
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
|
applications.Add(applicationData);
|
||||||
}
|
|
||||||
catch (InvalidDataException)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {filePath}");
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{filePath}' Error: {exception}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return applications;
|
return applications;
|
||||||
|
@ -319,52 +314,43 @@ namespace Ryujinx.UI.App.Common
|
||||||
BinaryReader reader = new(file);
|
BinaryReader reader = new(file);
|
||||||
ApplicationData application = new();
|
ApplicationData application = new();
|
||||||
|
|
||||||
try
|
file.Seek(24, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
int assetOffset = reader.ReadInt32();
|
||||||
|
|
||||||
|
if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
|
||||||
{
|
{
|
||||||
file.Seek(24, SeekOrigin.Begin);
|
byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);
|
||||||
|
|
||||||
int assetOffset = reader.ReadInt32();
|
long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
|
||||||
|
long iconSize = BitConverter.ToInt64(iconSectionInfo, 8);
|
||||||
|
|
||||||
if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
|
ulong nacpOffset = reader.ReadUInt64();
|
||||||
|
ulong nacpSize = reader.ReadUInt64();
|
||||||
|
|
||||||
|
// Reads and stores game icon as byte array
|
||||||
|
if (iconSize > 0)
|
||||||
{
|
{
|
||||||
byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);
|
application.Icon = Read(assetOffset + iconOffset, (int)iconSize);
|
||||||
|
|
||||||
long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
|
|
||||||
long iconSize = BitConverter.ToInt64(iconSectionInfo, 8);
|
|
||||||
|
|
||||||
ulong nacpOffset = reader.ReadUInt64();
|
|
||||||
ulong nacpSize = reader.ReadUInt64();
|
|
||||||
|
|
||||||
// Reads and stores game icon as byte array
|
|
||||||
if (iconSize > 0)
|
|
||||||
{
|
|
||||||
application.Icon = Read(assetOffset + iconOffset, (int)iconSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
application.Icon = _nroIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the NACP data
|
|
||||||
Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);
|
|
||||||
|
|
||||||
GetApplicationInformation(ref controlHolder.Value, ref application);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
application.Icon = _nroIcon;
|
application.Icon = _nroIcon;
|
||||||
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
application.ControlHolder = controlHolder;
|
// Read the NACP data
|
||||||
applications.Add(application);
|
Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");
|
|
||||||
|
|
||||||
return false;
|
GetApplicationInformation(ref controlHolder.Value, ref application);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
application.Icon = _nroIcon;
|
||||||
|
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
application.ControlHolder = controlHolder;
|
||||||
|
applications.Add(application);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -377,34 +363,21 @@ namespace Ryujinx.UI.App.Common
|
||||||
}
|
}
|
||||||
case ".nca":
|
case ".nca":
|
||||||
{
|
{
|
||||||
try
|
ApplicationData application = new();
|
||||||
|
|
||||||
|
Nca nca = new(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
|
||||||
|
|
||||||
|
if (!nca.IsProgram() || nca.IsPatch())
|
||||||
{
|
{
|
||||||
ApplicationData application = new();
|
|
||||||
|
|
||||||
Nca nca = new(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
|
|
||||||
|
|
||||||
if (!nca.IsProgram() || nca.IsPatch())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
application.Icon = _ncaIcon;
|
|
||||||
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
|
|
||||||
application.ControlHolder = controlHolder;
|
|
||||||
|
|
||||||
applications.Add(application);
|
|
||||||
}
|
|
||||||
catch (InvalidDataException)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
application.Icon = _ncaIcon;
|
||||||
|
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
|
||||||
|
application.ControlHolder = controlHolder;
|
||||||
|
|
||||||
|
applications.Add(application);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// If its an NSO we just set defaults
|
// If its an NSO we just set defaults
|
||||||
|
@ -417,16 +390,35 @@ namespace Ryujinx.UI.App.Common
|
||||||
};
|
};
|
||||||
|
|
||||||
applications.Add(application);
|
applications.Add(application);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (MissingKeyException exception)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (InvalidDataException)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
catch (IOException exception)
|
catch (IOException exception)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, exception.Message);
|
Logger.Warning?.Print(LogClass.Application, exception.Message);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var data in applications)
|
foreach (var data in applications)
|
||||||
{
|
{
|
||||||
|
|
|
@ -367,32 +367,24 @@ namespace Ryujinx.Ava
|
||||||
}
|
}
|
||||||
|
|
||||||
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
||||||
using var bitmap = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
|
using SKBitmap bitmap = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
|
||||||
|
|
||||||
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
|
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
|
||||||
|
|
||||||
SKBitmap bitmapToSave = null;
|
using SKBitmap bitmapToSave = new SKBitmap(bitmap.Width, bitmap.Height);
|
||||||
|
using SKCanvas canvas = new SKCanvas(bitmapToSave);
|
||||||
|
|
||||||
if (e.FlipX || e.FlipY)
|
canvas.Clear(SKColors.Black);
|
||||||
{
|
|
||||||
bitmapToSave = new SKBitmap(bitmap.Width, bitmap.Height);
|
|
||||||
|
|
||||||
using var canvas = new SKCanvas(bitmapToSave);
|
float scaleX = e.FlipX ? -1 : 1;
|
||||||
|
float scaleY = e.FlipY ? -1 : 1;
|
||||||
|
|
||||||
canvas.Clear(SKColors.Transparent);
|
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
|
||||||
|
|
||||||
float scaleX = e.FlipX ? -1 : 1;
|
canvas.SetMatrix(matrix);
|
||||||
float scaleY = e.FlipY ? -1 : 1;
|
canvas.DrawBitmap(bitmap, SKPoint.Empty);
|
||||||
|
|
||||||
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
|
SaveBitmapAsPng(bitmapToSave, path);
|
||||||
|
|
||||||
canvas.SetMatrix(matrix);
|
|
||||||
|
|
||||||
canvas.DrawBitmap(bitmap, new SKPoint(e.FlipX ? -bitmap.Width : 0, e.FlipY ? -bitmap.Height : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveBitmapAsPng(bitmapToSave ?? bitmap, path);
|
|
||||||
bitmapToSave?.Dispose();
|
|
||||||
|
|
||||||
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot");
|
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot");
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
_storageProvider = desktop.MainWindow.StorageProvider;
|
_storageProvider = desktop.MainWindow.StorageProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationData.IdString, "dlc.json");
|
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationData.IdBaseString, "dlc.json");
|
||||||
|
|
||||||
if (!File.Exists(_downloadableContentJsonPath))
|
if (!File.Exists(_downloadableContentJsonPath))
|
||||||
{
|
{
|
||||||
|
@ -263,7 +263,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
var content = new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true);
|
var content = new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true);
|
||||||
DownloadableContents.Add(content);
|
DownloadableContents.Add(content);
|
||||||
SelectedDownloadableContents.Add(content);
|
Dispatcher.UIThread.InvokeAsync(() => SelectedDownloadableContents.Add(content));
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
StorageProvider = desktop.MainWindow.StorageProvider;
|
StorageProvider = desktop.MainWindow.StorageProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, ApplicationData.IdString, "updates.json");
|
TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, ApplicationData.IdBaseString, "updates.json");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -96,7 +96,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {ApplicationData.IdString} at {TitleUpdateJsonPath}");
|
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {ApplicationData.IdBaseString} at {TitleUpdateJsonPath}");
|
||||||
|
|
||||||
TitleUpdateWindowData = new TitleUpdateMetadata
|
TitleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddUpdate(string path, bool ignoreNotFound = false)
|
private void AddUpdate(string path, bool ignoreNotFound = false, bool selected = false)
|
||||||
{
|
{
|
||||||
if (!File.Exists(path) || TitleUpdates.Any(x => x.Path == path))
|
if (!File.Exists(path) || TitleUpdates.Any(x => x.Path == path))
|
||||||
{
|
{
|
||||||
|
@ -204,7 +204,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
var update = new TitleUpdateModel(controlData, path);
|
||||||
|
TitleUpdates.Add(update);
|
||||||
|
|
||||||
|
if (selected)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.InvokeAsync(() => SelectedUpdate = update);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -245,7 +251,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
foreach (var file in result)
|
foreach (var file in result)
|
||||||
{
|
{
|
||||||
AddUpdate(file.Path.LocalPath);
|
AddUpdate(file.Path.LocalPath, selected: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SortUpdates();
|
SortUpdates();
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
SecondaryButtonText = "",
|
SecondaryButtonText = "",
|
||||||
CloseButtonText = "",
|
CloseButtonText = "",
|
||||||
Content = new DownloadableContentManagerWindow(virtualFileSystem, applicationData),
|
Content = new DownloadableContentManagerWindow(virtualFileSystem, applicationData),
|
||||||
Title = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowTitle], applicationData.Name, applicationData.IdString),
|
Title = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowTitle], applicationData.Name, applicationData.IdBaseString),
|
||||||
};
|
};
|
||||||
|
|
||||||
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
SecondaryButtonText = "",
|
SecondaryButtonText = "",
|
||||||
CloseButtonText = "",
|
CloseButtonText = "",
|
||||||
Content = new TitleUpdateWindow(virtualFileSystem, applicationData),
|
Content = new TitleUpdateWindow(virtualFileSystem, applicationData),
|
||||||
Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, applicationData.Name, applicationData.IdString),
|
Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, applicationData.Name, applicationData.IdBaseString),
|
||||||
};
|
};
|
||||||
|
|
||||||
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
||||||
|
|
Loading…
Reference in a new issue