From 4ffc8344273a44ce5dae1bd743ecb40ca02baa81 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 6 Jul 2022 14:49:34 -0700 Subject: [PATCH] Implement most of sdmmcsrv --- .../EmulatedStorageDeviceManagerFactory.cs | 6 +- src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs | 2 +- src/LibHac/Os/SdkMutex.cs | 5 + src/LibHac/Os/UniqueLock.cs | 4 +- src/LibHac/SdmmcSrv/Common.cs | 12 +- src/LibHac/SdmmcSrv/MmcDeviceOperator.cs | 161 ++++++- src/LibHac/SdmmcSrv/MmcManager.cs | 326 +++++++++++-- .../SdmmcSrv/MmcPartitionStorageDevice.cs | 90 +++- src/LibHac/SdmmcSrv/PatrolReader.cs | 5 +- .../SdmmcSrv/SdCardDetectionEventManager.cs | 2 +- src/LibHac/SdmmcSrv/SdCardDeviceOperator.cs | 117 ++++- src/LibHac/SdmmcSrv/SdCardManager.cs | 324 +++++++++++-- src/LibHac/SdmmcSrv/SdCardStorageDevice.cs | 86 +++- src/LibHac/SdmmcSrv/SdmmcResultConverter.cs | 440 +++++++++++++++++- src/LibHac/SdmmcSrv/SdmmcStorage.cs | 102 +++- 15 files changed, 1539 insertions(+), 143 deletions(-) diff --git a/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs b/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs index 72d0a8bf..283cd9f7 100644 --- a/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs +++ b/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs @@ -189,7 +189,8 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory { // Missing: Register device address space - _mmcDeviceManager.Reset(new MmcManager()); + using SharedRef mmcManager = MmcManager.CreateShared(_sdmmc); + _mmcDeviceManager.SetByMove(ref mmcManager.Ref); } } @@ -199,7 +200,8 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory if (!_sdCardDeviceManager.HasValue) { - _sdCardDeviceManager.Reset(new SdCardManager(_sdmmc)); + using SharedRef manager = SdCardManager.CreateShared(_sdmmc); + _sdCardDeviceManager.SetByMove(ref manager.Ref); // Todo: BuiltInStorageFileSystemCreator::SetSdCardPortReady } diff --git a/src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs b/src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs index 9fe61981..aa127913 100644 --- a/src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs +++ b/src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs @@ -7,7 +7,7 @@ namespace LibHac.FsSrv.Storage.Sf; // StorageServiceObjectAdapter is a template that is used with either IStorage or IStorageDevice public interface IStorageDevice : IStorage { - Result GetHandle(out GameCardHandle handle); + Result GetHandle(out uint handle); Result IsHandleValid(out bool isValid); Result OpenOperator(ref SharedRef outDeviceOperator); diff --git a/src/LibHac/Os/SdkMutex.cs b/src/LibHac/Os/SdkMutex.cs index d43d6974..3c6a17a2 100644 --- a/src/LibHac/Os/SdkMutex.cs +++ b/src/LibHac/Os/SdkMutex.cs @@ -36,6 +36,11 @@ public class SdkMutex : ILockable { return _mutex.IsLockedByCurrentThread(); } + + public ref SdkMutexType GetBase() + { + return ref _mutex; + } } public struct SdkMutexType : ILockable diff --git a/src/LibHac/Os/UniqueLock.cs b/src/LibHac/Os/UniqueLock.cs index 2b5e94ea..0e38690c 100644 --- a/src/LibHac/Os/UniqueLock.cs +++ b/src/LibHac/Os/UniqueLock.cs @@ -26,7 +26,7 @@ public static class UniqueLock } #pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type - public static unsafe ref UniqueLockRef Ref(this in UniqueLockRef value) where T : struct, ILockable + public static unsafe ref UniqueLockRef Ref(this scoped in UniqueLockRef value) where T : struct, ILockable { fixed (UniqueLockRef* p = &value) { @@ -70,7 +70,7 @@ public ref struct UniqueLockRef where TMutex : struct, ILockable other = default; } - public void Set(ref UniqueLockRef other) + public void Set(scoped ref UniqueLockRef other) { if (_ownsLock) _mutex.Value.Unlock(); diff --git a/src/LibHac/SdmmcSrv/Common.cs b/src/LibHac/SdmmcSrv/Common.cs index b69cd7a6..4d55089c 100644 --- a/src/LibHac/SdmmcSrv/Common.cs +++ b/src/LibHac/SdmmcSrv/Common.cs @@ -1,8 +1,10 @@ -using LibHac.Sdmmc; +using System; +using LibHac.Fs; +using LibHac.Sdmmc; namespace LibHac.SdmmcSrv; -public static class Common +internal static class Common { public static Result CheckConnection(out SpeedMode outSpeedMode, out BusWidth outBusWidth, Port port) { @@ -12,6 +14,12 @@ public static class Common return Result.Success; } + public static Result GetAndClearSdmmcStorageErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize, + Span logBuffer, SdmmcApi sdmmc) + { + throw new NotImplementedException(); + } + public static uint BytesToSectors(long byteCount) { return (uint)((ulong)byteCount / SdmmcApi.SectorSize); diff --git a/src/LibHac/SdmmcSrv/MmcDeviceOperator.cs b/src/LibHac/SdmmcSrv/MmcDeviceOperator.cs index 96dbe9cb..8f2da126 100644 --- a/src/LibHac/SdmmcSrv/MmcDeviceOperator.cs +++ b/src/LibHac/SdmmcSrv/MmcDeviceOperator.cs @@ -1,54 +1,191 @@ -using System; -using LibHac.Common; +using LibHac.Common; +using LibHac.Diag; +using LibHac.Fs; using LibHac.FsSrv.Storage.Sf; +using LibHac.FsSystem; +using LibHac.Os; +using LibHac.Sdmmc; using LibHac.Sf; +using static LibHac.Sdmmc.SdmmcApi; +using static LibHac.SdmmcSrv.SdmmcResultConverter; +using MmcPartition = LibHac.Sdmmc.MmcPartition; namespace LibHac.SdmmcSrv; internal class MmcDeviceOperator : IStorageDeviceOperator { - private SharedRef _baseDevice; + private SharedRef _storageDevice; - public MmcDeviceOperator(ref SharedRef baseDevice) + // LibHac additions + private readonly SdmmcApi _sdmmc; + + public MmcDeviceOperator(ref SharedRef storageDevice, SdmmcApi sdmmc) { - _baseDevice = SharedRef.CreateMove(ref baseDevice); + _storageDevice = SharedRef.CreateMove(ref storageDevice); + _sdmmc = sdmmc; } public void Dispose() { - _baseDevice.Destroy(); + _storageDevice.Destroy(); } public Result Operate(int operationId) { - throw new NotImplementedException(); + var operation = (MmcOperationIdValue)operationId; + + using var scopedLock = new UniqueLockRef(); + Result res = _storageDevice.Get.Lock(ref scopedLock.Ref()); + if (res.IsFailure()) return res.Miss(); + + switch (operation) + { + case MmcOperationIdValue.Erase: + { + Port port = _storageDevice.Get.GetPort(); + MmcPartition partition = _storageDevice.Get.GetPartition(); + + Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, partition)); + + try + { + res = GetFsResult(port, _sdmmc.EraseMmc(port)); + if (res.IsFailure()) return res.Miss(); + + return Result.Success; + } + finally + { + Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, MmcPartition.UserData)); + } + } + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateIn(InBuffer buffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + return ResultFs.NotImplemented.Log(); } public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId) { - throw new NotImplementedException(); + bytesWritten = 0; + var operation = (MmcOperationIdValue)operationId; + + using var scopedLock = new UniqueLockRef(); + Result res = _storageDevice.Get.Lock(ref scopedLock.Ref()); + if (res.IsFailure()) return res.Miss(); + + Port port = _storageDevice.Get.GetPort(); + + switch (operation) + { + case MmcOperationIdValue.GetSpeedMode: + { + if (buffer.Size < sizeof(SpeedMode)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, _sdmmc.GetDeviceSpeedMode(out buffer.As(), port)); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = sizeof(SpeedMode); + return Result.Success; + } + case MmcOperationIdValue.GetCid: + { + if (buffer.Size < DeviceCidSize) + return ResultFs.InvalidSize.Log(); + + res = GetFsResult(port, _sdmmc.GetDeviceCid(buffer.Buffer.Slice(0, DeviceCidSize), port)); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = DeviceCidSize; + return Result.Success; + } + case MmcOperationIdValue.GetPartitionSize: + { + if (buffer.Size < sizeof(long)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, GetPartitionCapacity(out uint numSectors, port)); + if (res.IsFailure()) return res.Miss(); + + buffer.As() = numSectors * SectorSize; + bytesWritten = sizeof(long); + + return Result.Success; + } + case MmcOperationIdValue.GetExtendedCsd: + { + if (buffer.Size < MmcExtendedCsdSize) + return ResultFs.InvalidSize.Log(); + + using var pooledBuffer = new PooledBuffer(MmcExtendedCsdSize, MmcExtendedCsdSize); + if (pooledBuffer.GetSize() < MmcExtendedCsdSize) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceB.Log(); + + res = GetFsResult(port, _sdmmc.GetMmcExtendedCsd(pooledBuffer.GetBuffer(), port)); + if (res.IsFailure()) return res.Miss(); + + pooledBuffer.GetBuffer().Slice(0, MmcExtendedCsdSize).CopyTo(buffer.Buffer); + bytesWritten = MmcExtendedCsdSize; + + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2, OutBuffer buffer2, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWrittenBuffer1, out bytesWrittenBuffer2); + + return ResultFs.NotImplemented.Log(); } public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); + } + + private Result GetPartitionCapacity(out uint outNumSectors, Port port) + { + UnsafeHelpers.SkipParamInit(out outNumSectors); + + switch (_storageDevice.Get.GetPartition()) + { + case MmcPartition.UserData: + { + Result res = _sdmmc.GetDeviceMemoryCapacity(out outNumSectors, port); + if (res.IsFailure()) return res.Miss(); + + return Result.Success; + } + case MmcPartition.BootPartition1: + case MmcPartition.BootPartition2: + { + Result res = _sdmmc.GetMmcBootPartitionCapacity(out outNumSectors, port); + if (res.IsFailure()) return res.Miss(); + + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/MmcManager.cs b/src/LibHac/SdmmcSrv/MmcManager.cs index 4a90abd4..b7a5fe54 100644 --- a/src/LibHac/SdmmcSrv/MmcManager.cs +++ b/src/LibHac/SdmmcSrv/MmcManager.cs @@ -1,141 +1,399 @@ -using System; +using System.Runtime.CompilerServices; using LibHac.Common; +using LibHac.Fs; using LibHac.FsSrv.Sf; using LibHac.FsSrv.Storage.Sf; using LibHac.Os; using LibHac.Sdmmc; using LibHac.Sf; using IStorage = LibHac.FsSrv.Sf.IStorage; +using MmcPartition = LibHac.Fs.MmcPartition; namespace LibHac.SdmmcSrv; -public class MmcManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager +internal class MmcManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager { - private Port _port; + private const SdmmcHandle MmcHandle = 1; + + private readonly Port _port; private bool _isInitialized; private bool _isActivated; - private SdkMutexType _mutex; + private SdkMutex _mutex; + private readonly SdmmcStorage _sdmmcStorage; + private PatrolReader _patrolReader; - public MmcManager() + // LibHac additions + private WeakRef _selfReference; + private readonly SdmmcApi _sdmmc; + + private MmcManager(SdmmcApi sdmmc) { - throw new NotImplementedException(); + _port = Port.Mmc0; + _mutex = new SdkMutex(); + + _sdmmcStorage = new SdmmcStorage(_port, sdmmc); + _patrolReader = new PatrolReader(_mutex, sdmmc); + + _isInitialized = false; + _isActivated = false; + + // Missing: Setting the device address space + + _sdmmc = sdmmc; + } + + public static SharedRef CreateShared(SdmmcApi sdmmc) + { + var manager = new MmcManager(sdmmc); + + using var sharedManager = new SharedRef(manager); + manager._selfReference.Set(in sharedManager); + + return SharedRef.CreateMove(ref sharedManager.Ref); } public void Dispose() { - throw new NotImplementedException(); + _patrolReader?.Dispose(); + _patrolReader = null; + + _selfReference.Destroy(); } - public void InitializeMmc() + private Result ActivateMmc() { - throw new NotImplementedException(); + InitializeMmc(); + + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_isActivated) + return Result.Success; + + Result res = SdmmcResultConverter.GetFsResult(_port, _sdmmc.Activate(_port)); + if (res.IsFailure()) return res.Miss(); + + _patrolReader.Start(); + _isActivated = true; + + return Result.Success; + } + + private void FinalizeMmc() + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_isInitialized) + _sdmmc.Finalize(_port); + } + + private void InitializeMmc() + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_isInitialized) + return; + + _sdmmc.Initialize(_port); + + // Missing: Register the device buffer + // Missing: Allocate work buffer + + _isInitialized = true; } public Result IsInserted(out bool isInserted) { - throw new NotImplementedException(); + isInserted = true; + + return Result.Success; } public Result IsHandleValid(out bool isValid, SdmmcHandle handle) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out isValid); + + using var scopedLock = new UniqueLockRef(); + isValid = Lock(ref scopedLock.Ref(), handle).IsSuccess(); + + return Result.Success; } public Result OpenDetectionEvent(ref SharedRef outDetectionEvent) { - throw new NotImplementedException(); + return ResultFs.UnsupportedOperation.Log(); } public Result OpenOperator(ref SharedRef outDeviceOperator) { - throw new NotImplementedException(); + Result res = ActivateMmc(); + if (res.IsFailure()) return res.Miss(); + + using SharedRef deviceOperator = SharedRef.Create(in _selfReference); + + if (!deviceOperator.HasValue) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log(); + + outDeviceOperator.SetByMove(ref deviceOperator.Ref); + + return Result.Success; } public Result OpenDevice(ref SharedRef outStorageDevice, ulong attribute) { - throw new NotImplementedException(); + using var storageDevice = new SharedRef(); + + Result res = OpenDeviceImpl(ref storageDevice.Ref, attribute); + if (res.IsFailure()) return res.Miss(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; } public Result OpenStorage(ref SharedRef outStorage, ulong attribute) { - throw new NotImplementedException(); + using var storageDevice = new SharedRef(); + + Result res = OpenDeviceImpl(ref storageDevice.Ref, attribute); + if (res.IsFailure()) return res.Miss(); + + outStorage.SetByMove(ref storageDevice.Ref); + + return Result.Success; } - private Result OpenStorageDevice(ref SharedRef outStorageDevice, ulong attribute) + private Result OpenDeviceImpl(ref SharedRef outStorageDevice, ulong attribute) { - throw new NotImplementedException(); + Result res = ActivateMmc(); + if (res.IsFailure()) return res.Miss(); + + using var storageDevice = new SharedRef(); + + switch ((MmcPartition)attribute) + { + case MmcPartition.UserData: + { + OpenDeviceUserDataPartition(ref storageDevice.Ref); + break; + } + case MmcPartition.BootPartition1: + { + OpenDeviceBootPartition(MmcPartition.BootPartition1, ref storageDevice.Ref); + break; + } + case MmcPartition.BootPartition2: + { + OpenDeviceBootPartition(MmcPartition.BootPartition2, ref storageDevice.Ref); + break; + } + default: + return ResultFs.InvalidArgument.Log(); + } + + if (!storageDevice.HasValue) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; + } + + private void OpenDeviceUserDataPartition(ref SharedRef outStorageDevice) + { + using SharedRef manager = SharedRef.Create(in _selfReference); + + using SharedRef storageDevice = + MmcUserDataPartitionStorageDevice.CreateShared(ref manager.Ref, MmcHandle, _sdmmc); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + } + + private void OpenDeviceBootPartition(MmcPartition partition, ref SharedRef outStorageDevice) + { + using SharedRef manager = SharedRef.Create(in _selfReference); + + using SharedRef storageDevice = + MmcBootPartitionStorageDevice.CreateShared(partition, ref manager.Ref, MmcHandle, _sdmmc); + + outStorageDevice.SetByMove(ref storageDevice.Ref); } public Result PutToSleep() { - throw new NotImplementedException(); + if (_isInitialized) + _patrolReader.Sleep(); + + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_isInitialized) + _sdmmc.PutMmcToSleep(_port); + + return Result.Success; } public Result Awaken() { - throw new NotImplementedException(); + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_isInitialized) + { + _sdmmc.AwakenMmc(_port); + _patrolReader.Resume(); + } + + return Result.Success; } public Result Shutdown() { - throw new NotImplementedException(); + if (_isInitialized) + _patrolReader.Stop(); + + FinalizeMmc(); + + return Result.Success; } public Result Invalidate() { - throw new NotImplementedException(); + return ResultFs.UnsupportedOperation.Log(); } public Result Lock(ref UniqueLockRef outLock, SdmmcHandle handle) { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(ref _mutex.GetBase()); + + if (handle != MmcHandle) + return ResultFs.PortMmcStorageDeviceInvalidated.Log(); + + outLock.Set(ref scopedLock.Ref()); + + return Result.Success; } public Fs.IStorage GetStorage() { - throw new NotImplementedException(); + return _sdmmcStorage; } public Port GetPort() { - throw new NotImplementedException(); + return _port; } - public void NotifyCloseStorageDevice(SdmmcHandle handle) - { - throw new NotImplementedException(); - } + public void NotifyCloseStorageDevice(SdmmcHandle handle) { } public Result Operate(int operationId) { - throw new NotImplementedException(); + var operation = (MmcManagerOperationIdValue)operationId; + + switch (operation) + { + case MmcManagerOperationIdValue.SuspendControl: + case MmcManagerOperationIdValue.ResumeControl: + return ResultFs.StorageDeviceInvalidOperation.Log(); + + case MmcManagerOperationIdValue.SuspendPatrol: + { + _patrolReader.Sleep(); + return Result.Success; + } + case MmcManagerOperationIdValue.ResumePatrol: + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + _patrolReader.Resume(); + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateIn(InBuffer buffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + return ResultFs.NotImplemented.Log(); } public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId) { - throw new NotImplementedException(); + bytesWritten = 0; + var operation = (MmcManagerOperationIdValue)operationId; + + switch (operation) + { + case MmcManagerOperationIdValue.GetPatrolCount: + { + if (buffer.Size < sizeof(uint)) + return ResultFs.InvalidArgument.Log(); + + Result res = _patrolReader.GetPatrolCount(out buffer.As()); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = sizeof(uint); + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2, OutBuffer buffer2, int operationId) { - throw new NotImplementedException(); + bytesWrittenBuffer1 = 0; + bytesWrittenBuffer2 = 0; + var operation = (MmcManagerOperationIdValue)operationId; + + switch (operation) + { + case MmcManagerOperationIdValue.GetAndClearErrorInfo: + { + if (buffer1.Size < Unsafe.SizeOf()) + return ResultFs.InvalidArgument.Log(); + + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + Result res = Common.GetAndClearSdmmcStorageErrorInfo(out buffer1.As(), + out bytesWrittenBuffer2, buffer2.Buffer, _sdmmc); + if (res.IsFailure()) return res.Miss(); + + bytesWrittenBuffer1 = Unsafe.SizeOf(); + return Result.Success; + } + case MmcManagerOperationIdValue.GetAndClearPatrolReadAllocateBufferCount: + { + if (buffer1.Size < sizeof(long)) + return ResultFs.InvalidArgument.Log(); + + if (buffer2.Size < sizeof(long)) + return ResultFs.InvalidArgument.Log(); + + _patrolReader.GetAndClearAllocateCount(out buffer1.As(), out buffer2.As()); + + bytesWrittenBuffer1 = sizeof(long); + bytesWrittenBuffer2 = sizeof(long); + + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/MmcPartitionStorageDevice.cs b/src/LibHac/SdmmcSrv/MmcPartitionStorageDevice.cs index 018878bc..053041a5 100644 --- a/src/LibHac/SdmmcSrv/MmcPartitionStorageDevice.cs +++ b/src/LibHac/SdmmcSrv/MmcPartitionStorageDevice.cs @@ -10,20 +10,30 @@ using MmcPartition = LibHac.Sdmmc.MmcPartition; namespace LibHac.SdmmcSrv; -internal class MmcPartitionStorageDevice : IDisposable +internal abstract class MmcPartitionStorageDevice : IDisposable { private SharedRef _manager; - private SdmmcHandle _handle; - private MmcPartition _partition; + private readonly SdmmcHandle _handle; + private readonly MmcPartition _partition; - public MmcPartitionStorageDevice(ref SharedRef manager, SdmmcHandle handle, MmcPartition partition) + // LibHac addition + protected WeakRef SelfReference; + protected readonly SdmmcApi Sdmmc; + + protected MmcPartitionStorageDevice(MmcPartition partition, ref SharedRef manager, + SdmmcHandle handle, SdmmcApi sdmmc) { + _partition = partition; _manager = SharedRef.CreateMove(ref manager); _handle = handle; - _partition = partition; + Sdmmc = sdmmc; } - public void Dispose() { } + public void Dispose() + { + _manager.Destroy(); + SelfReference.Destroy(); + } public Result GetHandle(out SdmmcHandle handle) { @@ -41,7 +51,18 @@ internal class MmcPartitionStorageDevice : IDisposable public Result OpenOperator(ref SharedRef outDeviceOperator) { - throw new NotImplementedException(); + using SharedRef storageDevice = + SharedRef.Create(in SelfReference); + + using var deviceOperator = + new SharedRef(new MmcDeviceOperator(ref storageDevice.Ref, Sdmmc)); + + if (!deviceOperator.HasValue) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log(); + + outDeviceOperator.SetByMove(ref deviceOperator.Ref); + + return Result.Success; } public Result Lock(ref UniqueLockRef outLock) @@ -63,12 +84,13 @@ internal class MmcPartitionStorageDevice : IDisposable // The Mmc*PartitionStorageDevice classes inherit both from SdmmcStorageInterfaceAdapter and MmcPartitionStorageDevice // Because C# doesn't have multiple inheritance, we make a copy of the SdmmcStorageInterfaceAdapter class that inherits // from MmcPartitionStorageDevice. This class must mirror any changes made to SdmmcStorageInterfaceAdapter. -internal class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDevice, IStorageDevice +internal abstract class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDevice, IStorageDevice { - private IStorage _baseStorage; + private readonly IStorage _baseStorage; - public MmcPartitionStorageDeviceInterfaceAdapter(IStorage baseStorage, ref SharedRef manager, - SdmmcHandle handle, MmcPartition partition) : base(ref manager, handle, partition) + protected MmcPartitionStorageDeviceInterfaceAdapter(IStorage baseStorage, MmcPartition partition, + ref SharedRef manager, SdmmcHandle handle, SdmmcApi sdmmc) + : base(partition, ref manager, handle, sdmmc) { _baseStorage = baseStorage; } @@ -109,10 +131,22 @@ internal class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDe internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter { - public MmcUserDataPartitionStorageDevice(ref SharedRef manager, SdmmcHandle handle) - : base(manager.Get.GetStorage(), ref manager, handle, MmcPartition.UserData) + private MmcUserDataPartitionStorageDevice(ref SharedRef manager, SdmmcHandle handle, + SdmmcApi sdmmc) + : base(manager.Get.GetStorage(), MmcPartition.UserData, ref manager, handle, sdmmc) { } + public static SharedRef CreateShared(ref SharedRef manager, + SdmmcHandle handle, SdmmcApi sdmmc) + { + var storageDevice = new MmcUserDataPartitionStorageDevice(ref manager, handle, sdmmc); + + using var sharedStorageDevice = new SharedRef(storageDevice); + storageDevice.SelfReference.Set(in sharedStorageDevice); + + return SharedRef.CreateMove(ref sharedStorageDevice.Ref); + } + public override Result Read(long offset, OutBuffer destination, long size) { using var scopedLock = new UniqueLockRef(); @@ -157,12 +191,20 @@ internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInte internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter { - private SdmmcApi _sdmmc; + private MmcBootPartitionStorageDevice(Fs.MmcPartition partition, ref SharedRef manager, + SdmmcHandle handle, SdmmcApi sdmmc) + : base(manager.Get.GetStorage(), GetPartition(partition), ref manager, handle, sdmmc) + { } - public MmcBootPartitionStorageDevice(ref SharedRef manager, Fs.MmcPartition partition, - SdmmcHandle handle, SdmmcApi sdmmc) : base(manager.Get.GetStorage(), ref manager, handle, GetPartition(partition)) + public static SharedRef CreateShared(Fs.MmcPartition partition, + ref SharedRef manager, SdmmcHandle handle, SdmmcApi sdmmc) { - _sdmmc = sdmmc; + var storageDevice = new MmcBootPartitionStorageDevice(partition, ref manager, handle, sdmmc); + + using var sharedStorageDevice = new SharedRef(storageDevice); + storageDevice.SelfReference.Set(in sharedStorageDevice); + + return SharedRef.CreateMove(ref sharedStorageDevice.Ref); } private static MmcPartition GetPartition(Fs.MmcPartition partition) @@ -188,7 +230,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac Result res = Lock(ref scopedLock.Ref()); if (res.IsFailure()) return res.Miss(); - Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), GetPartition())); + Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), GetPartition())); try { @@ -199,7 +241,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac } finally { - Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); + Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); } } @@ -210,7 +252,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac Result res = Lock(ref scopedLock.Ref()); if (res.IsFailure()) return res.Miss(); - Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), GetPartition())); + Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), GetPartition())); try { @@ -221,7 +263,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac } finally { - Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); + Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); } } @@ -236,11 +278,11 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac Port port = GetPort(); - Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, GetPartition())); + Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(port, GetPartition())); try { - res = SdmmcResultConverter.GetFsResult(port, _sdmmc.GetMmcBootPartitionCapacity(out uint numSectors, port)); + res = SdmmcResultConverter.GetFsResult(port, Sdmmc.GetMmcBootPartitionCapacity(out uint numSectors, port)); if (res.IsFailure()) return res.Miss(); size = numSectors * SdmmcApi.SectorSize; @@ -249,7 +291,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac } finally { - Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); + Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); } } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/PatrolReader.cs b/src/LibHac/SdmmcSrv/PatrolReader.cs index 546cfd57..14a9744b 100644 --- a/src/LibHac/SdmmcSrv/PatrolReader.cs +++ b/src/LibHac/SdmmcSrv/PatrolReader.cs @@ -1,11 +1,12 @@ using System; using LibHac.Os; +using LibHac.Sdmmc; namespace LibHac.SdmmcSrv; internal class PatrolReader { - public PatrolReader(SdkMutex mutex) + public PatrolReader(SdkMutex mutex, SdmmcApi sdmmc) { throw new NotImplementedException(); } @@ -30,7 +31,7 @@ internal class PatrolReader throw new NotImplementedException(); } - public void GetAndClearAllocateCount(out long outSuccessCount, out long outFailureCount) + public void GetAndClearAllocateCount(out ulong outSuccessCount, out ulong outFailureCount) { throw new NotImplementedException(); } diff --git a/src/LibHac/SdmmcSrv/SdCardDetectionEventManager.cs b/src/LibHac/SdmmcSrv/SdCardDetectionEventManager.cs index 85645ba8..d91b8ce1 100644 --- a/src/LibHac/SdmmcSrv/SdCardDetectionEventManager.cs +++ b/src/LibHac/SdmmcSrv/SdCardDetectionEventManager.cs @@ -6,7 +6,7 @@ namespace LibHac.SdmmcSrv; internal class SdCardDetectionEventManager : CardDeviceDetectionEventManager { // LibHac addition - private SdmmcApi _sdmmc; + private readonly SdmmcApi _sdmmc; public SdCardDetectionEventManager(Port port, SdmmcApi sdmmc) { diff --git a/src/LibHac/SdmmcSrv/SdCardDeviceOperator.cs b/src/LibHac/SdmmcSrv/SdCardDeviceOperator.cs index 14495ac3..267815e3 100644 --- a/src/LibHac/SdmmcSrv/SdCardDeviceOperator.cs +++ b/src/LibHac/SdmmcSrv/SdCardDeviceOperator.cs @@ -1,7 +1,11 @@ -using System; -using LibHac.Common; +using LibHac.Common; +using LibHac.Fs; using LibHac.FsSrv.Storage.Sf; +using LibHac.Os; +using LibHac.Sdmmc; using LibHac.Sf; +using static LibHac.Sdmmc.SdmmcApi; +using static LibHac.SdmmcSrv.SdmmcResultConverter; namespace LibHac.SdmmcSrv; @@ -9,9 +13,13 @@ internal class SdCardDeviceOperator : IStorageDeviceOperator { private SharedRef _storageDevice; - public SdCardDeviceOperator(ref SharedRef storageDevice) + // LibHac additions + private readonly SdmmcApi _sdmmc; + + public SdCardDeviceOperator(ref SharedRef storageDevice, SdmmcApi sdmmc) { - throw new NotImplementedException(); + _storageDevice = SharedRef.CreateMove(ref storageDevice); + _sdmmc = sdmmc; } public void Dispose() @@ -21,34 +29,123 @@ internal class SdCardDeviceOperator : IStorageDeviceOperator public Result Operate(int operationId) { - throw new NotImplementedException(); + return ResultFs.NotImplemented.Log(); } public Result OperateIn(InBuffer buffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + return ResultFs.NotImplemented.Log(); } public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId) { - throw new NotImplementedException(); + bytesWritten = 0; + var operation = (SdCardOperationIdValue)operationId; + + using var scopedLock = new UniqueLockRef(); + Result res = _storageDevice.Get.Lock(ref scopedLock.Ref()); + if (res.IsFailure()) return res.Miss(); + + Port port = _storageDevice.Get.GetPort(); + + switch (operation) + { + case SdCardOperationIdValue.GetSpeedMode: + { + if (buffer.Size < sizeof(SpeedMode)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, _sdmmc.GetDeviceSpeedMode(out buffer.As(), port)); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = sizeof(SpeedMode); + return Result.Success; + } + case SdCardOperationIdValue.GetCid: + { + if (buffer.Size < DeviceCidSize) + return ResultFs.InvalidSize.Log(); + + res = GetFsResult(port, _sdmmc.GetDeviceCid(buffer.Buffer.Slice(0, DeviceCidSize), port)); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = DeviceCidSize; + return Result.Success; + } + case SdCardOperationIdValue.GetUserAreaNumSectors: + { + if (buffer.Size < sizeof(uint)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, _sdmmc.GetDeviceMemoryCapacity(out buffer.As(), port)); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = sizeof(uint); + return Result.Success; + } + case SdCardOperationIdValue.GetUserAreaSize: + { + if (buffer.Size < sizeof(long)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, _sdmmc.GetDeviceMemoryCapacity(out uint numSectors, port)); + if (res.IsFailure()) return res.Miss(); + + buffer.As() = numSectors * SectorSize; + bytesWritten = sizeof(long); + + return Result.Success; + } + case SdCardOperationIdValue.GetProtectedAreaNumSectors: + { + if (buffer.Size < sizeof(uint)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, _sdmmc.GetSdCardProtectedAreaCapacity(out buffer.As(), port)); + if (res.IsFailure()) return res.Miss(); + + bytesWritten = sizeof(uint); + return Result.Success; + } + case SdCardOperationIdValue.GetProtectedAreaSize: + { + if (buffer.Size < sizeof(long)) + return ResultFs.InvalidArgument.Log(); + + res = GetFsResult(port, _sdmmc.GetSdCardProtectedAreaCapacity(out uint numSectors, port)); + if (res.IsFailure()) return res.Miss(); + + buffer.As() = numSectors * SectorSize; + bytesWritten = sizeof(long); + + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2, OutBuffer buffer2, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWrittenBuffer1, out bytesWrittenBuffer2); + + return ResultFs.NotImplemented.Log(); } public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/SdCardManager.cs b/src/LibHac/SdmmcSrv/SdCardManager.cs index 45630576..206295a0 100644 --- a/src/LibHac/SdmmcSrv/SdCardManager.cs +++ b/src/LibHac/SdmmcSrv/SdCardManager.cs @@ -1,28 +1,56 @@ using System; +using System.Runtime.CompilerServices; using LibHac.Common; +using LibHac.Fs; using LibHac.FsSrv.Sf; using LibHac.FsSrv.Storage.Sf; using LibHac.Os; using LibHac.Sdmmc; using LibHac.Sf; using LibHac.Util; +using IStorage = LibHac.Fs.IStorage; +using IStorageSf = LibHac.FsSrv.Sf.IStorage; namespace LibHac.SdmmcSrv; public class SdCardManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager { - private Port _port; + private const SdmmcHandle InvalidHandle = 0; + private const int OpenCountFinalized = -1; + + private readonly Port _port; private bool _isInitialized; + + /// + /// Tracks how many storage devices are open. A value of -1 indicates that the SD card device + /// has been shut down and won't be opened again. + /// + private int _openCount; private SdkMutexType _mutex; - private SdmmcStorage _sdStorage; + private readonly SdmmcStorage _sdStorage; private SdmmcHandle _handle; private Optional _detectionEventManager; - public SdCardManager(SdmmcApi sdmmc) + // LibHac additions + private WeakRef _selfReference; + private readonly SdmmcApi _sdmmc; + + private SdCardManager(SdmmcApi sdmmc) { _port = Port.SdCard0; _mutex = new SdkMutexType(); _sdStorage = new SdmmcStorage(_port, sdmmc); + _sdmmc = sdmmc; + } + + public static SharedRef CreateShared(SdmmcApi sdmmc) + { + var manager = new SdCardManager(sdmmc); + + using var sharedManager = new SharedRef(manager); + manager._selfReference.Set(in sharedManager); + + return SharedRef.CreateMove(ref sharedManager.Ref); } public void Dispose() @@ -30,120 +58,354 @@ public class SdCardManager : IStorageDeviceManager, IStorageDeviceOperator, ISdm if (_detectionEventManager.HasValue) { _detectionEventManager.Value.Dispose(); - _detectionEventManager = default; + _detectionEventManager.Clear(); + } + + _selfReference.Destroy(); + } + + private void DeactivateIfCardRemoved() + { + if (_openCount > 0 && _sdmmc.IsSdCardRemoved(_port)) + { + _sdmmc.Deactivate(_port); + _handle++; + _openCount = 0; } } - public void InitializeSd() + private bool IsShutDown() { - throw new NotImplementedException(); + return _openCount < 0; + } + + private void InitializeSd() + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_isInitialized) + return; + + // Missing: Work buffer management + + if (_detectionEventManager.HasValue) + { + _detectionEventManager.Value.Dispose(); + _detectionEventManager.Clear(); + } + + _detectionEventManager.Set(new SdCardDetectionEventManager(_port, _sdmmc)); + + _isInitialized = true; } public Result IsInserted(out bool isInserted) { - throw new NotImplementedException(); + InitializeSd(); + + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + DeactivateIfCardRemoved(); + + isInserted = _sdmmc.IsSdCardInserted(_port); + return Result.Success; } public Result IsHandleValid(out bool isValid, SdmmcHandle handle) { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + isValid = Lock(ref scopedLock.Ref(), handle).IsSuccess(); + + return Result.Success; } public Result OpenDetectionEvent(ref SharedRef outDetectionEvent) { - throw new NotImplementedException(); + InitializeSd(); + + Result res = _detectionEventManager.Value.CreateDetectionEvent(ref outDetectionEvent); + if (res.IsFailure()) return res.Miss(); + + return Result.Success; } public Result OpenOperator(ref SharedRef outDeviceOperator) { - throw new NotImplementedException(); + InitializeSd(); + + using SharedRef deviceOperator = SharedRef.Create(in _selfReference); + + if (!deviceOperator.HasValue) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log(); + + outDeviceOperator.SetByMove(ref deviceOperator.Ref); + + return Result.Success; + } public Result OpenDevice(ref SharedRef outStorageDevice, ulong attribute) { - throw new NotImplementedException(); + using var storageDevice = new SharedRef(); + + Result res = OpenDeviceImpl(ref storageDevice.Ref); + if (res.IsFailure()) return res.Miss(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; } - public Result OpenStorage(ref SharedRef outStorage, ulong attribute) + public Result OpenStorage(ref SharedRef outStorage, ulong attribute) { - throw new NotImplementedException(); + using var storageDevice = new SharedRef(); + + Result res = OpenDeviceImpl(ref storageDevice.Ref); + if (res.IsFailure()) return res.Miss(); + + outStorage.SetByMove(ref storageDevice.Ref); + + return Result.Success; } - private Result OpenStorageDevice(ref SharedRef outStorageDevice, ulong attribute) + private Result OpenDeviceImpl(ref SharedRef outStorageDevice) { - throw new NotImplementedException(); + InitializeSd(); + + Result res = EnsureActivated(out SdmmcHandle handle); + if (res.IsFailure()) return res.Miss(); + + using SharedRef manager = SharedRef.Create(in _selfReference); + + using SharedRef + storageDevice = SdCardStorageDevice.CreateShared(ref manager.Ref, handle, _sdmmc); + + if (!storageDevice.HasValue) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; + } + + private Result EnsureActivated(out SdmmcHandle outHandle) + { + UnsafeHelpers.SkipParamInit(out outHandle); + + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + DeactivateIfCardRemoved(); + + if (IsShutDown()) + { + outHandle = InvalidHandle; + return Result.Success; + } + + // Activate the device if we're the first to open it. + if (_openCount == 0) + { + Result res = SdmmcResultConverter.GetFsResult(_port, _sdmmc.Activate(_port)); + if (res.IsFailure()) return res.Miss(); + + // Increment the handle if this is the first time the device has been activated. + if (_handle == 0) + { + _handle++; + } + + if (_openCount++ >= 0) + { + outHandle = _handle; + return Result.Success; + } + + outHandle = InvalidHandle; + return Result.Success; + } + + // The device has already been activated. Just increment the open count. + _openCount++; + outHandle = _handle; + return Result.Success; } public Result PutToSleep() { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + if (_isInitialized) + _sdmmc.PutSdCardToSleep(_port); + + return Result.Success; } public Result Awaken() { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + if (_isInitialized) + _sdmmc.AwakenSdCard(_port); + + return Result.Success; } public Result Shutdown() { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + if (_isInitialized) + { + _sdmmc.Deactivate(_port); + _handle++; + _openCount = OpenCountFinalized; + } + + return Result.Success; } public Result Invalidate() { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + if (_openCount > 0) + { + _sdmmc.Deactivate(_port); + _handle++; + _openCount = 0; + } + + return Result.Success; } public Result Lock(ref UniqueLockRef outLock, SdmmcHandle handle) { - throw new NotImplementedException(); + InitializeSd(); + + using var scopedLock = new UniqueLockRef(ref _mutex); + + DeactivateIfCardRemoved(); + + if (handle == InvalidHandle || _handle != handle) + return ResultFs.PortSdCardStorageDeviceInvalidated.Log(); + + outLock.Set(ref scopedLock.Ref()); + + return Result.Success; } - public Fs.IStorage GetStorage() + public IStorage GetStorage() { - throw new NotImplementedException(); + return _sdStorage; } public Port GetPort() { - throw new NotImplementedException(); + return _port; } - public void NotifyCloseStorageDevice(uint handle) + public void NotifyCloseStorageDevice(SdmmcHandle handle) { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + if (_handle != handle) + return; + + if (_openCount > 0) + { + _openCount--; + + if (_openCount == 0) + { + _sdmmc.Deactivate(_port); + _handle++; + } + } } public Result Operate(int operationId) { - throw new NotImplementedException(); + var operation = (SdCardManagerOperationIdValue)operationId; + + switch (operation) + { + case SdCardManagerOperationIdValue.SuspendControl: + case SdCardManagerOperationIdValue.ResumeControl: + return ResultFs.StorageDeviceInvalidOperation.Log(); + + case SdCardManagerOperationIdValue.SimulateDetectionEventSignaled: + _detectionEventManager.Value.SignalAll(); + return Result.Success; + + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateIn(InBuffer buffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + return ResultFs.NotImplemented.Log(); } public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2, OutBuffer buffer2, int operationId) { - throw new NotImplementedException(); + var operation = (SdCardManagerOperationIdValue)operationId; + bytesWrittenBuffer1 = 0; + bytesWrittenBuffer2 = 0; + + switch (operation) + { + case SdCardManagerOperationIdValue.GetAndClearErrorInfo: + { + if (buffer1.Size < Unsafe.SizeOf()) + return ResultFs.InvalidArgument.Log(); + + Result res = GetAndClearSdCardErrorInfo(out buffer1.As(), out bytesWrittenBuffer2, + buffer2.Buffer); + if (res.IsFailure()) return res.Miss(); + + bytesWrittenBuffer1 = Unsafe.SizeOf(); + + return Result.Success; + } + + default: + return ResultFs.InvalidArgument.Log(); + } } public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); } public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2, long offset, long size, int operationId) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out bytesWritten); + + return ResultFs.NotImplemented.Log(); + } + + private Result GetAndClearSdCardErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize, + Span logBuffer) + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + Result res = Common.GetAndClearSdmmcStorageErrorInfo(out outStorageErrorInfo, out outLogSize, logBuffer, _sdmmc); + if (res.IsFailure()) return res.Miss(); + + return Result.Success; } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/SdCardStorageDevice.cs b/src/LibHac/SdmmcSrv/SdCardStorageDevice.cs index 440dd02c..7a9968c4 100644 --- a/src/LibHac/SdmmcSrv/SdCardStorageDevice.cs +++ b/src/LibHac/SdmmcSrv/SdCardStorageDevice.cs @@ -1,5 +1,5 @@ -using System; -using LibHac.Common; +using LibHac.Common; +using LibHac.Fs; using LibHac.FsSrv.Storage.Sf; using LibHac.Os; using LibHac.Sdmmc; @@ -10,52 +10,112 @@ namespace LibHac.SdmmcSrv; internal class SdCardStorageDevice : SdmmcStorageInterfaceAdapter, IStorageDevice { private SharedRef _manager; - private SdmmcHandle _handle; + private readonly SdmmcHandle _handle; - public SdCardStorageDevice(ref SharedRef manager, SdmmcHandle handle) + // LibHac additions + private WeakRef _selfReference; + private readonly SdmmcApi _sdmmc; + + private SdCardStorageDevice(ref SharedRef manager, SdmmcHandle handle, SdmmcApi sdmmc) : base(manager.Get.GetStorage()) { _manager = SharedRef.CreateMove(ref manager); _handle = handle; + _sdmmc = sdmmc; + } + + public static SharedRef CreateShared(ref SharedRef manager, + SdmmcHandle handle, SdmmcApi sdmmc) + { + var device = new SdCardStorageDevice(ref manager, handle, sdmmc); + + using var sharedDevice = new SharedRef(device); + device._selfReference.Set(in sharedDevice); + + return SharedRef.CreateMove(ref sharedDevice.Ref); + } + + public override void Dispose() + { + _manager.Get.NotifyCloseStorageDevice(_handle); + _manager.Destroy(); + + _selfReference.Destroy(); + + base.Dispose(); } public Port GetPort() { - throw new NotImplementedException(); + return _manager.Get.GetPort(); } - public Result GetHandle(out uint handle) + public Result GetHandle(out SdmmcHandle handle) { - throw new NotImplementedException(); + handle = _handle; + return Result.Success; } public Result IsHandleValid(out bool isValid) { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + isValid = Lock(ref scopedLock.Ref()).IsSuccess(); + + return Result.Success; } public Result OpenOperator(ref SharedRef outDeviceOperator) { - throw new NotImplementedException(); + using SharedRef storageDevice = SharedRef.Create(in _selfReference); + + using var deviceOperator = + new SharedRef(new SdCardDeviceOperator(ref storageDevice.Ref, _sdmmc)); + + if (!deviceOperator.HasValue) + return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log(); + + outDeviceOperator.SetByMove(ref deviceOperator.Ref); + + return Result.Success; } public Result Lock(ref UniqueLockRef outLock) { - throw new NotImplementedException(); + Result res = _manager.Get.Lock(ref outLock, _handle); + if (res.IsFailure()) return res.Miss(); + + return Result.Success; } public override Result Read(long offset, OutBuffer destination, long size) { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + Result res = Lock(ref scopedLock.Ref()); + if (res.IsFailure()) return res.Miss(); + + return base.Read(offset, destination, size).Ret(); } public override Result Write(long offset, InBuffer source, long size) { - throw new NotImplementedException(); + using var scopedLock = new UniqueLockRef(); + + Result res = Lock(ref scopedLock.Ref()); + if (res.IsFailure()) return res.Miss(); + + return base.Write(offset, source, size).Ret(); } public override Result GetSize(out long size) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out size); + + using var scopedLock = new UniqueLockRef(); + + Result res = Lock(ref scopedLock.Ref()); + if (res.IsFailure()) return res.Miss(); + + return base.GetSize(out size).Ret(); } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/SdmmcResultConverter.cs b/src/LibHac/SdmmcSrv/SdmmcResultConverter.cs index 9050fb2b..e76bd7a8 100644 --- a/src/LibHac/SdmmcSrv/SdmmcResultConverter.cs +++ b/src/LibHac/SdmmcSrv/SdmmcResultConverter.cs @@ -1,4 +1,4 @@ -using System; +using LibHac.Fs; using LibHac.Sdmmc; namespace LibHac.SdmmcSrv; @@ -22,11 +22,445 @@ public static class SdmmcResultConverter private static Result GetFsResultFromMmcResult(Result result) { - throw new NotImplementedException(); + if (ResultSdmmc.NoDevice.Includes(result)) + return ResultFs.PortMmcNoDevice.LogConverted(result); + + if (ResultSdmmc.NotActivated.Includes(result)) + return ResultFs.PortMmcNotActivated.LogConverted(result); + + if (ResultSdmmc.DeviceRemoved.Includes(result)) + return ResultFs.PortMmcDeviceRemoved.LogConverted(result); + + if (ResultSdmmc.NotAwakened.Includes(result)) + return ResultFs.PortMmcNotAwakened.LogConverted(result); + + + if (ResultSdmmc.ResponseIndexError.Includes(result)) + return ResultFs.PortMmcResponseIndexError.LogConverted(result); + + if (ResultSdmmc.ResponseEndBitError.Includes(result)) + return ResultFs.PortMmcResponseEndBitError.LogConverted(result); + + if (ResultSdmmc.ResponseCrcError.Includes(result)) + return ResultFs.PortMmcResponseCrcError.LogConverted(result); + + if (ResultSdmmc.ResponseTimeoutError.Includes(result)) + return ResultFs.PortMmcResponseTimeoutError.LogConverted(result); + + if (ResultSdmmc.DataEndBitError.Includes(result)) + return ResultFs.PortMmcDataEndBitError.LogConverted(result); + + if (ResultSdmmc.DataCrcError.Includes(result)) + return ResultFs.PortMmcDataCrcError.LogConverted(result); + + if (ResultSdmmc.DataTimeoutError.Includes(result)) + return ResultFs.PortMmcDataTimeoutError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseIndexError.Includes(result)) + return ResultFs.PortMmcAutoCommandResponseIndexError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseEndBitError.Includes(result)) + return ResultFs.PortMmcAutoCommandResponseEndBitError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseCrcError.Includes(result)) + return ResultFs.PortMmcAutoCommandResponseCrcError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseTimeoutError.Includes(result)) + return ResultFs.PortMmcAutoCommandResponseTimeoutError.LogConverted(result); + + if (ResultSdmmc.CommandCompleteSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcCommandCompleteSwTimeout.LogConverted(result); + + if (ResultSdmmc.TransferCompleteSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcTransferCompleteSwTimeout.LogConverted(result); + + + if (ResultSdmmc.DeviceStatusAddressOutOfRange.Includes(result)) + return ResultFs.PortMmcDeviceStatusAddressOutOfRange.LogConverted(result); + + if (ResultSdmmc.DeviceStatusAddressMisaligned.Includes(result)) + return ResultFs.PortMmcDeviceStatusAddressMisalign.LogConverted(result); + + if (ResultSdmmc.DeviceStatusBlockLenError.Includes(result)) + return ResultFs.PortMmcDeviceStatusBlockLenError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusEraseSeqError.Includes(result)) + return ResultFs.PortMmcDeviceStatusEraseSeqError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusEraseParam.Includes(result)) + return ResultFs.PortMmcDeviceStatusEraseParam.LogConverted(result); + + if (ResultSdmmc.DeviceStatusWpViolation.Includes(result)) + return ResultFs.PortMmcDeviceStatusWpViolation.LogConverted(result); + + if (ResultSdmmc.DeviceStatusLockUnlockFailed.Includes(result)) + return ResultFs.PortMmcDeviceStatusLockUnlockFailed.LogConverted(result); + + if (ResultSdmmc.DeviceStatusComCrcError.Includes(result)) + return ResultFs.PortMmcDeviceStatusComCrcError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusIllegalCommand.Includes(result)) + return ResultFs.PortMmcDeviceStatusIllegalCommand.LogConverted(result); + + if (ResultSdmmc.DeviceStatusDeviceEccFailed.Includes(result)) + return ResultFs.PortMmcDeviceStatusDeviceEccFailed.LogConverted(result); + + if (ResultSdmmc.DeviceStatusCcError.Includes(result)) + return ResultFs.PortMmcDeviceStatusCcError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusError.Includes(result)) + return ResultFs.PortMmcDeviceStatusError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusCidCsdOverwrite.Includes(result)) + return ResultFs.PortMmcDeviceStatusCidCsdOverwrite.LogConverted(result); + + if (ResultSdmmc.DeviceStatusWpEraseSkip.Includes(result)) + return ResultFs.PortMmcDeviceStatusWpEraseSkip.LogConverted(result); + + if (ResultSdmmc.DeviceStatusEraseReset.Includes(result)) + return ResultFs.PortMmcDeviceStatusEraseReset.LogConverted(result); + + if (ResultSdmmc.DeviceStatusSwitchError.Includes(result)) + return ResultFs.PortMmcDeviceStatusSwitchError.LogConverted(result); + + + if (ResultSdmmc.UnexpectedDeviceState.Includes(result)) + return ResultFs.PortMmcUnexpectedDeviceState.LogConverted(result); + + if (ResultSdmmc.UnexpectedDeviceCsdValue.Includes(result)) + return ResultFs.PortMmcUnexpectedDeviceCsdValue.LogConverted(result); + + if (ResultSdmmc.AbortTransactionSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcAbortTransactionSwTimeout.LogConverted(result); + + if (ResultSdmmc.CommandInhibitCmdSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcCommandInhibitCmdSwTimeout.LogConverted(result); + + if (ResultSdmmc.CommandInhibitDatSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcCommandInhibitDatSwTimeout.LogConverted(result); + + if (ResultSdmmc.BusySoftwareTimeout.Includes(result)) + return ResultFs.PortMmcBusySwTimeout.LogConverted(result); + + if (ResultSdmmc.IssueTuningCommandSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcIssueTuningCommandSwTimeout.LogConverted(result); + + if (ResultSdmmc.TuningFailed.Includes(result)) + return ResultFs.PortMmcTuningFailed.LogConverted(result); + + if (ResultSdmmc.MmcInitializationSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcMmcInitializationSwTimeout.LogConverted(result); + + if (ResultSdmmc.MmcNotSupportExtendedCsd.Includes(result)) + return ResultFs.PortMmcMmcNotSupportExtendedCsd.LogConverted(result); + + if (ResultSdmmc.UnexpectedMmcExtendedCsdValue.Includes(result)) + return ResultFs.PortMmcUnexpectedMmcExtendedCsdValue.LogConverted(result); + + if (ResultSdmmc.MmcEraseSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcMmcEraseSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdCardValidationError.Includes(result)) + return ResultFs.PortMmcSdCardValidationError.LogConverted(result); + + if (ResultSdmmc.SdCardInitializationSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcSdCardInitializationSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdCardGetValidRcaSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcSdCardGetValidRcaSwTimeout.LogConverted(result); + + if (ResultSdmmc.UnexpectedSdCardAcmdDisabled.Includes(result)) + return ResultFs.PortMmcUnexpectedSdCardAcmdDisabled.LogConverted(result); + + if (ResultSdmmc.SdCardNotSupportSwitchFunctionStatus.Includes(result)) + return ResultFs.PortMmcSdCardNotSupportSwitchFunctionStatus.LogConverted(result); + + if (ResultSdmmc.UnexpectedSdCardSwitchFunctionStatus.Includes(result)) + return ResultFs.PortMmcUnexpectedSdCardSwitchFunctionStatus.LogConverted(result); + + if (ResultSdmmc.SdCardNotSupportAccessMode.Includes(result)) + return ResultFs.PortMmcSdCardNotSupportAccessMode.LogConverted(result); + + if (ResultSdmmc.SdCardNot4BitBusWidthAtUhsIMode.Includes(result)) + return ResultFs.PortMmcSdCardNot4BitBusWidthAtUhsIMode.LogConverted(result); + + if (ResultSdmmc.SdCardNotSupportSdr104AndSdr50.Includes(result)) + return ResultFs.PortMmcSdCardNotSupportSdr104AndSdr50.LogConverted(result); + + if (ResultSdmmc.SdCardCannotSwitchAccessMode.Includes(result)) + return ResultFs.PortMmcSdCardCannotSwitchedAccessMode.LogConverted(result); + + if (ResultSdmmc.SdCardFailedSwitchAccessMode.Includes(result)) + return ResultFs.PortMmcSdCardFailedSwitchedAccessMode.LogConverted(result); + + if (ResultSdmmc.SdCardUnacceptableCurrentConsumption.Includes(result)) + return ResultFs.PortMmcSdCardUnacceptableCurrentConsumption.LogConverted(result); + + if (ResultSdmmc.SdCardNotReadyToVoltageSwitch.Includes(result)) + return ResultFs.PortMmcSdCardNotReadyToVoltageSwitch.LogConverted(result); + + if (ResultSdmmc.SdCardNotCompleteVoltageSwitch.Includes(result)) + return ResultFs.PortMmcSdCardNotCompleteVoltageSwitch.LogConverted(result); + + + if (ResultSdmmc.InternalClockStableSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcInternalClockStableSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdHostStandardUnknownAutoCmdError.Includes(result)) + return ResultFs.PortMmcSdHostStandardUnknownAutoCmdError.LogConverted(result); + + if (ResultSdmmc.SdHostStandardUnknownError.Includes(result)) + return ResultFs.PortMmcSdHostStandardUnknownError.LogConverted(result); + + if (ResultSdmmc.SdmmcDllCalibrationSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcSdmmcDllCalibrationSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdmmcDllApplicationSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcSdmmcDllApplicationSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdHostStandardFailSwitchTo18V.Includes(result)) + return ResultFs.PortMmcSdHostStandardFailSwitchTo18V.LogConverted(result); + + + if (ResultSdmmc.NoWaitedInterrupt.Includes(result)) + return ResultFs.PortMmcNoWaitedInterrupt.LogConverted(result); + + if (ResultSdmmc.WaitInterruptSoftwareTimeout.Includes(result)) + return ResultFs.PortMmcWaitInterruptSwTimeout.LogConverted(result); + + + if (ResultSdmmc.AbortCommandIssued.Includes(result)) + return ResultFs.PortMmcAbortCommandIssued.LogConverted(result); + + + if (ResultSdmmc.NotSupported.Includes(result)) + return ResultFs.PortMmcNotSupported.LogConverted(result); + + if (ResultSdmmc.NotImplemented.Includes(result)) + return ResultFs.PortMmcNotImplemented.LogConverted(result); + + return ResultFs.PortMmcUnexpected.LogConverted(result); } private static Result GetFsResultFromSdCardResult(Result result) { - throw new NotImplementedException(); + if (ResultSdmmc.NoDevice.Includes(result)) + return ResultFs.PortSdCardNoDevice.LogConverted(result); + + if (ResultSdmmc.NotActivated.Includes(result)) + return ResultFs.PortSdCardNotActivated.LogConverted(result); + + if (ResultSdmmc.DeviceRemoved.Includes(result)) + return ResultFs.PortSdCardDeviceRemoved.LogConverted(result); + + if (ResultSdmmc.NotAwakened.Includes(result)) + return ResultFs.PortSdCardNotAwakened.LogConverted(result); + + + if (ResultSdmmc.ResponseIndexError.Includes(result)) + return ResultFs.PortSdCardResponseIndexError.LogConverted(result); + + if (ResultSdmmc.ResponseEndBitError.Includes(result)) + return ResultFs.PortSdCardResponseEndBitError.LogConverted(result); + + if (ResultSdmmc.ResponseCrcError.Includes(result)) + return ResultFs.PortSdCardResponseCrcError.LogConverted(result); + + if (ResultSdmmc.ResponseTimeoutError.Includes(result)) + return ResultFs.PortSdCardResponseTimeoutError.LogConverted(result); + + if (ResultSdmmc.DataEndBitError.Includes(result)) + return ResultFs.PortSdCardDataEndBitError.LogConverted(result); + + if (ResultSdmmc.DataCrcError.Includes(result)) + return ResultFs.PortSdCardDataCrcError.LogConverted(result); + + if (ResultSdmmc.DataTimeoutError.Includes(result)) + return ResultFs.PortSdCardDataTimeoutError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseIndexError.Includes(result)) + return ResultFs.PortSdCardAutoCommandResponseIndexError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseEndBitError.Includes(result)) + return ResultFs.PortSdCardAutoCommandResponseEndBitError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseCrcError.Includes(result)) + return ResultFs.PortSdCardAutoCommandResponseCrcError.LogConverted(result); + + if (ResultSdmmc.AutoCommandResponseTimeoutError.Includes(result)) + return ResultFs.PortSdCardAutoCommandResponseTimeoutError.LogConverted(result); + + if (ResultSdmmc.CommandCompleteSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardCommandCompleteSwTimeout.LogConverted(result); + + if (ResultSdmmc.TransferCompleteSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardTransferCompleteSwTimeout.LogConverted(result); + + + if (ResultSdmmc.DeviceStatusAddressOutOfRange.Includes(result)) + return ResultFs.PortSdCardDeviceStatusAddressOutOfRange.LogConverted(result); + + if (ResultSdmmc.DeviceStatusAddressMisaligned.Includes(result)) + return ResultFs.PortSdCardDeviceStatusAddressMisalign.LogConverted(result); + + if (ResultSdmmc.DeviceStatusBlockLenError.Includes(result)) + return ResultFs.PortSdCardDeviceStatusBlockLenError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusEraseSeqError.Includes(result)) + return ResultFs.PortSdCardDeviceStatusEraseSeqError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusEraseParam.Includes(result)) + return ResultFs.PortSdCardDeviceStatusEraseParam.LogConverted(result); + + if (ResultSdmmc.DeviceStatusWpViolation.Includes(result)) + return ResultFs.PortSdCardDeviceStatusWpViolation.LogConverted(result); + + if (ResultSdmmc.DeviceStatusLockUnlockFailed.Includes(result)) + return ResultFs.PortSdCardDeviceStatusLockUnlockFailed.LogConverted(result); + + if (ResultSdmmc.DeviceStatusComCrcError.Includes(result)) + return ResultFs.PortSdCardDeviceStatusComCrcError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusIllegalCommand.Includes(result)) + return ResultFs.PortSdCardDeviceStatusIllegalCommand.LogConverted(result); + + if (ResultSdmmc.DeviceStatusDeviceEccFailed.Includes(result)) + return ResultFs.PortSdCardDeviceStatusDeviceEccFailed.LogConverted(result); + + if (ResultSdmmc.DeviceStatusCcError.Includes(result)) + return ResultFs.PortSdCardDeviceStatusCcError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusError.Includes(result)) + return ResultFs.PortSdCardDeviceStatusError.LogConverted(result); + + if (ResultSdmmc.DeviceStatusCidCsdOverwrite.Includes(result)) + return ResultFs.PortSdCardDeviceStatusCidCsdOverwrite.LogConverted(result); + + if (ResultSdmmc.DeviceStatusWpEraseSkip.Includes(result)) + return ResultFs.PortSdCardDeviceStatusWpEraseSkip.LogConverted(result); + + if (ResultSdmmc.DeviceStatusEraseReset.Includes(result)) + return ResultFs.PortSdCardDeviceStatusEraseReset.LogConverted(result); + + if (ResultSdmmc.DeviceStatusSwitchError.Includes(result)) + return ResultFs.PortSdCardDeviceStatusSwitchError.LogConverted(result); + + + if (ResultSdmmc.UnexpectedDeviceState.Includes(result)) + return ResultFs.PortSdCardUnexpectedDeviceState.LogConverted(result); + + if (ResultSdmmc.UnexpectedDeviceCsdValue.Includes(result)) + return ResultFs.PortSdCardUnexpectedDeviceCsdValue.LogConverted(result); + + if (ResultSdmmc.AbortTransactionSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardAbortTransactionSwTimeout.LogConverted(result); + + if (ResultSdmmc.CommandInhibitCmdSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardCommandInhibitCmdSwTimeout.LogConverted(result); + + if (ResultSdmmc.CommandInhibitDatSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardCommandInhibitDatSwTimeout.LogConverted(result); + + if (ResultSdmmc.BusySoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardBusySwTimeout.LogConverted(result); + + if (ResultSdmmc.IssueTuningCommandSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardIssueTuningCommandSwTimeout.LogConverted(result); + + if (ResultSdmmc.TuningFailed.Includes(result)) + return ResultFs.PortSdCardTuningFailed.LogConverted(result); + + if (ResultSdmmc.MmcInitializationSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardMmcInitializationSwTimeout.LogConverted(result); + + if (ResultSdmmc.MmcNotSupportExtendedCsd.Includes(result)) + return ResultFs.PortSdCardMmcNotSupportExtendedCsd.LogConverted(result); + + if (ResultSdmmc.UnexpectedMmcExtendedCsdValue.Includes(result)) + return ResultFs.PortSdCardUnexpectedMmcExtendedCsdValue.LogConverted(result); + + if (ResultSdmmc.MmcEraseSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardMmcEraseSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdCardValidationError.Includes(result)) + return ResultFs.PortSdCardSdCardValidationError.LogConverted(result); + + if (ResultSdmmc.SdCardInitializationSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardSdCardInitializationSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdCardGetValidRcaSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardSdCardGetValidRcaSwTimeout.LogConverted(result); + + if (ResultSdmmc.UnexpectedSdCardAcmdDisabled.Includes(result)) + return ResultFs.PortSdCardUnexpectedSdCardAcmdDisabled.LogConverted(result); + + if (ResultSdmmc.SdCardNotSupportSwitchFunctionStatus.Includes(result)) + return ResultFs.PortSdCardSdCardNotSupportSwitchFunctionStatus.LogConverted(result); + + if (ResultSdmmc.UnexpectedSdCardSwitchFunctionStatus.Includes(result)) + return ResultFs.PortSdCardUnexpectedSdCardSwitchFunctionStatus.LogConverted(result); + + if (ResultSdmmc.SdCardNotSupportAccessMode.Includes(result)) + return ResultFs.PortSdCardSdCardNotSupportAccessMode.LogConverted(result); + + if (ResultSdmmc.SdCardNot4BitBusWidthAtUhsIMode.Includes(result)) + return ResultFs.PortSdCardSdCardNot4BitBusWidthAtUhsIMode.LogConverted(result); + + if (ResultSdmmc.SdCardNotSupportSdr104AndSdr50.Includes(result)) + return ResultFs.PortSdCardSdCardNotSupportSdr104AndSdr50.LogConverted(result); + + if (ResultSdmmc.SdCardCannotSwitchAccessMode.Includes(result)) + return ResultFs.PortSdCardSdCardCannotSwitchedAccessMode.LogConverted(result); + + if (ResultSdmmc.SdCardFailedSwitchAccessMode.Includes(result)) + return ResultFs.PortSdCardSdCardFailedSwitchedAccessMode.LogConverted(result); + + if (ResultSdmmc.SdCardUnacceptableCurrentConsumption.Includes(result)) + return ResultFs.PortSdCardSdCardUnacceptableCurrentConsumption.LogConverted(result); + + if (ResultSdmmc.SdCardNotReadyToVoltageSwitch.Includes(result)) + return ResultFs.PortSdCardSdCardNotReadyToVoltageSwitch.LogConverted(result); + + if (ResultSdmmc.SdCardNotCompleteVoltageSwitch.Includes(result)) + return ResultFs.PortSdCardSdCardNotCompleteVoltageSwitch.LogConverted(result); + + + if (ResultSdmmc.InternalClockStableSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardInternalClockStableSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdHostStandardUnknownAutoCmdError.Includes(result)) + return ResultFs.PortSdCardSdHostStandardUnknownAutoCmdError.LogConverted(result); + + if (ResultSdmmc.SdHostStandardUnknownError.Includes(result)) + return ResultFs.PortSdCardSdHostStandardUnknownError.LogConverted(result); + + if (ResultSdmmc.SdmmcDllCalibrationSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardSdmmcDllCalibrationSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdmmcDllApplicationSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardSdmmcDllApplicationSwTimeout.LogConverted(result); + + if (ResultSdmmc.SdHostStandardFailSwitchTo18V.Includes(result)) + return ResultFs.PortSdCardSdHostStandardFailSwitchTo18V.LogConverted(result); + + + if (ResultSdmmc.NoWaitedInterrupt.Includes(result)) + return ResultFs.PortSdCardNoWaitedInterrupt.LogConverted(result); + + if (ResultSdmmc.WaitInterruptSoftwareTimeout.Includes(result)) + return ResultFs.PortSdCardWaitInterruptSwTimeout.LogConverted(result); + + + if (ResultSdmmc.AbortCommandIssued.Includes(result)) + return ResultFs.PortSdCardAbortCommandIssued.LogConverted(result); + + + if (ResultSdmmc.NotSupported.Includes(result)) + return ResultFs.PortSdCardNotSupported.LogConverted(result); + + if (ResultSdmmc.NotImplemented.Includes(result)) + return ResultFs.PortSdCardNotImplemented.LogConverted(result); + + return ResultFs.PortSdCardUnexpected.LogConverted(result); } } \ No newline at end of file diff --git a/src/LibHac/SdmmcSrv/SdmmcStorage.cs b/src/LibHac/SdmmcSrv/SdmmcStorage.cs index bb22a746..7643da57 100644 --- a/src/LibHac/SdmmcSrv/SdmmcStorage.cs +++ b/src/LibHac/SdmmcSrv/SdmmcStorage.cs @@ -1,8 +1,15 @@ using System; +using System.Runtime.CompilerServices; using LibHac.Common; +using LibHac.Diag; using LibHac.Fs; +using LibHac.FsSystem; using LibHac.Sdmmc; using LibHac.Sf; +using LibHac.Util; +using static LibHac.Sdmmc.SdmmcApi; +using static LibHac.SdmmcSrv.Common; +using static LibHac.SdmmcSrv.SdmmcResultConverter; using IStorageSf = LibHac.FsSrv.Sf.IStorage; namespace LibHac.SdmmcSrv; @@ -22,33 +29,116 @@ internal class SdmmcStorage : IStorage public override Result Read(long offset, Span destination) { - throw new NotImplementedException(); + Assert.SdkRequiresAligned(offset, SectorSize); + Assert.SdkRequiresAligned(destination.Length, SectorSize); + + if (destination.Length == 0) + return Result.Success; + + // Missing: Allocate a device buffer if the destination buffer is not one + + return _sdmmc.Read(destination, _port, BytesToSectors(offset), BytesToSectors(destination.Length)).Ret(); } public override Result Write(long offset, ReadOnlySpan source) { - throw new NotImplementedException(); + const int alignment = 0x4000; + Result res; + + Assert.SdkRequiresAligned(offset, SectorSize); + Assert.SdkRequiresAligned(source.Length, SectorSize); + + if (source.Length == 0) + return Result.Success; + + // Missing: Allocate a device buffer if the source buffer is not one + + // Check if we have any unaligned data at the head of the source buffer. + long alignedUpOffset = Alignment.AlignUp(offset, alignment); + int unalignedHeadSize = (int)(alignedUpOffset - offset); + int remainingSize = source.Length; + + // The start offset must be aligned to 0x4000 bytes. The end offset does not need to be aligned to 0x4000 bytes. + if (alignedUpOffset != offset) + { + // Get the number of bytes that come before the unaligned data. + int paddingSize = alignment - unalignedHeadSize; + + // If the end offset is inside the first 0x4000-byte block, don't write past the end offset. + // Otherwise write the entire aligned block. + int writeSize = Math.Min(alignment, paddingSize + source.Length); + + using var pooledBuffer = new PooledBuffer(writeSize, alignment); + + // Get the number of bytes from source to be written to the aligned buffer, and copy that data to the buffer. + int unalignedSize = writeSize - paddingSize; + source.Slice(0, unalignedSize).CopyTo(pooledBuffer.GetBuffer().Slice(paddingSize)); + + // Read the current data into the aligned buffer. + res = GetFsResult(_port, + _sdmmc.Read(pooledBuffer.GetBuffer().Slice(0, paddingSize), _port, + BytesToSectors(alignedUpOffset - alignment), BytesToSectors(paddingSize))); + if (res.IsFailure()) return res.Miss(); + + // Write the aligned buffer. + res = GetFsResult(_port, + _sdmmc.Write(_port, BytesToSectors(alignedUpOffset - alignment), BytesToSectors(writeSize), + pooledBuffer.GetBuffer().Slice(0, writeSize))); + if (res.IsFailure()) return res.Miss(); + + remainingSize -= unalignedSize; + } + + // We've written any unaligned data. Write the remaining aligned data. + if (remainingSize > 0) + { + res = GetFsResult(_port, + _sdmmc.Write(_port, BytesToSectors(alignedUpOffset), BytesToSectors(remainingSize), + source.Slice(unalignedHeadSize, remainingSize))); + if (res.IsFailure()) return res.Miss(); + } + + return Result.Success; } public override Result Flush() { - throw new NotImplementedException(); + return Result.Success; } public override Result SetSize(long size) { - throw new NotImplementedException(); + return ResultFs.UnsupportedSetSizeForSdmmcStorage.Log(); } public override Result GetSize(out long size) { - throw new NotImplementedException(); + UnsafeHelpers.SkipParamInit(out size); + + Result res = GetFsResult(_port, _sdmmc.GetDeviceMemoryCapacity(out uint numSectors, _port)); + if (res.IsFailure()) return res.Miss(); + + size = numSectors * SectorSize; + return Result.Success; } public override Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) { - throw new NotImplementedException(); + switch (operationId) + { + case OperationId.InvalidateCache: + return Result.Success; + case OperationId.QueryRange: + if (outBuffer.Length != Unsafe.SizeOf()) + return ResultFs.InvalidSize.Log(); + + SpanHelpers.AsStruct(outBuffer).Clear(); + + return Result.Success; + default: + return ResultFs.UnsupportedOperateRangeForSdmmcStorage.Log(); + } } }