mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add GameCardStorageDevice
This commit is contained in:
parent
43d63086bf
commit
f4c59771cb
7 changed files with 400 additions and 7 deletions
|
@ -7,7 +7,7 @@ namespace LibHac.FsSrv.Storage.Sf;
|
|||
// StorageServiceObjectAdapter is a template that is used with either IStorage or IStorageDevice
|
||||
public interface IStorageDevice : IStorage
|
||||
{
|
||||
Result GetHandle(out uint handle);
|
||||
Result GetHandle(out GameCardHandle handle);
|
||||
Result IsHandleValid(out bool isValid);
|
||||
Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator);
|
||||
|
||||
|
|
|
@ -8,4 +8,5 @@ public static class Values
|
|||
public static int GcCardExistenceResponseDataSize => 0x58;
|
||||
public static int GcCardImageHashSize => 0x20;
|
||||
public static int GcDeviceCertificateSize => 0x200;
|
||||
public static int GcCardKeyAreaSize => 0x1000;
|
||||
}
|
|
@ -16,7 +16,7 @@ using IStorage = LibHac.FsSrv.Sf.IStorage;
|
|||
|
||||
namespace LibHac.GcSrv;
|
||||
|
||||
public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IGameCardDeviceManager
|
||||
public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IGameCardManager, IGameCardKeyManager
|
||||
{
|
||||
private enum CardState
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
_rwLock = null;
|
||||
}
|
||||
|
||||
private uint BytesToPages(long byteCount)
|
||||
public static uint BytesToPages(long byteCount)
|
||||
{
|
||||
return (uint)((ulong)byteCount / (ulong)Values.GcPageSize);
|
||||
}
|
||||
|
@ -320,15 +320,50 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
|
||||
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res = InitializeGcLibrary();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using SharedRef<GameCardManager> deviceOperator = SharedRef<GameCardManager>.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)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res = InitializeGcLibrary();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var storageDevice = new SharedRef<IStorageDevice>();
|
||||
|
||||
res = OpenDeviceImpl(ref storageDevice.Ref, (OpenGameCardAttribute)attribute);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outStorageDevice.SetByMove(ref storageDevice.Ref);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenStorage(ref SharedRef<IStorage> outStorage, ulong attribute)
|
||||
{
|
||||
Result res = InitializeGcLibrary();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var storageDevice = new SharedRef<IStorageDevice>();
|
||||
|
||||
res = OpenDeviceImpl(ref storageDevice.Ref, (OpenGameCardAttribute)attribute);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outStorage.SetByMove(ref storageDevice.Ref);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result OpenDeviceImpl(ref SharedRef<IStorageDevice> outStorageDevice, OpenGameCardAttribute attribute)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -894,4 +929,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
{
|
||||
return _state == CardState.Secure;
|
||||
}
|
||||
|
||||
public void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
156
src/LibHac/GcSrv/GameCardStorage.cs
Normal file
156
src/LibHac/GcSrv/GameCardStorage.cs
Normal file
|
@ -0,0 +1,156 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Gc;
|
||||
using static LibHac.Gc.Values;
|
||||
|
||||
namespace LibHac.GcSrv;
|
||||
|
||||
internal class ReadOnlyGameCardStorage : IStorage
|
||||
{
|
||||
private SharedRef<IGameCardManager> _deviceManager;
|
||||
|
||||
// LibHac additions
|
||||
private readonly GameCardDummy _gc;
|
||||
|
||||
public ReadOnlyGameCardStorage(ref SharedRef<IGameCardManager> deviceManger, GameCardDummy gc)
|
||||
{
|
||||
_deviceManager = SharedRef<IGameCardManager>.CreateMove(ref deviceManger);
|
||||
_gc = gc;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_deviceManager.Destroy();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public override Result Read(long offset, Span<byte> destination)
|
||||
{
|
||||
Assert.SdkRequiresAligned(offset, GcPageSize);
|
||||
Assert.SdkRequiresAligned(destination.Length, GcPageSize);
|
||||
|
||||
if (destination.Length == 0)
|
||||
return Result.Success;
|
||||
|
||||
// Missing: Allocate a device buffer if the destination buffer is not one
|
||||
|
||||
return _gc.Read(destination, GameCardManager.BytesToPages(offset),
|
||||
GameCardManager.BytesToPages(destination.Length)).Ret();
|
||||
}
|
||||
|
||||
public override Result Write(long offset, ReadOnlySpan<byte> source)
|
||||
{
|
||||
return ResultFs.UnsupportedWriteForReadOnlyGameCardStorage.Log();
|
||||
}
|
||||
|
||||
public override Result Flush()
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out size);
|
||||
|
||||
Result res = _gc.GetCardStatus(out GameCardStatus status);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
size = status.Size;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result SetSize(long size)
|
||||
{
|
||||
return ResultFs.UnsupportedSetSizeForReadOnlyGameCardStorage.Log();
|
||||
}
|
||||
|
||||
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||
ReadOnlySpan<byte> inBuffer)
|
||||
{
|
||||
switch (operationId)
|
||||
{
|
||||
case OperationId.InvalidateCache:
|
||||
return Result.Success;
|
||||
case OperationId.QueryRange:
|
||||
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer).Clear();
|
||||
|
||||
return Result.Success;
|
||||
default:
|
||||
return ResultFs.UnsupportedOperateRangeForReadOnlyGameCardStorage.Log();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class WriteOnlyGameCardStorage : IStorage
|
||||
{
|
||||
private SharedRef<IGameCardManager> _deviceManager;
|
||||
|
||||
// LibHac additions
|
||||
private readonly GameCardDummy _gc;
|
||||
|
||||
public WriteOnlyGameCardStorage(ref SharedRef<IGameCardManager> deviceManger, GameCardDummy gc)
|
||||
{
|
||||
_deviceManager = SharedRef<IGameCardManager>.CreateMove(ref deviceManger);
|
||||
_gc = gc;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_deviceManager.Destroy();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public override Result Read(long offset, Span<byte> destination)
|
||||
{
|
||||
return ResultFs.UnsupportedReadForWriteOnlyGameCardStorage.Log();
|
||||
}
|
||||
|
||||
public override Result Write(long offset, ReadOnlySpan<byte> source)
|
||||
{
|
||||
Assert.SdkRequiresAligned(offset, GcPageSize);
|
||||
Assert.SdkRequiresAligned(source.Length, GcPageSize);
|
||||
|
||||
if (source.Length == 0)
|
||||
return Result.Success;
|
||||
|
||||
// Missing: Allocate a device buffer if the destination buffer is not one
|
||||
|
||||
return _gc.Writer.Write(source, GameCardManager.BytesToPages(offset),
|
||||
GameCardManager.BytesToPages(source.Length)).Ret();
|
||||
}
|
||||
|
||||
public override Result Flush()
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out size);
|
||||
|
||||
Result res = _gc.Writer.GetCardAvailableRawSize(out long gameCardSize);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
size = gameCardSize + GcCardKeyAreaSize;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result SetSize(long size)
|
||||
{
|
||||
return ResultFs.UnsupportedSetSizeForWriteOnlyGameCardStorage.Log();
|
||||
}
|
||||
|
||||
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||
ReadOnlySpan<byte> inBuffer)
|
||||
{
|
||||
return ResultFs.NotImplemented.Log();
|
||||
}
|
||||
}
|
196
src/LibHac/GcSrv/GameCardStorageDevice.cs
Normal file
196
src/LibHac/GcSrv/GameCardStorageDevice.cs
Normal file
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSrv.Storage.Sf;
|
||||
using LibHac.Gc;
|
||||
using LibHac.Os;
|
||||
using LibHac.Sf;
|
||||
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
|
||||
|
||||
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
|
||||
{
|
||||
private SharedRef<IGameCardManager> _manager;
|
||||
private GameCardHandle _handle;
|
||||
private bool _isSecure;
|
||||
private Array16<byte> _cardDeviceId;
|
||||
private Array32<byte> _cardImageHash;
|
||||
|
||||
public GameCardStorageDevice(ref SharedRef<IGameCardManager> manager, ref SharedRef<IStorage> baseStorage,
|
||||
GameCardHandle handle) : base(ref baseStorage)
|
||||
{
|
||||
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
||||
_handle = handle;
|
||||
_isSecure = false;
|
||||
}
|
||||
|
||||
public GameCardStorageDevice(ref SharedRef<IGameCardManager> manager, ref SharedRef<IStorage> baseStorage,
|
||||
GameCardHandle handle, bool isSecure, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
||||
: base(ref baseStorage)
|
||||
{
|
||||
Assert.SdkRequiresEqual(cardDeviceId.Length, Values.GcCardDeviceIdSize);
|
||||
Assert.SdkRequiresEqual(cardImageHash.Length, Values.GcCardImageHashSize);
|
||||
|
||||
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
||||
_handle = handle;
|
||||
_isSecure = isSecure;
|
||||
|
||||
cardDeviceId.CopyTo(_cardDeviceId.Items);
|
||||
cardImageHash.CopyTo(_cardImageHash.Items);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_manager.Destroy();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock)
|
||||
{
|
||||
if (_isSecure)
|
||||
{
|
||||
Result res = _manager.Get.AcquireSecureLock(ref outLock, ref _handle, _cardDeviceId, _cardImageHash);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
}
|
||||
else
|
||||
{
|
||||
Result res = _manager.Get.AcquireReadLock(ref outLock, _handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result AcquireWriteLock(ref UniqueLock<ReaderWriterLock> outLock)
|
||||
{
|
||||
return _manager.Get.AcquireWriteLock(ref outLock).Ret();
|
||||
}
|
||||
|
||||
public Result HandleGameCardAccessResult(Result result)
|
||||
{
|
||||
return _manager.Get.HandleGameCardAccessResult(result);
|
||||
}
|
||||
|
||||
public Result GetHandle(out GameCardHandle handle)
|
||||
{
|
||||
handle = _handle;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result IsHandleValid(out bool isValid)
|
||||
{
|
||||
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||
isValid = _manager.Get.AcquireReadLock(ref readLock.Ref(), _handle).IsSuccess();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Result Read(long offset, OutBuffer destination, long size)
|
||||
{
|
||||
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||
|
||||
Result res = AcquireReadLock(ref readLock.Ref());
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = base.Read(offset, destination, size);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result Write(long offset, InBuffer source, long size)
|
||||
{
|
||||
using var readLock = new SharedLock<ReaderWriterLock>();
|
||||
|
||||
Result res = AcquireReadLock(ref readLock.Ref());
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = base.Write(offset, source, size);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
{
|
||||
Result resultGetSize;
|
||||
UnsafeHelpers.SkipParamInit(out size);
|
||||
|
||||
using (var readLock = new SharedLock<ReaderWriterLock>())
|
||||
{
|
||||
Result res = AcquireReadLock(ref readLock.Ref());
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
resultGetSize = base.GetSize(out size);
|
||||
}
|
||||
|
||||
if (resultGetSize.IsSuccess())
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace LibHac.GcSrv;
|
||||
|
||||
public interface IGameCardKeyManager
|
||||
public interface IGameCardKeyManager : IDisposable
|
||||
{
|
||||
void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate);
|
||||
}
|
|
@ -3,7 +3,7 @@ using LibHac.Os;
|
|||
|
||||
namespace LibHac.GcSrv;
|
||||
|
||||
internal interface IGameCardDeviceManager
|
||||
internal interface IGameCardManager : IDisposable
|
||||
{
|
||||
Result AcquireReadLock(ref SharedLock<ReaderWriterLock> outLock, GameCardHandle handle);
|
||||
Result AcquireSecureLock(ref SharedLock<ReaderWriterLock> outLock, ref GameCardHandle handle, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash);
|
Loading…
Reference in a new issue