2021-08-12 23:56:24 +02:00
|
|
|
|
using LibHac;
|
|
|
|
|
using LibHac.Bcat;
|
2021-08-20 22:36:14 +02:00
|
|
|
|
using LibHac.Common;
|
|
|
|
|
using LibHac.Fs.Fsa;
|
|
|
|
|
using LibHac.Fs.Shim;
|
2021-08-12 23:56:24 +02:00
|
|
|
|
using LibHac.FsSrv.Impl;
|
|
|
|
|
using LibHac.Loader;
|
|
|
|
|
using LibHac.Ncm;
|
|
|
|
|
using Ryujinx.HLE.FileSystem;
|
|
|
|
|
using Ryujinx.HLE.HOS.Services.Arp;
|
|
|
|
|
using System;
|
|
|
|
|
using StorageId = LibHac.Ncm.StorageId;
|
|
|
|
|
|
|
|
|
|
namespace Ryujinx.HLE.HOS
|
|
|
|
|
{
|
|
|
|
|
public class LibHacHorizonManager
|
|
|
|
|
{
|
|
|
|
|
private LibHac.Horizon Server { get; set; }
|
|
|
|
|
|
2021-09-15 01:24:49 +02:00
|
|
|
|
public HorizonClient RyujinxClient { get; private set; }
|
2021-08-12 23:56:24 +02:00
|
|
|
|
public HorizonClient ApplicationClient { get; private set; }
|
2021-09-15 01:24:49 +02:00
|
|
|
|
public HorizonClient AccountClient { get; private set; }
|
|
|
|
|
public HorizonClient AmClient { get; private set; }
|
|
|
|
|
public HorizonClient BcatClient { get; private set; }
|
|
|
|
|
public HorizonClient FsClient { get; private set; }
|
|
|
|
|
public HorizonClient NsClient { get; private set; }
|
|
|
|
|
public HorizonClient SdbClient { get; private set; }
|
2021-08-12 23:56:24 +02:00
|
|
|
|
|
2021-12-23 17:55:50 +01:00
|
|
|
|
private SharedRef<LibHacIReader> _arpIReader;
|
|
|
|
|
internal LibHacIReader ArpIReader => _arpIReader.Get;
|
2021-08-12 23:56:24 +02:00
|
|
|
|
|
|
|
|
|
public LibHacHorizonManager()
|
|
|
|
|
{
|
|
|
|
|
InitializeServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void InitializeServer()
|
|
|
|
|
{
|
|
|
|
|
Server = new LibHac.Horizon(new HorizonConfiguration());
|
|
|
|
|
|
|
|
|
|
RyujinxClient = Server.CreatePrivilegedHorizonClient();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitializeArpServer()
|
|
|
|
|
{
|
2021-12-23 17:55:50 +01:00
|
|
|
|
_arpIReader.Reset(new LibHacIReader());
|
|
|
|
|
RyujinxClient.Sm.RegisterService(new LibHacArpServiceObject(ref _arpIReader), "arp:r").ThrowIfFailure();
|
2021-08-12 23:56:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitializeBcatServer()
|
|
|
|
|
{
|
2021-09-15 01:24:49 +02:00
|
|
|
|
BcatClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Bcat, StorageId.BuiltInSystem), BcatFsPermissions);
|
2021-08-12 23:56:24 +02:00
|
|
|
|
|
|
|
|
|
_ = new BcatServer(BcatClient);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitializeFsServer(VirtualFileSystem virtualFileSystem)
|
|
|
|
|
{
|
|
|
|
|
virtualFileSystem.InitializeFsServer(Server, out var fsClient);
|
|
|
|
|
|
|
|
|
|
FsClient = fsClient;
|
2021-08-20 22:36:14 +02:00
|
|
|
|
|
|
|
|
|
CleanSdCardDirectory();
|
2021-08-12 23:56:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitializeSystemClients()
|
|
|
|
|
{
|
2021-09-15 01:24:49 +02:00
|
|
|
|
AccountClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Account, StorageId.BuiltInSystem), AccountFsPermissions);
|
|
|
|
|
AmClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Am, StorageId.BuiltInSystem), AmFsPermissions);
|
|
|
|
|
NsClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Ns, StorageId.BuiltInSystem), NsFsPermissions);
|
|
|
|
|
SdbClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Sdb, StorageId.BuiltInSystem), SdbFacData, SdbFacDescriptor);
|
2021-08-12 23:56:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitializeApplicationClient(ProgramId programId, in Npdm npdm)
|
|
|
|
|
{
|
2021-09-15 01:24:49 +02:00
|
|
|
|
ApplicationClient = Server.CreateHorizonClient(new ProgramLocation(programId, StorageId.BuiltInUser), npdm.FsAccessControlData, npdm.FsAccessControlDescriptor);
|
2021-08-12 23:56:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-20 22:36:14 +02:00
|
|
|
|
// This function was added to avoid errors that come from a user's keys or SD encryption seed changing.
|
|
|
|
|
// Catching these errors and recreating the file ended up not working because of the different ways
|
|
|
|
|
// applications respond to a file suddenly containing all zeros or having a length of zero.
|
|
|
|
|
// Clearing the SD card save directory was determined to be the best option for the moment since
|
|
|
|
|
// the saves on the SD card are meant as caches that can be deleted at any time.
|
|
|
|
|
private void CleanSdCardDirectory()
|
|
|
|
|
{
|
|
|
|
|
Result rc = RyujinxClient.Fs.MountSdCard("sdcard".ToU8Span());
|
|
|
|
|
if (rc.IsFailure()) return;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2021-08-26 23:18:49 +02:00
|
|
|
|
RyujinxClient.Fs.CleanDirectoryRecursively("sdcard:/Nintendo/save".ToU8Span()).IgnoreResult();
|
|
|
|
|
RyujinxClient.Fs.DeleteDirectoryRecursively("sdcard:/save".ToU8Span()).IgnoreResult();
|
2021-08-20 22:36:14 +02:00
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
RyujinxClient.Fs.Unmount("sdcard".ToU8Span());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-12 23:56:24 +02:00
|
|
|
|
private static AccessControlBits.Bits AccountFsPermissions => AccessControlBits.Bits.SystemSaveData |
|
|
|
|
|
AccessControlBits.Bits.GameCard |
|
|
|
|
|
AccessControlBits.Bits.SaveDataMeta |
|
|
|
|
|
AccessControlBits.Bits.GetRightsId;
|
|
|
|
|
|
|
|
|
|
private static AccessControlBits.Bits AmFsPermissions => AccessControlBits.Bits.SaveDataManagement |
|
|
|
|
|
AccessControlBits.Bits.CreateSaveData |
|
|
|
|
|
AccessControlBits.Bits.SystemData;
|
|
|
|
|
private static AccessControlBits.Bits BcatFsPermissions => AccessControlBits.Bits.SystemSaveData;
|
|
|
|
|
|
|
|
|
|
private static AccessControlBits.Bits NsFsPermissions => AccessControlBits.Bits.ApplicationInfo |
|
|
|
|
|
AccessControlBits.Bits.SystemSaveData |
|
|
|
|
|
AccessControlBits.Bits.GameCard |
|
|
|
|
|
AccessControlBits.Bits.SaveDataManagement |
|
|
|
|
|
AccessControlBits.Bits.ContentManager |
|
|
|
|
|
AccessControlBits.Bits.ImageManager |
|
|
|
|
|
AccessControlBits.Bits.SystemSaveDataManagement |
|
|
|
|
|
AccessControlBits.Bits.SystemUpdate |
|
|
|
|
|
AccessControlBits.Bits.SdCard |
|
|
|
|
|
AccessControlBits.Bits.FormatSdCard |
|
|
|
|
|
AccessControlBits.Bits.GetRightsId |
|
|
|
|
|
AccessControlBits.Bits.RegisterProgramIndexMapInfo |
|
|
|
|
|
AccessControlBits.Bits.MoveCacheStorage;
|
|
|
|
|
|
|
|
|
|
// Sdb has save data access control info so we can't store just its access control bits
|
|
|
|
|
private static ReadOnlySpan<byte> SdbFacData => new byte[]
|
|
|
|
|
{
|
|
|
|
|
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
|
|
|
0x03, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x10, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x01
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private static ReadOnlySpan<byte> SdbFacDescriptor => new byte[]
|
|
|
|
|
{
|
|
|
|
|
0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x01, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
|
|
|
|
};
|
|
|
|
|
}
|
2021-09-15 01:24:49 +02:00
|
|
|
|
}
|