Просмотр исходного кода

ns/nim: Stub eShop related calls (#1420)

* ns/nim: Stub eShop related calls

As we aren't able to process purchase on the eShop throught the emulator, I have:
- Stub IPurchaseEventManager::SetDefaultDeliveryTarget (with RE check).
- Implement IPurchaseEventManager::GetPurchasedEventReadableHandle (with RE check).

As we can't do any eShop async call throught the emulator, I have:
- Stub IShopServiceAccessServerInterface::CreateServerInterface
- Stub IShopServiceAccessServer::CreateAccessorInterface
- Stub IShopServiceAccessor::IShopServiceAsync

Close #1084 and #1322

* fix handle copy

* Fix align

* Fix readonly event
Ac_K 5 лет назад
Родитель
Сommit
ca0d1f8205

+ 1 - 0
Ryujinx.Common/Logging/LogClass.cs

@@ -37,6 +37,7 @@ namespace Ryujinx.Common.Logging
         ServiceMm,
         ServiceNfp,
         ServiceNifm,
+        ServiceNim,
         ServiceNs,
         ServiceNsd,
         ServiceNv,

+ 21 - 0
Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServer.cs

@@ -0,0 +1,21 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer;
+
+namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface
+{
+    class IShopServiceAccessServer : IpcService
+    {
+        public IShopServiceAccessServer() { }
+
+        [Command(0)]
+        // CreateAccessorInterface(u8) -> object<nn::ec::IShopServiceAccessor>
+        public ResultCode CreateAccessorInterface(ServiceCtx context)
+        {
+            MakeObject(context, new IShopServiceAccessor(context.Device.System));
+
+            Logger.PrintStub(LogClass.ServiceNim);
+
+            return ResultCode.Success;
+        }
+    }
+}

+ 15 - 1
Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs

@@ -1,8 +1,22 @@
-namespace Ryujinx.HLE.HOS.Services.Nim
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface;
+
+namespace Ryujinx.HLE.HOS.Services.Nim
 {
     [Service("nim:eca")] // 5.0.0+
     class IShopServiceAccessServerInterface : IpcService
     {
         public IShopServiceAccessServerInterface(ServiceCtx context) { }
+
+        [Command(0)]
+        // CreateServerInterface(pid, handle<unknown>, u64) -> object<nn::ec::IShopServiceAccessServer>
+        public ResultCode CreateServerInterface(ServiceCtx context)
+        {
+            MakeObject(context, new IShopServiceAccessServer());
+
+            Logger.PrintStub(LogClass.ServiceNim);
+
+            return ResultCode.Success;
+        }
     }
 }

+ 37 - 0
Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs

@@ -0,0 +1,37 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer.ShopServiceAccessor;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer
+{
+    class IShopServiceAccessor : IpcService
+    {
+        private readonly KEvent _event;
+
+        public IShopServiceAccessor(Horizon system)
+        {
+            _event = new KEvent(system.KernelContext);
+        }
+
+        [Command(0)]
+        // CreateAsyncInterface(u64) -> (handle<copy>, object<nn::ec::IShopServiceAsync>)
+        public ResultCode CreateAsyncInterface(ServiceCtx context)
+        {
+            MakeObject(context, new IShopServiceAsync());
+
+            if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
+
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+
+            Logger.PrintStub(LogClass.ServiceNim);
+
+            return ResultCode.Success;
+        }
+    }
+}

+ 7 - 0
Ryujinx.HLE/HOS/Services/Nim/IShopServiceAsync.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer.ShopServiceAccessor
+{
+    class IShopServiceAsync : IpcService
+    {
+        public IShopServiceAsync() { }
+    }
+}

+ 2 - 2
Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs

@@ -165,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
         // CreateEcPurchasedEventManager() -> object<nn::ec::IPurchaseEventManager>
         public ResultCode CreateEcPurchasedEventManager(ServiceCtx context)
         {
-            MakeObject(context, new IPurchaseEventManager());
+            MakeObject(context, new IPurchaseEventManager(context.Device.System));
 
             Logger.PrintStub(LogClass.ServiceNs);
 
@@ -178,7 +178,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
         {
             // Very similar to CreateEcPurchasedEventManager but with some extra code
 
-            MakeObject(context, new IPurchaseEventManager());
+            MakeObject(context, new IPurchaseEventManager(context.Device.System));
 
             Logger.PrintStub(LogClass.ServiceNs);
 

+ 46 - 2
Ryujinx.HLE/HOS/Services/Ns/IPurchaseEventManager.cs

@@ -1,8 +1,52 @@
+using Ryujinx.Common;
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
+
 namespace Ryujinx.HLE.HOS.Services.Ns
 {
     class IPurchaseEventManager : IpcService
     {
-        // TODO: Implement this
-        // Size seems to be atleast 0x7a8
+        private readonly KEvent _purchasedEvent;
+
+        public IPurchaseEventManager(Horizon system)
+        {
+            _purchasedEvent = new KEvent(system.KernelContext);
+        }
+
+        [Command(0)]
+        // SetDefaultDeliveryTarget(pid, buffer<bytes, 5> unknown)
+        public ResultCode SetDefaultDeliveryTarget(ServiceCtx context)
+        {
+            long   inBufferPosition = context.Request.SendBuff[0].Position;
+            long   inBufferSize     = context.Request.SendBuff[0].Size;
+            byte[] buffer           = new byte[inBufferSize];
+
+            context.Memory.Read((ulong)inBufferPosition, buffer);
+
+            // NOTE: Service use the pid to call arp:r GetApplicationLaunchProperty and store it in internal field.
+            //       Then it seems to use the buffer content and compare it with a stored linked instrusive list.
+            //       Since we don't support purchase from eShop, we can stub it.
+
+            Logger.PrintStub(LogClass.ServiceNs);
+
+            return ResultCode.Success;
+        }
+
+        [Command(2)]
+        // GetPurchasedEventReadableHandle() -> handle<copy, event>
+        public ResultCode GetPurchasedEventReadableHandle(ServiceCtx context)
+        {
+            if (context.Process.HandleTable.GenerateHandle(_purchasedEvent.ReadableEvent, out int handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
+
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+
+            return ResultCode.Success;
+        }
     }
 }