mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add GameCardDeviceOperator
This commit is contained in:
parent
f4c59771cb
commit
e18f6a9daf
10 changed files with 474 additions and 155 deletions
|
@ -1,6 +1,7 @@
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.FsSrv.Storage.Sf;
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
using LibHac.Gc;
|
||||||
using LibHac.GcSrv;
|
using LibHac.GcSrv;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
using LibHac.SdmmcSrv;
|
using LibHac.SdmmcSrv;
|
||||||
|
@ -22,6 +23,7 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
|
||||||
private readonly bool _hasGameCard;
|
private readonly bool _hasGameCard;
|
||||||
|
|
||||||
private readonly FileSystemServer _fsServer;
|
private readonly FileSystemServer _fsServer;
|
||||||
|
private readonly GameCardDummy _gc;
|
||||||
|
|
||||||
public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, bool hasGameCard)
|
public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, bool hasGameCard)
|
||||||
{
|
{
|
||||||
|
@ -138,12 +140,13 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
|
||||||
{
|
{
|
||||||
if (_hasGameCard)
|
if (_hasGameCard)
|
||||||
{
|
{
|
||||||
using SharedRef<GameCardManager> manger = GameCardManager.CreateShared(_fsServer);
|
using SharedRef<GameCardManager> manager = GameCardManager.CreateShared(_gc, _fsServer);
|
||||||
_gameCardDeviceManager.SetByMove(ref manger.Ref);
|
_gameCardDeviceManager.SetByMove(ref manager.Ref);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dummyGameCardDeviceManager.Reset(new DummyGameCardManager());
|
using SharedRef<DummyGameCardManager> manager = DummyGameCardManager.CreateShared();
|
||||||
|
_dummyGameCardDeviceManager.SetByMove(ref manager.Ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,26 @@
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
|
using LibHac.FsSrv.Sf;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
|
using LibHac.Sf;
|
||||||
|
using IDirectory = LibHac.Fs.Fsa.IDirectory;
|
||||||
|
using IFile = LibHac.Fs.Fsa.IFile;
|
||||||
|
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
|
||||||
|
using Path = LibHac.Fs.Path;
|
||||||
|
|
||||||
namespace LibHac.FsSystem;
|
namespace LibHac.FsSystem;
|
||||||
|
|
||||||
|
public class DummyEventNotifier : IEventNotifier
|
||||||
|
{
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public Result GetEventHandle(out NativeHandle handle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Various utility functions used by the <see cref="LibHac.FsSystem"/> namespace.
|
/// Various utility functions used by the <see cref="LibHac.FsSystem"/> namespace.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -9,4 +9,6 @@ public static class Values
|
||||||
public static int GcCardImageHashSize => 0x20;
|
public static int GcCardImageHashSize => 0x20;
|
||||||
public static int GcDeviceCertificateSize => 0x200;
|
public static int GcDeviceCertificateSize => 0x200;
|
||||||
public static int GcCardKeyAreaSize => 0x1000;
|
public static int GcCardKeyAreaSize => 0x1000;
|
||||||
|
public static int GcCardKeyAreaPageCount => 8;
|
||||||
|
public static int GcCertAreaStartPageAddress => 56;
|
||||||
}
|
}
|
|
@ -4,21 +4,38 @@ using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.FsSrv.Sf;
|
using LibHac.FsSrv.Sf;
|
||||||
using LibHac.FsSrv.Storage.Sf;
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
using LibHac.FsSystem;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
|
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
|
||||||
|
|
||||||
namespace LibHac.GcSrv;
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
public class DummyGameCardManager : IStorageDeviceManager, IStorageDeviceOperator
|
public class DummyGameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IGameCardKeyManager
|
||||||
{
|
{
|
||||||
public DummyGameCardManager()
|
private SharedRef<DummyEventNotifier> _eventNotifier;
|
||||||
|
|
||||||
|
// LibHac additions
|
||||||
|
private WeakRef<DummyGameCardManager> _selfReference;
|
||||||
|
|
||||||
|
private DummyGameCardManager()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_eventNotifier = new SharedRef<DummyEventNotifier>(new DummyEventNotifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedRef<DummyGameCardManager> CreateShared()
|
||||||
|
{
|
||||||
|
var manager = new DummyGameCardManager();
|
||||||
|
|
||||||
|
using var sharedManager = new SharedRef<DummyGameCardManager>(manager);
|
||||||
|
manager._selfReference.Set(in sharedManager);
|
||||||
|
|
||||||
|
return SharedRef<DummyGameCardManager>.CreateMove(ref sharedManager.Ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_eventNotifier.Destroy();
|
||||||
|
_selfReference.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result IsInserted(out bool isInserted)
|
public Result IsInserted(out bool isInserted)
|
||||||
|
@ -35,12 +52,20 @@ public class DummyGameCardManager : IStorageDeviceManager, IStorageDeviceOperato
|
||||||
|
|
||||||
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
outDetectionEvent.SetByCopy(in _eventNotifier);
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
using SharedRef<DummyGameCardManager> deviceOperator = SharedRef<DummyGameCardManager>.Create(in _selfReference);
|
||||||
|
|
||||||
|
if (!deviceOperator.HasValue)
|
||||||
|
return ResultFs.AllocationMemoryFailedInGameCardManagerG.Log();
|
||||||
|
|
||||||
|
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
|
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
|
||||||
|
@ -157,7 +182,7 @@ public class DummyGameCardManager : IStorageDeviceManager, IStorageDeviceOperato
|
||||||
{
|
{
|
||||||
case GameCardManagerOperationIdValue.IsGameCardActivationValid:
|
case GameCardManagerOperationIdValue.IsGameCardActivationValid:
|
||||||
{
|
{
|
||||||
if (outBuffer.Size < Unsafe.SizeOf<bool>())
|
if (outBuffer.Size < sizeof(bool))
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
outBuffer.As<bool>() = false;
|
outBuffer.As<bool>() = false;
|
||||||
|
@ -186,4 +211,9 @@ public class DummyGameCardManager : IStorageDeviceManager, IStorageDeviceOperato
|
||||||
|
|
||||||
return ResultFs.NotImplemented.Log();
|
return ResultFs.NotImplemented.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate)
|
||||||
|
{
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,9 +3,9 @@ using LibHac.FsSystem;
|
||||||
|
|
||||||
namespace LibHac.GcSrv;
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
internal class GameCardDeviceDetectionEventManager : CardDeviceDetectionEventManager
|
internal class GameCardDetectionEventManager : CardDeviceDetectionEventManager
|
||||||
{
|
{
|
||||||
public GameCardDeviceDetectionEventManager()
|
public GameCardDetectionEventManager()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
196
src/LibHac/GcSrv/GameCardDeviceOperator.cs
Normal file
196
src/LibHac/GcSrv/GameCardDeviceOperator.cs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSrv.Storage.Sf;
|
||||||
|
using LibHac.Gc;
|
||||||
|
using LibHac.Gc.Writer;
|
||||||
|
using LibHac.Os;
|
||||||
|
using LibHac.Sf;
|
||||||
|
using static LibHac.Gc.Values;
|
||||||
|
|
||||||
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
|
internal class GameCardDeviceOperator : IStorageDeviceOperator
|
||||||
|
{
|
||||||
|
private SharedRef<GameCardStorageDevice> _storageDevice;
|
||||||
|
|
||||||
|
// LibHac additions
|
||||||
|
private readonly GameCardDummy _gc;
|
||||||
|
|
||||||
|
public static uint BytesToPages(long byteCount)
|
||||||
|
{
|
||||||
|
return (uint)((ulong)byteCount / (ulong)GcPageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameCardDeviceOperator(ref SharedRef<GameCardStorageDevice> storageDevice, GameCardDummy gc)
|
||||||
|
{
|
||||||
|
_storageDevice = SharedRef<GameCardStorageDevice>.CreateMove(ref storageDevice);
|
||||||
|
_gc = gc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_storageDevice.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Operate(int operationId)
|
||||||
|
{
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
|
||||||
|
{
|
||||||
|
Result result;
|
||||||
|
var operation = (GameCardOperationIdValue)operationId;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardOperationIdValue.EraseGameCard:
|
||||||
|
{
|
||||||
|
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (buffer.Size != sizeof(long))
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.Writer.EraseAndWriteParameter((MemorySize)size, BytesToPages(buffer.As<long>()));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _storageDevice.Get.HandleGameCardAccessResult(result).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
|
||||||
|
{
|
||||||
|
Result result;
|
||||||
|
bytesWritten = 0;
|
||||||
|
var operation = (GameCardOperationIdValue)operationId;
|
||||||
|
|
||||||
|
using (var readLock = new SharedLock<ReaderWriterLock>())
|
||||||
|
{
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardOperationIdValue.GetGameCardIdSet:
|
||||||
|
{
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<GameCardIdSet>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.GetGameCardIdSet(out buffer.As<GameCardIdSet>());
|
||||||
|
bytesWritten = Unsafe.SizeOf<GameCardIdSet>();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GameCardOperationIdValue.GetGameCardDeviceId:
|
||||||
|
{
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (buffer.Size < GcCardDeviceIdSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.GetCardDeviceId(buffer.Buffer);
|
||||||
|
bytesWritten = GcCardDeviceIdSize;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GameCardOperationIdValue.GetGameCardImageHash:
|
||||||
|
{
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (buffer.Size < GcCardImageHashSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.GetCardImageHash(buffer.Buffer);
|
||||||
|
bytesWritten = GcCardImageHashSize;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GameCardOperationIdValue.GetGameCardDeviceCertificate:
|
||||||
|
{
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (buffer.Size < GcDeviceCertificateSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.GetCardDeviceCertificate(buffer.Buffer);
|
||||||
|
bytesWritten = GcDeviceCertificateSize;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GameCardOperationIdValue.GetGameCardStatus:
|
||||||
|
{
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (buffer.Size < Unsafe.SizeOf<GameCardStatus>())
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.GetCardStatus(out buffer.As<GameCardStatus>());
|
||||||
|
bytesWritten = Unsafe.SizeOf<GameCardStatus>();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _storageDevice.Get.HandleGameCardAccessResult(result).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out bytesWritten);
|
||||||
|
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
|
||||||
|
long offset, long size, int operationId)
|
||||||
|
{
|
||||||
|
Result result;
|
||||||
|
bytesWritten = 0;
|
||||||
|
var operation = (GameCardOperationIdValue)operationId;
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case GameCardOperationIdValue.ChallengeCardExistence:
|
||||||
|
{
|
||||||
|
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||||
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (outBuffer.Size < GcCardExistenceResponseDataSize)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
result = _gc.ChallengeCardExistence(outBuffer.Buffer, inBuffer1.Buffer, inBuffer2.Buffer);
|
||||||
|
bytesWritten = GcCardExistenceResponseDataSize;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _storageDevice.Get.HandleGameCardAccessResult(result).Ret();
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ using LibHac.Gc.Impl;
|
||||||
using LibHac.Gc.Writer;
|
using LibHac.Gc.Writer;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
|
using static LibHac.Gc.Values;
|
||||||
|
using static LibHac.GcSrv.GameCardDeviceOperator;
|
||||||
using IStorage = LibHac.FsSrv.Sf.IStorage;
|
using IStorage = LibHac.FsSrv.Sf.IStorage;
|
||||||
|
|
||||||
namespace LibHac.GcSrv;
|
namespace LibHac.GcSrv;
|
||||||
|
@ -31,23 +33,24 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
private bool _isFinalized;
|
private bool _isFinalized;
|
||||||
private CardState _state;
|
private CardState _state;
|
||||||
private GameCardHandle _currentHandle;
|
private GameCardHandle _currentHandle;
|
||||||
private GameCardDeviceDetectionEventManager _detectionEventManager;
|
private GameCardDetectionEventManager _detectionEventManager;
|
||||||
|
|
||||||
// LibHac additions
|
// LibHac additions
|
||||||
private WeakRef<GameCardManager> _selfReference;
|
private WeakRef<GameCardManager> _selfReference;
|
||||||
private readonly FileSystemServer _fsServer;
|
private readonly FileSystemServer _fsServer;
|
||||||
private readonly GameCardDummy _gc;
|
private readonly GameCardDummy _gc;
|
||||||
|
|
||||||
private GameCardManager(FileSystemServer fsServer)
|
private GameCardManager(GameCardDummy gc, FileSystemServer fsServer)
|
||||||
{
|
{
|
||||||
_rwLock = new ReaderWriterLock(fsServer.Hos.Os);
|
_rwLock = new ReaderWriterLock(fsServer.Hos.Os);
|
||||||
|
|
||||||
_fsServer = fsServer;
|
_fsServer = fsServer;
|
||||||
|
_gc = gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SharedRef<GameCardManager> CreateShared(FileSystemServer fsServer)
|
public static SharedRef<GameCardManager> CreateShared(GameCardDummy gc, FileSystemServer fsServer)
|
||||||
{
|
{
|
||||||
var manager = new GameCardManager(fsServer);
|
var manager = new GameCardManager(gc, fsServer);
|
||||||
|
|
||||||
using var sharedManager = new SharedRef<GameCardManager>(manager);
|
using var sharedManager = new SharedRef<GameCardManager>(manager);
|
||||||
manager._selfReference.Set(in sharedManager);
|
manager._selfReference.Set(in sharedManager);
|
||||||
|
@ -62,11 +65,8 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
_rwLock?.Dispose();
|
_rwLock?.Dispose();
|
||||||
_rwLock = null;
|
_rwLock = null;
|
||||||
}
|
|
||||||
|
|
||||||
public static uint BytesToPages(long byteCount)
|
_selfReference.Destroy();
|
||||||
{
|
|
||||||
return (uint)((ulong)byteCount / (ulong)Values.GcPageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeactivateAndChangeState()
|
private void DeactivateAndChangeState()
|
||||||
|
@ -102,6 +102,16 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
return HandleGameCardAccessResult(_gc.SetCardToSecureMode());
|
return HandleGameCardAccessResult(_gc.SetCardToSecureMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Result LockAndHandleGameCardAccessResult(Result result)
|
||||||
|
{
|
||||||
|
if (result.IsSuccess())
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
|
return HandleGameCardAccessResult(result).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
public Result IsInserted(out bool isInserted)
|
public Result IsInserted(out bool isInserted)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out isInserted);
|
UnsafeHelpers.SkipParamInit(out isInserted);
|
||||||
|
@ -129,7 +139,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
_gc.Initialize(default, default);
|
_gc.Initialize(default, default);
|
||||||
// Missing: Register the device buffer
|
// Missing: Register the device buffer
|
||||||
|
|
||||||
_detectionEventManager = new GameCardDeviceDetectionEventManager();
|
_detectionEventManager = new GameCardDetectionEventManager();
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -371,7 +381,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
public Result PutToSleep()
|
public Result PutToSleep()
|
||||||
{
|
{
|
||||||
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
_gc.PutToSleep();
|
|
||||||
|
if (_isInitialized)
|
||||||
|
_gc.PutToSleep();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -379,7 +391,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
public Result Awaken()
|
public Result Awaken()
|
||||||
{
|
{
|
||||||
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
_gc.Awaken();
|
|
||||||
|
if (_isInitialized)
|
||||||
|
_gc.Awaken();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -387,7 +401,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
public Result Shutdown()
|
public Result Shutdown()
|
||||||
{
|
{
|
||||||
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
_gc.PutToSleep();
|
|
||||||
|
if (_isInitialized)
|
||||||
|
_gc.PutToSleep();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -438,13 +454,15 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
case GameCardManagerOperationIdValue.SetVerifyEnableFlag:
|
case GameCardManagerOperationIdValue.SetVerifyEnableFlag:
|
||||||
|
{
|
||||||
if (buffer.Size < sizeof(bool))
|
if (buffer.Size < sizeof(bool))
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
SetVerifyEnableFlag(buffer.As<bool>());
|
SetVerifyEnableFlag(buffer.As<bool>());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
case GameCardManagerOperationIdValue.EraseAndWriteParamDirectly:
|
case GameCardManagerOperationIdValue.EraseAndWriteParamDirectly:
|
||||||
|
{
|
||||||
if (buffer.Size < Unsafe.SizeOf<DevCardParameter>())
|
if (buffer.Size < Unsafe.SizeOf<DevCardParameter>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
@ -452,6 +470,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
@ -482,6 +501,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
case GameCardManagerOperationIdValue.GetGameCardErrorInfo:
|
case GameCardManagerOperationIdValue.GetGameCardErrorInfo:
|
||||||
|
{
|
||||||
if (buffer.Size < Unsafe.SizeOf<GameCardErrorInfo>())
|
if (buffer.Size < Unsafe.SizeOf<GameCardErrorInfo>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
@ -490,8 +510,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
bytesWritten = Unsafe.SizeOf<GameCardErrorInfo>();
|
bytesWritten = Unsafe.SizeOf<GameCardErrorInfo>();
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
case GameCardManagerOperationIdValue.GetGameCardErrorReportInfo:
|
case GameCardManagerOperationIdValue.GetGameCardErrorReportInfo:
|
||||||
|
{
|
||||||
if (buffer.Size < Unsafe.SizeOf<GameCardErrorReportInfo>())
|
if (buffer.Size < Unsafe.SizeOf<GameCardErrorReportInfo>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
@ -500,8 +521,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
bytesWritten = Unsafe.SizeOf<GameCardErrorReportInfo>();
|
bytesWritten = Unsafe.SizeOf<GameCardErrorReportInfo>();
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
case GameCardManagerOperationIdValue.ReadParamDirectly:
|
case GameCardManagerOperationIdValue.ReadParamDirectly:
|
||||||
|
{
|
||||||
if (buffer.Size < Unsafe.SizeOf<DevCardParameter>())
|
if (buffer.Size < Unsafe.SizeOf<DevCardParameter>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
@ -510,6 +532,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
bytesWritten = Unsafe.SizeOf<DevCardParameter>();
|
bytesWritten = Unsafe.SizeOf<DevCardParameter>();
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
@ -536,6 +559,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
case GameCardManagerOperationIdValue.IsGameCardActivationValid:
|
case GameCardManagerOperationIdValue.IsGameCardActivationValid:
|
||||||
|
{
|
||||||
if (inBuffer.Size != sizeof(GameCardHandle))
|
if (inBuffer.Size != sizeof(GameCardHandle))
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
@ -546,9 +570,10 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
bytesWritten = sizeof(bool);
|
bytesWritten = sizeof(bool);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
case GameCardManagerOperationIdValue.GetGameCardAsicInfo:
|
case GameCardManagerOperationIdValue.GetGameCardAsicInfo:
|
||||||
if (inBuffer.Size != Values.GcAsicFirmwareSize)
|
{
|
||||||
|
if (inBuffer.Size != GcAsicFirmwareSize)
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
if (outBuffer.Size < Unsafe.SizeOf<RmaInformation>())
|
if (outBuffer.Size < Unsafe.SizeOf<RmaInformation>())
|
||||||
|
@ -561,20 +586,22 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
bytesWritten = Unsafe.SizeOf<RmaInformation>();
|
bytesWritten = Unsafe.SizeOf<RmaInformation>();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
case GameCardManagerOperationIdValue.GetGameCardDeviceIdForProdCard:
|
case GameCardManagerOperationIdValue.GetGameCardDeviceIdForProdCard:
|
||||||
if (inBuffer.Size < Values.GcPageSize)
|
{
|
||||||
|
if (inBuffer.Size < GcPageSize)
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
if (outBuffer.Size < Values.GcPageSize)
|
if (outBuffer.Size < GcPageSize)
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
res = GetGameCardDeviceIdForProdCard(outBuffer.Buffer, inBuffer.Buffer);
|
res = GetGameCardDeviceIdForProdCard(outBuffer.Buffer, inBuffer.Buffer);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
bytesWritten = Values.GcPageSize;
|
bytesWritten = GcPageSize;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
case GameCardManagerOperationIdValue.WriteToGameCardDirectly:
|
case GameCardManagerOperationIdValue.WriteToGameCardDirectly:
|
||||||
return WriteToGameCardDirectly(offset, outBuffer.Buffer.Slice(0, (int)size)).Ret();
|
return WriteToGameCardDirectly(offset, outBuffer.Buffer.Slice(0, (int)size)).Ret();
|
||||||
|
@ -601,6 +628,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
_gc.UnregisterDetectionEventCallback();
|
_gc.UnregisterDetectionEventCallback();
|
||||||
_isFinalized = true;
|
_isFinalized = true;
|
||||||
_gc.FinalizeGc();
|
_gc.FinalizeGc();
|
||||||
|
// nn::fssystem::PooledBuffer::Deallocate
|
||||||
// nn::gc::UnregisterDeviceVirtualAddress
|
// nn::gc::UnregisterDeviceVirtualAddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -650,7 +678,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out outRmaInfo);
|
UnsafeHelpers.SkipParamInit(out outRmaInfo);
|
||||||
|
|
||||||
Assert.SdkRequiresEqual(asicFirmwareBuffer.Length, Values.GcAsicFirmwareSize);
|
Assert.SdkRequiresEqual(asicFirmwareBuffer.Length, GcAsicFirmwareSize);
|
||||||
|
|
||||||
_gc.Writer.SetUserAsicFirmwareBuffer(asicFirmwareBuffer);
|
_gc.Writer.SetUserAsicFirmwareBuffer(asicFirmwareBuffer);
|
||||||
_gc.Writer.ChangeMode(AsicMode.Write);
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
|
@ -664,36 +692,36 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
private Result GetGameCardDeviceIdForProdCard(Span<byte> outBuffer, ReadOnlySpan<byte> devHeaderBuffer)
|
private Result GetGameCardDeviceIdForProdCard(Span<byte> outBuffer, ReadOnlySpan<byte> devHeaderBuffer)
|
||||||
{
|
{
|
||||||
Assert.SdkRequiresGreaterEqual(outBuffer.Length, Values.GcPageSize);
|
Assert.SdkRequiresGreaterEqual(outBuffer.Length, GcPageSize);
|
||||||
Assert.SdkRequiresGreaterEqual(devHeaderBuffer.Length, Values.GcPageSize);
|
Assert.SdkRequiresGreaterEqual(devHeaderBuffer.Length, GcPageSize);
|
||||||
|
|
||||||
Result res = InitializeGcLibrary();
|
Result res = InitializeGcLibrary();
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
||||||
|
|
||||||
int writeSize = Values.GcPageSize;
|
int writeSize = GcPageSize;
|
||||||
var pooledBuffer = new PooledBuffer(writeSize, writeSize);
|
using var pooledBuffer = new PooledBuffer(writeSize, writeSize);
|
||||||
Assert.SdkGreaterEqual(pooledBuffer.GetSize(), writeSize);
|
Assert.SdkGreaterEqual(pooledBuffer.GetSize(), writeSize);
|
||||||
|
|
||||||
// Read the current card header into a temporary buffer
|
// Read the current card header into a temporary buffer
|
||||||
_gc.Writer.ChangeMode(AsicMode.Read);
|
_gc.Writer.ChangeMode(AsicMode.Read);
|
||||||
|
|
||||||
Span<byte> tmpBuffer = stackalloc byte[writeSize];
|
Span<byte> originalHeaderBuffer = stackalloc byte[writeSize];
|
||||||
tmpBuffer.Clear();
|
originalHeaderBuffer.Clear();
|
||||||
|
|
||||||
_gc.GetCardHeader(pooledBuffer.GetBuffer());
|
_gc.GetCardHeader(pooledBuffer.GetBuffer());
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
pooledBuffer.GetBuffer().CopyTo(tmpBuffer);
|
pooledBuffer.GetBuffer().CopyTo(originalHeaderBuffer);
|
||||||
|
|
||||||
// Write the provided card header
|
// Write the provided card header
|
||||||
_gc.Writer.ChangeMode(AsicMode.Write);
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
res = HandleGameCardAccessResult(_gc.Writer.ActivateForWriter());
|
res = ActivateGameCardForWriter();
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
devHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
devHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
||||||
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), 8, 1);
|
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), (uint)GcCardKeyAreaPageCount, 1);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
// Read the cert area
|
// Read the cert area
|
||||||
|
@ -701,7 +729,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
res = _gc.Activate();
|
res = _gc.Activate();
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
res = _gc.Read(pooledBuffer.GetBuffer(), 0x38, 1);
|
res = _gc.Read(pooledBuffer.GetBuffer(), (uint)GcCertAreaStartPageAddress, 1);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
Span<byte> deviceCert = stackalloc byte[writeSize];
|
Span<byte> deviceCert = stackalloc byte[writeSize];
|
||||||
|
@ -709,11 +737,11 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
// Restore the original card header
|
// Restore the original card header
|
||||||
_gc.Writer.ChangeMode(AsicMode.Write);
|
_gc.Writer.ChangeMode(AsicMode.Write);
|
||||||
res = HandleGameCardAccessResult(_gc.Writer.ActivateForWriter());
|
res = ActivateGameCardForWriter();
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
tmpBuffer.CopyTo(pooledBuffer.GetBuffer());
|
originalHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
||||||
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), 8, 1);
|
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), (uint)GcCardKeyAreaPageCount, 1);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
deviceCert.CopyTo(outBuffer);
|
deviceCert.CopyTo(outBuffer);
|
||||||
|
@ -749,25 +777,17 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
private Result WriteToGameCardDirectly(long offset, Span<byte> buffer)
|
private Result WriteToGameCardDirectly(long offset, Span<byte> buffer)
|
||||||
{
|
{
|
||||||
Result res;
|
Result result;
|
||||||
|
|
||||||
using (new SharedLock<ReaderWriterLock>(_rwLock))
|
using (new SharedLock<ReaderWriterLock>(_rwLock))
|
||||||
{
|
{
|
||||||
if (buffer.Length == 0)
|
if (buffer.Length == 0)
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
|
||||||
res = _gc.Writer.Write(buffer, BytesToPages(offset), BytesToPages(buffer.Length));
|
result = _gc.Writer.Write(buffer, BytesToPages(offset), BytesToPages(buffer.Length));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res != Result.Success)
|
return LockAndHandleGameCardAccessResult(result).Ret();
|
||||||
{
|
|
||||||
using var writeLock = new UniqueLock<ReaderWriterLock>(_rwLock);
|
|
||||||
res = HandleGameCardAccessResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.IsFailure()) return res.Miss();
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result ForceEraseGameCard()
|
private Result ForceEraseGameCard()
|
||||||
|
@ -786,24 +806,26 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
public Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle)
|
public Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle)
|
||||||
{
|
{
|
||||||
using var readLock = new SharedLock<ReaderWriterLock>(_rwLock);
|
using (var readLock = new SharedLock<ReaderWriterLock>(_rwLock))
|
||||||
|
|
||||||
if (_state != CardState.Initial && !_gc.IsCardActivationValid())
|
|
||||||
{
|
{
|
||||||
readLock.Unlock();
|
if (_state == CardState.Initial || _gc.IsCardActivationValid())
|
||||||
Invalidate().IgnoreResult();
|
{
|
||||||
|
if (_currentHandle == handle)
|
||||||
|
{
|
||||||
|
outLock.Set(ref readLock.Ref());
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
return ResultFs.GameCardFsCheckHandleInAcquireReadLock.Log();
|
return ResultFs.GameCardFsCheckHandleInAcquireReadLock.Log();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentHandle != handle)
|
Invalidate().IgnoreResult();
|
||||||
return ResultFs.GameCardFsCheckHandleInAcquireReadLock.Log();
|
|
||||||
|
|
||||||
outLock.Set(ref readLock.Ref());
|
return ResultFs.GameCardFsCheckHandleInAcquireReadLock.Log();
|
||||||
return Result.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle handle,
|
public Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle inOutHandle,
|
||||||
ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
||||||
{
|
{
|
||||||
using (var readLock = new SharedLock<ReaderWriterLock>(_rwLock))
|
using (var readLock = new SharedLock<ReaderWriterLock>(_rwLock))
|
||||||
|
@ -818,7 +840,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
readLock.Unlock();
|
readLock.Unlock();
|
||||||
Invalidate().IgnoreResult();
|
Invalidate().IgnoreResult();
|
||||||
}
|
}
|
||||||
else if (_currentHandle == handle)
|
else if (_currentHandle == inOutHandle)
|
||||||
{
|
{
|
||||||
outLock.Set(ref readLock.Ref());
|
outLock.Set(ref readLock.Ref());
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -834,8 +856,8 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<byte> currentCardDeviceId = stackalloc byte[Values.GcCardDeviceIdSize];
|
Span<byte> currentCardDeviceId = stackalloc byte[GcCardDeviceIdSize];
|
||||||
Span<byte> currentCardImageHash = stackalloc byte[Values.GcCardImageHashSize];
|
Span<byte> currentCardImageHash = stackalloc byte[GcCardImageHashSize];
|
||||||
|
|
||||||
Result res = HandleGameCardAccessResult(_gc.GetCardDeviceId(currentCardDeviceId));
|
Result res = HandleGameCardAccessResult(_gc.GetCardDeviceId(currentCardDeviceId));
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
@ -843,8 +865,8 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
res = HandleGameCardAccessResult(_gc.GetCardImageHash(currentCardImageHash));
|
res = HandleGameCardAccessResult(_gc.GetCardImageHash(currentCardImageHash));
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
if (!Crypto.CryptoUtil.IsSameBytes(currentCardDeviceId, cardDeviceId, Values.GcCardDeviceIdSize) ||
|
if (!Crypto.CryptoUtil.IsSameBytes(currentCardDeviceId, cardDeviceId, GcCardDeviceIdSize) ||
|
||||||
!Crypto.CryptoUtil.IsSameBytes(currentCardImageHash, cardImageHash, Values.GcCardImageHashSize))
|
!Crypto.CryptoUtil.IsSameBytes(currentCardImageHash, cardImageHash, GcCardImageHashSize))
|
||||||
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
return ResultFs.GameCardFsCheckModeInAcquireSecureLock.Log();
|
||||||
|
|
||||||
res = GetHandle(out newHandle);
|
res = GetHandle(out newHandle);
|
||||||
|
@ -856,7 +878,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
Result res = AcquireReadLock(ref readLock.Ref(), newHandle);
|
Result res = AcquireReadLock(ref readLock.Ref(), newHandle);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
handle = newHandle;
|
inOutHandle = newHandle;
|
||||||
outLock.Set(ref readLock.Ref());
|
outLock.Set(ref readLock.Ref());
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -876,6 +898,8 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
|
|
||||||
public Result HandleGameCardAccessResult(Result result)
|
public Result HandleGameCardAccessResult(Result result)
|
||||||
{
|
{
|
||||||
|
Assert.SdkRequires(_rwLock.IsWriteLockHeldByCurrentThread());
|
||||||
|
|
||||||
if (result.IsFailure())
|
if (result.IsFailure())
|
||||||
{
|
{
|
||||||
DeactivateAndChangeState();
|
DeactivateAndChangeState();
|
||||||
|
|
|
@ -4,7 +4,10 @@ using LibHac.Common;
|
||||||
using LibHac.Diag;
|
using LibHac.Diag;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Gc;
|
using LibHac.Gc;
|
||||||
|
using LibHac.Sf;
|
||||||
using static LibHac.Gc.Values;
|
using static LibHac.Gc.Values;
|
||||||
|
using static LibHac.GcSrv.GameCardDeviceOperator;
|
||||||
|
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
|
||||||
|
|
||||||
namespace LibHac.GcSrv;
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
|
@ -38,8 +41,7 @@ internal class ReadOnlyGameCardStorage : IStorage
|
||||||
|
|
||||||
// Missing: Allocate a device buffer if the destination buffer is not one
|
// Missing: Allocate a device buffer if the destination buffer is not one
|
||||||
|
|
||||||
return _gc.Read(destination, GameCardManager.BytesToPages(offset),
|
return _gc.Read(destination, BytesToPages(offset), BytesToPages(destination.Length)).Ret();
|
||||||
GameCardManager.BytesToPages(destination.Length)).Ret();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Write(long offset, ReadOnlySpan<byte> source)
|
public override Result Write(long offset, ReadOnlySpan<byte> source)
|
||||||
|
@ -123,8 +125,7 @@ internal class WriteOnlyGameCardStorage : IStorage
|
||||||
|
|
||||||
// Missing: Allocate a device buffer if the destination buffer is not one
|
// Missing: Allocate a device buffer if the destination buffer is not one
|
||||||
|
|
||||||
return _gc.Writer.Write(source, GameCardManager.BytesToPages(offset),
|
return _gc.Writer.Write(source, BytesToPages(offset), BytesToPages(source.Length)).Ret();
|
||||||
GameCardManager.BytesToPages(source.Length)).Ret();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Flush()
|
public override Result Flush()
|
||||||
|
@ -154,3 +155,51 @@ internal class WriteOnlyGameCardStorage : IStorage
|
||||||
return ResultFs.NotImplemented.Log();
|
return ResultFs.NotImplemented.Log();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal abstract class GameCardStorageInterfaceAdapter : IStorageSf
|
||||||
|
{
|
||||||
|
private SharedRef<IStorage> _baseStorage;
|
||||||
|
|
||||||
|
protected GameCardStorageInterfaceAdapter(ref SharedRef<IStorage> baseStorage)
|
||||||
|
{
|
||||||
|
_baseStorage = SharedRef<IStorage>.CreateMove(ref baseStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
_baseStorage.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Result Read(long offset, OutBuffer destination, long size)
|
||||||
|
{
|
||||||
|
return _baseStorage.Get.Read(offset, destination.Buffer.Slice(0, (int)size)).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Result Write(long offset, InBuffer source, long size)
|
||||||
|
{
|
||||||
|
return _baseStorage.Get.Write(offset, source.Buffer.Slice(0, (int)size)).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Result Flush()
|
||||||
|
{
|
||||||
|
return _baseStorage.Get.Flush().Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Result SetSize(long size)
|
||||||
|
{
|
||||||
|
return _baseStorage.Get.SetSize(size).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Result GetSize(out long size)
|
||||||
|
{
|
||||||
|
return _baseStorage.Get.GetSize(out size).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out rangeInfo);
|
||||||
|
|
||||||
|
return _baseStorage.Get.OperateRange(SpanHelpers.AsByteSpan(ref rangeInfo), (OperationId)operationId, offset,
|
||||||
|
size, ReadOnlySpan<byte>.Empty).Ret();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,58 +7,9 @@ using LibHac.FsSrv.Storage.Sf;
|
||||||
using LibHac.Gc;
|
using LibHac.Gc;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
|
|
||||||
|
|
||||||
namespace LibHac.GcSrv;
|
namespace LibHac.GcSrv;
|
||||||
|
|
||||||
internal abstract class GameCardStorageInterfaceAdapter : IStorageSf
|
|
||||||
{
|
|
||||||
private SharedRef<IStorage> _baseStorage;
|
|
||||||
|
|
||||||
protected GameCardStorageInterfaceAdapter(ref SharedRef<IStorage> baseStorage)
|
|
||||||
{
|
|
||||||
_baseStorage = SharedRef<IStorage>.CreateMove(ref baseStorage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Dispose()
|
|
||||||
{
|
|
||||||
_baseStorage.Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result Read(long offset, OutBuffer destination, long size)
|
|
||||||
{
|
|
||||||
return _baseStorage.Get.Read(offset, destination.Buffer.Slice(0, (int)size)).Ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result Write(long offset, InBuffer source, long size)
|
|
||||||
{
|
|
||||||
return _baseStorage.Get.Write(offset, source.Buffer.Slice(0, (int)size)).Ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result Flush()
|
|
||||||
{
|
|
||||||
return _baseStorage.Get.Flush().Ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result SetSize(long size)
|
|
||||||
{
|
|
||||||
return _baseStorage.Get.SetSize(size).Ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result GetSize(out long size)
|
|
||||||
{
|
|
||||||
return _baseStorage.Get.GetSize(out size).Ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size)
|
|
||||||
{
|
|
||||||
UnsafeHelpers.SkipParamInit(out rangeInfo);
|
|
||||||
|
|
||||||
return _baseStorage.Get.OperateRange(SpanHelpers.AsByteSpan(ref rangeInfo), (OperationId)operationId, offset,
|
|
||||||
size, ReadOnlySpan<byte>.Empty).Ret();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorageDevice
|
internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorageDevice
|
||||||
{
|
{
|
||||||
private SharedRef<IGameCardManager> _manager;
|
private SharedRef<IGameCardManager> _manager;
|
||||||
|
@ -67,16 +18,23 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
private Array16<byte> _cardDeviceId;
|
private Array16<byte> _cardDeviceId;
|
||||||
private Array32<byte> _cardImageHash;
|
private Array32<byte> _cardImageHash;
|
||||||
|
|
||||||
public GameCardStorageDevice(ref SharedRef<IGameCardManager> manager, ref SharedRef<IStorage> baseStorage,
|
// LibHac additions
|
||||||
GameCardHandle handle) : base(ref baseStorage)
|
private WeakRef<GameCardStorageDevice> _selfReference;
|
||||||
|
private readonly GameCardDummy _gc;
|
||||||
|
|
||||||
|
private GameCardStorageDevice(GameCardDummy gc, ref SharedRef<IGameCardManager> manager,
|
||||||
|
ref SharedRef<IStorage> baseStorage, GameCardHandle handle) : base(ref baseStorage)
|
||||||
{
|
{
|
||||||
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
||||||
_handle = handle;
|
_handle = handle;
|
||||||
_isSecure = false;
|
_isSecure = false;
|
||||||
|
|
||||||
|
_gc = gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameCardStorageDevice(ref SharedRef<IGameCardManager> manager, ref SharedRef<IStorage> baseStorage,
|
private GameCardStorageDevice(GameCardDummy gc, ref SharedRef<IGameCardManager> manager,
|
||||||
GameCardHandle handle, bool isSecure, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
ref SharedRef<IStorage> baseStorage, GameCardHandle handle, bool isSecure, ReadOnlySpan<byte> cardDeviceId,
|
||||||
|
ReadOnlySpan<byte> cardImageHash)
|
||||||
: base(ref baseStorage)
|
: base(ref baseStorage)
|
||||||
{
|
{
|
||||||
Assert.SdkRequiresEqual(cardDeviceId.Length, Values.GcCardDeviceIdSize);
|
Assert.SdkRequiresEqual(cardDeviceId.Length, Values.GcCardDeviceIdSize);
|
||||||
|
@ -88,27 +46,49 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
|
|
||||||
cardDeviceId.CopyTo(_cardDeviceId.Items);
|
cardDeviceId.CopyTo(_cardDeviceId.Items);
|
||||||
cardImageHash.CopyTo(_cardImageHash.Items);
|
cardImageHash.CopyTo(_cardImageHash.Items);
|
||||||
|
|
||||||
|
_gc = gc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedRef<GameCardStorageDevice> CreateShared(GameCardDummy gc,
|
||||||
|
ref SharedRef<IGameCardManager> manager, ref SharedRef<IStorage> baseStorage, GameCardHandle handle)
|
||||||
|
{
|
||||||
|
var storageDevice = new GameCardStorageDevice(gc, ref manager, ref baseStorage, handle);
|
||||||
|
|
||||||
|
using var sharedStorageDevice = new SharedRef<GameCardStorageDevice>(storageDevice);
|
||||||
|
storageDevice._selfReference.Set(in sharedStorageDevice);
|
||||||
|
|
||||||
|
return SharedRef<GameCardStorageDevice>.CreateMove(ref sharedStorageDevice.Ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedRef<GameCardStorageDevice> CreateShared(GameCardDummy gc,
|
||||||
|
ref SharedRef<IGameCardManager> manager, ref SharedRef<IStorage> baseStorage, GameCardHandle handle,
|
||||||
|
bool isSecure, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
||||||
|
{
|
||||||
|
var storageDevice = new GameCardStorageDevice(gc, ref manager, ref baseStorage, handle, isSecure, cardDeviceId,
|
||||||
|
cardImageHash);
|
||||||
|
|
||||||
|
using var sharedStorageDevice = new SharedRef<GameCardStorageDevice>(storageDevice);
|
||||||
|
storageDevice._selfReference.Set(in sharedStorageDevice);
|
||||||
|
|
||||||
|
return SharedRef<GameCardStorageDevice>.CreateMove(ref sharedStorageDevice.Ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_manager.Destroy();
|
_manager.Destroy();
|
||||||
|
_selfReference.Destroy();
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock)
|
public Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock)
|
||||||
{
|
{
|
||||||
if (_isSecure)
|
Result res = _isSecure
|
||||||
{
|
? _manager.Get.AcquireSecureLock(ref outLock, ref _handle, _cardDeviceId, _cardImageHash)
|
||||||
Result res = _manager.Get.AcquireSecureLock(ref outLock, ref _handle, _cardDeviceId, _cardImageHash);
|
: _manager.Get.AcquireReadLock(ref outLock, _handle);
|
||||||
if (res.IsFailure()) return res.Miss();
|
|
||||||
}
|
if (res.IsFailure()) return res.Miss();
|
||||||
else
|
|
||||||
{
|
|
||||||
Result res = _manager.Get.AcquireReadLock(ref outLock, _handle);
|
|
||||||
if (res.IsFailure()) return res.Miss();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -118,11 +98,23 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
return _manager.Get.AcquireWriteLock(ref outLock).Ret();
|
return _manager.Get.AcquireWriteLock(ref outLock).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result HandleGameCardAccessResult(Result result)
|
private Result HandleGameCardAccessResultImpl(Result result)
|
||||||
{
|
{
|
||||||
return _manager.Get.HandleGameCardAccessResult(result);
|
return _manager.Get.HandleGameCardAccessResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result HandleGameCardAccessResult(Result result)
|
||||||
|
{
|
||||||
|
if (result.IsSuccess())
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
using var writeLock = new UniqueLock<ReaderWriterLock>();
|
||||||
|
Result res = AcquireWriteLock(ref writeLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return HandleGameCardAccessResultImpl(result).Ret();
|
||||||
|
}
|
||||||
|
|
||||||
public Result GetHandle(out GameCardHandle handle)
|
public Result GetHandle(out GameCardHandle handle)
|
||||||
{
|
{
|
||||||
handle = _handle;
|
handle = _handle;
|
||||||
|
@ -140,7 +132,23 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
|
|
||||||
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||||
|
|
||||||
|
Result res = AcquireReadLock(ref readLock.Ref());
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using SharedRef<GameCardStorageDevice> storageDevice =
|
||||||
|
SharedRef<GameCardStorageDevice>.Create(in _selfReference);
|
||||||
|
|
||||||
|
using var deviceOperator =
|
||||||
|
new SharedRef<GameCardDeviceOperator>(new GameCardDeviceOperator(ref storageDevice.Ref, _gc));
|
||||||
|
|
||||||
|
if (!deviceOperator.HasValue)
|
||||||
|
return ResultFs.AllocationMemoryFailedInGameCardManagerG.Log();
|
||||||
|
|
||||||
|
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Result Read(long offset, OutBuffer destination, long size)
|
public override Result Read(long offset, OutBuffer destination, long size)
|
||||||
|
@ -182,15 +190,6 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
resultGetSize = base.GetSize(out size);
|
resultGetSize = base.GetSize(out size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultGetSize.IsSuccess())
|
return HandleGameCardAccessResult(resultGetSize).Ret();
|
||||||
return Result.Success;
|
|
||||||
|
|
||||||
using (var writeLock = new UniqueLock<ReaderWriterLock>())
|
|
||||||
{
|
|
||||||
Result res = AcquireWriteLock(ref writeLock.Ref());
|
|
||||||
if (res.IsFailure()) return res.Miss();
|
|
||||||
|
|
||||||
return HandleGameCardAccessResult(resultGetSize).Ret();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ namespace LibHac.GcSrv;
|
||||||
internal interface IGameCardManager : IDisposable
|
internal interface IGameCardManager : IDisposable
|
||||||
{
|
{
|
||||||
Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle);
|
Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle);
|
||||||
Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle handle, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash);
|
Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle inOutHandle, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash);
|
||||||
Result AcquireWriteLock(ref UniqueLock<ReaderWriterLock> outLock);
|
Result AcquireWriteLock(ref UniqueLock<ReaderWriterLock> outLock);
|
||||||
Result HandleGameCardAccessResult(Result result);
|
Result HandleGameCardAccessResult(Result result);
|
||||||
Result GetHandle(out GameCardHandle outHandle);
|
Result GetHandle(out GameCardHandle outHandle);
|
||||||
|
|
Loading…
Reference in a new issue