mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add a simple emulated GC API implementation
This commit is contained in:
parent
80588438c0
commit
fab5efc4de
19 changed files with 506 additions and 438 deletions
|
@ -14,7 +14,7 @@ public class DefaultFsServerObjects
|
|||
public FileSystemCreatorInterfaces FsCreators { get; set; }
|
||||
public EmulatedGameCard GameCard { get; set; }
|
||||
public SdmmcApi Sdmmc { get; set; }
|
||||
public GameCardDummy GameCardNew { get; set; }
|
||||
public GameCardEmulated GameCardNew { get; set; }
|
||||
public EmulatedStorageDeviceManagerFactory StorageDeviceManagerFactory { get; set; }
|
||||
|
||||
public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, KeySet keySet,
|
||||
|
@ -23,10 +23,10 @@ public class DefaultFsServerObjects
|
|||
var creators = new FileSystemCreatorInterfaces();
|
||||
var gameCard = new EmulatedGameCard(keySet);
|
||||
|
||||
var gameCardNew = new GameCardDummy();
|
||||
var gameCardNew = new GameCardEmulated();
|
||||
var sdmmcNew = new SdmmcApi(fsServer);
|
||||
|
||||
var gcStorageCreator = new EmulatedGameCardStorageCreator(gameCard);
|
||||
var gcStorageCreator = new GameCardStorageCreator(fsServer);
|
||||
|
||||
using var sharedRootFileSystem = new SharedRef<IFileSystem>(rootFileSystem);
|
||||
using SharedRef<IFileSystem> sharedRootFileSystemCopy =
|
||||
|
@ -39,7 +39,7 @@ public class DefaultFsServerObjects
|
|||
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
|
||||
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, keySet, null, randomGenerator);
|
||||
creators.GameCardStorageCreator = gcStorageCreator;
|
||||
creators.GameCardFileSystemCreator = new EmulatedGameCardFsCreator(gcStorageCreator, gameCard);
|
||||
creators.GameCardFileSystemCreator = new GameCardFileSystemCreator(new ArrayPoolMemoryResource(), gcStorageCreator, fsServer);
|
||||
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);
|
||||
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref);
|
||||
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdmmcNew, ref sharedRootFileSystemCopy.Ref);
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Tools.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
public class EmulatedGameCardFsCreator : IGameCardFileSystemCreator
|
||||
{
|
||||
// ReSharper disable once NotAccessedField.Local
|
||||
private EmulatedGameCardStorageCreator _storageCreator;
|
||||
private EmulatedGameCard _gameCard;
|
||||
|
||||
public EmulatedGameCardFsCreator(EmulatedGameCardStorageCreator storageCreator, EmulatedGameCard gameCard)
|
||||
{
|
||||
_storageCreator = storageCreator;
|
||||
_gameCard = gameCard;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public Result Create(ref SharedRef<IFileSystem> outFileSystem, GameCardHandle handle,
|
||||
GameCardPartition partitionType)
|
||||
{
|
||||
// Use the old xci code temporarily
|
||||
|
||||
Result res = _gameCard.GetXci(out Xci xci, handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (!xci.HasPartition((XciPartitionType)partitionType))
|
||||
{
|
||||
return ResultFs.PartitionNotFound.Log();
|
||||
}
|
||||
|
||||
XciPartition fs = xci.OpenPartition((XciPartitionType)partitionType);
|
||||
outFileSystem.Reset(fs);
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
public class EmulatedGameCardStorageCreator : IGameCardStorageCreator
|
||||
{
|
||||
private EmulatedGameCard GameCard { get; }
|
||||
|
||||
public EmulatedGameCardStorageCreator(EmulatedGameCard gameCard)
|
||||
{
|
||||
GameCard = gameCard;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public Result CreateReadOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage)
|
||||
{
|
||||
if (GameCard.IsGameCardHandleInvalid(handle))
|
||||
{
|
||||
return ResultFs.GameCardFsCheckHandleInCreateReadOnlyFailure.Log();
|
||||
}
|
||||
|
||||
using var baseStorage = new SharedRef<IStorage>(new ReadOnlyGameCardStorage(GameCard, handle));
|
||||
|
||||
Result res = GameCard.GetCardInfo(out GameCardInfo cardInfo, handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outStorage.Reset(new SubStorage(in baseStorage, 0, cardInfo.SecureAreaOffset));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateSecureReadOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage)
|
||||
{
|
||||
if (GameCard.IsGameCardHandleInvalid(handle))
|
||||
{
|
||||
return ResultFs.GameCardFsCheckHandleInCreateSecureReadOnlyFailure.Log();
|
||||
}
|
||||
|
||||
Span<byte> deviceId = stackalloc byte[0x10];
|
||||
Span<byte> imageHash = stackalloc byte[0x20];
|
||||
|
||||
Result res = GameCard.GetGameCardDeviceId(deviceId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = GameCard.GetGameCardImageHash(imageHash);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var baseStorage =
|
||||
new SharedRef<IStorage>(new ReadOnlyGameCardStorage(GameCard, handle, deviceId, imageHash));
|
||||
|
||||
res = GameCard.GetCardInfo(out GameCardInfo cardInfo, handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outStorage.Reset(new SubStorage(in baseStorage, cardInfo.SecureAreaOffset, cardInfo.SecureAreaSize));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateWriteOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private class ReadOnlyGameCardStorage : IStorage
|
||||
{
|
||||
private EmulatedGameCard GameCard { get; }
|
||||
private GameCardHandle Handle { get; set; }
|
||||
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Local
|
||||
private bool IsSecureMode { get; }
|
||||
private byte[] DeviceId { get; } = new byte[0x10];
|
||||
private byte[] ImageHash { get; } = new byte[0x20];
|
||||
|
||||
public ReadOnlyGameCardStorage(EmulatedGameCard gameCard, GameCardHandle handle)
|
||||
{
|
||||
GameCard = gameCard;
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
public ReadOnlyGameCardStorage(EmulatedGameCard gameCard, GameCardHandle handle,
|
||||
ReadOnlySpan<byte> deviceId, ReadOnlySpan<byte> imageHash)
|
||||
{
|
||||
GameCard = gameCard;
|
||||
Handle = handle;
|
||||
IsSecureMode = true;
|
||||
deviceId.CopyTo(DeviceId);
|
||||
imageHash.CopyTo(ImageHash);
|
||||
}
|
||||
|
||||
public override Result Read(long offset, Span<byte> destination)
|
||||
{
|
||||
// In secure mode, if Handle is old and the card's device ID and
|
||||
// header hash are still the same, Handle is updated to the new handle
|
||||
|
||||
return GameCard.Read(Handle, offset, destination);
|
||||
}
|
||||
|
||||
public override Result Write(long offset, ReadOnlySpan<byte> source)
|
||||
{
|
||||
return ResultFs.UnsupportedWriteForReadOnlyGameCardStorage.Log();
|
||||
}
|
||||
|
||||
public override Result Flush()
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result SetSize(long size)
|
||||
{
|
||||
return ResultFs.UnsupportedSetSizeForReadOnlyGameCardStorage.Log();
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out size);
|
||||
|
||||
Result res = GameCard.GetCardInfo(out GameCardInfo info, Handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
size = info.Size;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||
ReadOnlySpan<byte> inBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -108,6 +108,7 @@ public class GameCardRootPartition : IDisposable
|
|||
return ResultFs.PartitionNotFound.Log();
|
||||
|
||||
ref readonly PartitionEntry entry = ref _partitionFsMeta.Get.GetEntry(entryIndex);
|
||||
outEntry = new ReadOnlyRef<PartitionEntry>(in entry);
|
||||
|
||||
switch (partitionType)
|
||||
{
|
||||
|
@ -261,9 +262,9 @@ public class GameCardFileSystemCreator : IGameCardFileSystemCreator
|
|||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
// Get an IStorage of the start of the root partition to the start of the secure area.
|
||||
long updateAndNormalPartitionSize = status.SecureAreaOffset - status.PartitionFsHeaderOffset;
|
||||
long updateAndNormalPartitionSize = status.NormalAreaSize - status.PartitionFsHeaderAddress;
|
||||
using var rootFsStorage = new SharedRef<IStorage>(new SubStorage(in alignedRootStorage,
|
||||
status.PartitionFsHeaderOffset, updateAndNormalPartitionSize));
|
||||
status.PartitionFsHeaderAddress, updateAndNormalPartitionSize));
|
||||
|
||||
if (!rootFsStorage.HasValue)
|
||||
return ResultFs.AllocationMemoryFailedInGameCardFileSystemCreatorD.Log();
|
||||
|
|
|
@ -251,8 +251,8 @@ public class DeviceOperator : IDeviceOperator
|
|||
Result res = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outCupVersion = gameCardStatus.UpdatePartitionVersion;
|
||||
outCupId = gameCardStatus.UpdatePartitionId;
|
||||
outCupVersion = gameCardStatus.CupVersion;
|
||||
outCupId = gameCardStatus.CupId;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ public class DeviceOperator : IDeviceOperator
|
|||
Result res = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outAttribute = gameCardStatus.GameCardAttribute;
|
||||
outAttribute = gameCardStatus.Flags;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
|
|||
|
||||
private readonly FileSystemServer _fsServer;
|
||||
private readonly SdmmcApi _sdmmc;
|
||||
private readonly GameCardDummy _gc;
|
||||
private readonly GameCardEmulated _gc;
|
||||
|
||||
public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, SdmmcApi sdmmc, GameCardDummy gc,
|
||||
public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, SdmmcApi sdmmc, GameCardEmulated gc,
|
||||
bool hasGameCard)
|
||||
{
|
||||
_fsServer = fsServer;
|
||||
|
|
|
@ -320,7 +320,7 @@ internal static class GameCardService
|
|||
size: 0, operationId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
Assert.SdkEqual(GcCardExistenceResponseDataSize, bytesWritten);
|
||||
Assert.SdkEqual(GcChallengeCardExistenceResponseSize, bytesWritten);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
using System;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Gc.Impl;
|
||||
using LibHac.Gc.Writer;
|
||||
|
||||
namespace LibHac.Gc;
|
||||
|
||||
public class GameCardDummy
|
||||
{
|
||||
public GameCardWriter Writer => new GameCardWriter();
|
||||
|
||||
public readonly struct GameCardWriter
|
||||
{
|
||||
public GameCardWriter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ChangeMode(AsicMode mode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result ActivateForWriter()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result EraseAndWriteParameter(MemorySize size, uint romAreaStartPageIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result Write(ReadOnlySpan<byte> source, uint pageIndex, uint pageCount)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetCardAvailableRawSize(out long outSize)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetVerifyEnableFlag(bool isEnabled)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetUserAsicFirmwareBuffer(ReadOnlySpan<byte> firmwareBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetRmaInformation(out RmaInformation outRmaInformation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result WriteDevCardParam(in DevCardParameter devCardParam)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result ReadDevCardParam(out DevCardParameter outDevCardParam)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result ForceErase()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Initialize(Memory<byte> workBuffer, ulong deviceBufferAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void FinalizeGc()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PowerOffGameCard()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RegisterDeviceVirtualAddress(Memory<byte> buffer, ulong deviceBufferAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void UnregisterDeviceVirtualAddress(Memory<byte> buffer, ulong deviceBufferAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetInitializationResult()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result Activate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result SetCardToSecureMode()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result Read(Span<byte> destination, uint pageIndex, uint pageCount)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PutToSleep()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Awaken()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsCardInserted()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsCardActivationValid()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetCardStatus(out GameCardStatus outStatus)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetCardDeviceId(Span<byte> destBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetCardDeviceCertificate(Span<byte> destBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result ChallengeCardExistence(Span<byte> responseBuffer, ReadOnlySpan<byte> challengeSeedBuffer,
|
||||
ReadOnlySpan<byte> challengeValueBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetCardImageHash(Span<byte> destBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetGameCardIdSet(out GameCardIdSet outGcIdSet)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RegisterDetectionEventCallback(Action<object> function, object args)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void UnregisterDetectionEventCallback()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetCardHeader(Span<byte> destBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result GetErrorInfo(out GameCardErrorReportInfo outErrorReportInfo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
430
src/LibHac/Gc/GameCardEmulated.cs
Normal file
430
src/LibHac/Gc/GameCardEmulated.cs
Normal file
|
@ -0,0 +1,430 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Gc.Impl;
|
||||
using LibHac.Gc.Writer;
|
||||
using static LibHac.Gc.Values;
|
||||
|
||||
namespace LibHac.Gc;
|
||||
|
||||
public class GameCardEmulated
|
||||
{
|
||||
private static ReadOnlySpan<byte> CardHeaderKey => new byte[]
|
||||
{ 0x01, 0xC5, 0x8F, 0xE7, 0x00, 0x2D, 0x13, 0x5A, 0xB2, 0x9A, 0x3F, 0x69, 0x33, 0x95, 0x74, 0xB1 };
|
||||
|
||||
private const string LibNotInitializedMessage = "Error: Gc lib is not initialized\n";
|
||||
|
||||
private SharedRef<IStorage> _cardStorage;
|
||||
private bool _attached;
|
||||
private bool _activated;
|
||||
private bool _isSecureMode;
|
||||
private bool _initialized;
|
||||
private bool _writeMode;
|
||||
private bool _hasKeyArea;
|
||||
private CardHeader _cardHeader;
|
||||
private T1CardCertificate _certificate;
|
||||
private Array32<byte> _imageHash;
|
||||
|
||||
public GameCardWriter Writer => new GameCardWriter(this);
|
||||
|
||||
private Result CheckCardReady()
|
||||
{
|
||||
if (!_attached)
|
||||
return ResultFs.GameCardCardNotInserted.Log();
|
||||
|
||||
if (!_activated)
|
||||
return ResultFs.GameCardCardNotActivated.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private void DecryptCardHeader(ref CardHeader header)
|
||||
{
|
||||
Span<byte> iv = stackalloc byte[GcAesCbcIvLength];
|
||||
for (int i = 0; i < GcAesCbcIvLength; i++)
|
||||
{
|
||||
iv[i] = header.Iv[GcAesCbcIvLength - 1 - i];
|
||||
}
|
||||
|
||||
Aes.DecryptCbc128(SpanHelpers.AsReadOnlyByteSpan(in header.EncryptedData),
|
||||
SpanHelpers.AsByteSpan(ref header.EncryptedData), CardHeaderKey, iv);
|
||||
}
|
||||
|
||||
private long GetCardSize(MemoryCapacity memoryCapacity)
|
||||
{
|
||||
return memoryCapacity switch
|
||||
{
|
||||
MemoryCapacity.Capacity1GB => AvailableSizeBase * 1,
|
||||
MemoryCapacity.Capacity2GB => AvailableSizeBase * 2,
|
||||
MemoryCapacity.Capacity4GB => AvailableSizeBase * 4,
|
||||
MemoryCapacity.Capacity8GB => AvailableSizeBase * 8,
|
||||
MemoryCapacity.Capacity16GB => AvailableSizeBase * 16,
|
||||
MemoryCapacity.Capacity32GB => AvailableSizeBase * 32,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
public void InsertGameCard(in SharedRef<IStorage> storage)
|
||||
{
|
||||
_attached = false;
|
||||
_activated = false;
|
||||
|
||||
_cardStorage.SetByCopy(in storage);
|
||||
_hasKeyArea = HasKeyArea(_cardStorage.Get);
|
||||
|
||||
if (storage.HasValue)
|
||||
{
|
||||
Abort.DoAbortUnlessSuccess(ReadBaseStorage(0x100, SpanHelpers.AsByteSpan(ref _cardHeader)));
|
||||
Abort.DoAbortUnlessSuccess(ReadBaseStorage(GcCertAreaPageAddress * GcPageSize, SpanHelpers.AsByteSpan(ref _certificate)));
|
||||
|
||||
Sha256.GenerateSha256Hash(SpanHelpers.AsReadOnlyByteSpan(in _cardHeader), _imageHash.Items);
|
||||
|
||||
DecryptCardHeader(ref _cardHeader);
|
||||
|
||||
_attached = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveGameCard()
|
||||
{
|
||||
_cardStorage.Destroy();
|
||||
|
||||
_attached = false;
|
||||
_activated = false;
|
||||
}
|
||||
|
||||
private static bool HasKeyArea(IStorage baseStorage)
|
||||
{
|
||||
if (baseStorage is null)
|
||||
return false;
|
||||
|
||||
Result res = baseStorage.GetSize(out long storageSize);
|
||||
if (res.IsFailure()) return false;
|
||||
|
||||
if (storageSize >= 0x1104)
|
||||
{
|
||||
uint magic = 0;
|
||||
res = baseStorage.Read(0x1100, SpanHelpers.AsByteSpan(ref magic));
|
||||
if (res.IsFailure()) return false;
|
||||
|
||||
if (magic == CardHeader.HeaderMagic)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Result ReadBaseStorage(long offset, Span<byte> destination)
|
||||
{
|
||||
long baseStorageOffset = _hasKeyArea ? GcCardKeyAreaSize + offset : offset;
|
||||
|
||||
return _cardStorage.Get.Read(baseStorageOffset, destination).Ret();
|
||||
}
|
||||
|
||||
public readonly struct GameCardWriter
|
||||
{
|
||||
private readonly GameCardEmulated _card;
|
||||
|
||||
public GameCardWriter(GameCardEmulated card)
|
||||
{
|
||||
_card = card;
|
||||
}
|
||||
|
||||
public void ChangeMode(AsicMode mode)
|
||||
{
|
||||
Abort.DoAbortUnless(_card._initialized, LibNotInitializedMessage);
|
||||
}
|
||||
|
||||
public Result ActivateForWriter()
|
||||
{
|
||||
Abort.DoAbortUnless(_card._initialized, LibNotInitializedMessage);
|
||||
|
||||
_card._writeMode = true;
|
||||
_card._activated = true;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result EraseAndWriteParameter(MemorySize size, uint romAreaStartPageIndex)
|
||||
{
|
||||
return ResultFs.NotImplemented.Log();
|
||||
}
|
||||
|
||||
public Result Write(ReadOnlySpan<byte> source, uint pageIndex, uint pageCount)
|
||||
{
|
||||
return ResultFs.NotImplemented.Log();
|
||||
}
|
||||
|
||||
public Result GetCardAvailableRawSize(out long outSize)
|
||||
{
|
||||
outSize = 0;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void SetVerifyEnableFlag(bool isEnabled)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public void SetUserAsicFirmwareBuffer(ReadOnlySpan<byte> firmwareBuffer)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public Result GetRmaInformation(out RmaInformation outRmaInformation)
|
||||
{
|
||||
outRmaInformation = default;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result WriteDevCardParam(in DevCardParameter devCardParam)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result ReadDevCardParam(out DevCardParameter outDevCardParam)
|
||||
{
|
||||
outDevCardParam = default;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result ForceErase()
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public void Initialize(Memory<byte> workBuffer, ulong deviceBufferAddress)
|
||||
{
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public void FinalizeGc()
|
||||
{
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
public void PowerOffGameCard()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public void RegisterDeviceVirtualAddress(Memory<byte> buffer, ulong deviceBufferAddress)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public void UnregisterDeviceVirtualAddress(Memory<byte> buffer, ulong deviceBufferAddress)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public Result GetInitializationResult()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Activate()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
_activated = true;
|
||||
_writeMode = false;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
_activated = false;
|
||||
_isSecureMode = false;
|
||||
}
|
||||
|
||||
public Result SetCardToSecureMode()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
Result res = CheckCardReady();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
_isSecureMode = true;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Read(Span<byte> destination, uint pageAddress, uint pageCount)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
Result res = CheckCardReady();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (destination.Length == 0)
|
||||
return Result.Success;
|
||||
|
||||
int limArea = (int)_cardHeader.LimAreaPage;
|
||||
bool isNormal = pageAddress < limArea;
|
||||
bool isSecure = (pageAddress + pageCount - 1) >= limArea;
|
||||
|
||||
// Reads cannot span the boundary between the normal area and secure area.
|
||||
if (isNormal && isSecure)
|
||||
return ResultFs.GameCardInvalidAccessAcrossMode.Log();
|
||||
|
||||
// Reads to the secure area cannot be done in normal mode.
|
||||
if (isSecure && !_isSecureMode)
|
||||
return ResultFs.GameCardInvalidSecureAccess.Log();
|
||||
|
||||
// Reads to the normal area cannot be done in secure mode.
|
||||
if (isNormal && _isSecureMode)
|
||||
return ResultFs.GameCardInvalidNormalAccess.Log();
|
||||
|
||||
res = ReadBaseStorage(pageAddress * GcPageSize, destination);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void PutToSleep()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
}
|
||||
|
||||
public void Awaken()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
}
|
||||
|
||||
public bool IsCardInserted()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
return _attached;
|
||||
}
|
||||
|
||||
public bool IsCardActivationValid()
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
return _activated;
|
||||
}
|
||||
|
||||
public Result GetCardStatus(out GameCardStatus outStatus)
|
||||
{
|
||||
outStatus = default;
|
||||
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
Result res = CheckCardReady();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
long cardSize = GetCardSize((MemoryCapacity)_cardHeader.RomSize);
|
||||
|
||||
GameCardStatus status = default;
|
||||
|
||||
status.CupVersion = _cardHeader.EncryptedData.CupVersion;
|
||||
status.PackageId = _cardHeader.PackageId;
|
||||
status.CardSize = cardSize;
|
||||
status.PartitionFsHeaderHash = _cardHeader.PartitionFsHeaderHash;
|
||||
status.CupId = _cardHeader.EncryptedData.CupId;
|
||||
status.CompatibilityType = _cardHeader.EncryptedData.CompatibilityType;
|
||||
status.PartitionFsHeaderAddress = _cardHeader.PartitionFsHeaderAddress;
|
||||
status.PartitionFsHeaderSize = _cardHeader.PartitionFsHeaderSize;
|
||||
status.NormalAreaSize = _cardHeader.LimAreaPage * GcPageSize;
|
||||
status.SecureAreaSize = cardSize - status.NormalAreaSize;
|
||||
status.Flags = _cardHeader.Flags;
|
||||
|
||||
outStatus = status;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetCardDeviceId(Span<byte> destBuffer)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
if (!_isSecureMode)
|
||||
return ResultFs.GameCardStateCardSecureModeRequired.Log();
|
||||
|
||||
Result res = CheckCardReady();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
_certificate.T1CardDeviceId.ItemsRo.CopyTo(destBuffer);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetCardDeviceCertificate(Span<byte> destBuffer)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
if (!_isSecureMode)
|
||||
return ResultFs.GameCardInvalidGetCardDeviceCertificate.Log();
|
||||
|
||||
Result res = CheckCardReady();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
SpanHelpers.AsReadOnlyByteSpan(in _certificate).Slice(0, GcDeviceCertificateSize).CopyTo(destBuffer);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result ChallengeCardExistence(Span<byte> responseBuffer, ReadOnlySpan<byte> challengeSeedBuffer,
|
||||
ReadOnlySpan<byte> challengeValueBuffer)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
return CheckCardReady().Ret();
|
||||
}
|
||||
|
||||
public Result GetCardImageHash(Span<byte> destBuffer)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
Result res = CheckCardReady();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
_imageHash.ItemsRo.CopyTo(destBuffer);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetGameCardIdSet(out GameCardIdSet outGcIdSet)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
outGcIdSet = default;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void RegisterDetectionEventCallback(Action<object> function, object args)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public void UnregisterDetectionEventCallback()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public Result GetCardHeader(Span<byte> destBuffer)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetErrorInfo(out GameCardErrorReportInfo outErrorReportInfo)
|
||||
{
|
||||
Abort.DoAbortUnless(_initialized, LibNotInitializedMessage);
|
||||
|
||||
outErrorReportInfo = default;
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
|
@ -6,18 +6,18 @@ namespace LibHac.Gc;
|
|||
public struct GameCardStatus
|
||||
{
|
||||
public Array32<byte> PartitionFsHeaderHash;
|
||||
public ulong PackageId;
|
||||
public long Size;
|
||||
public long PartitionFsHeaderOffset;
|
||||
public Array8<byte> PackageId;
|
||||
public long CardSize;
|
||||
public long PartitionFsHeaderAddress;
|
||||
public long PartitionFsHeaderSize;
|
||||
public long SecureAreaOffset;
|
||||
public long NormalAreaSize;
|
||||
public long SecureAreaSize;
|
||||
public uint UpdatePartitionVersion;
|
||||
public ulong UpdatePartitionId;
|
||||
public uint CupVersion;
|
||||
public ulong CupId;
|
||||
public byte CompatibilityType;
|
||||
public Array3<byte> Reserved61;
|
||||
public byte GameCardAttribute;
|
||||
public Array11<byte> Reserved65;
|
||||
public Array3<byte> Reserved1;
|
||||
public byte Flags;
|
||||
public Array11<byte> Reserved2;
|
||||
}
|
||||
|
||||
public struct RmaInformation
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
namespace LibHac.Gc;
|
||||
using LibHac.Crypto;
|
||||
|
||||
namespace LibHac.Gc;
|
||||
|
||||
public static class Values
|
||||
{
|
||||
public static int GcPageSize => 0x200;
|
||||
public static int GcAsicFirmwareSize => 0x7800;
|
||||
public static int GcCardDeviceIdSize => 0x10;
|
||||
public static int GcCardExistenceResponseDataSize => 0x58;
|
||||
public static int GcCardImageHashSize => 0x20;
|
||||
public static int GcDeviceCertificateSize => 0x200;
|
||||
public static int GcCardKeyAreaSize => 0x1000;
|
||||
public static int GcCardKeyAreaPageCount => 8;
|
||||
public static int GcCertAreaStartPageAddress => 56;
|
||||
public const int GcPageSize = 0x200;
|
||||
public const int GcAsicFirmwareSize = 1024 * 30; // 30 KiB
|
||||
public const int GcCardDeviceIdSize = 0x10;
|
||||
public const int GcChallengeCardExistenceResponseSize = 0x58;
|
||||
public const int GcCardImageHashSize = 0x20;
|
||||
public const int GcDeviceCertificateSize = 0x200;
|
||||
public const int GcCardKeyAreaSize = GcCardKeyAreaPageCount * GcPageSize;
|
||||
public const int GcCardKeyAreaPageCount = 8;
|
||||
public const int GcCertAreaPageAddress = 56;
|
||||
public const int GcAesCbcIvLength = Aes.KeySize128;
|
||||
|
||||
public const long UnusedAreaSizeBase = 1024 * 1024 * 72; // 72 MiB
|
||||
public const long MemorySizeBase = 1024 * 1024 * 1024; // 1 GiB
|
||||
public const long AvailableSizeBase = MemorySizeBase - UnusedAreaSizeBase;
|
||||
}
|
|
@ -118,8 +118,8 @@ public struct CardHeader
|
|||
public uint ValidDataEndPage;
|
||||
public Array4<byte> Reserved11C;
|
||||
public Array16<byte> Iv;
|
||||
public ulong PartitionFsHeaderAddress;
|
||||
public ulong PartitionFsHeaderSize;
|
||||
public long PartitionFsHeaderAddress;
|
||||
public long PartitionFsHeaderSize;
|
||||
public Array32<byte> PartitionFsHeaderHash;
|
||||
public Array32<byte> InitialDataHash;
|
||||
public uint SelSec;
|
||||
|
|
|
@ -9,9 +9,9 @@ namespace LibHac.GcSrv;
|
|||
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
||||
internal class GameCardDetectionEventManager : CardDeviceDetectionEventManager
|
||||
{
|
||||
private GameCardDummy _gc;
|
||||
private GameCardEmulated _gc;
|
||||
|
||||
public GameCardDetectionEventManager(GameCardDummy gc)
|
||||
public GameCardDetectionEventManager(GameCardEmulated gc)
|
||||
{
|
||||
_gc = gc;
|
||||
|
||||
|
|
|
@ -15,14 +15,14 @@ internal class GameCardDeviceOperator : IStorageDeviceOperator
|
|||
private SharedRef<GameCardStorageDevice> _storageDevice;
|
||||
|
||||
// LibHac additions
|
||||
private readonly GameCardDummy _gc;
|
||||
private readonly GameCardEmulated _gc;
|
||||
|
||||
public static uint BytesToPages(long byteCount)
|
||||
{
|
||||
return (uint)((ulong)byteCount / (ulong)GcPageSize);
|
||||
return (uint)((ulong)byteCount / GcPageSize);
|
||||
}
|
||||
|
||||
public GameCardDeviceOperator(ref SharedRef<GameCardStorageDevice> storageDevice, GameCardDummy gc)
|
||||
public GameCardDeviceOperator(ref SharedRef<GameCardStorageDevice> storageDevice, GameCardEmulated gc)
|
||||
{
|
||||
_storageDevice = SharedRef<GameCardStorageDevice>.CreateMove(ref storageDevice);
|
||||
_gc = gc;
|
||||
|
@ -179,11 +179,11 @@ internal class GameCardDeviceOperator : IStorageDeviceOperator
|
|||
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (outBuffer.Size < GcCardExistenceResponseDataSize)
|
||||
if (outBuffer.Size < GcChallengeCardExistenceResponseSize)
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
|
||||
result = _gc.ChallengeCardExistence(outBuffer.Buffer, inBuffer1.Buffer, inBuffer2.Buffer);
|
||||
bytesWritten = GcCardExistenceResponseDataSize;
|
||||
bytesWritten = GcChallengeCardExistenceResponseSize;
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
// LibHac additions
|
||||
private WeakRef<GameCardManager> _selfReference;
|
||||
private readonly FileSystemServer _fsServer;
|
||||
private readonly GameCardDummy _gc;
|
||||
private readonly GameCardEmulated _gc;
|
||||
|
||||
private GameCardManager(GameCardDummy gc, FileSystemServer fsServer)
|
||||
private GameCardManager(GameCardEmulated gc, FileSystemServer fsServer)
|
||||
{
|
||||
_rwLock = new ReaderWriterLock(fsServer.Hos.Os);
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
_gc = gc;
|
||||
}
|
||||
|
||||
public static SharedRef<GameCardManager> CreateShared(GameCardDummy gc, FileSystemServer fsServer)
|
||||
public static SharedRef<GameCardManager> CreateShared(GameCardEmulated gc, FileSystemServer fsServer)
|
||||
{
|
||||
var manager = new GameCardManager(gc, fsServer);
|
||||
|
||||
|
@ -506,7 +506,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus));
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
long size = cardStatus.SecureAreaOffset;
|
||||
long size = cardStatus.NormalAreaSize;
|
||||
|
||||
outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, 0, size));
|
||||
|
||||
|
@ -522,7 +522,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus));
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
long offset = cardStatus.SecureAreaOffset;
|
||||
long offset = cardStatus.NormalAreaSize;
|
||||
long size = cardStatus.SecureAreaSize;
|
||||
|
||||
outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, offset, size));
|
||||
|
@ -912,7 +912,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
Span<byte> originalHeaderBuffer = stackalloc byte[writeSize];
|
||||
originalHeaderBuffer.Clear();
|
||||
|
||||
_gc.GetCardHeader(pooledBuffer.GetBuffer());
|
||||
res = _gc.GetCardHeader(pooledBuffer.GetBuffer());
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
pooledBuffer.GetBuffer().CopyTo(originalHeaderBuffer);
|
||||
|
@ -923,7 +923,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
devHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
||||
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), (uint)GcCardKeyAreaPageCount, 1);
|
||||
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), GcCardKeyAreaPageCount, 1);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
// Read the cert area
|
||||
|
@ -931,7 +931,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
res = _gc.Activate();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = _gc.Read(pooledBuffer.GetBuffer(), (uint)GcCertAreaStartPageAddress, 1);
|
||||
res = _gc.Read(pooledBuffer.GetBuffer(), GcCertAreaPageAddress, 1);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
Span<byte> deviceCert = stackalloc byte[writeSize];
|
||||
|
@ -943,7 +943,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
|||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
originalHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
||||
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), (uint)GcCardKeyAreaPageCount, 1);
|
||||
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), GcCardKeyAreaPageCount, 1);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
deviceCert.CopyTo(outBuffer);
|
||||
|
|
|
@ -20,9 +20,9 @@ internal class ReadOnlyGameCardStorage : IStorage
|
|||
private SharedRef<IGameCardManager> _deviceManager;
|
||||
|
||||
// LibHac additions
|
||||
private readonly GameCardDummy _gc;
|
||||
private readonly GameCardEmulated _gc;
|
||||
|
||||
public ReadOnlyGameCardStorage(ref SharedRef<IGameCardManager> deviceManger, GameCardDummy gc)
|
||||
public ReadOnlyGameCardStorage(ref SharedRef<IGameCardManager> deviceManger, GameCardEmulated gc)
|
||||
{
|
||||
_deviceManager = SharedRef<IGameCardManager>.CreateMove(ref deviceManger);
|
||||
_gc = gc;
|
||||
|
@ -65,7 +65,7 @@ internal class ReadOnlyGameCardStorage : IStorage
|
|||
Result res = _gc.GetCardStatus(out GameCardStatus status);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
size = status.Size;
|
||||
size = status.CardSize;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -103,9 +103,9 @@ internal class WriteOnlyGameCardStorage : IStorage
|
|||
private SharedRef<IGameCardManager> _deviceManager;
|
||||
|
||||
// LibHac additions
|
||||
private readonly GameCardDummy _gc;
|
||||
private readonly GameCardEmulated _gc;
|
||||
|
||||
public WriteOnlyGameCardStorage(ref SharedRef<IGameCardManager> deviceManger, GameCardDummy gc)
|
||||
public WriteOnlyGameCardStorage(ref SharedRef<IGameCardManager> deviceManger, GameCardEmulated gc)
|
||||
{
|
||||
_deviceManager = SharedRef<IGameCardManager>.CreateMove(ref deviceManger);
|
||||
_gc = gc;
|
||||
|
|
|
@ -20,9 +20,9 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
|||
|
||||
// LibHac additions
|
||||
private WeakRef<GameCardStorageDevice> _selfReference;
|
||||
private readonly GameCardDummy _gc;
|
||||
private readonly GameCardEmulated _gc;
|
||||
|
||||
private GameCardStorageDevice(GameCardDummy gc, ref SharedRef<IGameCardManager> manager,
|
||||
private GameCardStorageDevice(GameCardEmulated gc, ref SharedRef<IGameCardManager> manager,
|
||||
in SharedRef<IStorage> baseStorage, GameCardHandle handle) : base(in baseStorage)
|
||||
{
|
||||
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
||||
|
@ -32,7 +32,7 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
|||
_gc = gc;
|
||||
}
|
||||
|
||||
private GameCardStorageDevice(GameCardDummy gc, ref SharedRef<IGameCardManager> manager,
|
||||
private GameCardStorageDevice(GameCardEmulated gc, ref SharedRef<IGameCardManager> manager,
|
||||
in SharedRef<IStorage> baseStorage, GameCardHandle handle, bool isSecure, ReadOnlySpan<byte> cardDeviceId,
|
||||
ReadOnlySpan<byte> cardImageHash)
|
||||
: base(in baseStorage)
|
||||
|
@ -50,7 +50,7 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
|||
_gc = gc;
|
||||
}
|
||||
|
||||
public static SharedRef<GameCardStorageDevice> CreateShared(GameCardDummy gc,
|
||||
public static SharedRef<GameCardStorageDevice> CreateShared(GameCardEmulated gc,
|
||||
ref SharedRef<IGameCardManager> manager, in SharedRef<IStorage> baseStorage, GameCardHandle handle)
|
||||
{
|
||||
var storageDevice = new GameCardStorageDevice(gc, ref manager, in baseStorage, handle);
|
||||
|
@ -61,7 +61,7 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
|||
return SharedRef<GameCardStorageDevice>.CreateMove(ref sharedStorageDevice.Ref);
|
||||
}
|
||||
|
||||
public static SharedRef<GameCardStorageDevice> CreateShared(GameCardDummy gc,
|
||||
public static SharedRef<GameCardStorageDevice> CreateShared(GameCardEmulated gc,
|
||||
ref SharedRef<IGameCardManager> manager, in SharedRef<IStorage> baseStorage, GameCardHandle handle,
|
||||
bool isSecure, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
||||
{
|
||||
|
|
|
@ -205,7 +205,7 @@ public struct SharedLock<TMutex> : IDisposable where TMutex : class, ISharedMute
|
|||
|
||||
public void Unlock()
|
||||
{
|
||||
if (_ownsLock)
|
||||
if (!_ownsLock)
|
||||
throw new SynchronizationLockException("SharedLock.Unlock: Not locked");
|
||||
|
||||
_mutex.UnlockShared();
|
||||
|
|
|
@ -17,17 +17,17 @@ public class TypeLayoutTests
|
|||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.PartitionFsHeaderHash));
|
||||
Assert.Equal(0x20, GetOffset(in s, in s.PackageId));
|
||||
Assert.Equal(0x28, GetOffset(in s, in s.Size));
|
||||
Assert.Equal(0x30, GetOffset(in s, in s.PartitionFsHeaderOffset));
|
||||
Assert.Equal(0x28, GetOffset(in s, in s.CardSize));
|
||||
Assert.Equal(0x30, GetOffset(in s, in s.PartitionFsHeaderAddress));
|
||||
Assert.Equal(0x38, GetOffset(in s, in s.PartitionFsHeaderSize));
|
||||
Assert.Equal(0x40, GetOffset(in s, in s.SecureAreaOffset));
|
||||
Assert.Equal(0x40, GetOffset(in s, in s.NormalAreaSize));
|
||||
Assert.Equal(0x48, GetOffset(in s, in s.SecureAreaSize));
|
||||
Assert.Equal(0x50, GetOffset(in s, in s.UpdatePartitionVersion));
|
||||
Assert.Equal(0x58, GetOffset(in s, in s.UpdatePartitionId));
|
||||
Assert.Equal(0x50, GetOffset(in s, in s.CupVersion));
|
||||
Assert.Equal(0x58, GetOffset(in s, in s.CupId));
|
||||
Assert.Equal(0x60, GetOffset(in s, in s.CompatibilityType));
|
||||
Assert.Equal(0x61, GetOffset(in s, in s.Reserved61));
|
||||
Assert.Equal(0x64, GetOffset(in s, in s.GameCardAttribute));
|
||||
Assert.Equal(0x65, GetOffset(in s, in s.Reserved65));
|
||||
Assert.Equal(0x61, GetOffset(in s, in s.Reserved1));
|
||||
Assert.Equal(0x64, GetOffset(in s, in s.Flags));
|
||||
Assert.Equal(0x65, GetOffset(in s, in s.Reserved2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
Loading…
Reference in a new issue