mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Begin implementing StorageDeviceManagerFactory and GameCardManager
This commit is contained in:
parent
dfd37d314f
commit
43d63086bf
@ -310,8 +310,8 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
|||||||
2,2955,,,,GameCardFsCheckHandleInGetDeviceCertFailure,
|
2,2955,,,,GameCardFsCheckHandleInGetDeviceCertFailure,
|
||||||
2,2956,,,,GameCardFsCheckHandleInGetCardImageHashFailure,
|
2,2956,,,,GameCardFsCheckHandleInGetCardImageHashFailure,
|
||||||
2,2957,,,,GameCardFsCheckHandleInChallengeCardExistence,
|
2,2957,,,,GameCardFsCheckHandleInChallengeCardExistence,
|
||||||
2,2958,,,,GameCardFsCheckHandleInOnAcquireLock,
|
2,2958,,,,GameCardFsCheckHandleInAcquireReadLock,
|
||||||
2,2959,,,,GameCardFsCheckModeInOnAcquireSecureLock,
|
2,2959,,,,GameCardFsCheckModeInAcquireSecureLock,
|
||||||
2,2960,,,,GameCardFsCheckHandleInCreateReadOnlyFailure,
|
2,2960,,,,GameCardFsCheckHandleInCreateReadOnlyFailure,
|
||||||
2,2961,,,,GameCardFsCheckHandleInCreateSecureReadOnlyFailure,
|
2,2961,,,,GameCardFsCheckHandleInCreateSecureReadOnlyFailure,
|
||||||
2,2962,,,,GameCardFsInvalidCompatibilityType,
|
2,2962,,,,GameCardFsInvalidCompatibilityType,
|
||||||
|
|
@ -45,6 +45,12 @@ public enum GameCardSizeInternal : byte
|
|||||||
Size32Gb = 0xE2
|
Size32Gb = 0xE2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum GameCardClockRate
|
||||||
|
{
|
||||||
|
ClockRate25 = 25,
|
||||||
|
ClockRate50 = 50
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum GameCardAttribute : byte
|
public enum GameCardAttribute : byte
|
||||||
{
|
{
|
||||||
|
@ -518,9 +518,9 @@ public static class ResultFs
|
|||||||
/// <summary>Error code: 2002-2957; Inner value: 0x171a02</summary>
|
/// <summary>Error code: 2002-2957; Inner value: 0x171a02</summary>
|
||||||
public static Result.Base GameCardFsCheckHandleInChallengeCardExistence => new Result.Base(ModuleFs, 2957);
|
public static Result.Base GameCardFsCheckHandleInChallengeCardExistence => new Result.Base(ModuleFs, 2957);
|
||||||
/// <summary>Error code: 2002-2958; Inner value: 0x171c02</summary>
|
/// <summary>Error code: 2002-2958; Inner value: 0x171c02</summary>
|
||||||
public static Result.Base GameCardFsCheckHandleInOnAcquireLock => new Result.Base(ModuleFs, 2958);
|
public static Result.Base GameCardFsCheckHandleInAcquireReadLock => new Result.Base(ModuleFs, 2958);
|
||||||
/// <summary>Error code: 2002-2959; Inner value: 0x171e02</summary>
|
/// <summary>Error code: 2002-2959; Inner value: 0x171e02</summary>
|
||||||
public static Result.Base GameCardFsCheckModeInOnAcquireSecureLock => new Result.Base(ModuleFs, 2959);
|
public static Result.Base GameCardFsCheckModeInAcquireSecureLock => new Result.Base(ModuleFs, 2959);
|
||||||
/// <summary>Error code: 2002-2960; Inner value: 0x172002</summary>
|
/// <summary>Error code: 2002-2960; Inner value: 0x172002</summary>
|
||||||
public static Result.Base GameCardFsCheckHandleInCreateReadOnlyFailure => new Result.Base(ModuleFs, 2960);
|
public static Result.Base GameCardFsCheckHandleInCreateReadOnlyFailure => new Result.Base(ModuleFs, 2960);
|
||||||
/// <summary>Error code: 2002-2961; Inner value: 0x172202</summary>
|
/// <summary>Error code: 2002-2961; Inner value: 0x172202</summary>
|
||||||
|
@ -136,8 +136,11 @@ public readonly struct BaseStorageService
|
|||||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
res = _serviceImpl.OpenDeviceOperator(ref outDeviceOperator, programInfo.AccessControl);
|
using var deviceOperator =
|
||||||
if (res.IsFailure()) return res.Miss();
|
new SharedRef<IDeviceOperator>(new DeviceOperator(_serviceImpl.FsServer, programInfo.AccessControl,
|
||||||
|
_processId));
|
||||||
|
|
||||||
|
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
@ -180,13 +183,11 @@ public class BaseStorageServiceImpl
|
|||||||
{
|
{
|
||||||
private Configuration _config;
|
private Configuration _config;
|
||||||
|
|
||||||
// LibHac addition
|
internal FileSystemServer FsServer => _config.FsServer;
|
||||||
private SharedRef<IDeviceOperator> _deviceOperator;
|
|
||||||
|
|
||||||
public BaseStorageServiceImpl(in Configuration configuration)
|
public BaseStorageServiceImpl(in Configuration configuration)
|
||||||
{
|
{
|
||||||
_config = configuration;
|
_config = configuration;
|
||||||
_deviceOperator = new SharedRef<IDeviceOperator>(configuration.DeviceOperator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Configuration
|
public struct Configuration
|
||||||
@ -196,8 +197,6 @@ public class BaseStorageServiceImpl
|
|||||||
|
|
||||||
// LibHac additions
|
// LibHac additions
|
||||||
public FileSystemServer FsServer;
|
public FileSystemServer FsServer;
|
||||||
// Todo: The DeviceOperator in FS uses mostly global state. Decide how to handle this.
|
|
||||||
public IDeviceOperator DeviceOperator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
|
internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
|
||||||
@ -231,12 +230,4 @@ public class BaseStorageServiceImpl
|
|||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LibHac addition
|
|
||||||
internal Result OpenDeviceOperator(ref SharedRef<IDeviceOperator> outDeviceOperator,
|
|
||||||
AccessControl accessControl)
|
|
||||||
{
|
|
||||||
outDeviceOperator.SetByCopy(in _deviceOperator);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Common.Keys;
|
using LibHac.Common.Keys;
|
||||||
using LibHac.FsSrv.FsCreator;
|
using LibHac.FsSrv.FsCreator;
|
||||||
using LibHac.FsSrv.Sf;
|
using LibHac.FsSrv.Storage;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
|
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
|
||||||
|
|
||||||
@ -10,9 +10,9 @@ namespace LibHac.FsSrv;
|
|||||||
public class DefaultFsServerObjects
|
public class DefaultFsServerObjects
|
||||||
{
|
{
|
||||||
public FileSystemCreatorInterfaces FsCreators { get; set; }
|
public FileSystemCreatorInterfaces FsCreators { get; set; }
|
||||||
public IDeviceOperator DeviceOperator { get; set; }
|
|
||||||
public EmulatedGameCard GameCard { get; set; }
|
public EmulatedGameCard GameCard { get; set; }
|
||||||
public EmulatedSdCard SdCard { get; set; }
|
public EmulatedSdCard SdCard { get; set; }
|
||||||
|
public EmulatedStorageDeviceManagerFactory StorageDeviceManagerFactory { get; set; }
|
||||||
|
|
||||||
public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, KeySet keySet,
|
public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, KeySet keySet,
|
||||||
FileSystemServer fsServer, RandomDataGenerator randomGenerator)
|
FileSystemServer fsServer, RandomDataGenerator randomGenerator)
|
||||||
@ -39,14 +39,14 @@ public class DefaultFsServerObjects
|
|||||||
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref);
|
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref);
|
||||||
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdCard, ref sharedRootFileSystemCopy.Ref);
|
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdCard, ref sharedRootFileSystemCopy.Ref);
|
||||||
|
|
||||||
var deviceOperator = new EmulatedDeviceOperator(gameCard, sdCard);
|
var storageDeviceManagerFactory = new EmulatedStorageDeviceManagerFactory(fsServer, true);
|
||||||
|
|
||||||
return new DefaultFsServerObjects
|
return new DefaultFsServerObjects
|
||||||
{
|
{
|
||||||
FsCreators = creators,
|
FsCreators = creators,
|
||||||
DeviceOperator = deviceOperator,
|
|
||||||
GameCard = gameCard,
|
GameCard = gameCard,
|
||||||
SdCard = sdCard
|
SdCard = sdCard,
|
||||||
|
StorageDeviceManagerFactory = storageDeviceManagerFactory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,11 +31,11 @@ public static class FileSystemServerInitializer
|
|||||||
if (config.FsCreators == null)
|
if (config.FsCreators == null)
|
||||||
throw new ArgumentException("FsCreators must not be null");
|
throw new ArgumentException("FsCreators must not be null");
|
||||||
|
|
||||||
if (config.DeviceOperator == null)
|
if (config.StorageDeviceManagerFactory == null)
|
||||||
throw new ArgumentException("DeviceOperator must not be null");
|
throw new ArgumentException("StorageDeviceManagerFactory must not be null");
|
||||||
|
|
||||||
server.SetDebugFlagEnabled(false);
|
server.SetDebugFlagEnabled(false);
|
||||||
server.Storage.InitializeStorageDeviceManagerFactory(null);
|
server.Storage.InitializeStorageDeviceManagerFactory(config.StorageDeviceManagerFactory);
|
||||||
|
|
||||||
FileSystemProxyConfiguration fspConfig = InitializeFileSystemProxy(server, config);
|
FileSystemProxyConfiguration fspConfig = InitializeFileSystemProxy(server, config);
|
||||||
|
|
||||||
@ -55,6 +55,9 @@ public static class FileSystemServerInitializer
|
|||||||
saveService.FixSaveData().IgnoreResult();
|
saveService.FixSaveData().IgnoreResult();
|
||||||
saveService.RecoverMultiCommit().IgnoreResult();
|
saveService.RecoverMultiCommit().IgnoreResult();
|
||||||
|
|
||||||
|
config.StorageDeviceManagerFactory.SetReady(StorageDevicePortId.SdCard, null);
|
||||||
|
config.StorageDeviceManagerFactory.SetReady(StorageDevicePortId.GameCard, null);
|
||||||
|
|
||||||
// NS usually takes care of this
|
// NS usually takes care of this
|
||||||
if (client.Fs.IsSdCardInserted())
|
if (client.Fs.IsSdCardInserted())
|
||||||
client.Fs.SetSdCardAccessibility(true);
|
client.Fs.SetSdCardAccessibility(true);
|
||||||
@ -86,7 +89,6 @@ public static class FileSystemServerInitializer
|
|||||||
baseStorageConfig.BisStorageCreator = config.FsCreators.BuiltInStorageCreator;
|
baseStorageConfig.BisStorageCreator = config.FsCreators.BuiltInStorageCreator;
|
||||||
baseStorageConfig.GameCardStorageCreator = config.FsCreators.GameCardStorageCreator;
|
baseStorageConfig.GameCardStorageCreator = config.FsCreators.GameCardStorageCreator;
|
||||||
baseStorageConfig.FsServer = server;
|
baseStorageConfig.FsServer = server;
|
||||||
baseStorageConfig.DeviceOperator = config.DeviceOperator;
|
|
||||||
var baseStorageService = new BaseStorageServiceImpl(in baseStorageConfig);
|
var baseStorageService = new BaseStorageServiceImpl(in baseStorageConfig);
|
||||||
|
|
||||||
var timeService = new TimeServiceImpl(server);
|
var timeService = new TimeServiceImpl(server);
|
||||||
@ -263,9 +265,9 @@ public class FileSystemServerConfig
|
|||||||
public FileSystemCreatorInterfaces FsCreators { get; set; }
|
public FileSystemCreatorInterfaces FsCreators { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IDeviceOperator"/> for managing the gamecard and SD card.
|
/// An <see cref="IStorageDeviceManagerFactory"/> for managing the gamecard and SD card.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDeviceOperator DeviceOperator { get; set; }
|
public IStorageDeviceManagerFactory StorageDeviceManagerFactory { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A keyset containing rights IDs and title keys.
|
/// A keyset containing rights IDs and title keys.
|
||||||
|
150
src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs
Normal file
150
src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
using LibHac.GcSrv;
|
||||||
|
using LibHac.Os;
|
||||||
|
using LibHac.SdmmcSrv;
|
||||||
|
using LibHac.Sf;
|
||||||
|
|
||||||
|
namespace LibHac.FsSrv.Storage;
|
||||||
|
|
||||||
|
public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
|
||||||
|
{
|
||||||
|
private SdkMutexType _gameCardDeviceMutex;
|
||||||
|
private SdkMutexType _sdCardDeviceMutex;
|
||||||
|
private SdkMutexType _mmcDeviceMutex;
|
||||||
|
|
||||||
|
private SharedRef<SdCardManager> _sdCardDeviceManager;
|
||||||
|
private SharedRef<DummyGameCardManager> _dummyGameCardDeviceManager;
|
||||||
|
private SharedRef<GameCardManager> _gameCardDeviceManager;
|
||||||
|
private SharedRef<MmcManager> _mmcDeviceManager;
|
||||||
|
|
||||||
|
private readonly bool _hasGameCard;
|
||||||
|
|
||||||
|
private readonly FileSystemServer _fsServer;
|
||||||
|
|
||||||
|
public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, bool hasGameCard)
|
||||||
|
{
|
||||||
|
_fsServer = fsServer;
|
||||||
|
_hasGameCard = hasGameCard;
|
||||||
|
|
||||||
|
_gameCardDeviceMutex = new SdkMutexType();
|
||||||
|
_sdCardDeviceMutex = new SdkMutexType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_sdCardDeviceManager.Destroy();
|
||||||
|
_dummyGameCardDeviceManager.Destroy();
|
||||||
|
_gameCardDeviceManager.Destroy();
|
||||||
|
_mmcDeviceManager.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Create(ref SharedRef<IStorageDeviceManager> outDeviceManager, StorageDevicePortId portId)
|
||||||
|
{
|
||||||
|
switch (portId)
|
||||||
|
{
|
||||||
|
case StorageDevicePortId.Mmc:
|
||||||
|
EnsureMmcReady();
|
||||||
|
outDeviceManager.SetByCopy(in _mmcDeviceManager);
|
||||||
|
break;
|
||||||
|
case StorageDevicePortId.SdCard:
|
||||||
|
{
|
||||||
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _sdCardDeviceMutex);
|
||||||
|
|
||||||
|
if (!_sdCardDeviceManager.HasValue)
|
||||||
|
return ResultFs.StorageDeviceNotReady.Log();
|
||||||
|
|
||||||
|
outDeviceManager.SetByCopy(in _sdCardDeviceManager);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageDevicePortId.GameCard:
|
||||||
|
{
|
||||||
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _gameCardDeviceMutex);
|
||||||
|
|
||||||
|
if (!_dummyGameCardDeviceManager.HasValue && !_gameCardDeviceManager.HasValue)
|
||||||
|
return ResultFs.StorageDeviceNotReady.Log();
|
||||||
|
|
||||||
|
if (_hasGameCard)
|
||||||
|
{
|
||||||
|
outDeviceManager.SetByCopy(in _gameCardDeviceManager);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outDeviceManager.SetByCopy(in _dummyGameCardDeviceManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ResultFs.StorageDeviceInvalidOperation.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result SetReady(StorageDevicePortId portId, NativeHandle handle)
|
||||||
|
{
|
||||||
|
switch (portId)
|
||||||
|
{
|
||||||
|
case StorageDevicePortId.Mmc:
|
||||||
|
EnsureMmcReady();
|
||||||
|
break;
|
||||||
|
case StorageDevicePortId.SdCard:
|
||||||
|
EnsureSdCardReady();
|
||||||
|
break;
|
||||||
|
case StorageDevicePortId.GameCard:
|
||||||
|
EnsureGameCardReady();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ResultFs.StorageDeviceInvalidOperation.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result UnsetReady(StorageDevicePortId portId)
|
||||||
|
{
|
||||||
|
return ResultFs.StorageDeviceInvalidOperation.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureMmcReady()
|
||||||
|
{
|
||||||
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mmcDeviceMutex);
|
||||||
|
|
||||||
|
if (!_mmcDeviceManager.HasValue)
|
||||||
|
{
|
||||||
|
_mmcDeviceManager.Reset(new MmcManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureSdCardReady()
|
||||||
|
{
|
||||||
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _sdCardDeviceMutex);
|
||||||
|
|
||||||
|
if (!_sdCardDeviceManager.HasValue)
|
||||||
|
{
|
||||||
|
_sdCardDeviceManager.Reset(new SdCardManager());
|
||||||
|
|
||||||
|
// Todo: BuiltInStorageFileSystemCreator::SetSdCardPortReady
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureGameCardReady()
|
||||||
|
{
|
||||||
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _gameCardDeviceMutex);
|
||||||
|
|
||||||
|
if (!_dummyGameCardDeviceManager.HasValue && !_gameCardDeviceManager.HasValue)
|
||||||
|
{
|
||||||
|
if (_hasGameCard)
|
||||||
|
{
|
||||||
|
using SharedRef<GameCardManager> manger = GameCardManager.CreateShared(_fsServer);
|
||||||
|
_gameCardDeviceManager.SetByMove(ref manger.Ref);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dummyGameCardDeviceManager.Reset(new DummyGameCardManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,8 @@ namespace LibHac.FsSrv.Storage.Sf;
|
|||||||
public interface IStorageDeviceManager : IDisposable
|
public interface IStorageDeviceManager : IDisposable
|
||||||
{
|
{
|
||||||
Result IsInserted(out bool isInserted);
|
Result IsInserted(out bool isInserted);
|
||||||
Result IsHandleValid(out bool isValid, uint handle);
|
Result IsHandleValid(out bool isValid, GameCardHandle handle);
|
||||||
Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outEventNotifier);
|
Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent);
|
||||||
Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator);
|
Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator);
|
||||||
Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute);
|
Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute);
|
||||||
Result OpenStorage(ref SharedRef<IStorageSf> outStorage, ulong attribute);
|
Result OpenStorage(ref SharedRef<IStorageSf> outStorage, ulong attribute);
|
||||||
|
@ -33,7 +33,7 @@ internal static class StorageDeviceManagerFactory
|
|||||||
IStorageDeviceManagerFactory factory = storage.GetStorageDeviceManagerFactory(null);
|
IStorageDeviceManagerFactory factory = storage.GetStorageDeviceManagerFactory(null);
|
||||||
Assert.SdkNotNull(factory);
|
Assert.SdkNotNull(factory);
|
||||||
|
|
||||||
return factory.Create(ref outDeviceManager, portId);
|
return factory.Create(ref outDeviceManager, portId).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IStorageDeviceManagerFactory GetStorageDeviceManagerFactory(this StorageService storage,
|
public static IStorageDeviceManagerFactory GetStorageDeviceManagerFactory(this StorageService storage,
|
||||||
|
76
src/LibHac/FsSystem/CardDeviceDetectionEvent.cs
Normal file
76
src/LibHac/FsSystem/CardDeviceDetectionEvent.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.FsSrv.Sf;
|
||||||
|
using LibHac.Os;
|
||||||
|
using LibHac.Sf;
|
||||||
|
|
||||||
|
namespace LibHac.FsSystem;
|
||||||
|
|
||||||
|
internal class CardDeviceDetectionEventManager : IDisposable
|
||||||
|
{
|
||||||
|
private LinkedList<CardDeviceDetectionEvent> _events;
|
||||||
|
private SdkMutex _mutex;
|
||||||
|
protected CallbackArguments CallbackArgs;
|
||||||
|
|
||||||
|
protected class CallbackArguments
|
||||||
|
{
|
||||||
|
public CardDeviceDetectionEventManager EventManager;
|
||||||
|
public SdkMutex Mutex;
|
||||||
|
public Sdmmc.Port Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CardDeviceDetectionEventManager()
|
||||||
|
{
|
||||||
|
_events = new LinkedList<CardDeviceDetectionEvent>();
|
||||||
|
_mutex = new SdkMutex();
|
||||||
|
|
||||||
|
CallbackArgs = new CallbackArguments { EventManager = this, Mutex = _mutex };
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result CreateDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlink(CardDeviceDetectionEvent detectionEvent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SignalAll()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void DetectionEventCallback(object args)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CardDeviceDetectionEvent : IEventNotifier
|
||||||
|
{
|
||||||
|
private CardDeviceDetectionEventManager _eventManager;
|
||||||
|
// Todo: SystemEvent
|
||||||
|
|
||||||
|
public CardDeviceDetectionEvent(CardDeviceDetectionEventManager eventManager)
|
||||||
|
{
|
||||||
|
_eventManager = eventManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetEventHandle(out NativeHandle handle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
200
src/LibHac/Gc/GameCardDummy.cs
Normal file
200
src/LibHac/Gc/GameCardDummy.cs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
using System;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Gc.Impl;
|
||||||
|
using LibHac.Gc.Writer;
|
||||||
|
|
||||||
|
namespace LibHac.Gc;
|
||||||
|
|
||||||
|
public class GameCardDummy
|
||||||
|
{
|
||||||
|
public GameCardWriter Writer => new GameCardWriter();
|
||||||
|
|
||||||
|
public readonly struct GameCardWriter
|
||||||
|
{
|
||||||
|
public GameCardWriter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeMode(AsicMode mode)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ActivateForWriter()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result EraseAndWriteParameter(MemorySize size, uint romAreaStartPageIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Write(ReadOnlySpan<byte> source, uint pageIndex, uint pageCount)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCardAvailableRawSize(out long outSize)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetVerifyEnableFlag(bool isEnabled)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUserAsicFirmwareBuffer(ReadOnlySpan<byte> firmwareBuffer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetRmaInformation(out RmaInformation outRmaInformation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result WriteDevCardParam(in DevCardParameter devCardParam)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ReadDevCardParam(out DevCardParameter outDevCardParam)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ForceErase()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(Memory<byte> workBuffer, ulong deviceBufferAddress)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinalizeGc()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PowerOffGameCard()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterDeviceVirtualAddress(Memory<byte> buffer, ulong deviceBufferAddress)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterDeviceVirtualAddress(Memory<byte> buffer, ulong deviceBufferAddress)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetInitializationResult()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Activate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deactivate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result SetCardToSecureMode()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Read(Span<byte> destination, uint pageIndex, uint pageCount)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PutToSleep()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Awaken()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCardInserted()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCardActivationValid()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCardStatus(out GameCardStatus outStatus)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCardDeviceId(Span<byte> destBuffer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCardDeviceCertificate(Span<byte> destBuffer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ChallengeCardExistence(Span<byte> responseBuffer, ReadOnlySpan<byte> challengeSeedBuffer,
|
||||||
|
ReadOnlySpan<byte> challengeValueBuffer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCardImageHash(Span<byte> destBuffer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetGameCardIdSet(out GameCardIdSet outGcIdSet)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterDetectionEventCallback(Action<object> function, object args)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterDetectionEventCallback()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCardHeader(Span<byte> destBuffer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetErrorInfo(out GameCardErrorReportInfo outErrorReportInfo)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,11 @@ public struct CardId3
|
|||||||
public Array4<byte> Reserved;
|
public Array4<byte> Reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct DevCardParameter
|
||||||
|
{
|
||||||
|
public Array512<byte> Data;
|
||||||
|
}
|
||||||
|
|
||||||
public struct CardInitialDataPayload
|
public struct CardInitialDataPayload
|
||||||
{
|
{
|
||||||
public Array8<byte> PackageId;
|
public Array8<byte> PackageId;
|
||||||
|
19
src/LibHac/Gc/Writer/WriterTypes.cs
Normal file
19
src/LibHac/Gc/Writer/WriterTypes.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace LibHac.Gc.Writer;
|
||||||
|
|
||||||
|
public enum AsicMode : byte
|
||||||
|
{
|
||||||
|
Read = 0,
|
||||||
|
Write = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MemorySize
|
||||||
|
{
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
Size1GB = 1,
|
||||||
|
Size2GB = 2,
|
||||||
|
Size4GB = 4,
|
||||||
|
Size8GB = 8,
|
||||||
|
Size16GB = 16,
|
||||||
|
Size32GB = 32
|
||||||
|
// ReSharper restore InconsistentNaming
|
||||||
|
}
|
189
src/LibHac/GcSrv/DummyGameCardManager.cs
Normal file
189
src/LibHac/GcSrv/DummyGameCardManager.cs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSrv.Sf;
|
||||||
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
using LibHac.Sf;
|
||||||
|
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
|
||||||
|
|
||||||
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
|
public class DummyGameCardManager : IStorageDeviceManager, IStorageDeviceOperator
|
||||||
|
{
|
||||||
|
public DummyGameCardManager()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsInserted(out bool isInserted)
|
||||||
|
{
|
||||||
|
isInserted = false;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsHandleValid(out bool isValid, uint handle)
|
||||||
|
{
|
||||||
|
isValid = false;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
|
||||||
|
{
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenStorage(ref SharedRef<IStorageSf> outStorage, ulong attribute)
|
||||||
|
{
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Invalidate()
|
||||||
|
{
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Operate(int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.Finalize:
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.GetInitializationResult:
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.ForceErase:
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.SimulateDetectionEventSignaled:
|
||||||
|
return ResultFs.GameCardNotSupportedOnDeviceModel.Log();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.SetVerifyEnableFlag:
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.EraseAndWriteParamDirectly:
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
bytesWritten = 0;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.GetHandle:
|
||||||
|
{
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
}
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardErrorInfo:
|
||||||
|
{
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<GameCardErrorInfo>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
buffer.As<GameCardErrorInfo>() = default;
|
||||||
|
bytesWritten = Unsafe.SizeOf<GameCardErrorInfo>();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardErrorReportInfo:
|
||||||
|
{
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<GameCardErrorReportInfo>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
buffer.As<GameCardErrorReportInfo>() = default;
|
||||||
|
bytesWritten = Unsafe.SizeOf<GameCardErrorReportInfo>();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
case GameCardManagerOperationIdValue.ReadParamDirectly:
|
||||||
|
{
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
|
||||||
|
OutBuffer buffer2, int operationId)
|
||||||
|
{
|
||||||
|
bytesWrittenBuffer1 = 0;
|
||||||
|
bytesWrittenBuffer2 = 0;
|
||||||
|
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
|
||||||
|
int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
bytesWritten = 0;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.IsGameCardActivationValid:
|
||||||
|
{
|
||||||
|
if (outBuffer.Size < Unsafe.SizeOf<bool>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
outBuffer.As<bool>() = false;
|
||||||
|
bytesWritten = sizeof(bool);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardAsicInfo:
|
||||||
|
return ResultFs.GameCardAccessFailed.Log();
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardDeviceIdForProdCard:
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.WriteToGameCardDirectly:
|
||||||
|
return ResultFs.GameCardCardNotInserted.Log();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
|
||||||
|
long offset, long size, int operationId)
|
||||||
|
{
|
||||||
|
bytesWritten = 0;
|
||||||
|
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
}
|
17
src/LibHac/GcSrv/GameCardDeviceDetectionEventManager.cs
Normal file
17
src/LibHac/GcSrv/GameCardDeviceDetectionEventManager.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using LibHac.FsSystem;
|
||||||
|
|
||||||
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
|
internal class GameCardDeviceDetectionEventManager : CardDeviceDetectionEventManager
|
||||||
|
{
|
||||||
|
public GameCardDeviceDetectionEventManager()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
897
src/LibHac/GcSrv/GameCardManager.cs
Normal file
897
src/LibHac/GcSrv/GameCardManager.cs
Normal file
@ -0,0 +1,897 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Diag;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSrv;
|
||||||
|
using LibHac.FsSrv.Sf;
|
||||||
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
using LibHac.FsSystem;
|
||||||
|
using LibHac.Gc;
|
||||||
|
using LibHac.Gc.Impl;
|
||||||
|
using LibHac.Gc.Writer;
|
||||||
|
using LibHac.Os;
|
||||||
|
using LibHac.Sf;
|
||||||
|
using IStorage = LibHac.FsSrv.Sf.IStorage;
|
||||||
|
|
||||||
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
|
public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IGameCardDeviceManager
|
||||||
|
{
|
||||||
|
private enum CardState
|
||||||
|
{
|
||||||
|
Initial = 0,
|
||||||
|
Normal = 1,
|
||||||
|
Secure = 2,
|
||||||
|
Write = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReaderWriterLock _rwLock;
|
||||||
|
private bool _isInitialized;
|
||||||
|
private bool _isFinalized;
|
||||||
|
private CardState _state;
|
||||||
|
private GameCardHandle _currentHandle;
|
||||||
|
private GameCardDeviceDetectionEventManager _detectionEventManager;
|
||||||
|
|
||||||
|
// LibHac additions
|
||||||
|
private WeakRef<GameCardManager> _selfReference;
|
||||||
|
private readonly FileSystemServer _fsServer;
|
||||||
|
private readonly GameCardDummy _gc;
|
||||||
|
|
||||||
|
private GameCardManager(FileSystemServer fsServer)
|
||||||
|
{
|
||||||
|
_rwLock = new ReaderWriterLock(fsServer.Hos.Os);
|
||||||
|
|
||||||
|
_fsServer = fsServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedRef<GameCardManager> CreateShared(FileSystemServer fsServer)
|
||||||
|
{
|
||||||
|
var manager = new GameCardManager(fsServer);
|
||||||
|
|
||||||
|
using var sharedManager = new SharedRef<GameCardManager>(manager);
|
||||||
|
manager._selfReference.Set(in sharedManager);
|
||||||
|
|
||||||
|
return SharedRef<GameCardManager>.CreateMove(ref sharedManager.Ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_detectionEventManager?.Dispose();
|
||||||
|
_detectionEventManager = null;
|
||||||
|
|
||||||
|
_rwLock?.Dispose();
|
||||||
|
_rwLock = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint BytesToPages(long byteCount)
|
||||||
|
{
|
||||||
|
return (uint)((ulong)byteCount / (ulong)Values.GcPageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateAndChangeState()
|
||||||
|
{
|
||||||
|
_gc.Deactivate();
|
||||||
|
_currentHandle++;
|
||||||
|
_state = CardState.Initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckGameCardAndDeactivate()
|
||||||
|
{
|
||||||
|
if (_state != CardState.Initial && !_gc.IsCardActivationValid())
|
||||||
|
{
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result ActivateGameCard()
|
||||||
|
{
|
||||||
|
Result res = HandleGameCardAccessResult(_gc.Activate());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result ActivateGameCardForWriter()
|
||||||
|
{
|
||||||
|
return HandleGameCardAccessResult(_gc.Writer.ActivateForWriter());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result SetGameCardToSecureMode()
|
||||||
|
{
|
||||||
|
return HandleGameCardAccessResult(_gc.SetCardToSecureMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsInserted(out bool isInserted)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out isInserted);
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
isInserted = _gc.IsCardInserted();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result InitializeGcLibrary()
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
if (_isFinalized)
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
// Missing: Wait on settings-ready event
|
||||||
|
// Missing: Allocate work buffer and pass it to nn::gc::Initialize
|
||||||
|
_gc.Initialize(default, default);
|
||||||
|
// Missing: Register the device buffer
|
||||||
|
|
||||||
|
_detectionEventManager = new GameCardDeviceDetectionEventManager();
|
||||||
|
_isInitialized = true;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result EnsureGameCardNormalMode(out GameCardHandle outNewHandle)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out outNewHandle);
|
||||||
|
|
||||||
|
if (_state == CardState.Normal)
|
||||||
|
CheckGameCardAndDeactivate();
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case CardState.Initial:
|
||||||
|
{
|
||||||
|
// Initial -> Normal
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Normal;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Normal:
|
||||||
|
{
|
||||||
|
outNewHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
case CardState.Secure:
|
||||||
|
{
|
||||||
|
// Secure -> Initial -> Normal
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Normal;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Write:
|
||||||
|
{
|
||||||
|
// Write -> Initial -> Normal
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Read);
|
||||||
|
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Normal;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outNewHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result EnsureGameCardSecureMode(out GameCardHandle outNewHandle)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out outNewHandle);
|
||||||
|
|
||||||
|
if (_state == CardState.Secure)
|
||||||
|
CheckGameCardAndDeactivate();
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case CardState.Initial:
|
||||||
|
{
|
||||||
|
// Initial -> Normal -> Secure
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Normal;
|
||||||
|
|
||||||
|
res = SetGameCardToSecureMode();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Secure;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Normal:
|
||||||
|
{
|
||||||
|
// Normal -> Secure
|
||||||
|
Result res = SetGameCardToSecureMode();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Secure;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Secure:
|
||||||
|
{
|
||||||
|
outNewHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
case CardState.Write:
|
||||||
|
{
|
||||||
|
// Write -> Initial -> Normal -> Secure
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Read);
|
||||||
|
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Normal;
|
||||||
|
|
||||||
|
res = SetGameCardToSecureMode();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Secure;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outNewHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result EnsureGameCardWriteMode(out GameCardHandle outNewHandle)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out outNewHandle);
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case CardState.Initial:
|
||||||
|
{
|
||||||
|
// Initial -> Write
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
Result res = ActivateGameCardForWriter();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Write;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Normal:
|
||||||
|
case CardState.Secure:
|
||||||
|
{
|
||||||
|
// Normal/Secure -> Initial -> Write
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
Result res = ActivateGameCardForWriter();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
_state = CardState.Write;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Write:
|
||||||
|
{
|
||||||
|
outNewHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outNewHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsHandleValid(out bool isValid, GameCardHandle handle)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out isValid);
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||||
|
isValid = AcquireReadLock(ref readLock.Ref(), handle).IsSuccess();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
||||||
|
{
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = _detectionEventManager.CreateDetectionEvent(ref outDetectionEvent);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenStorage(ref SharedRef<IStorage> outStorage, ulong attribute)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result PutToSleep()
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
_gc.PutToSleep();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Awaken()
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
_gc.Awaken();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Shutdown()
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
_gc.PutToSleep();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Invalidate()
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Operate(int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.Finalize:
|
||||||
|
FinalizeGcLibrary();
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.GetInitializationResult:
|
||||||
|
return GetInitializationResult().Ret();
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.ForceErase:
|
||||||
|
return ForceEraseGameCard().Ret();
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.SimulateDetectionEventSignaled:
|
||||||
|
_detectionEventManager.SignalAll();
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.SetVerifyEnableFlag:
|
||||||
|
if (buffer.Size < sizeof(bool))
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
SetVerifyEnableFlag(buffer.As<bool>());
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.EraseAndWriteParamDirectly:
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<DevCardParameter>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = EraseAndWriteParamDirectly(buffer.Buffer);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
bytesWritten = 0;
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.GetHandle:
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
if (buffer.Size < sizeof(GameCardHandle))
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = GetHandle(out buffer.As<GameCardHandle>());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
bytesWritten = sizeof(GameCardHandle);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardErrorInfo:
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<GameCardErrorInfo>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = GetGameCardErrorInfo(out buffer.As<GameCardErrorInfo>());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
bytesWritten = Unsafe.SizeOf<GameCardErrorInfo>();
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardErrorReportInfo:
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<GameCardErrorReportInfo>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = GetGameCardErrorReportInfo(out buffer.As<GameCardErrorReportInfo>());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
bytesWritten = Unsafe.SizeOf<GameCardErrorReportInfo>();
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.ReadParamDirectly:
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<DevCardParameter>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = ReadParamDirectly(buffer.Buffer);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
bytesWritten = Unsafe.SizeOf<DevCardParameter>();
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
|
||||||
|
OutBuffer buffer2, int operationId)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out bytesWrittenBuffer1, out bytesWrittenBuffer2);
|
||||||
|
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
|
||||||
|
int operationId)
|
||||||
|
{
|
||||||
|
var operation = (GameCardManagerOperationIdValue)operationId;
|
||||||
|
bytesWritten = 0;
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardManagerOperationIdValue.IsGameCardActivationValid:
|
||||||
|
if (inBuffer.Size != sizeof(GameCardHandle))
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (outBuffer.Size < sizeof(bool))
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
outBuffer.As<bool>() = IsGameCardActivationValid(inBuffer.As<GameCardHandle>());
|
||||||
|
bytesWritten = sizeof(bool);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardAsicInfo:
|
||||||
|
if (inBuffer.Size != Values.GcAsicFirmwareSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (outBuffer.Size < Unsafe.SizeOf<RmaInformation>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = GetGameCardAsicInfo(out RmaInformation rmaInfo, inBuffer.Buffer);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
SpanHelpers.AsReadOnlyByteSpan(in rmaInfo).CopyTo(outBuffer.Buffer);
|
||||||
|
bytesWritten = Unsafe.SizeOf<RmaInformation>();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.GetGameCardDeviceIdForProdCard:
|
||||||
|
if (inBuffer.Size < Values.GcPageSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (outBuffer.Size < Values.GcPageSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
res = GetGameCardDeviceIdForProdCard(outBuffer.Buffer, inBuffer.Buffer);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
bytesWritten = Values.GcPageSize;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
case GameCardManagerOperationIdValue.WriteToGameCardDirectly:
|
||||||
|
return WriteToGameCardDirectly(offset, outBuffer.Buffer.Slice(0, (int)size)).Ret();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
|
||||||
|
long offset, long size, int operationId)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out bytesWritten);
|
||||||
|
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FinalizeGcLibrary()
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
_gc.UnregisterDetectionEventCallback();
|
||||||
|
_isFinalized = true;
|
||||||
|
_gc.FinalizeGc();
|
||||||
|
// nn::gc::UnregisterDeviceVirtualAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsGameCardActivationValid(GameCardHandle handle)
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
return handle == _currentHandle && _gc.IsCardActivationValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result GetInitializationResult()
|
||||||
|
{
|
||||||
|
return _gc.GetInitializationResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result GetGameCardErrorInfo(out GameCardErrorInfo outErrorInfo)
|
||||||
|
{
|
||||||
|
outErrorInfo = default;
|
||||||
|
|
||||||
|
Result res = _gc.GetErrorInfo(out GameCardErrorReportInfo errorInfo);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
outErrorInfo.GameCardCrcErrorCount = errorInfo.ErrorInfo.GameCardCrcErrorCount;
|
||||||
|
outErrorInfo.AsicCrcErrorCount = errorInfo.ErrorInfo.AsicCrcErrorCount;
|
||||||
|
outErrorInfo.RefreshCount = errorInfo.ErrorInfo.RefreshCount;
|
||||||
|
outErrorInfo.TimeoutRetryErrorCount = errorInfo.ErrorInfo.TimeoutRetryErrorCount;
|
||||||
|
outErrorInfo.ReadRetryCount = errorInfo.ErrorInfo.ReadRetryCount;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result GetGameCardErrorReportInfo(out GameCardErrorReportInfo outErrorInfo)
|
||||||
|
{
|
||||||
|
Result res = _gc.GetErrorInfo(out outErrorInfo);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetVerifyEnableFlag(bool isEnabled)
|
||||||
|
{
|
||||||
|
_gc.Writer.SetVerifyEnableFlag(isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result GetGameCardAsicInfo(out RmaInformation outRmaInfo, ReadOnlySpan<byte> asicFirmwareBuffer)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out outRmaInfo);
|
||||||
|
|
||||||
|
Assert.SdkRequiresEqual(asicFirmwareBuffer.Length, Values.GcAsicFirmwareSize);
|
||||||
|
|
||||||
|
_gc.Writer.SetUserAsicFirmwareBuffer(asicFirmwareBuffer);
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
|
||||||
|
Result res = _gc.Writer.GetRmaInformation(out RmaInformation rmaInfo);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
outRmaInfo = rmaInfo;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result GetGameCardDeviceIdForProdCard(Span<byte> outBuffer, ReadOnlySpan<byte> devHeaderBuffer)
|
||||||
|
{
|
||||||
|
Assert.SdkRequiresGreaterEqual(outBuffer.Length, Values.GcPageSize);
|
||||||
|
Assert.SdkRequiresGreaterEqual(devHeaderBuffer.Length, Values.GcPageSize);
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
int writeSize = Values.GcPageSize;
|
||||||
|
var pooledBuffer = new PooledBuffer(writeSize, writeSize);
|
||||||
|
Assert.SdkGreaterEqual(pooledBuffer.GetSize(), writeSize);
|
||||||
|
|
||||||
|
// Read the current card header into a temporary buffer
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Read);
|
||||||
|
|
||||||
|
Span<byte> tmpBuffer = stackalloc byte[writeSize];
|
||||||
|
tmpBuffer.Clear();
|
||||||
|
|
||||||
|
_gc.GetCardHeader(pooledBuffer.GetBuffer());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
pooledBuffer.GetBuffer().CopyTo(tmpBuffer);
|
||||||
|
|
||||||
|
// Write the provided card header
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
res = HandleGameCardAccessResult(_gc.Writer.ActivateForWriter());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
devHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
||||||
|
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), 8, 1);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
// Read the cert area
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Read);
|
||||||
|
res = _gc.Activate();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = _gc.Read(pooledBuffer.GetBuffer(), 0x38, 1);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
Span<byte> deviceCert = stackalloc byte[writeSize];
|
||||||
|
pooledBuffer.GetBuffer().CopyTo(deviceCert);
|
||||||
|
|
||||||
|
// Restore the original card header
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
res = HandleGameCardAccessResult(_gc.Writer.ActivateForWriter());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
tmpBuffer.CopyTo(pooledBuffer.GetBuffer());
|
||||||
|
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), 8, 1);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
deviceCert.CopyTo(outBuffer);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result EraseAndWriteParamDirectly(ReadOnlySpan<byte> inBuffer)
|
||||||
|
{
|
||||||
|
Assert.SdkRequires(inBuffer.Length >= Unsafe.SizeOf<DevCardParameter>());
|
||||||
|
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
var devCardParam = SpanHelpers.AsReadOnlyStruct<DevCardParameter>(inBuffer);
|
||||||
|
return _gc.Writer.WriteDevCardParam(in devCardParam).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result ReadParamDirectly(Span<byte> outBuffer)
|
||||||
|
{
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
res = _gc.Writer.ReadDevCardParam(out DevCardParameter devCardParam);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
SpanHelpers.AsReadOnlyByteSpan(in devCardParam).CopyTo(outBuffer);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result WriteToGameCardDirectly(long offset, Span<byte> buffer)
|
||||||
|
{
|
||||||
|
Result res;
|
||||||
|
|
||||||
|
using (new SharedLock<ReaderWriterLock>(_rwLock))
|
||||||
|
{
|
||||||
|
if (buffer.Length == 0)
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
res = _gc.Writer.Write(buffer, BytesToPages(offset), BytesToPages(buffer.Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != Result.Success)
|
||||||
|
{
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
res = HandleGameCardAccessResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result ForceEraseGameCard()
|
||||||
|
{
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
res = _gc.Writer.ForceErase();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle)
|
||||||
|
{
|
||||||
|
using var readLock = new SharedLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
if (_state != CardState.Initial && !_gc.IsCardActivationValid())
|
||||||
|
{
|
||||||
|
readLock.Unlock();
|
||||||
|
Invalidate().IgnoreResult();
|
||||||
|
|
||||||
|
return ResultFs.GameCardFsCheckHandleInAcquireReadLock.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentHandle != handle)
|
||||||
|
return ResultFs.GameCardFsCheckHandleInAcquireReadLock.Log();
|
||||||
|
|
||||||
|
outLock.Set(ref readLock.Ref());
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle handle,
|
||||||
|
ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
||||||
|
{
|
||||||
|
using (var readLock = new SharedLock<ReaderWriterLock>(_rwLock))
|
||||||
|
{
|
||||||
|
if (!IsSecureMode())
|
||||||
|
{
|
||||||
|
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state != CardState.Initial && !_gc.IsCardActivationValid())
|
||||||
|
{
|
||||||
|
readLock.Unlock();
|
||||||
|
Invalidate().IgnoreResult();
|
||||||
|
}
|
||||||
|
else if (_currentHandle == handle)
|
||||||
|
{
|
||||||
|
outLock.Set(ref readLock.Ref());
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameCardHandle newHandle;
|
||||||
|
|
||||||
|
using (new UniqueLock<ReaderWriterLock>(_rwLock))
|
||||||
|
{
|
||||||
|
if (!IsSecureMode())
|
||||||
|
{
|
||||||
|
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> currentCardDeviceId = stackalloc byte[Values.GcCardDeviceIdSize];
|
||||||
|
Span<byte> currentCardImageHash = stackalloc byte[Values.GcCardImageHashSize];
|
||||||
|
|
||||||
|
Result res = HandleGameCardAccessResult(_gc.GetCardDeviceId(currentCardDeviceId));
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = HandleGameCardAccessResult(_gc.GetCardImageHash(currentCardImageHash));
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (!Crypto.CryptoUtil.IsSameBytes(currentCardDeviceId, cardDeviceId, Values.GcCardDeviceIdSize) ||
|
||||||
|
!Crypto.CryptoUtil.IsSameBytes(currentCardImageHash, cardImageHash, Values.GcCardImageHashSize))
|
||||||
|
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
||||||
|
|
||||||
|
res = GetHandle(out newHandle);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var readLock = new SharedLock<ReaderWriterLock>())
|
||||||
|
{
|
||||||
|
Result res = AcquireReadLock(ref readLock.Ref(), newHandle);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
handle = newHandle;
|
||||||
|
outLock.Set(ref readLock.Ref());
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result AcquireWriteLock(ref UniqueLock<ReaderWriterLock> outLock)
|
||||||
|
{
|
||||||
|
Result res = InitializeGcLibrary();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
outLock.Set(ref writeLock.Ref());
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result HandleGameCardAccessResult(Result result)
|
||||||
|
{
|
||||||
|
if (result.IsFailure())
|
||||||
|
{
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetHandle(out GameCardHandle outHandle)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out outHandle);
|
||||||
|
|
||||||
|
if (_state == CardState.Normal || _state == CardState.Secure)
|
||||||
|
{
|
||||||
|
CheckGameCardAndDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case CardState.Initial:
|
||||||
|
{
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CardState.Normal:
|
||||||
|
case CardState.Secure:
|
||||||
|
break;
|
||||||
|
case CardState.Write:
|
||||||
|
{
|
||||||
|
DeactivateAndChangeState();
|
||||||
|
_gc.Writer.ChangeMode(AsicMode.Read);
|
||||||
|
|
||||||
|
Result res = ActivateGameCard();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
_state = CardState.Normal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outHandle = _currentHandle;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSecureMode()
|
||||||
|
{
|
||||||
|
return _state == CardState.Secure;
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using LibHac.Fs.Impl;
|
using LibHac.Os;
|
||||||
|
|
||||||
namespace LibHac.GcSrv;
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
internal interface IGameCardDeviceManager
|
internal interface IGameCardDeviceManager
|
||||||
{
|
{
|
||||||
Result AcquireReadLock(out UniqueLock locker, uint handle);
|
Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle);
|
||||||
Result AcquireReadLockSecureMode(out UniqueLock locker, ref uint handle, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash);
|
Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle handle, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash);
|
||||||
Result AcquireWriteLock(out SharedLock locker);
|
Result AcquireWriteLock(ref UniqueLock<ReaderWriterLock> outLock);
|
||||||
Result HandleGameCardAccessResult(Result result);
|
Result HandleGameCardAccessResult(Result result);
|
||||||
Result GetHandle(out uint handle);
|
Result GetHandle(out GameCardHandle outHandle);
|
||||||
bool IsSecureMode();
|
bool IsSecureMode();
|
||||||
}
|
}
|
@ -24,9 +24,9 @@ public static class HorizonFactory
|
|||||||
|
|
||||||
var fsServerConfig = new FileSystemServerConfig
|
var fsServerConfig = new FileSystemServerConfig
|
||||||
{
|
{
|
||||||
DeviceOperator = defaultObjects.DeviceOperator,
|
|
||||||
ExternalKeySet = keySet.ExternalKeySet,
|
ExternalKeySet = keySet.ExternalKeySet,
|
||||||
FsCreators = defaultObjects.FsCreators,
|
FsCreators = defaultObjects.FsCreators,
|
||||||
|
StorageDeviceManagerFactory = defaultObjects.StorageDeviceManagerFactory,
|
||||||
RandomGenerator = randomGenerator
|
RandomGenerator = randomGenerator
|
||||||
};
|
};
|
||||||
|
|
||||||
|
54
src/LibHac/SdmmcSrv/MmcManager.cs
Normal file
54
src/LibHac/SdmmcSrv/MmcManager.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.FsSrv.Sf;
|
||||||
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
|
||||||
|
namespace LibHac.SdmmcSrv;
|
||||||
|
|
||||||
|
public class MmcManager : IStorageDeviceManager
|
||||||
|
{
|
||||||
|
public MmcManager()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsInserted(out bool isInserted)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsHandleValid(out bool isValid, uint handle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenStorage(ref SharedRef<IStorage> outStorage, ulong attribute)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Invalidate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
19
src/LibHac/SdmmcSrv/SdCardDeviceDetectionEvent.cs
Normal file
19
src/LibHac/SdmmcSrv/SdCardDeviceDetectionEvent.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using LibHac.FsSystem;
|
||||||
|
|
||||||
|
namespace LibHac.SdmmcSrv;
|
||||||
|
|
||||||
|
internal class SdCardDeviceDetectionEventManager : CardDeviceDetectionEventManager
|
||||||
|
{
|
||||||
|
public SdCardDeviceDetectionEventManager(Sdmmc.Port port)
|
||||||
|
{
|
||||||
|
CallbackArgs.Port = port;
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
54
src/LibHac/SdmmcSrv/SdCardManager.cs
Normal file
54
src/LibHac/SdmmcSrv/SdCardManager.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.FsSrv.Sf;
|
||||||
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
|
||||||
|
namespace LibHac.SdmmcSrv;
|
||||||
|
|
||||||
|
public class SdCardManager : IStorageDeviceManager
|
||||||
|
{
|
||||||
|
public SdCardManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsInserted(out bool isInserted)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result IsHandleValid(out bool isValid, uint handle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenStorage(ref SharedRef<IStorage> outStorage, ulong attribute)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Invalidate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,11 @@ public readonly ref struct InBuffer
|
|||||||
_buffer = buffer;
|
_buffer = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ref readonly T As<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
return ref SpanHelpers.AsReadOnlyStruct<T>(_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static InBuffer FromSpan<T>(ReadOnlySpan<T> buffer) where T : unmanaged
|
public static InBuffer FromSpan<T>(ReadOnlySpan<T> buffer) where T : unmanaged
|
||||||
{
|
{
|
||||||
@ -42,6 +47,11 @@ public readonly ref struct OutBuffer
|
|||||||
_buffer = buffer;
|
_buffer = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ref T As<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
return ref SpanHelpers.AsStruct<T>(_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static OutBuffer FromSpan<T>(Span<T> buffer) where T : unmanaged
|
public static OutBuffer FromSpan<T>(Span<T> buffer) where T : unmanaged
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,7 @@ public static class FileSystemServerFactory
|
|||||||
|
|
||||||
var config = new FileSystemServerConfig();
|
var config = new FileSystemServerConfig();
|
||||||
config.FsCreators = defaultObjects.FsCreators;
|
config.FsCreators = defaultObjects.FsCreators;
|
||||||
config.DeviceOperator = defaultObjects.DeviceOperator;
|
config.StorageDeviceManagerFactory = defaultObjects.StorageDeviceManagerFactory;
|
||||||
config.ExternalKeySet = new ExternalKeySet();
|
config.ExternalKeySet = new ExternalKeySet();
|
||||||
config.RandomGenerator = randomGenerator;
|
config.RandomGenerator = randomGenerator;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public static class HorizonFactory
|
|||||||
|
|
||||||
var config = new FileSystemServerConfig();
|
var config = new FileSystemServerConfig();
|
||||||
config.FsCreators = defaultObjects.FsCreators;
|
config.FsCreators = defaultObjects.FsCreators;
|
||||||
config.DeviceOperator = defaultObjects.DeviceOperator;
|
config.StorageDeviceManagerFactory = defaultObjects.StorageDeviceManagerFactory;
|
||||||
config.ExternalKeySet = new ExternalKeySet();
|
config.ExternalKeySet = new ExternalKeySet();
|
||||||
config.RandomGenerator = randomGenerator;
|
config.RandomGenerator = randomGenerator;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user