From 1364f3616111b8517ac48ee506d556c364c8a6a5 Mon Sep 17 00:00:00 2001
From: Ac_K <Acoustik666@gmail.com>
Date: Tue, 19 Jan 2021 03:28:35 +0100
Subject: [PATCH] am: Implement CreateHandleStorage and fixes (#1929)

---
 .../ILibraryAppletCreator.cs                  | 47 +++++++++++++++----
 .../HOS/Services/Am/AppletAE/IStorage.cs      |  8 ++--
 .../Services/Am/AppletAE/IStorageAccessor.cs  |  5 ++
 3 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs
index 5b91e235ed..9fd002a217 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs
@@ -26,8 +26,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         {
             long size = context.RequestData.ReadInt64();
 
+            if (size <= 0)
+            {
+                return ResultCode.ObjectInvalid;
+            }
+
             MakeObject(context, new IStorage(new byte[size]));
 
+            // NOTE: Returns ResultCode.MemoryAllocationFailed if IStorage is null, it doesn't occur in our case.
+
             return ResultCode.Success;
         }
 
@@ -35,20 +42,44 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
         // CreateTransferMemoryStorage(b8, u64, handle<copy>) -> object<nn::am::service::IStorage>
         public ResultCode CreateTransferMemoryStorage(ServiceCtx context)
         {
-            bool unknown = context.RequestData.ReadBoolean();
-            long size    = context.RequestData.ReadInt64();
-            int  handle  = context.Request.HandleDesc.ToCopy[0];
+            bool isReadOnly = context.RequestData.ReadBoolean();
+            long size       = context.RequestData.ReadInt64();
+            int  handle     = context.Request.HandleDesc.ToCopy[0];
 
             KTransferMemory transferMem = context.Process.HandleTable.GetObject<KTransferMemory>(handle);
 
-            if (transferMem == null)
+            if (size <= 0)
             {
-                Logger.Warning?.Print(LogClass.ServiceAm, $"Invalid TransferMemory Handle: {handle:X}");
-
-                return ResultCode.Success; // TODO: Find correct error code
+                return ResultCode.ObjectInvalid;
             }
 
-            var data = new byte[transferMem.Size];
+            byte[] data = new byte[transferMem.Size];
+
+            transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
+
+            context.Device.System.KernelContext.Syscall.CloseHandle(handle);
+
+            MakeObject(context, new IStorage(data, isReadOnly));
+
+            return ResultCode.Success;
+        }
+
+        [Command(12)] // 2.0.0+
+        // CreateHandleStorage(u64, handle<copy>) -> object<nn::am::service::IStorage>
+        public ResultCode CreateHandleStorage(ServiceCtx context)
+        {
+            long size   = context.RequestData.ReadInt64();
+            int  handle = context.Request.HandleDesc.ToCopy[0];
+
+            KTransferMemory transferMem = context.Process.HandleTable.GetObject<KTransferMemory>(handle);
+
+            if (size <= 0)
+            {
+                return ResultCode.ObjectInvalid;
+            }
+
+            byte[] data = new byte[transferMem.Size];
+
             transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
 
             context.Device.System.KernelContext.Syscall.CloseHandle(handle);
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs
index 37514275db..e4b7d1984d 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs
@@ -2,11 +2,13 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
 {
     class IStorage : IpcService
     {
-        public byte[] Data { get; private set; }
+        public bool   IsReadOnly { get; private set; }
+        public byte[] Data       { get; private set; }
 
-        public IStorage(byte[] data)
+        public IStorage(byte[] data, bool isReadOnly = false)
         {
-            Data = data;
+            IsReadOnly = isReadOnly;
+            Data       = data;
         }
 
         [Command(0)]
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs
index ddd97a4c02..721cf1f9d2 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs
@@ -24,6 +24,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
         // Write(u64, buffer<bytes, 0x21>)
         public ResultCode Write(ServiceCtx context)
         {
+            if (_storage.IsReadOnly)
+            {
+                return ResultCode.ObjectInvalid;
+            }
+
             long writePosition = context.RequestData.ReadInt64();
 
             if (writePosition > _storage.Data.Length)