Merge branch 'master' into MoreDynamicStatesPartOne

This commit is contained in:
sunshineinabox 2024-07-23 20:59:44 -07:00 committed by GitHub
commit 34ac6f33ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 347 additions and 354 deletions

View file

@ -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)

View file

@ -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;
} }

View file

@ -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);

View file

@ -1,10 +0,0 @@
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
enum AddressSpaceType
{
Addr32Bits = 0,
Addr36Bits = 1,
Addr32BitsNoMap = 2,
Addr39Bits = 3,
}
}

View file

@ -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;
} }

View file

@ -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);
}
} }
} }

View file

@ -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;
}
} }
} }

View file

@ -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,
} }
} }

View file

@ -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,
} }
} }

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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)
{ {

View file

@ -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>();

View file

@ -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();

View file

@ -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()

View file

@ -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);

View file

@ -72,17 +72,21 @@ 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); Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
if (ResultFs.PathNotFound.Includes(result)) if (ResultFs.PathNotFound.Includes(result))
@ -95,14 +99,16 @@ namespace Ryujinx.UI.App.Common
return data; 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;
}
}
/// <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,13 +176,15 @@ 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()
@ -251,19 +259,6 @@ namespace Ryujinx.UI.App.Common
applications.Add(applicationData); applications.Add(applicationData);
} }
}
catch (MissingKeyException exception)
{
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
}
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,8 +314,6 @@ 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); file.Seek(24, SeekOrigin.Begin);
int assetOffset = reader.ReadInt32(); int assetOffset = reader.ReadInt32();
@ -358,13 +351,6 @@ namespace Ryujinx.UI.App.Common
application.ControlHolder = controlHolder; application.ControlHolder = controlHolder;
applications.Add(application); applications.Add(application);
}
catch
{
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");
return false;
}
break; break;
@ -376,8 +362,6 @@ namespace Ryujinx.UI.App.Common
} }
} }
case ".nca": case ".nca":
{
try
{ {
ApplicationData application = new(); ApplicationData application = new();
@ -393,17 +377,6 @@ namespace Ryujinx.UI.App.Common
application.ControlHolder = controlHolder; application.ControlHolder = controlHolder;
applications.Add(application); 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;
}
break; break;
} }
@ -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)
{ {

View file

@ -367,19 +367,14 @@ 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);
canvas.Clear(SKColors.Transparent);
float scaleX = e.FlipX ? -1 : 1; float scaleX = e.FlipX ? -1 : 1;
float scaleY = e.FlipY ? -1 : 1; float scaleY = e.FlipY ? -1 : 1;
@ -387,12 +382,9 @@ namespace Ryujinx.Ava
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f); var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
canvas.SetMatrix(matrix); canvas.SetMatrix(matrix);
canvas.DrawBitmap(bitmap, SKPoint.Empty);
canvas.DrawBitmap(bitmap, new SKPoint(e.FlipX ? -bitmap.Width : 0, e.FlipY ? -bitmap.Height : 0)); SaveBitmapAsPng(bitmapToSave, path);
}
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");
} }

View file

@ -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;
} }

View file

@ -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();

View file

@ -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>());

View file

@ -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>());