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 FileSystemCreatorInterfaces FsCreators { get; set; }
|
||||||
public EmulatedGameCard GameCard { get; set; }
|
public EmulatedGameCard GameCard { get; set; }
|
||||||
public SdmmcApi Sdmmc { get; set; }
|
public SdmmcApi Sdmmc { get; set; }
|
||||||
public GameCardDummy GameCardNew { get; set; }
|
public GameCardEmulated GameCardNew { get; set; }
|
||||||
public EmulatedStorageDeviceManagerFactory StorageDeviceManagerFactory { get; set; }
|
public EmulatedStorageDeviceManagerFactory StorageDeviceManagerFactory { get; set; }
|
||||||
|
|
||||||
public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, KeySet keySet,
|
public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, KeySet keySet,
|
||||||
|
@ -23,10 +23,10 @@ public class DefaultFsServerObjects
|
||||||
var creators = new FileSystemCreatorInterfaces();
|
var creators = new FileSystemCreatorInterfaces();
|
||||||
var gameCard = new EmulatedGameCard(keySet);
|
var gameCard = new EmulatedGameCard(keySet);
|
||||||
|
|
||||||
var gameCardNew = new GameCardDummy();
|
var gameCardNew = new GameCardEmulated();
|
||||||
var sdmmcNew = new SdmmcApi(fsServer);
|
var sdmmcNew = new SdmmcApi(fsServer);
|
||||||
|
|
||||||
var gcStorageCreator = new EmulatedGameCardStorageCreator(gameCard);
|
var gcStorageCreator = new GameCardStorageCreator(fsServer);
|
||||||
|
|
||||||
using var sharedRootFileSystem = new SharedRef<IFileSystem>(rootFileSystem);
|
using var sharedRootFileSystem = new SharedRef<IFileSystem>(rootFileSystem);
|
||||||
using SharedRef<IFileSystem> sharedRootFileSystemCopy =
|
using SharedRef<IFileSystem> sharedRootFileSystemCopy =
|
||||||
|
@ -39,7 +39,7 @@ public class DefaultFsServerObjects
|
||||||
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
|
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
|
||||||
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, keySet, null, randomGenerator);
|
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, keySet, null, randomGenerator);
|
||||||
creators.GameCardStorageCreator = gcStorageCreator;
|
creators.GameCardStorageCreator = gcStorageCreator;
|
||||||
creators.GameCardFileSystemCreator = new EmulatedGameCardFsCreator(gcStorageCreator, gameCard);
|
creators.GameCardFileSystemCreator = new GameCardFileSystemCreator(new ArrayPoolMemoryResource(), gcStorageCreator, fsServer);
|
||||||
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);
|
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);
|
||||||
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref);
|
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref);
|
||||||
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdmmcNew, ref sharedRootFileSystemCopy.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();
|
return ResultFs.PartitionNotFound.Log();
|
||||||
|
|
||||||
ref readonly PartitionEntry entry = ref _partitionFsMeta.Get.GetEntry(entryIndex);
|
ref readonly PartitionEntry entry = ref _partitionFsMeta.Get.GetEntry(entryIndex);
|
||||||
|
outEntry = new ReadOnlyRef<PartitionEntry>(in entry);
|
||||||
|
|
||||||
switch (partitionType)
|
switch (partitionType)
|
||||||
{
|
{
|
||||||
|
@ -261,9 +262,9 @@ public class GameCardFileSystemCreator : IGameCardFileSystemCreator
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
// Get an IStorage of the start of the root partition to the start of the secure area.
|
// 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,
|
using var rootFsStorage = new SharedRef<IStorage>(new SubStorage(in alignedRootStorage,
|
||||||
status.PartitionFsHeaderOffset, updateAndNormalPartitionSize));
|
status.PartitionFsHeaderAddress, updateAndNormalPartitionSize));
|
||||||
|
|
||||||
if (!rootFsStorage.HasValue)
|
if (!rootFsStorage.HasValue)
|
||||||
return ResultFs.AllocationMemoryFailedInGameCardFileSystemCreatorD.Log();
|
return ResultFs.AllocationMemoryFailedInGameCardFileSystemCreatorD.Log();
|
||||||
|
|
|
@ -251,8 +251,8 @@ public class DeviceOperator : IDeviceOperator
|
||||||
Result res = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
|
Result res = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
outCupVersion = gameCardStatus.UpdatePartitionVersion;
|
outCupVersion = gameCardStatus.CupVersion;
|
||||||
outCupId = gameCardStatus.UpdatePartitionId;
|
outCupId = gameCardStatus.CupId;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ public class DeviceOperator : IDeviceOperator
|
||||||
Result res = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
|
Result res = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
outAttribute = gameCardStatus.GameCardAttribute;
|
outAttribute = gameCardStatus.Flags;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
|
||||||
|
|
||||||
private readonly FileSystemServer _fsServer;
|
private readonly FileSystemServer _fsServer;
|
||||||
private readonly SdmmcApi _sdmmc;
|
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)
|
bool hasGameCard)
|
||||||
{
|
{
|
||||||
_fsServer = fsServer;
|
_fsServer = fsServer;
|
||||||
|
|
|
@ -320,7 +320,7 @@ internal static class GameCardService
|
||||||
size: 0, operationId);
|
size: 0, operationId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
Assert.SdkEqual(GcCardExistenceResponseDataSize, bytesWritten);
|
Assert.SdkEqual(GcChallengeCardExistenceResponseSize, bytesWritten);
|
||||||
|
|
||||||
return Result.Success;
|
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 struct GameCardStatus
|
||||||
{
|
{
|
||||||
public Array32<byte> PartitionFsHeaderHash;
|
public Array32<byte> PartitionFsHeaderHash;
|
||||||
public ulong PackageId;
|
public Array8<byte> PackageId;
|
||||||
public long Size;
|
public long CardSize;
|
||||||
public long PartitionFsHeaderOffset;
|
public long PartitionFsHeaderAddress;
|
||||||
public long PartitionFsHeaderSize;
|
public long PartitionFsHeaderSize;
|
||||||
public long SecureAreaOffset;
|
public long NormalAreaSize;
|
||||||
public long SecureAreaSize;
|
public long SecureAreaSize;
|
||||||
public uint UpdatePartitionVersion;
|
public uint CupVersion;
|
||||||
public ulong UpdatePartitionId;
|
public ulong CupId;
|
||||||
public byte CompatibilityType;
|
public byte CompatibilityType;
|
||||||
public Array3<byte> Reserved61;
|
public Array3<byte> Reserved1;
|
||||||
public byte GameCardAttribute;
|
public byte Flags;
|
||||||
public Array11<byte> Reserved65;
|
public Array11<byte> Reserved2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct RmaInformation
|
public struct RmaInformation
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
namespace LibHac.Gc;
|
using LibHac.Crypto;
|
||||||
|
|
||||||
|
namespace LibHac.Gc;
|
||||||
|
|
||||||
public static class Values
|
public static class Values
|
||||||
{
|
{
|
||||||
public static int GcPageSize => 0x200;
|
public const int GcPageSize = 0x200;
|
||||||
public static int GcAsicFirmwareSize => 0x7800;
|
public const int GcAsicFirmwareSize = 1024 * 30; // 30 KiB
|
||||||
public static int GcCardDeviceIdSize => 0x10;
|
public const int GcCardDeviceIdSize = 0x10;
|
||||||
public static int GcCardExistenceResponseDataSize => 0x58;
|
public const int GcChallengeCardExistenceResponseSize = 0x58;
|
||||||
public static int GcCardImageHashSize => 0x20;
|
public const int GcCardImageHashSize = 0x20;
|
||||||
public static int GcDeviceCertificateSize => 0x200;
|
public const int GcDeviceCertificateSize = 0x200;
|
||||||
public static int GcCardKeyAreaSize => 0x1000;
|
public const int GcCardKeyAreaSize = GcCardKeyAreaPageCount * GcPageSize;
|
||||||
public static int GcCardKeyAreaPageCount => 8;
|
public const int GcCardKeyAreaPageCount = 8;
|
||||||
public static int GcCertAreaStartPageAddress => 56;
|
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 uint ValidDataEndPage;
|
||||||
public Array4<byte> Reserved11C;
|
public Array4<byte> Reserved11C;
|
||||||
public Array16<byte> Iv;
|
public Array16<byte> Iv;
|
||||||
public ulong PartitionFsHeaderAddress;
|
public long PartitionFsHeaderAddress;
|
||||||
public ulong PartitionFsHeaderSize;
|
public long PartitionFsHeaderSize;
|
||||||
public Array32<byte> PartitionFsHeaderHash;
|
public Array32<byte> PartitionFsHeaderHash;
|
||||||
public Array32<byte> InitialDataHash;
|
public Array32<byte> InitialDataHash;
|
||||||
public uint SelSec;
|
public uint SelSec;
|
||||||
|
|
|
@ -9,9 +9,9 @@ namespace LibHac.GcSrv;
|
||||||
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
||||||
internal class GameCardDetectionEventManager : CardDeviceDetectionEventManager
|
internal class GameCardDetectionEventManager : CardDeviceDetectionEventManager
|
||||||
{
|
{
|
||||||
private GameCardDummy _gc;
|
private GameCardEmulated _gc;
|
||||||
|
|
||||||
public GameCardDetectionEventManager(GameCardDummy gc)
|
public GameCardDetectionEventManager(GameCardEmulated gc)
|
||||||
{
|
{
|
||||||
_gc = gc;
|
_gc = gc;
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,14 @@ internal class GameCardDeviceOperator : IStorageDeviceOperator
|
||||||
private SharedRef<GameCardStorageDevice> _storageDevice;
|
private SharedRef<GameCardStorageDevice> _storageDevice;
|
||||||
|
|
||||||
// LibHac additions
|
// LibHac additions
|
||||||
private readonly GameCardDummy _gc;
|
private readonly GameCardEmulated _gc;
|
||||||
|
|
||||||
public static uint BytesToPages(long byteCount)
|
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);
|
_storageDevice = SharedRef<GameCardStorageDevice>.CreateMove(ref storageDevice);
|
||||||
_gc = gc;
|
_gc = gc;
|
||||||
|
@ -179,11 +179,11 @@ internal class GameCardDeviceOperator : IStorageDeviceOperator
|
||||||
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
Result res = _storageDevice.Get.AcquireReadLock(ref readLock.Ref());
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
if (outBuffer.Size < GcCardExistenceResponseDataSize)
|
if (outBuffer.Size < GcChallengeCardExistenceResponseSize)
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
result = _gc.ChallengeCardExistence(outBuffer.Buffer, inBuffer1.Buffer, inBuffer2.Buffer);
|
result = _gc.ChallengeCardExistence(outBuffer.Buffer, inBuffer1.Buffer, inBuffer2.Buffer);
|
||||||
bytesWritten = GcCardExistenceResponseDataSize;
|
bytesWritten = GcChallengeCardExistenceResponseSize;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
// 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 GameCardEmulated _gc;
|
||||||
|
|
||||||
private GameCardManager(GameCardDummy gc, FileSystemServer fsServer)
|
private GameCardManager(GameCardEmulated gc, FileSystemServer fsServer)
|
||||||
{
|
{
|
||||||
_rwLock = new ReaderWriterLock(fsServer.Hos.Os);
|
_rwLock = new ReaderWriterLock(fsServer.Hos.Os);
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
_gc = gc;
|
_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);
|
var manager = new GameCardManager(gc, fsServer);
|
||||||
|
|
||||||
|
@ -506,7 +506,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus));
|
Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus));
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
long size = cardStatus.SecureAreaOffset;
|
long size = cardStatus.NormalAreaSize;
|
||||||
|
|
||||||
outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, 0, size));
|
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));
|
Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus));
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
long offset = cardStatus.SecureAreaOffset;
|
long offset = cardStatus.NormalAreaSize;
|
||||||
long size = cardStatus.SecureAreaSize;
|
long size = cardStatus.SecureAreaSize;
|
||||||
|
|
||||||
outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, offset, size));
|
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];
|
Span<byte> originalHeaderBuffer = stackalloc byte[writeSize];
|
||||||
originalHeaderBuffer.Clear();
|
originalHeaderBuffer.Clear();
|
||||||
|
|
||||||
_gc.GetCardHeader(pooledBuffer.GetBuffer());
|
res = _gc.GetCardHeader(pooledBuffer.GetBuffer());
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
pooledBuffer.GetBuffer().CopyTo(originalHeaderBuffer);
|
pooledBuffer.GetBuffer().CopyTo(originalHeaderBuffer);
|
||||||
|
@ -923,7 +923,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
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(), (uint)GcCardKeyAreaPageCount, 1);
|
res = _gc.Writer.Write(pooledBuffer.GetBuffer(), GcCardKeyAreaPageCount, 1);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
// Read the cert area
|
// Read the cert area
|
||||||
|
@ -931,7 +931,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(), (uint)GcCertAreaStartPageAddress, 1);
|
res = _gc.Read(pooledBuffer.GetBuffer(), GcCertAreaPageAddress, 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];
|
||||||
|
@ -943,7 +943,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
originalHeaderBuffer.CopyTo(pooledBuffer.GetBuffer());
|
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();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
deviceCert.CopyTo(outBuffer);
|
deviceCert.CopyTo(outBuffer);
|
||||||
|
|
|
@ -20,9 +20,9 @@ internal class ReadOnlyGameCardStorage : IStorage
|
||||||
private SharedRef<IGameCardManager> _deviceManager;
|
private SharedRef<IGameCardManager> _deviceManager;
|
||||||
|
|
||||||
// LibHac additions
|
// 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);
|
_deviceManager = SharedRef<IGameCardManager>.CreateMove(ref deviceManger);
|
||||||
_gc = gc;
|
_gc = gc;
|
||||||
|
@ -65,7 +65,7 @@ internal class ReadOnlyGameCardStorage : IStorage
|
||||||
Result res = _gc.GetCardStatus(out GameCardStatus status);
|
Result res = _gc.GetCardStatus(out GameCardStatus status);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
size = status.Size;
|
size = status.CardSize;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,9 +103,9 @@ internal class WriteOnlyGameCardStorage : IStorage
|
||||||
private SharedRef<IGameCardManager> _deviceManager;
|
private SharedRef<IGameCardManager> _deviceManager;
|
||||||
|
|
||||||
// LibHac additions
|
// 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);
|
_deviceManager = SharedRef<IGameCardManager>.CreateMove(ref deviceManger);
|
||||||
_gc = gc;
|
_gc = gc;
|
||||||
|
|
|
@ -20,9 +20,9 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
|
|
||||||
// LibHac additions
|
// LibHac additions
|
||||||
private WeakRef<GameCardStorageDevice> _selfReference;
|
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)
|
in SharedRef<IStorage> baseStorage, GameCardHandle handle) : base(in baseStorage)
|
||||||
{
|
{
|
||||||
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
_manager = SharedRef<IGameCardManager>.CreateMove(ref manager);
|
||||||
|
@ -32,7 +32,7 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
_gc = gc;
|
_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,
|
in SharedRef<IStorage> baseStorage, GameCardHandle handle, bool isSecure, ReadOnlySpan<byte> cardDeviceId,
|
||||||
ReadOnlySpan<byte> cardImageHash)
|
ReadOnlySpan<byte> cardImageHash)
|
||||||
: base(in baseStorage)
|
: base(in baseStorage)
|
||||||
|
@ -50,7 +50,7 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage
|
||||||
_gc = gc;
|
_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)
|
ref SharedRef<IGameCardManager> manager, in SharedRef<IStorage> baseStorage, GameCardHandle handle)
|
||||||
{
|
{
|
||||||
var storageDevice = new GameCardStorageDevice(gc, ref manager, in baseStorage, 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);
|
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,
|
ref SharedRef<IGameCardManager> manager, in SharedRef<IStorage> baseStorage, GameCardHandle handle,
|
||||||
bool isSecure, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
bool isSecure, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash)
|
||||||
{
|
{
|
||||||
|
|
|
@ -205,7 +205,7 @@ public struct SharedLock<TMutex> : IDisposable where TMutex : class, ISharedMute
|
||||||
|
|
||||||
public void Unlock()
|
public void Unlock()
|
||||||
{
|
{
|
||||||
if (_ownsLock)
|
if (!_ownsLock)
|
||||||
throw new SynchronizationLockException("SharedLock.Unlock: Not locked");
|
throw new SynchronizationLockException("SharedLock.Unlock: Not locked");
|
||||||
|
|
||||||
_mutex.UnlockShared();
|
_mutex.UnlockShared();
|
||||||
|
|
|
@ -17,17 +17,17 @@ public class TypeLayoutTests
|
||||||
|
|
||||||
Assert.Equal(0x00, GetOffset(in s, in s.PartitionFsHeaderHash));
|
Assert.Equal(0x00, GetOffset(in s, in s.PartitionFsHeaderHash));
|
||||||
Assert.Equal(0x20, GetOffset(in s, in s.PackageId));
|
Assert.Equal(0x20, GetOffset(in s, in s.PackageId));
|
||||||
Assert.Equal(0x28, GetOffset(in s, in s.Size));
|
Assert.Equal(0x28, GetOffset(in s, in s.CardSize));
|
||||||
Assert.Equal(0x30, GetOffset(in s, in s.PartitionFsHeaderOffset));
|
Assert.Equal(0x30, GetOffset(in s, in s.PartitionFsHeaderAddress));
|
||||||
Assert.Equal(0x38, GetOffset(in s, in s.PartitionFsHeaderSize));
|
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(0x48, GetOffset(in s, in s.SecureAreaSize));
|
||||||
Assert.Equal(0x50, GetOffset(in s, in s.UpdatePartitionVersion));
|
Assert.Equal(0x50, GetOffset(in s, in s.CupVersion));
|
||||||
Assert.Equal(0x58, GetOffset(in s, in s.UpdatePartitionId));
|
Assert.Equal(0x58, GetOffset(in s, in s.CupId));
|
||||||
Assert.Equal(0x60, GetOffset(in s, in s.CompatibilityType));
|
Assert.Equal(0x60, GetOffset(in s, in s.CompatibilityType));
|
||||||
Assert.Equal(0x61, GetOffset(in s, in s.Reserved61));
|
Assert.Equal(0x61, GetOffset(in s, in s.Reserved1));
|
||||||
Assert.Equal(0x64, GetOffset(in s, in s.GameCardAttribute));
|
Assert.Equal(0x64, GetOffset(in s, in s.Flags));
|
||||||
Assert.Equal(0x65, GetOffset(in s, in s.Reserved65));
|
Assert.Equal(0x65, GetOffset(in s, in s.Reserved2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
Loading…
Reference in a new issue