Add GameCardDeviceOperator

This commit is contained in:
Alex Barney 2022-05-23 13:09:42 -07:00
parent f4c59771cb
commit e18f6a9daf
10 changed files with 474 additions and 155 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View 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();
}
}

View file

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

View file

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

View file

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

View file

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