Implement DeviceOperator

This commit is contained in:
Alex Barney 2022-05-04 13:09:06 -07:00
parent 612359f0a4
commit 902e3e1424
9 changed files with 942 additions and 31 deletions

View file

@ -194,28 +194,30 @@ public enum SdCardSpeedMode
public enum SdmmcBusWidth
{
Width1Bit = 0,
Width4Bit = 1,
Width8Bit = 2,
Unknown = 0,
Width1Bit = 1,
Width4Bit = 2,
Width8Bit = 3,
}
public enum SdmmcSpeedMode
{
MmcIdentification = 0,
MmcLegacySpeed = 1,
MmcHighSpeed = 2,
MmcHs200 = 3,
MmcHs400 = 4,
SdCardIdentification = 5,
SdCardDefaultSpeed = 6,
SdCardHighSpeed = 7,
SdCardSdr12 = 8,
SdCardSdr25 = 9,
SdCardSdr50 = 10,
SdCardSdr104 = 11,
SdCardDdr50 = 12,
GcAsicFpgaSpeed = 13,
GcAsicSpeed = 14
Unknown = 0,
MmcIdentification = 1,
MmcLegacySpeed = 2,
MmcHighSpeed = 3,
MmcHs200 = 4,
MmcHs400 = 5,
SdCardIdentification = 6,
SdCardDefaultSpeed = 7,
SdCardHighSpeed = 8,
SdCardSdr12 = 9,
SdCardSdr25 = 10,
SdCardSdr50 = 11,
SdCardSdr104 = 12,
SdCardDdr50 = 13,
GcAsicFpgaSpeed = 14,
GcAsicSpeed = 15
}
public enum SdmmcPort

View file

@ -72,9 +72,9 @@ public static class GameCard
}
}
public static Result GetGameCardHandle(this FileSystemClient fs, out GameCardHandle handle)
public static Result GetGameCardHandle(this FileSystemClient fs, out GameCardHandle outHandle)
{
UnsafeHelpers.SkipParamInit(out handle);
UnsafeHelpers.SkipParamInit(out outHandle);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var deviceOperator = new SharedRef<IDeviceOperator>();
@ -83,9 +83,12 @@ public static class GameCard
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
rc = deviceOperator.Get.GetGameCardHandle(out handle);
rc = deviceOperator.Get.GetGameCardHandle(out uint handle);
fs.Impl.AbortIfNeeded(rc);
return rc;
if (rc.IsFailure()) return rc.Miss();
outHandle = new GameCardHandle((int)handle);
return Result.Success;
}
public static Result MountGameCardPartition(this FileSystemClient fs, U8Span mountName, GameCardHandle handle,

View file

@ -1,6 +1,8 @@
using LibHac.Common;
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Sf;
using LibHac.Sf;
namespace LibHac.FsSrv;
@ -17,18 +19,229 @@ public class EmulatedDeviceOperator : IDeviceOperator
public void Dispose() { }
public Result IsSdCardInserted(out bool isInserted)
public Result IsSdCardInserted(out bool outIsInserted)
{
isInserted = SdCard.IsSdCardInserted();
outIsInserted = SdCard.IsSdCardInserted();
return Result.Success;
}
public Result IsGameCardInserted(out bool isInserted)
public Result GetSdCardSpeedMode(out long outSpeedMode)
{
isInserted = GameCard.IsGameCardInserted();
throw new NotImplementedException();
}
public Result GetSdCardCid(OutBuffer outBuffer, long outBufferSize)
{
throw new NotImplementedException();
}
public Result GetSdCardUserAreaSize(out long outSize)
{
throw new NotImplementedException();
}
public Result GetSdCardProtectedAreaSize(out long outSize)
{
throw new NotImplementedException();
}
public Result GetAndClearSdCardErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize,
OutBuffer logBuffer, long logBufferSize)
{
throw new NotImplementedException();
}
public Result GetMmcCid(OutBuffer outBuffer, long outBufferSize)
{
throw new NotImplementedException();
}
public Result GetMmcSpeedMode(out long outSpeedMode)
{
throw new NotImplementedException();
}
public Result EraseMmc(uint partitionId)
{
throw new NotImplementedException();
}
public Result GetMmcPartitionSize(out long outSize, uint partitionId)
{
throw new NotImplementedException();
}
public Result GetMmcPatrolCount(out uint outCount)
{
throw new NotImplementedException();
}
public Result GetAndClearMmcErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize,
OutBuffer logBuffer, long logBufferSize)
{
throw new NotImplementedException();
}
public Result GetMmcExtendedCsd(OutBuffer outBuffer, long outBufferSize)
{
throw new NotImplementedException();
}
public Result SuspendMmcPatrol()
{
throw new NotImplementedException();
}
public Result ResumeMmcPatrol()
{
throw new NotImplementedException();
}
public Result IsGameCardInserted(out bool outIsInserted)
{
outIsInserted = GameCard.IsGameCardInserted();
return Result.Success;
}
public Result EraseGameCard(uint gameCardSize, ulong romAreaStartPageAddress)
{
throw new NotImplementedException();
}
public Result GetGameCardHandle(out uint outHandle)
{
throw new NotImplementedException();
}
public Result GetGameCardUpdatePartitionInfo(out uint outCupVersion, out ulong outCupId, uint handle)
{
throw new NotImplementedException();
}
public Result FinalizeGameCardDriver()
{
throw new NotImplementedException();
}
public Result GetGameCardAttribute(out byte outAttribute, uint handle)
{
throw new NotImplementedException();
}
public Result GetGameCardDeviceCertificate(OutBuffer outBuffer, long outBufferSize, uint handle)
{
throw new NotImplementedException();
}
public Result GetGameCardAsicInfo(OutBuffer outRmaInfoBuffer, long rmaInfoBufferSize, InBuffer asicFirmwareBuffer,
long asicFirmwareBufferSize)
{
throw new NotImplementedException();
}
public Result GetGameCardIdSet(OutBuffer outBuffer, long outBufferSize)
{
throw new NotImplementedException();
}
public Result WriteToGameCardDirectly(long offset, OutBuffer buffer, long bufferSize)
{
throw new NotImplementedException();
}
public Result SetVerifyWriteEnableFlag(bool isEnabled)
{
throw new NotImplementedException();
}
public Result GetGameCardImageHash(OutBuffer outBuffer, long outBufferSize, uint handle)
{
throw new NotImplementedException();
}
public Result GetGameCardDeviceIdForProdCard(OutBuffer outBuffer, long outBufferSize, InBuffer devHeaderBuffer,
long devHeaderBufferSize)
{
throw new NotImplementedException();
}
public Result EraseAndWriteParamDirectly(InBuffer inBuffer, long inBufferSize)
{
throw new NotImplementedException();
}
public Result ReadParamDirectly(OutBuffer outBuffer, long outBufferSize)
{
throw new NotImplementedException();
}
public Result ForceEraseGameCard()
{
throw new NotImplementedException();
}
public Result GetGameCardErrorInfo(out GameCardErrorInfo outErrorInfo)
{
throw new NotImplementedException();
}
public Result GetGameCardErrorReportInfo(out GameCardErrorReportInfo outErrorInfo)
{
throw new NotImplementedException();
}
public Result GetGameCardDeviceId(OutBuffer outBuffer, long outBufferSize)
{
throw new NotImplementedException();
}
public Result ChallengeCardExistence(OutBuffer outResponseBuffer, InBuffer challengeSeedBuffer,
InBuffer challengeValueBuffer, uint handle)
{
throw new NotImplementedException();
}
public Result GetGameCardCompatibilityType(out byte outCompatibilityType, uint handle)
{
throw new NotImplementedException();
}
public Result SetSpeedEmulationMode(int mode)
{
throw new NotImplementedException();
}
public Result GetSpeedEmulationMode(out int outMode)
{
throw new NotImplementedException();
}
public Result SuspendSdmmcControl()
{
throw new NotImplementedException();
}
public Result ResumeSdmmcControl()
{
throw new NotImplementedException();
}
public Result GetSdmmcConnectionStatus(out int outSpeedMode, out int outBusWidth, int port)
{
throw new NotImplementedException();
}
public Result SetDeviceSimulationEvent(uint port, uint simulatedOperationType, uint simulatedFailureType,
uint failureResult, bool autoClearEvent)
{
throw new NotImplementedException();
}
public Result ClearDeviceSimulationEvent(uint port)
{
throw new NotImplementedException();
}
public Result GetGameCardHandle(out GameCardHandle handle)
{
UnsafeHelpers.SkipParamInit(out handle);
@ -39,4 +252,4 @@ public class EmulatedDeviceOperator : IDeviceOperator
handle = GameCard.GetGameCardHandle();
return Result.Success;
}
}
}

View file

@ -45,6 +45,7 @@ internal struct FileSystemServerGlobals : IDisposable
public PooledBufferGlobals PooledBuffer;
public GameCardServiceGlobals GameCardService;
public HierarchicalIntegrityVerificationStorageGlobals HierarchicalIntegrityVerificationStorage;
public SpeedEmulationConfigurationGlobals SpeedEmulationConfiguration;
public void Initialize(HorizonClient horizonClient, FileSystemServer fsServer)
{

View file

@ -0,0 +1,606 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.FsSrv.Sf;
using LibHac.FsSrv.Storage;
using LibHac.FsSystem;
using LibHac.Gc;
using LibHac.Sdmmc;
using LibHac.Sf;
using LibHac.Util;
namespace LibHac.FsSrv.Impl;
/// <summary>
/// Verifies permissions for <see cref="IDeviceOperator"/> calls and forwards them
/// to the appropriate <see cref="LibHac.FsSrv.Storage"/> functions.
/// </summary>
/// <remarks>Based on nnSdk 14.3.0</remarks>
public class DeviceOperator : IDeviceOperator
{
private AccessControl _accessControl;
// ReSharper disable once NotAccessedField.Local
private ulong _processId;
// LibHac addition
private FileSystemServer _fsServer;
public DeviceOperator(FileSystemServer fsServer, AccessControl accessControl, ulong processId)
{
_accessControl = accessControl;
_processId = processId;
_fsServer = fsServer;
}
public void Dispose() { }
private static Span<byte> GetSpan(OutBuffer buffer, long size)
{
Assert.True(IntUtil.IsIntValueRepresentableAsInt(size));
return buffer.Buffer.Slice(0, (int)size);
}
private static ReadOnlySpan<byte> GetSpan(InBuffer buffer, long size)
{
Assert.True(IntUtil.IsIntValueRepresentableAsInt(size));
return buffer.Buffer.Slice(0, (int)size);
}
public Result IsSdCardInserted(out bool outIsInserted)
{
return _fsServer.Storage.IsSdCardInserted(out outIsInserted).Ret();
}
public Result GetSdCardCid(OutBuffer outBuffer, long outBufferSize)
{
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetSdCardCid(GetSpan(outBuffer, outBufferSize)).Ret();
}
public Result GetSdCardSpeedMode(out long outSpeedMode)
{
UnsafeHelpers.SkipParamInit(out outSpeedMode);
Result rc = _fsServer.Storage.GetSdCardSpeedMode(out SdCardSpeedMode speedMode);
if (rc.IsFailure()) return rc.Miss();
outSpeedMode = (long)speedMode;
return Result.Success;
}
public Result GetSdCardUserAreaSize(out long outSize)
{
UnsafeHelpers.SkipParamInit(out outSize);
Result rc = _fsServer.Storage.GetSdCardUserAreaSize(out long size);
if (rc.IsFailure()) return rc.Miss();
outSize = size;
return Result.Success;
}
public Result GetSdCardProtectedAreaSize(out long outSize)
{
UnsafeHelpers.SkipParamInit(out outSize);
Result rc = _fsServer.Storage.GetSdCardProtectedAreaSize(out long size);
if (rc.IsFailure()) return rc.Miss();
outSize = size;
return Result.Success;
}
public Result GetAndClearSdCardErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize,
OutBuffer logBuffer, long logBufferSize)
{
UnsafeHelpers.SkipParamInit(out outStorageErrorInfo, out outLogSize);
if (logBuffer.Size < logBufferSize)
return ResultFs.InvalidSize.Log();
Result rc = _fsServer.Storage.GetAndClearSdCardErrorInfo(out StorageErrorInfo storageErrorInfo,
out long logSize, GetSpan(logBuffer, logBufferSize));
if (rc.IsFailure()) return rc.Miss();
outStorageErrorInfo = storageErrorInfo;
outLogSize = logSize;
return Result.Success;
}
public Result GetMmcCid(OutBuffer outBuffer, long outBufferSize)
{
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetMmcCid(GetSpan(outBuffer, outBufferSize));
}
public Result GetMmcSpeedMode(out long outSpeedMode)
{
UnsafeHelpers.SkipParamInit(out outSpeedMode);
Result rc = _fsServer.Storage.GetMmcSpeedMode(out MmcSpeedMode speedMode);
if (rc.IsFailure()) return rc.Miss();
outSpeedMode = (long)speedMode;
return Result.Success;
}
public Result EraseMmc(uint partitionId)
{
if (!_accessControl.CanCall(OperationType.EraseMmc))
return ResultFs.PermissionDenied.Log();
return _fsServer.Storage.EraseMmc((MmcPartition)partitionId).Ret();
}
public Result GetMmcPartitionSize(out long outSize, uint partitionId)
{
UnsafeHelpers.SkipParamInit(out outSize);
Result rc = _fsServer.Storage.GetMmcPartitionSize(out long mmcPartitionSize, (MmcPartition)partitionId);
if (rc.IsFailure()) return rc.Miss();
outSize = mmcPartitionSize;
return Result.Success;
}
public Result GetMmcPatrolCount(out uint outCount)
{
UnsafeHelpers.SkipParamInit(out outCount);
Result rc = _fsServer.Storage.GetMmcPatrolCount(out uint mmcPatrolCount);
if (rc.IsFailure()) return rc.Miss();
outCount = mmcPatrolCount;
return Result.Success;
}
public Result GetAndClearMmcErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize,
OutBuffer logBuffer, long logBufferSize)
{
UnsafeHelpers.SkipParamInit(out outStorageErrorInfo, out outLogSize);
if (logBuffer.Size < logBufferSize)
return ResultFs.InvalidSize.Log();
Result rc = _fsServer.Storage.GetAndClearMmcErrorInfo(out StorageErrorInfo storageErrorInfo, out long logSize,
GetSpan(logBuffer, logBufferSize));
if (rc.IsFailure()) return rc.Miss();
outStorageErrorInfo = storageErrorInfo;
outLogSize = logSize;
return Result.Success;
}
public Result GetMmcExtendedCsd(OutBuffer outBuffer, long outBufferSize)
{
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetMmcExtendedCsd(GetSpan(outBuffer, outBufferSize)).Ret();
}
public Result SuspendMmcPatrol()
{
if (!_accessControl.CanCall(OperationType.ControlMmcPatrol))
return ResultFs.PermissionDenied.Log();
return _fsServer.Storage.SuspendMmcPatrol().Ret();
}
public Result ResumeMmcPatrol()
{
if (!_accessControl.CanCall(OperationType.ControlMmcPatrol))
return ResultFs.PermissionDenied.Log();
return _fsServer.Storage.ResumeMmcPatrol().Ret();
}
public Result IsGameCardInserted(out bool outIsInserted)
{
UnsafeHelpers.SkipParamInit(out outIsInserted);
Result rc = _fsServer.Storage.IsGameCardInserted(out bool isInserted);
if (rc.IsFailure()) return rc.Miss();
outIsInserted = isInserted;
return Result.Success;
}
public Result EraseGameCard(uint gameCardSize, ulong romAreaStartPageAddress)
{
Accessibility accessibility = _accessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
if (!accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
return _fsServer.Storage.EraseGameCard(gameCardSize, romAreaStartPageAddress).Ret();
}
public Result GetGameCardHandle(out uint outHandle)
{
UnsafeHelpers.SkipParamInit(out outHandle);
Result rc = _fsServer.Storage.GetInitializationResult();
if (rc.IsFailure()) return rc.Miss();
_fsServer.Storage.IsGameCardInserted(out bool isInserted).IgnoreResult();
if (!isInserted)
return ResultFs.GameCardFsGetHandleFailure.Log();
rc = _fsServer.Storage.GetGameCardHandle(out uint handle);
if (rc.IsFailure()) return rc.Miss();
outHandle = handle;
return Result.Success;
}
public Result GetGameCardUpdatePartitionInfo(out uint outCupVersion, out ulong outCupId, uint handle)
{
UnsafeHelpers.SkipParamInit(out outCupVersion, out outCupId);
Result rc = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
if (rc.IsFailure()) return rc.Miss();
outCupVersion = gameCardStatus.UpdatePartitionVersion;
outCupId = gameCardStatus.UpdatePartitionId;
return Result.Success;
}
public Result FinalizeGameCardDriver()
{
if (!_accessControl.CanCall(OperationType.FinalizeGameCardDriver))
return ResultFs.PermissionDenied.Log();
_fsServer.Storage.FinalizeGameCardLibrary().IgnoreResult();
return Result.Success;
}
public Result GetGameCardAttribute(out byte outAttribute, uint handle)
{
UnsafeHelpers.SkipParamInit(out outAttribute);
Result rc = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
if (rc.IsFailure()) return rc.Miss();
outAttribute = gameCardStatus.GameCardAttribute;
return Result.Success;
}
public Result GetGameCardCompatibilityType(out byte outCompatibilityType, uint handle)
{
UnsafeHelpers.SkipParamInit(out outCompatibilityType);
Result rc = _fsServer.Storage.GetGameCardStatus(out GameCardStatus gameCardStatus, handle);
if (rc.IsFailure()) return rc.Miss();
outCompatibilityType = gameCardStatus.CompatibilityType;
return Result.Success;
}
public Result GetGameCardDeviceCertificate(OutBuffer outBuffer, long outBufferSize, uint handle)
{
if (!_accessControl.CanCall(OperationType.GetGameCardDeviceCertificate))
return ResultFs.PermissionDenied.Log();
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetGameCardDeviceCertificate(GetSpan(outBuffer, outBufferSize), handle).Ret();
}
public Result ChallengeCardExistence(OutBuffer outResponseBuffer, InBuffer challengeSeedBuffer,
InBuffer challengeValueBuffer, uint handle)
{
if (!_accessControl.CanCall(OperationType.ChallengeCardExistence))
return ResultFs.PermissionDenied.Log();
return _fsServer.Storage.ChallengeCardExistence(outResponseBuffer.Buffer, challengeSeedBuffer.Buffer,
challengeValueBuffer.Buffer, handle).Ret();
}
public Result GetGameCardAsicInfo(OutBuffer outRmaInfoBuffer, long rmaInfoBufferSize, InBuffer asicFirmwareBuffer,
long asicFirmwareBufferSize)
{
if (!_accessControl.CanCall(OperationType.GetGameCardAsicInfo))
return ResultFs.PermissionDenied.Log();
if (outRmaInfoBuffer.Size < rmaInfoBufferSize)
return ResultFs.InvalidSize.Log();
if (asicFirmwareBuffer.Size < asicFirmwareBufferSize)
return ResultFs.InvalidSize.Log();
if (rmaInfoBufferSize != Unsafe.SizeOf<RmaInformation>())
return ResultFs.InvalidArgument.Log();
Result rc = _fsServer.Storage.GetGameCardAsicInfo(out RmaInformation rmaInfo,
GetSpan(asicFirmwareBuffer, asicFirmwareBufferSize));
if (rc.IsFailure()) return rc.Miss();
SpanHelpers.AsReadOnlyByteSpan(in rmaInfo).CopyTo(outRmaInfoBuffer.Buffer);
return Result.Success;
}
public Result GetGameCardIdSet(OutBuffer outBuffer, long outBufferSize)
{
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
if (outBufferSize != Unsafe.SizeOf<GameCardIdSet>())
return ResultFs.InvalidArgument.Log();
Result rc = _fsServer.Storage.GetGameCardIdSet(out GameCardIdSet gcIdSet);
if (rc.IsFailure()) return rc.Miss();
SpanHelpers.AsReadOnlyByteSpan(in gcIdSet).CopyTo(outBuffer.Buffer);
return Result.Success;
}
public Result WriteToGameCardDirectly(long offset, OutBuffer buffer, long bufferSize)
{
Accessibility accessibility = _accessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
if (!accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
if (buffer.Size < bufferSize)
return ResultFs.InvalidSize.Log();
// Changed: Removed the alignment check for the buffer address
if (!Alignment.IsAlignedPow2(bufferSize, 0x1000))
return ResultFs.InvalidAlignment.Log();
return _fsServer.Storage.WriteToGameCardDirectly(offset, GetSpan(buffer, bufferSize)).Ret();
}
public Result SetVerifyWriteEnableFlag(bool isEnabled)
{
_fsServer.Storage.SetVerifyWriteEnableFlag(isEnabled);
return Result.Success;
}
public Result GetGameCardImageHash(OutBuffer outBuffer, long outBufferSize, uint handle)
{
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetGameCardImageHash(GetSpan(outBuffer, outBufferSize), handle).Ret();
}
public Result GetGameCardDeviceIdForProdCard(OutBuffer outBuffer, long outBufferSize, InBuffer devHeaderBuffer,
long devHeaderBufferSize)
{
Accessibility accessibility = _accessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
if (!accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
if (devHeaderBuffer.Size < devHeaderBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetGameCardDeviceIdForProdCard(GetSpan(outBuffer, outBufferSize),
GetSpan(devHeaderBuffer, devHeaderBufferSize)).Ret();
}
public Result EraseAndWriteParamDirectly(InBuffer inBuffer, long inBufferSize)
{
Accessibility accessibility = _accessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
if (!accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
if (inBuffer.Size < inBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.EraseAndWriteParamDirectly(GetSpan(inBuffer, inBufferSize)).Ret();
}
public Result ReadParamDirectly(OutBuffer outBuffer, long outBufferSize)
{
Accessibility accessibility = _accessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
if (!accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.ReadParamDirectly(GetSpan(outBuffer, outBufferSize)).Ret();
}
public Result ForceEraseGameCard()
{
Accessibility accessibility = _accessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
if (!accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
return _fsServer.Storage.ForceEraseGameCard().Ret();
}
public Result GetGameCardErrorInfo(out GameCardErrorInfo outErrorInfo)
{
UnsafeHelpers.SkipParamInit(out outErrorInfo);
Result rc = _fsServer.Storage.GetGameCardErrorInfo(out GameCardErrorInfo gameCardErrorInfo);
if (rc.IsFailure()) return rc.Miss();
outErrorInfo = gameCardErrorInfo;
return Result.Success;
}
public Result GetGameCardErrorReportInfo(out GameCardErrorReportInfo outErrorInfo)
{
UnsafeHelpers.SkipParamInit(out outErrorInfo);
Result rc = _fsServer.Storage.GetGameCardErrorReportInfo(out GameCardErrorReportInfo gameCardErrorReportInfo);
if (rc.IsFailure()) return rc.Miss();
outErrorInfo = gameCardErrorReportInfo;
return Result.Success;
}
public Result GetGameCardDeviceId(OutBuffer outBuffer, long outBufferSize)
{
if (outBuffer.Size < outBufferSize)
return ResultFs.InvalidSize.Log();
return _fsServer.Storage.GetGameCardDeviceId(GetSpan(outBuffer, outBufferSize)).Ret();
}
public Result SetSpeedEmulationMode(int mode)
{
if (!_accessControl.CanCall(OperationType.SetSpeedEmulationMode))
return ResultFs.PermissionDenied.Log();
_fsServer.SetSpeedEmulationMode((SpeedEmulationMode)mode);
return Result.Success;
}
public Result GetSpeedEmulationMode(out int outMode)
{
outMode = (int)_fsServer.GetSpeedEmulationMode();
return Result.Success;
}
public Result SuspendSdmmcControl()
{
Result rc = _fsServer.Storage.SuspendSdCardControl();
if (rc.IsFailure()) return rc.Miss();
// Missing: Detach SD card device buffer
rc = _fsServer.Storage.SuspendMmcControl();
if (rc.IsFailure()) return rc.Miss();
// Missing: Detach MMC device buffer
return Result.Success;
}
public Result ResumeSdmmcControl()
{
// Missing: Attach MMC device buffer
Result rc = _fsServer.Storage.ResumeMmcControl();
if (rc.IsFailure()) return rc.Miss();
// Missing: Attach SD card device buffer
rc = _fsServer.Storage.ResumeSdCardControl();
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public Result GetSdmmcConnectionStatus(out int outSpeedMode, out int outBusWidth, int port)
{
UnsafeHelpers.SkipParamInit(out outSpeedMode, out outBusWidth);
if ((uint)port > (uint)Port.GcAsic0)
return ResultFs.InvalidArgument.Log();
Result rc = SdmmcSrv.Common.CheckConnection(out SpeedMode speedMode, out BusWidth busWidth, (Port)port);
if (rc.IsFailure()) return rc.Miss();
SdmmcSpeedMode sdmmcSpeedMode = speedMode switch
{
SpeedMode.MmcIdentification => SdmmcSpeedMode.MmcIdentification,
SpeedMode.MmcLegacySpeed => SdmmcSpeedMode.MmcLegacySpeed,
SpeedMode.MmcHighSpeed => SdmmcSpeedMode.MmcHighSpeed,
SpeedMode.MmcHs200 => SdmmcSpeedMode.MmcHs200,
SpeedMode.MmcHs400 => SdmmcSpeedMode.MmcHs400,
SpeedMode.SdCardIdentification => SdmmcSpeedMode.SdCardIdentification,
SpeedMode.SdCardDefaultSpeed => SdmmcSpeedMode.SdCardDefaultSpeed,
SpeedMode.SdCardHighSpeed => SdmmcSpeedMode.SdCardHighSpeed,
SpeedMode.SdCardSdr12 => SdmmcSpeedMode.SdCardSdr12,
SpeedMode.SdCardSdr25 => SdmmcSpeedMode.SdCardSdr25,
SpeedMode.SdCardSdr50 => SdmmcSpeedMode.SdCardSdr50,
SpeedMode.SdCardSdr104 => SdmmcSpeedMode.SdCardSdr104,
SpeedMode.SdCardDdr50 => SdmmcSpeedMode.SdCardDdr50,
SpeedMode.GcAsicFpgaSpeed => SdmmcSpeedMode.GcAsicFpgaSpeed,
SpeedMode.GcAsicSpeed => SdmmcSpeedMode.GcAsicSpeed,
_ => SdmmcSpeedMode.Unknown
};
SdmmcBusWidth sdmmcBusWidth = busWidth switch
{
BusWidth.Width1Bit => SdmmcBusWidth.Width1Bit,
BusWidth.Width4Bit => SdmmcBusWidth.Width4Bit,
BusWidth.Width8Bit => SdmmcBusWidth.Width8Bit,
_ => SdmmcBusWidth.Unknown
};
outSpeedMode = (int)sdmmcSpeedMode;
outBusWidth = (int)sdmmcBusWidth;
return Result.Success;
}
public Result SetDeviceSimulationEvent(uint port, uint simulatedOperationType, uint simulatedFailureType,
uint failureResult, bool autoClearEvent)
{
if (!_accessControl.CanCall(OperationType.SimulateDevice))
return ResultFs.PermissionDenied.Log();
var respondingFailureResult = new Result(failureResult);
switch ((Port)port)
{
case Port.GcAsic0:
_fsServer.Impl.GetGameCardEventSimulator().SetDeviceEvent(
(SimulatingDeviceTargetOperation)simulatedOperationType,
(SimulatingDeviceAccessFailureEventType)simulatedFailureType, respondingFailureResult,
autoClearEvent);
break;
case Port.SdCard0:
_fsServer.Impl.GetSdCardEventSimulator().SetDeviceEvent(
(SimulatingDeviceTargetOperation)simulatedOperationType,
(SimulatingDeviceAccessFailureEventType)simulatedFailureType, respondingFailureResult,
autoClearEvent);
break;
case Port.Mmc0:
return ResultFs.NotImplemented.Log();
default:
return ResultFs.StorageDeviceInvalidOperation.Log();
}
return Result.Success;
}
public Result ClearDeviceSimulationEvent(uint port)
{
if (!_accessControl.CanCall(OperationType.SimulateDevice))
return ResultFs.PermissionDenied.Log();
switch ((Port)port)
{
case Port.GcAsic0:
_fsServer.Impl.GetGameCardEventSimulator().ClearDeviceEvent();
break;
case Port.SdCard0:
_fsServer.Impl.GetSdCardEventSimulator().ClearDeviceEvent();
break;
case Port.Mmc0:
return ResultFs.NotImplemented.Log();
default:
return ResultFs.StorageDeviceInvalidOperation.Log();
}
return Result.Success;
}
}

View file

@ -1,11 +1,52 @@
using System;
using LibHac.Fs;
using LibHac.Sf;
namespace LibHac.FsSrv.Sf;
public interface IDeviceOperator : IDisposable
{
Result IsSdCardInserted(out bool isInserted);
Result IsGameCardInserted(out bool isInserted);
Result GetGameCardHandle(out GameCardHandle handle);
Result IsSdCardInserted(out bool outIsInserted);
Result GetSdCardSpeedMode(out long outSpeedMode);
Result GetSdCardCid(OutBuffer outBuffer, long outBufferSize);
Result GetSdCardUserAreaSize(out long outSize);
Result GetSdCardProtectedAreaSize(out long outSize);
Result GetAndClearSdCardErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize, OutBuffer logBuffer, long logBufferSize);
Result GetMmcCid(OutBuffer outBuffer, long outBufferSize);
Result GetMmcSpeedMode(out long outSpeedMode);
Result EraseMmc(uint partitionId);
Result GetMmcPartitionSize(out long outSize, uint partitionId);
Result GetMmcPatrolCount(out uint outCount);
Result GetAndClearMmcErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize, OutBuffer logBuffer, long logBufferSize);
Result GetMmcExtendedCsd(OutBuffer outBuffer, long outBufferSize);
Result SuspendMmcPatrol();
Result ResumeMmcPatrol();
Result IsGameCardInserted(out bool outIsInserted);
Result EraseGameCard(uint gameCardSize, ulong romAreaStartPageAddress);
Result GetGameCardHandle(out uint outHandle);
Result GetGameCardUpdatePartitionInfo(out uint outCupVersion, out ulong outCupId, uint handle);
Result FinalizeGameCardDriver();
Result GetGameCardAttribute(out byte outAttribute, uint handle);
Result GetGameCardDeviceCertificate(OutBuffer outBuffer, long outBufferSize, uint handle);
Result GetGameCardAsicInfo(OutBuffer outRmaInfoBuffer, long rmaInfoBufferSize, InBuffer asicFirmwareBuffer, long asicFirmwareBufferSize);
Result GetGameCardIdSet(OutBuffer outBuffer, long outBufferSize);
Result WriteToGameCardDirectly(long offset, OutBuffer buffer, long bufferSize);
Result SetVerifyWriteEnableFlag(bool isEnabled);
Result GetGameCardImageHash(OutBuffer outBuffer, long outBufferSize, uint handle);
Result GetGameCardDeviceIdForProdCard(OutBuffer outBuffer, long outBufferSize, InBuffer devHeaderBuffer, long devHeaderBufferSize);
Result EraseAndWriteParamDirectly(InBuffer inBuffer, long inBufferSize);
Result ReadParamDirectly(OutBuffer outBuffer, long outBufferSize);
Result ForceEraseGameCard();
Result GetGameCardErrorInfo(out GameCardErrorInfo outErrorInfo);
Result GetGameCardErrorReportInfo(out GameCardErrorReportInfo outErrorInfo);
Result GetGameCardDeviceId(OutBuffer outBuffer, long outBufferSize);
Result ChallengeCardExistence(OutBuffer outResponseBuffer, InBuffer challengeSeedBuffer, InBuffer challengeValueBuffer, uint handle);
Result GetGameCardCompatibilityType(out byte outCompatibilityType, uint handle);
Result SetSpeedEmulationMode(int mode);
Result GetSpeedEmulationMode(out int outMode);
Result SuspendSdmmcControl();
Result ResumeSdmmcControl();
Result GetSdmmcConnectionStatus(out int outSpeedMode, out int outBusWidth, int port);
Result SetDeviceSimulationEvent(uint port, uint simulatedOperationType, uint simulatedFailureType, uint failureResult, bool autoClearEvent);
Result ClearDeviceSimulationEvent(uint port);
}

View file

@ -0,0 +1,26 @@
using LibHac.Fs;
using LibHac.FsSrv;
namespace LibHac.FsSystem;
internal struct SpeedEmulationConfigurationGlobals
{
public SpeedEmulationMode SpeedEmulationMode;
}
/// <summary>
/// Handles getting and setting the configuration for storage speed emulation.
/// </summary>
/// <remarks>Based on nnSdk 14.3.0</remarks>
internal static class SpeedEmulationConfiguration
{
public static void SetSpeedEmulationMode(this FileSystemServer fsServer, SpeedEmulationMode mode)
{
fsServer.Globals.SpeedEmulationConfiguration.SpeedEmulationMode = mode;
}
public static SpeedEmulationMode GetSpeedEmulationMode(this FileSystemServer fsServer)
{
return fsServer.Globals.SpeedEmulationConfiguration.SpeedEmulationMode;
}
}

View file

@ -0,0 +1,14 @@
using LibHac.Sdmmc;
namespace LibHac.SdmmcSrv;
public static class Common
{
public static Result CheckConnection(out SpeedMode outSpeedMode, out BusWidth outBusWidth, Port port)
{
outSpeedMode = default;
outBusWidth = default;
return Result.Success;
}
}

View file

@ -13,6 +13,11 @@ public static class IntUtil
return value >= 0;
}
public static bool IsIntValueRepresentableAsInt(long value)
{
return value >= int.MinValue && value <= int.MaxValue;
}
public static bool IsIntValueRepresentableAsUInt(long value)
{
return value >= uint.MinValue && value <= uint.MaxValue;